diff --git a/front/package.json b/front/package.json index 2a320aa..84aefe3 100644 --- a/front/package.json +++ b/front/package.json @@ -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", diff --git a/front/src/components/Posts.module.scss b/front/src/components/Posts.module.scss index 0da5507..3d31071 100644 --- a/front/src/components/Posts.module.scss +++ b/front/src/components/Posts.module.scss @@ -1,3 +1,10 @@ .posts { - display: block; + display: flex; + flex-direction: column; + + li { + display: flex; + align-items: center; + gap: 1rem; + } } \ No newline at end of file diff --git a/front/src/components/Posts.tsx b/front/src/components/Posts.tsx index eceb248..12431a7 100644 --- a/front/src/components/Posts.tsx +++ b/front/src/components/Posts.tsx @@ -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 ( -
- { rows.map(row => ) } -
+ ); } \ No newline at end of file diff --git a/front/src/pages/index.module.scss b/front/src/pages/index.module.scss index 158402e..7058559 100644 --- a/front/src/pages/index.module.scss +++ b/front/src/pages/index.module.scss @@ -1,4 +1,7 @@ .index { + .selection { + background: antiquewhite; + } .paginator { border-bottom: 1px solid black; padding-bottom: 1rem; diff --git a/front/src/pages/index.tsx b/front/src/pages/index.tsx index 0c4f824..6010e6a 100644 --- a/front/src/pages/index.tsx +++ b/front/src/pages/index.tsx @@ -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 (
- + { - data - ? - :
loading . . .
+ selected + ? +
+

Selection

+ +
+ : null } + + loading . . .} + useWindow={false} + > + { + data + ? selected ? selected?.indexOf(x) === -1 : true)} onSelectChange={select} /> + : <> + } +
) } \ No newline at end of file diff --git a/front/yarn.lock b/front/yarn.lock index 54ed43e..d84267f 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -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"