add search bar
This commit is contained in:
parent
cec41d9cbb
commit
c23994091b
|
@ -9,6 +9,7 @@
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"delay": "^6.0.0",
|
||||||
"ky": "^1.7.2",
|
"ky": "^1.7.2",
|
||||||
"preact": "^10.24.3",
|
"preact": "^10.24.3",
|
||||||
"react-draggable-list": "^4.2.1",
|
"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 { useCallback, useEffect, useState } from "preact/hooks";
|
||||||
import { DataRow } from "../api/DataRow";
|
import { DataRow, DataRowSearchOptions } from "../api/DataRow";
|
||||||
import style from './index.module.scss';
|
import style from './index.module.scss';
|
||||||
import { Posts } from "../components/Posts";
|
import { Posts } from "../components/Posts";
|
||||||
|
|
||||||
import InfiniteScroller from 'react-infinite-scroller';
|
import InfiniteScroller from 'react-infinite-scroller';
|
||||||
import { DraggablePostsList } from "../components/DraggablePostsList";
|
import { DraggablePostsList } from "../components/DraggablePostsList";
|
||||||
import { DataRowSelection } from "../api/DataRowSelection";
|
import { DataRowSelection } from "../api/DataRowSelection";
|
||||||
|
import { SearchBar } from "../components/display/SearchBar";
|
||||||
|
import delay from "delay";
|
||||||
|
|
||||||
export function Index() {
|
export function Index() {
|
||||||
const [ data, setData ] = useState(null as null | DataRow[]);
|
const [ data, setData ] = useState(null as null | DataRow[]);
|
||||||
|
@ -15,6 +17,8 @@ export function Index() {
|
||||||
const [ hasMore, setHasMore ] = useState(true);
|
const [ hasMore, setHasMore ] = useState(true);
|
||||||
const [ fetching, setFetching ] = useState(false);
|
const [ fetching, setFetching ] = useState(false);
|
||||||
|
|
||||||
|
const [ filter, setFilter ] = useState(null as null | string);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
setSelected(await dataRowSelection.get());
|
setSelected(await dataRowSelection.get());
|
||||||
|
@ -22,14 +26,17 @@ export function Index() {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fetchMore = useCallback(
|
const fetchMore = useCallback(
|
||||||
async function(_page: number) {
|
async function() {
|
||||||
if (fetching) return;
|
if (fetching) return;
|
||||||
|
|
||||||
setFetching(true);
|
setFetching(true);
|
||||||
// await new Promise(r => setTimeout(r, 1000));
|
|
||||||
const newData = await DataRow.find({
|
const query = {
|
||||||
page: data ? Math.floor(data.length / 20) : 0
|
page: data ? Math.floor(data.length / 20) : 0,
|
||||||
});
|
} as DataRowSearchOptions;
|
||||||
|
if (filter) query.search = `%${filter}%`;
|
||||||
|
|
||||||
|
const newData = await DataRow.find(query);
|
||||||
setData([ ...data ?? [], ...newData ]);
|
setData([ ...data ?? [], ...newData ]);
|
||||||
setHasMore(newData.length === 20);
|
setHasMore(newData.length === 20);
|
||||||
setFetching(false);
|
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 (
|
return (
|
||||||
<div className={style.index}>
|
<div className={style.index}>
|
||||||
|
|
||||||
{
|
{
|
||||||
selected
|
selected
|
||||||
?
|
?
|
||||||
|
@ -65,6 +82,8 @@ export function Index() {
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<SearchBar onSearch={search} placeholder="filter" />
|
||||||
|
|
||||||
<InfiniteScroller
|
<InfiniteScroller
|
||||||
pageStart={0}
|
pageStart={0}
|
||||||
loadMore={fetchMore}
|
loadMore={fetchMore}
|
||||||
|
|
|
@ -678,6 +678,11 @@ debug@^4.1.0, debug@^4.3.1, debug@^4.3.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms "^2.1.3"
|
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:
|
detect-libc@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||||
|
|
Loading…
Reference in New Issue