scroll view and boilderplate selection
This commit is contained in:
parent
6dcce42cab
commit
9f7c9f5e10
|
@ -10,10 +10,12 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"ky": "^1.7.2",
|
||||
"preact": "^10.24.3"
|
||||
"preact": "^10.24.3",
|
||||
"react-infinite-scroller": "^1.2.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preact/preset-vite": "^2.9.1",
|
||||
"@types/react-infinite-scroller": "^1.2.5",
|
||||
"sass": "^1.80.6",
|
||||
"sass-embedded": "^1.80.6",
|
||||
"typescript": "~5.6.2",
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
.posts {
|
||||
display: block;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
|
@ -1,13 +1,34 @@
|
|||
import { ComponentChildren, toChildArray } from "preact";
|
||||
import { DataRow } from "../api/DataRow";
|
||||
import style from './Posts.module.scss';
|
||||
import { Post } from "./display/Post";
|
||||
|
||||
export type PostsProps = { rows: DataRow[] };
|
||||
export type PostsProps = {
|
||||
rows: DataRow[],
|
||||
checked?: boolean,
|
||||
onSelectChange?: (row: DataRow) => void
|
||||
};
|
||||
|
||||
export function Posts(props: PostsProps) {
|
||||
|
||||
function onChange(row: DataRow) {
|
||||
if (props.onSelectChange) props.onSelectChange(row)
|
||||
}
|
||||
|
||||
export function Posts({ rows }: PostsProps) {
|
||||
return (
|
||||
<div className={style.posts}>
|
||||
{ rows.map(row => <Post row={row} />) }
|
||||
</div>
|
||||
<ul className={style.posts}>
|
||||
{
|
||||
props.rows.map(
|
||||
row =>
|
||||
<li>
|
||||
<span>
|
||||
<label for={`row-list-${row.id}`} style={{ display: 'none' }}>Select</label>
|
||||
<input type='checkbox' checked={props.checked ?? false} id={`row-list-${row.id}`} onChange={_ => onChange(row)}/>
|
||||
</span>
|
||||
<Post row={row} />
|
||||
</li>
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
);
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
.index {
|
||||
.selection {
|
||||
background: antiquewhite;
|
||||
}
|
||||
.paginator {
|
||||
border-bottom: 1px solid black;
|
||||
padding-bottom: 1rem;
|
||||
|
|
|
@ -1,63 +1,70 @@
|
|||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useCallback, useState } from "preact/hooks";
|
||||
import { DataRow } from "../api/DataRow";
|
||||
import style from './index.module.scss';
|
||||
import { Posts } from "../components/Posts";
|
||||
import { Paginator } from "../components/display/Paginator";
|
||||
|
||||
const cachedPages: {
|
||||
[ key: number ]: DataRow[]
|
||||
} = {};
|
||||
import InfiniteScroller from 'react-infinite-scroller';
|
||||
|
||||
let firstRender = true;
|
||||
// let page = -1;
|
||||
|
||||
export function Index() {
|
||||
const [ data, setData ] = useState(null as null | DataRow[]);
|
||||
const [ page, setPage ] = useState(NaN);
|
||||
const [ pageBlocked, setPageBlocked ] = useState(false);
|
||||
const [ selected, setSelected ] = useState(null as null | DataRow[]);
|
||||
|
||||
async function goToPage(newPage: number) {
|
||||
if (newPage < 0) newPage = 0;
|
||||
if (pageBlocked) return;
|
||||
const [ hasMore, setHasMore ] = useState(true);
|
||||
const [ fetching, setFetching ] = useState(false);
|
||||
|
||||
let newData = null as DataRow[] | null;
|
||||
if (cachedPages[newPage]) {
|
||||
newData = cachedPages[newPage];
|
||||
} else {
|
||||
setData(null);
|
||||
}
|
||||
const fetchMore = useCallback(
|
||||
async function(_page: number) {
|
||||
if (fetching) return;
|
||||
|
||||
setPage(newPage);
|
||||
setPageBlocked(true);
|
||||
try {
|
||||
newData = await DataRow.find({
|
||||
page: newPage
|
||||
setFetching(true);
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
const newData = await DataRow.find({
|
||||
page: data ? Math.floor(data.length / 20) : 0
|
||||
});
|
||||
} catch (_) {
|
||||
return setPageBlocked(false)
|
||||
}
|
||||
setData([ ...data ?? [], ...newData ]);
|
||||
setHasMore(newData.length === 20);
|
||||
setFetching(false);
|
||||
},
|
||||
[ fetching, hasMore ]
|
||||
);
|
||||
|
||||
if (newData === undefined) {
|
||||
newData = [] as DataRow[];
|
||||
function select(row: DataRow) {
|
||||
console.log(row);
|
||||
if (data) {
|
||||
if (data.indexOf(row) == -1) throw new Error('Selected element that does not exist');
|
||||
setSelected([ ...selected ?? [], row ])
|
||||
setData(data)
|
||||
}
|
||||
|
||||
cachedPages[newPage] = newData;
|
||||
setPageBlocked(false);
|
||||
setData(newData);
|
||||
}
|
||||
|
||||
if (firstRender) {
|
||||
goToPage(0);
|
||||
firstRender = false;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={style.index}>
|
||||
<Paginator page={page} onChange={goToPage} className={style.paginator} />
|
||||
|
||||
{
|
||||
selected
|
||||
?
|
||||
<div className={style.selection}>
|
||||
<h2>Selection</h2>
|
||||
<Posts rows={selected} checked />
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
|
||||
<InfiniteScroller
|
||||
pageStart={0}
|
||||
loadMore={fetchMore}
|
||||
hasMore={hasMore}
|
||||
loader={<pre>loading . . .</pre>}
|
||||
useWindow={false}
|
||||
>
|
||||
{
|
||||
data
|
||||
? <Posts rows={data} />
|
||||
: <pre>loading . . .</pre>
|
||||
? <Posts rows={data.filter(x => selected ? selected?.indexOf(x) === -1 : true)} onSelectChange={select} />
|
||||
: <></>
|
||||
}
|
||||
</InfiniteScroller>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -569,6 +569,26 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50"
|
||||
integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.13"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451"
|
||||
integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==
|
||||
|
||||
"@types/react-infinite-scroller@^1.2.5":
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-infinite-scroller/-/react-infinite-scroller-1.2.5.tgz#7c770be59465f3aaa1b86377d792d52de5e74047"
|
||||
integrity sha512-fJU1jhMgoL6NJFrqTM0Ob7tnd2sQWGxe2ESwiU6FZWbJK/VO/Er5+AOhc+e2zbT0dk5pLygqctsulOLJ8xnSzw==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*":
|
||||
version "18.3.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.12.tgz#99419f182ccd69151813b7ee24b792fe08774f60"
|
||||
integrity sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
babel-plugin-transform-hook-names@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-hook-names/-/babel-plugin-transform-hook-names-1.0.2.tgz#0d75c2d78e8bbcdb258241131562b9cf07f010f3"
|
||||
|
@ -639,6 +659,11 @@ css-what@^6.1.0:
|
|||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
|
||||
integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
|
||||
|
||||
csstype@^3.0.2:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
|
||||
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
|
||||
|
||||
debug@^4.1.0, debug@^4.3.1, debug@^4.3.4:
|
||||
version "4.3.7"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
|
||||
|
@ -784,7 +809,7 @@ is-number@^7.0.0:
|
|||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
|
||||
js-tokens@^4.0.0:
|
||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||
|
@ -809,6 +834,13 @@ ky@^1.7.2:
|
|||
resolved "https://registry.yarnpkg.com/ky/-/ky-1.7.2.tgz#b97d9b997ba51ff1e152f0815d3d27b86513eb1c"
|
||||
integrity sha512-OzIvbHKKDpi60TnF9t7UUVAF1B4mcqc02z5PIvrm08Wyb+yOcz63GRvEuVxNT18a9E1SrNouhB4W2NNLeD7Ykg==
|
||||
|
||||
loose-envify@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
dependencies:
|
||||
js-tokens "^3.0.0 || ^4.0.0"
|
||||
|
||||
lru-cache@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
||||
|
@ -866,6 +898,11 @@ nth-check@^2.0.1:
|
|||
dependencies:
|
||||
boolbase "^1.0.0"
|
||||
|
||||
object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||
|
||||
picocolors@^1.0.0, picocolors@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
|
||||
|
@ -890,6 +927,27 @@ preact@^10.24.3:
|
|||
resolved "https://registry.yarnpkg.com/preact/-/preact-10.24.3.tgz#086386bd47071e3b45410ef20844c21e23828f64"
|
||||
integrity sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==
|
||||
|
||||
prop-types@^15.5.8:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
dependencies:
|
||||
loose-envify "^1.4.0"
|
||||
object-assign "^4.1.1"
|
||||
react-is "^16.13.1"
|
||||
|
||||
react-infinite-scroller@^1.2.6:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/react-infinite-scroller/-/react-infinite-scroller-1.2.6.tgz#8b80233226dc753a597a0eb52621247f49b15f18"
|
||||
integrity sha512-mGdMyOD00YArJ1S1F3TVU9y4fGSfVVl6p5gh/Vt4u99CJOptfVu/q5V/Wlle72TMgYlBwIhbxK5wF0C/R33PXQ==
|
||||
dependencies:
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-is@^16.13.1:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
readdirp@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a"
|
||||
|
|
Loading…
Reference in New Issue