add search bar
This commit is contained in:
parent
cec41d9cbb
commit
c23994091b
|
@ -9,6 +9,7 @@
|
|||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"delay": "^6.0.0",
|
||||
"ky": "^1.7.2",
|
||||
"preact": "^10.24.3",
|
||||
"react-draggable-list": "^4.2.1",
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
.search {
|
||||
margin: 1rem 0;
|
||||
|
||||
border: 1px solid gray;
|
||||
|
||||
display: flex;
|
||||
|
||||
* {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
input {
|
||||
border: none;
|
||||
background: none;
|
||||
height: 100%; width: 100%;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
background: royalblue;
|
||||
border: none;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import { useState } from "preact/hooks";
|
||||
import styles from './SearchBar.module.scss';
|
||||
import { SearchIcon } from "./SearchIcon";
|
||||
import { TargetedEvent } from "preact/compat";
|
||||
|
||||
export type SearchBarProps = {
|
||||
default?: string,
|
||||
placeholder?: string,
|
||||
onChange?: (data: string) => void,
|
||||
onSearch?: (data: string) => void
|
||||
};
|
||||
export function SearchBar({ default: def, placeholder, onChange, onSearch }: SearchBarProps) {
|
||||
const [ query, setQuery ] = useState(def ?? '');
|
||||
|
||||
function updateValue(e: TargetedEvent<HTMLInputElement>) {
|
||||
setQuery(e.currentTarget.value);
|
||||
if (onChange) onChange(e.currentTarget.value);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.search}>
|
||||
<SearchIcon />
|
||||
<input type='text' value={query} onChange={updateValue} placeholder={placeholder} />
|
||||
<button onClick={onSearch ? () => onSearch(query) : undefined}>go</button>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import type React from "preact/compat";
|
||||
|
||||
export function SearchIcon(props: React.JSX.SVGAttributes<SVGSVGElement>) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16" {...props}>
|
||||
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
import { useCallback, useEffect, useState } from "preact/hooks";
|
||||
import { DataRow } from "../api/DataRow";
|
||||
import { DataRow, DataRowSearchOptions } from "../api/DataRow";
|
||||
import style from './index.module.scss';
|
||||
import { Posts } from "../components/Posts";
|
||||
|
||||
import InfiniteScroller from 'react-infinite-scroller';
|
||||
import { DraggablePostsList } from "../components/DraggablePostsList";
|
||||
import { DataRowSelection } from "../api/DataRowSelection";
|
||||
import { SearchBar } from "../components/display/SearchBar";
|
||||
import delay from "delay";
|
||||
|
||||
export function Index() {
|
||||
const [ data, setData ] = useState(null as null | DataRow[]);
|
||||
|
@ -15,6 +17,8 @@ export function Index() {
|
|||
const [ hasMore, setHasMore ] = useState(true);
|
||||
const [ fetching, setFetching ] = useState(false);
|
||||
|
||||
const [ filter, setFilter ] = useState(null as null | string);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
setSelected(await dataRowSelection.get());
|
||||
|
@ -22,14 +26,17 @@ export function Index() {
|
|||
}, []);
|
||||
|
||||
const fetchMore = useCallback(
|
||||
async function(_page: number) {
|
||||
async function() {
|
||||
if (fetching) return;
|
||||
|
||||
setFetching(true);
|
||||
// await new Promise(r => setTimeout(r, 1000));
|
||||
const newData = await DataRow.find({
|
||||
page: data ? Math.floor(data.length / 20) : 0
|
||||
});
|
||||
|
||||
const query = {
|
||||
page: data ? Math.floor(data.length / 20) : 0,
|
||||
} as DataRowSearchOptions;
|
||||
if (filter) query.search = `%${filter}%`;
|
||||
|
||||
const newData = await DataRow.find(query);
|
||||
setData([ ...data ?? [], ...newData ]);
|
||||
setHasMore(newData.length === 20);
|
||||
setFetching(false);
|
||||
|
@ -52,9 +59,19 @@ export function Index() {
|
|||
}
|
||||
}
|
||||
|
||||
async function search(query: string) {
|
||||
setFetching(true);
|
||||
|
||||
setHasMore(true);
|
||||
setFilter(query);
|
||||
setData(null);
|
||||
await delay(0); // stupid thing won't work w/o delay
|
||||
|
||||
setFetching(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={style.index}>
|
||||
|
||||
{
|
||||
selected
|
||||
?
|
||||
|
@ -65,6 +82,8 @@ export function Index() {
|
|||
: null
|
||||
}
|
||||
|
||||
<SearchBar onSearch={search} placeholder="filter" />
|
||||
|
||||
<InfiniteScroller
|
||||
pageStart={0}
|
||||
loadMore={fetchMore}
|
||||
|
|
|
@ -678,6 +678,11 @@ debug@^4.1.0, debug@^4.3.1, debug@^4.3.4:
|
|||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
delay@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delay/-/delay-6.0.0.tgz#43749aefdf6cabd9e17b0d00bd3904525137e607"
|
||||
integrity sha512-2NJozoOHQ4NuZuVIr5CWd0iiLVIRSDepakaovIN+9eIDHEhdCAEvSy2cuf1DCrPPQLvHmbqTHODlhHg8UCy4zw==
|
||||
|
||||
detect-libc@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||
|
|
Loading…
Reference in New Issue