diff --git a/components/basicList/basicList.tsx b/components/basicList/basicList.tsx index 29be9b5..f396915 100644 --- a/components/basicList/basicList.tsx +++ b/components/basicList/basicList.tsx @@ -24,6 +24,8 @@ import ClearIcon from "@mui/icons-material/Clear"; import { NixType, nixTypes } from "../../types/nix"; import { Filter } from "../searchInput/searchInput"; import { useRouter } from "next/router"; +import { FunctionOfTheDay } from "../functionOfTheDay"; +import { EmptyRecordsPlaceholder } from "../emptyRecordsPlaceholder"; export type BasicListItem = { item: React.ReactNode; @@ -31,10 +33,13 @@ export type BasicListItem = { }; export type BasicListProps = BasicDataViewProps & { handleFilter: (filter: Filter | ((curr: Filter) => Filter)) => void; + filter: Filter; + term: string; selected?: string | null; itemsPerPage: number; }; +type ViewMode = "explore" | "browse"; export function BasicList(props: BasicListProps) { const { items, @@ -43,11 +48,13 @@ export function BasicList(props: BasicListProps) { handleSearch, handleFilter, selected = "", + filter, + term, } = props; - // const [from, setFrom] = useState("any"); - // const [to, setTo] = useState("any"); const [page, setPage] = useState(1); + const [mode, setMode] = useState("explore"); + const router = useRouter(); useEffect(() => { const { query } = router; @@ -57,7 +64,6 @@ export function BasicList(props: BasicListProps) { setPage(page); } } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [router]); @@ -67,8 +73,6 @@ export function BasicList(props: BasicListProps) { return items.slice(startIdx, endIdx); }, [page, items, itemsPerPage]); - const [searchTerm, setSearchTerm] = useState(""); - const handlePageChange = ( _event: React.ChangeEvent, value: number @@ -77,16 +81,23 @@ export function BasicList(props: BasicListProps) { }; const _handleFilter = (filter: Filter | ((curr: Filter) => Filter)) => { + setMode("browse"); handleFilter(filter); setPage(1); }; const _handleSearch = (term: string) => { + setMode("browse"); handleSearch && handleSearch(term); - setSearchTerm(term); + setPage(1); }; + const showFunctionExplore = + mode === "explore" && + filter.to === "any" && + filter.from === "any" && + term === ""; return ( _handleSearch("")} /> + {showFunctionExplore ? ( + setMode("browse")} /> + ) : ( + + {items.length ? ( + pageItems.map(({ item, key }, idx) => ( + + + {item} + + + )) + ) : ( + + + + )} + + )} - - {pageItems.map(({ item, key }, idx) => ( - - - {item} - - - ))} - - - + {Math.ceil(items.length / itemsPerPage) > 0 && !showFunctionExplore && ( + + )} ); } diff --git a/components/emptyRecordsPlaceholder/emptyRecordsPlaceholder.tsx b/components/emptyRecordsPlaceholder/emptyRecordsPlaceholder.tsx new file mode 100644 index 0000000..15b4c80 --- /dev/null +++ b/components/emptyRecordsPlaceholder/emptyRecordsPlaceholder.tsx @@ -0,0 +1,61 @@ +import { Card, CardContent, CardProps, Typography } from "@mui/material"; + +import InboxIcon from "@mui/icons-material/Inbox"; + +interface EmptyRecordsPlaceholderProps { + title: string; + subtitle?: string; + icon?: React.ReactNode; + CardProps?: CardProps; +} + +export const EmptyRecordsPlaceholder = ( + props: EmptyRecordsPlaceholderProps +) => { + const { title, subtitle, icon, CardProps = {} } = props; + return ( + + + + {icon || ( + + )} + + + + {title} + + + + {subtitle} + + + + ); +}; diff --git a/components/emptyRecordsPlaceholder/index.tsx b/components/emptyRecordsPlaceholder/index.tsx new file mode 100644 index 0000000..41d8a97 --- /dev/null +++ b/components/emptyRecordsPlaceholder/index.tsx @@ -0,0 +1 @@ +export { EmptyRecordsPlaceholder } from "./emptyRecordsPlaceholder"; diff --git a/components/functionOfTheDay/functionOfTheDay.tsx b/components/functionOfTheDay/functionOfTheDay.tsx new file mode 100644 index 0000000..2dde822 --- /dev/null +++ b/components/functionOfTheDay/functionOfTheDay.tsx @@ -0,0 +1,140 @@ +import { + Button, + Card, + CardActions, + CardContent, + CardHeader, + Divider, + IconButton, + useTheme, +} from "@mui/material"; + +import { useMemo, useState } from "react"; +import seedrandom from "seedrandom"; +import { data } from "../../models/data"; +import { DocItem } from "../../types/nix"; +import { Preview } from "../preview/preview"; +import ClearIcon from "@mui/icons-material/Clear"; + +const date = new Date(); + +const dayOfYear = (date: Date) => { + const diff = Number(date) - Number(new Date(date.getFullYear(), 0, 0)); + return Math.floor(diff / 1000 / 60 / 60 / 24); +}; + +const seed = dayOfYear(date).toString() + date.getFullYear().toString(); +const rng = seedrandom(seed); + +function getRandomIntInclusive( + min: number, + max: number, + generator: () => number +) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(generator() * (max - min + 1) + min); // The maximum is inclusive and the minimum is inclusive +} + +// const todaysFunction = data.at( +const todaysIdx = getRandomIntInclusive(0, data.length - 1, rng); +// ) as DocItem; + +interface FunctionOfTheDayProps { + handleClose: () => void; +} +export const FunctionOfTheDay = (props: FunctionOfTheDayProps) => { + const { handleClose } = props; + const { + palette: { info, error }, + } = useTheme(); + const [idx, setIdx] = useState(todaysIdx); + const slectedFunction = useMemo(() => data.at(idx) as DocItem, [idx]); + + const setNext = () => { + setIdx((curr) => { + if (curr >= data.length - 1) { + return data.length - 1; + } + return curr + 1; + }); + }; + const setPrev = () => { + setIdx((curr) => { + if (curr <= 0) { + return 0; + } + return curr - 1; + }); + }; + + const setRandom = () => { + setIdx(getRandomIntInclusive(0, data.length - 1, Math.random)); + }; + const setFunctionOfTheDay = () => { + setIdx(todaysIdx); + }; + + return ( + <> + + handleClose()}> + + + } + /> + + } /> + + + + + + + + + + + + ); +}; diff --git a/components/functionOfTheDay/index.ts b/components/functionOfTheDay/index.ts new file mode 100644 index 0000000..2cf48d6 --- /dev/null +++ b/components/functionOfTheDay/index.ts @@ -0,0 +1 @@ +export {FunctionOfTheDay} from "./functionOfTheDay" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 009372a..1632ef1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,11 +26,13 @@ "react-highlight": "^0.15.0", "react-markdown": "^8.0.4", "rehype-highlight": "^6.0.0", + "seedrandom": "^3.0.5", "typescript": "4.8.4", "usehooks-ts": "^2.9.1" }, "devDependencies": { - "@types/react-highlight": "^0.12.5" + "@types/react-highlight": "^0.12.5", + "@types/seedrandom": "^3.0.4" } }, "node_modules/@ampproject/remapping": { @@ -1378,6 +1380,12 @@ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, + "node_modules/@types/seedrandom": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.4.tgz", + "integrity": "sha512-/rWdxeiuZenlawrHU+XV6ZHMTKOqrC2hMfeDfLTIWJhDZP5aVqXRysduYHBbhD7CeJO6FJr/D2uBVXB7GT6v7w==", + "dev": true + }, "node_modules/@types/unist": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", @@ -4519,6 +4527,11 @@ "loose-envify": "^1.1.0" } }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + }, "node_modules/semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -6039,6 +6052,12 @@ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, + "@types/seedrandom": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.4.tgz", + "integrity": "sha512-/rWdxeiuZenlawrHU+XV6ZHMTKOqrC2hMfeDfLTIWJhDZP5aVqXRysduYHBbhD7CeJO6FJr/D2uBVXB7GT6v7w==", + "dev": true + }, "@types/unist": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", @@ -8123,6 +8142,11 @@ "loose-envify": "^1.1.0" } }, + "seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + }, "semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", diff --git a/package.json b/package.json index 66184b2..a717020 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,12 @@ "react-highlight": "^0.15.0", "react-markdown": "^8.0.4", "rehype-highlight": "^6.0.0", + "seedrandom": "^3.0.5", "typescript": "4.8.4", "usehooks-ts": "^2.9.1" }, "devDependencies": { - "@types/react-highlight": "^0.12.5" + "@types/react-highlight": "^0.12.5", + "@types/seedrandom": "^3.0.4" } } diff --git a/pages/index.tsx b/pages/index.tsx index 485f960..82a4331 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -64,10 +64,11 @@ export default function FunctionsPage() { }; } ); - return ( - +