mirror of
https://github.com/Steffo99/todocolors.git
synced 2024-11-22 16:24:19 +00:00
Add starring mechanism
This commit is contained in:
parent
d750d7949b
commit
567818e95e
8 changed files with 149 additions and 5 deletions
|
@ -23,6 +23,7 @@
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"server-only": "^0.0.1",
|
"server-only": "^0.0.1",
|
||||||
"typescript": "5.1.6"
|
"typescript": "5.1.6",
|
||||||
|
"use-local-storage": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {CreatePrivateBoardPanel} from "@/app/CreatePrivateBoardPanel"
|
import {CreatePrivateBoardPanel} from "@/app/CreatePrivateBoardPanel"
|
||||||
import {CreatePublicBoardPanel} from "@/app/CreatePublicBoardPanel"
|
import {CreatePublicBoardPanel} from "@/app/CreatePublicBoardPanel"
|
||||||
import style from "@/app/page.module.css"
|
import style from "@/app/page.module.css"
|
||||||
|
import {StarredBoardsPanel} from "@/app/StarredBoardsPanel"
|
||||||
import {default as React} from "react"
|
import {default as React} from "react"
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +15,12 @@ export function RootMain() {
|
||||||
<CreatePublicBoardPanel/>
|
<CreatePublicBoardPanel/>
|
||||||
<CreatePrivateBoardPanel/>
|
<CreatePrivateBoardPanel/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={"chapter-1"}>
|
||||||
|
<h2>
|
||||||
|
Usa un tabellone già esistente
|
||||||
|
</h2>
|
||||||
|
<StarredBoardsPanel/>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
57
todoblue/src/app/StarContext.tsx
Normal file
57
todoblue/src/app/StarContext.tsx
Normal file
|
@ -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<SetStateAction<string[] | undefined>>
|
||||||
|
addStarred: (key: string) => void,
|
||||||
|
removeStarred: (key: string) => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
const StarContext = createContext<StarContextData | null>(null)
|
||||||
|
|
||||||
|
export function StarredManager({children}: {children: ReactNode}) {
|
||||||
|
const [starred, setStarred] = useLocalStorage<string[]>("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 (
|
||||||
|
<StarContext.Provider value={{starred, setStarred, addStarred, removeStarred}}>
|
||||||
|
{children}
|
||||||
|
</StarContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useManagedStarred(): StarContextData {
|
||||||
|
const context = useContext(StarContext)
|
||||||
|
|
||||||
|
if(context === null) {
|
||||||
|
throw new Error("useStarContext used outside a StarContext.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
52
todoblue/src/app/StarredBoardsPanel.tsx
Normal file
52
todoblue/src/app/StarredBoardsPanel.tsx
Normal file
|
@ -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<true | null>(null);
|
||||||
|
const {starred} = useManagedStarred()
|
||||||
|
|
||||||
|
useEffect(() => setIsClient(true), [])
|
||||||
|
|
||||||
|
let content;
|
||||||
|
if(!isClient) {
|
||||||
|
content = <>
|
||||||
|
<p>
|
||||||
|
Sto recuperando i dati salvati sul tuo browser...
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
content = <>
|
||||||
|
<p>
|
||||||
|
Puoi stellare un tabellone cliccando sulla stellina una volta che ci sei dentro.
|
||||||
|
</p>
|
||||||
|
{starred.length > 0 ?
|
||||||
|
<ul>
|
||||||
|
{starred.map(s => <li key={s}><Link href={`/board/${s}`}><code>{s}</code></Link></li>)}
|
||||||
|
</ul>
|
||||||
|
:
|
||||||
|
<p className={"fade"}>
|
||||||
|
Non hai ancora stellato nessun tabellone.
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn({
|
||||||
|
"panel": true,
|
||||||
|
"box": true,
|
||||||
|
"fade": !isClient,
|
||||||
|
})}>
|
||||||
|
<h3>
|
||||||
|
Tabelloni stellati
|
||||||
|
</h3>
|
||||||
|
{content}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,13 +1,15 @@
|
||||||
|
import {useManagedStarred} from "@/app/StarContext"
|
||||||
import {useRouter} from "next/navigation"
|
import {useRouter} from "next/navigation"
|
||||||
import {ReactNode, useCallback} from "react"
|
import {ReactNode, useCallback} from "react"
|
||||||
import style from "./BoardHeader.module.css"
|
import style from "./BoardHeader.module.css"
|
||||||
import {useManagedBoard} from "@/app/board/[board]/BoardManager"
|
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 {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
|
|
||||||
|
|
||||||
export function BoardHeader({className}: {className?: string}) {
|
export function BoardHeader({className}: {boardName: string, className?: string}) {
|
||||||
const {isEditingTitle} = useManagedBoard();
|
const {isEditingTitle} = useManagedBoard();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -17,6 +19,7 @@ export function BoardHeader({className}: {className?: string}) {
|
||||||
</TitleArea>
|
</TitleArea>
|
||||||
<LeftButtonsArea>
|
<LeftButtonsArea>
|
||||||
<HomeButton/>
|
<HomeButton/>
|
||||||
|
<StarButton/>
|
||||||
<EditTitleButton/>
|
<EditTitleButton/>
|
||||||
</LeftButtonsArea>
|
</LeftButtonsArea>
|
||||||
<RightButtonsArea>
|
<RightButtonsArea>
|
||||||
|
@ -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 (
|
||||||
|
<button title={"Stella tabellone"} onClick={toggleStarred}>
|
||||||
|
<FontAwesomeIcon icon={isStarred ? faStarSolid : faStarRegular}/>
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function EditTitleButton() {
|
function EditTitleButton() {
|
||||||
const {webSocketState, toggleEditingTitle} = useManagedBoard()
|
const {webSocketState, toggleEditingTitle} = useManagedBoard()
|
||||||
|
|
||||||
|
@ -116,7 +133,7 @@ function RightButtonsArea({children}: {children: ReactNode}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ToggleSingleColumnButton() {
|
function ToggleSingleColumnButton() {
|
||||||
const {webSocketState, isSingleColumn, setSingleColumn} = useManagedBoard()
|
const {webSocketState, setSingleColumn} = useManagedBoard()
|
||||||
|
|
||||||
if(webSocketState != WebSocket.OPEN) {
|
if(webSocketState != WebSocket.OPEN) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {useCycleState} from "@/app/useCycleState"
|
||||||
import {Dispatch, SetStateAction, useState} from "react"
|
import {Dispatch, SetStateAction, useState} from "react"
|
||||||
|
|
||||||
export interface UseBoardReturns {
|
export interface UseBoardReturns {
|
||||||
|
name: string,
|
||||||
title: string,
|
title: string,
|
||||||
tasksById: {[id: string]: Task},
|
tasksById: {[id: string]: Task},
|
||||||
taskGroups: TaskGroup[],
|
taskGroups: TaskGroup[],
|
||||||
|
@ -50,6 +51,7 @@ export function useBoard(name: string): UseBoardReturns {
|
||||||
const [isSingleColumn, setSingleColumn] = useState<boolean>(false)
|
const [isSingleColumn, setSingleColumn] = useState<boolean>(false)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
name,
|
||||||
title,
|
title,
|
||||||
tasksById,
|
tasksById,
|
||||||
taskGroups,
|
taskGroups,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import "./layout.css";
|
import "./layout.css";
|
||||||
import {AppBody} from "@/app/AppBody"
|
import {AppBody} from "@/app/AppBody"
|
||||||
|
import {StarredManager} from "@/app/StarContext"
|
||||||
import type {Metadata as NextMetadata} from "next"
|
import type {Metadata as NextMetadata} from "next"
|
||||||
import {default as React, ReactNode} from "react"
|
import {default as React, ReactNode} from "react"
|
||||||
|
|
||||||
|
@ -24,7 +25,9 @@ export default function layout({children}: { children: ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<AppBody>
|
<AppBody>
|
||||||
{children}
|
<StarredManager>
|
||||||
|
{children}
|
||||||
|
</StarredManager>
|
||||||
</AppBody>
|
</AppBody>
|
||||||
</html>
|
</html>
|
||||||
)
|
)
|
||||||
|
|
|
@ -302,6 +302,11 @@ typescript@5.1.6:
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274"
|
||||||
integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
|
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:
|
watchpack@2.4.0:
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
|
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
|
||||||
|
|
Loading…
Reference in a new issue