From 567818e95eab07fa2d966dc8439d92bdfd588dfa Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Mon, 7 Aug 2023 18:40:40 +0200 Subject: [PATCH] Add starring mechanism --- todoblue/package.json | 3 +- todoblue/src/app/RootMain.tsx | 7 +++ todoblue/src/app/StarContext.tsx | 57 +++++++++++++++++++ todoblue/src/app/StarredBoardsPanel.tsx | 52 +++++++++++++++++ .../src/app/board/[board]/BoardHeader.tsx | 23 +++++++- todoblue/src/app/board/[board]/useBoard.tsx | 2 + todoblue/src/app/layout.tsx | 5 +- todoblue/yarn.lock | 5 ++ 8 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 todoblue/src/app/StarContext.tsx create mode 100644 todoblue/src/app/StarredBoardsPanel.tsx diff --git a/todoblue/package.json b/todoblue/package.json index 0657e6b..802d7b6 100644 --- a/todoblue/package.json +++ b/todoblue/package.json @@ -23,6 +23,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "server-only": "^0.0.1", - "typescript": "5.1.6" + "typescript": "5.1.6", + "use-local-storage": "^3.0.0" } } diff --git a/todoblue/src/app/RootMain.tsx b/todoblue/src/app/RootMain.tsx index 2b16623..ec2e95e 100644 --- a/todoblue/src/app/RootMain.tsx +++ b/todoblue/src/app/RootMain.tsx @@ -1,6 +1,7 @@ import {CreatePrivateBoardPanel} from "@/app/CreatePrivateBoardPanel" import {CreatePublicBoardPanel} from "@/app/CreatePublicBoardPanel" import style from "@/app/page.module.css" +import {StarredBoardsPanel} from "@/app/StarredBoardsPanel" import {default as React} from "react" @@ -14,6 +15,12 @@ export function RootMain() { +
+

+ Usa un tabellone giĆ  esistente +

+ +
) } diff --git a/todoblue/src/app/StarContext.tsx b/todoblue/src/app/StarContext.tsx new file mode 100644 index 0000000..fde32ad --- /dev/null +++ b/todoblue/src/app/StarContext.tsx @@ -0,0 +1,57 @@ +"use client"; + +import {createContext, Dispatch, ReactNode, SetStateAction, useCallback, useContext} from "react" +import useLocalStorage from "use-local-storage" + +export interface StarContextData { + starred: string[], + setStarred: Dispatch> + addStarred: (key: string) => void, + removeStarred: (key: string) => void, +} + +const StarContext = createContext(null) + +export function StarredManager({children}: {children: ReactNode}) { + const [starred, setStarred] = useLocalStorage("TODOBLUE_STARRED", []) + + const addStarred = useCallback((value: string) => { + setStarred(prev => { + if(!prev) { + return [value] + } + else { + return [...prev, value] + } + }) + }, []) + + const removeStarred = useCallback((value: string) => { + setStarred(prev => { + if(!prev) { + return [] + } + else { + const result = [...prev] + delete result[result.indexOf(value)] + return result + } + }) + }, []) + + return ( + + {children} + + ) +} + +export function useManagedStarred(): StarContextData { + const context = useContext(StarContext) + + if(context === null) { + throw new Error("useStarContext used outside a StarContext.") + } + + return context +} diff --git a/todoblue/src/app/StarredBoardsPanel.tsx b/todoblue/src/app/StarredBoardsPanel.tsx new file mode 100644 index 0000000..c387b4f --- /dev/null +++ b/todoblue/src/app/StarredBoardsPanel.tsx @@ -0,0 +1,52 @@ +"use client"; + +import {useManagedStarred} from "@/app/StarContext" +import cn from "classnames" +import Link from "next/link" +import {useEffect, useState} from "react" + + +export function StarredBoardsPanel() { + const [isClient, setIsClient] = useState(null); + const {starred} = useManagedStarred() + + useEffect(() => setIsClient(true), []) + + let content; + if(!isClient) { + content = <> +

+ Sto recuperando i dati salvati sul tuo browser... +

+ + } + else { + content = <> +

+ Puoi stellare un tabellone cliccando sulla stellina una volta che ci sei dentro. +

+ {starred.length > 0 ? +
    + {starred.map(s =>
  • {s}
  • )} +
+ : +

+ Non hai ancora stellato nessun tabellone. +

+ } + + } + + return ( +
+

+ Tabelloni stellati +

+ {content} +
+ ) +} diff --git a/todoblue/src/app/board/[board]/BoardHeader.tsx b/todoblue/src/app/board/[board]/BoardHeader.tsx index 9c33ea1..4d68c60 100644 --- a/todoblue/src/app/board/[board]/BoardHeader.tsx +++ b/todoblue/src/app/board/[board]/BoardHeader.tsx @@ -1,13 +1,15 @@ +import {useManagedStarred} from "@/app/StarContext" import {useRouter} from "next/navigation" import {ReactNode, useCallback} from "react" import style from "./BoardHeader.module.css" import {useManagedBoard} from "@/app/board/[board]/BoardManager" -import {faArrowDownWideShort, faHouse, faPencil, faObjectGroup, faTableColumns} from "@fortawesome/free-solid-svg-icons" +import {faArrowDownWideShort, faHouse, faPencil, faObjectGroup, faTableColumns, faStar as faStarSolid} from "@fortawesome/free-solid-svg-icons" +import {faStar as faStarRegular} from "@fortawesome/free-regular-svg-icons" import {FontAwesomeIcon} from "@fortawesome/react-fontawesome" import cn from "classnames" -export function BoardHeader({className}: {className?: string}) { +export function BoardHeader({className}: {boardName: string, className?: string}) { const {isEditingTitle} = useManagedBoard(); return ( @@ -17,6 +19,7 @@ export function BoardHeader({className}: {className?: string}) { + @@ -93,6 +96,20 @@ function HomeButton() { ) } +function StarButton() { + const {name} = useManagedBoard() + const {starred, addStarred, removeStarred} = useManagedStarred() + const isStarred = starred.indexOf(name) >= 0 + + const toggleStarred = useCallback(() => isStarred ? removeStarred(name) : addStarred(name), [name, isStarred, addStarred, removeStarred]) + + return ( + + ) +} + function EditTitleButton() { const {webSocketState, toggleEditingTitle} = useManagedBoard() @@ -116,7 +133,7 @@ function RightButtonsArea({children}: {children: ReactNode}) { } function ToggleSingleColumnButton() { - const {webSocketState, isSingleColumn, setSingleColumn} = useManagedBoard() + const {webSocketState, setSingleColumn} = useManagedBoard() if(webSocketState != WebSocket.OPEN) { return null; diff --git a/todoblue/src/app/board/[board]/useBoard.tsx b/todoblue/src/app/board/[board]/useBoard.tsx index a16a173..d379abc 100644 --- a/todoblue/src/app/board/[board]/useBoard.tsx +++ b/todoblue/src/app/board/[board]/useBoard.tsx @@ -11,6 +11,7 @@ import {useCycleState} from "@/app/useCycleState" import {Dispatch, SetStateAction, useState} from "react" export interface UseBoardReturns { + name: string, title: string, tasksById: {[id: string]: Task}, taskGroups: TaskGroup[], @@ -50,6 +51,7 @@ export function useBoard(name: string): UseBoardReturns { const [isSingleColumn, setSingleColumn] = useState(false) return { + name, title, tasksById, taskGroups, diff --git a/todoblue/src/app/layout.tsx b/todoblue/src/app/layout.tsx index 8ef2cbe..7c1a6c6 100644 --- a/todoblue/src/app/layout.tsx +++ b/todoblue/src/app/layout.tsx @@ -2,6 +2,7 @@ import "./layout.css"; import {AppBody} from "@/app/AppBody" +import {StarredManager} from "@/app/StarContext" import type {Metadata as NextMetadata} from "next" import {default as React, ReactNode} from "react" @@ -24,7 +25,9 @@ export default function layout({children}: { children: ReactNode }) { return ( - {children} + + {children} + ) diff --git a/todoblue/yarn.lock b/todoblue/yarn.lock index a649c92..34d5ffe 100644 --- a/todoblue/yarn.lock +++ b/todoblue/yarn.lock @@ -302,6 +302,11 @@ typescript@5.1.6: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== +use-local-storage@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/use-local-storage/-/use-local-storage-3.0.0.tgz#ecf90952374150f0c65baf027eaaf2062a4c20c6" + integrity sha512-wlPNnBCG3ULIJMr5A+dvWqLiPWCfsN1Kwijq+sAhT5yV4ex0u6XmZuNwP+RerIOfzBuz1pwSZuzhZMiluGQHfQ== + watchpack@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"