mirror of
https://github.com/Steffo99/todocolors.git
synced 2024-11-22 08:14:18 +00:00
Final progress for today
This commit is contained in:
parent
0865ca94e7
commit
7a17afc267
15 changed files with 352 additions and 30 deletions
|
@ -7,7 +7,9 @@
|
|||
</scripts>
|
||||
<arguments value="--port=8081" />
|
||||
<node-interpreter value="project" />
|
||||
<envs />
|
||||
<envs>
|
||||
<env name="NEXT_PUBLIC_API_BASE_URL" value="ws://192.168.1.135:8080" />
|
||||
</envs>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
|
@ -10,7 +10,7 @@
|
|||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs>
|
||||
<env name="AXUM_HOST" value="127.0.0.1:8080" />
|
||||
<env name="AXUM_HOST" value="0.0.0.0:8080" />
|
||||
<env name="REDIS_CONN" value="redis://127.0.0.1:6379/" />
|
||||
<env name="RUST_LOG" value="todored" />
|
||||
</envs>
|
||||
|
|
|
@ -3,14 +3,22 @@
|
|||
import {useBoardCreator} from "@/app/useBoardCreator"
|
||||
import {faKey} from "@fortawesome/free-solid-svg-icons"
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||
import classNames from "classnames"
|
||||
import {default as React} from "react"
|
||||
|
||||
export function CreatePrivateBoard() {
|
||||
const {createBoard} = useBoardCreator();
|
||||
|
||||
const isSecure = typeof window !== "undefined" && window.isSecureContext;
|
||||
|
||||
return (
|
||||
<form
|
||||
className={"panel box form-flex"}
|
||||
className={classNames({
|
||||
"panel": true,
|
||||
"box": true,
|
||||
"form-flex": true,
|
||||
"red": !isSecure,
|
||||
})}
|
||||
onSubmit={e => {
|
||||
e.preventDefault();
|
||||
createBoard(crypto.randomUUID().toString());
|
||||
|
@ -21,18 +29,28 @@ export function CreatePrivateBoard() {
|
|||
{" "}
|
||||
Privato
|
||||
</h3>
|
||||
<p>
|
||||
Crea un nuovo tabellone privato utilizzando un codice segreto autogenerato!
|
||||
<br/>
|
||||
<small>Esso sarà accessibile solo da chi ne conosce il link.</small>
|
||||
</p>
|
||||
<label className={"float-bottom"}>
|
||||
<span/>
|
||||
<button>
|
||||
Crea
|
||||
</button>
|
||||
<span/>
|
||||
</label>
|
||||
{isSecure ?
|
||||
<>
|
||||
<p>
|
||||
Crea un nuovo tabellone privato utilizzando un codice segreto autogenerato!
|
||||
<br/>
|
||||
<small>Esso sarà accessibile solo da chi ne conosce il link.</small>
|
||||
</p>
|
||||
<label className={"float-bottom"}>
|
||||
<span/>
|
||||
<button>
|
||||
Crea
|
||||
</button>
|
||||
<span/>
|
||||
</label>
|
||||
</> : <>
|
||||
<p>
|
||||
Questa funzionalità non è disponibile al di fuori di contesti sicuri.
|
||||
<br/>
|
||||
<small>Assicurati di stare usando HTTPS!</small>
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import {BoardColumns} from "@/app/board/[board]/BoardColumns"
|
||||
import {BoardError} from "@/app/board/[board]/BoardError"
|
||||
import {BoardLoading} from "@/app/board/[board]/BoardLoading"
|
||||
import {useBoardContext} from "@/app/board/[board]/useBoardContext"
|
||||
|
@ -12,7 +13,7 @@ export function BoardBody() {
|
|||
case WebSocket.CONNECTING:
|
||||
return <BoardLoading text={"Connessione..."}/>
|
||||
case WebSocket.OPEN:
|
||||
return <>nothing here</>
|
||||
return <BoardColumns/>
|
||||
case WebSocket.CLOSING:
|
||||
case WebSocket.CLOSED:
|
||||
return <BoardError text={"Errore"}/>
|
||||
|
|
13
todoblue/src/app/board/[board]/BoardColumns.tsx
Normal file
13
todoblue/src/app/board/[board]/BoardColumns.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import {TaskGroupColumn} from "@/app/board/[board]/TaskGroupColumn"
|
||||
import {useBoardContext} from "@/app/board/[board]/useBoardContext"
|
||||
|
||||
|
||||
export function BoardColumns() {
|
||||
const {taskGroups} = useBoardContext()
|
||||
|
||||
return (
|
||||
<div className={"chapter-5"}>
|
||||
{taskGroups.map((tg) => <TaskGroupColumn taskGroup={tg}/>)}
|
||||
</div>
|
||||
)
|
||||
}
|
94
todoblue/src/app/board/[board]/TaskDiv.module.css
Normal file
94
todoblue/src/app/board/[board]/TaskDiv.module.css
Normal file
|
@ -0,0 +1,94 @@
|
|||
.taskDiv {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"icon description"
|
||||
;
|
||||
grid-template-columns: auto 1fr;
|
||||
align-items: center;
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
.taskIcon {
|
||||
grid-area: icon;
|
||||
justify-self: start;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.taskDescription {
|
||||
grid-area: description;
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
.taskDescriptionComplete {
|
||||
text-decoration: 2px currentColor solid line-through;
|
||||
}
|
||||
|
||||
.taskPriorityHighest {
|
||||
border: 4px solid hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.15);
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.taskPriorityHigh {
|
||||
border: 3px solid hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.15);
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.taskPriorityNormal {
|
||||
border: 2px solid hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.15);
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.taskPriorityLow {
|
||||
border: 1px solid hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.15);
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
.taskPriorityLowest {
|
||||
border: 0;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.taskImportanceHighest {
|
||||
--bhsl-current-hue: 100deg;
|
||||
--bhsl-current-saturation: 37%;
|
||||
--bhsl-current-lightness: 68.2%;
|
||||
}
|
||||
|
||||
.taskImportanceHigh {
|
||||
--bhsl-current-hue: 159deg;
|
||||
--bhsl-current-saturation: 30%;
|
||||
--bhsl-current-lightness: 52%;
|
||||
}
|
||||
|
||||
.taskImportanceNormal {
|
||||
--bhsl-current-hue: 186deg;
|
||||
--bhsl-current-saturation: 47%;
|
||||
--bhsl-current-lightness: 38%;
|
||||
}
|
||||
|
||||
.taskImportanceLow {
|
||||
--bhsl-current-hue: 203deg;
|
||||
--bhsl-current-saturation: 64%;
|
||||
--bhsl-current-lightness: 32%;
|
||||
}
|
||||
|
||||
.taskImportanceLowest {
|
||||
--bhsl-current-hue: 237deg;
|
||||
--bhsl-current-saturation: 44%;
|
||||
--bhsl-current-lightness: 31%;
|
||||
}
|
||||
|
||||
@keyframes inProgress {
|
||||
0% {
|
||||
filter: brightness(100%);
|
||||
}
|
||||
|
||||
100% {
|
||||
filter: brightness(150%);
|
||||
}
|
||||
}
|
||||
|
||||
.taskStatusInProgress {
|
||||
animation: 1.7s inProgress ease-out infinite alternate-reverse;
|
||||
}
|
49
todoblue/src/app/board/[board]/TaskDiv.tsx
Normal file
49
todoblue/src/app/board/[board]/TaskDiv.tsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
import {TaskIconEl} from "@/app/board/[board]/TaskIconEl"
|
||||
import {Task, TaskWithId} from "@/app/board/[board]/Types"
|
||||
import {useBoardContext} from "@/app/board/[board]/useBoardContext"
|
||||
import {useCallback} from "react"
|
||||
import style from "./TaskDiv.module.css"
|
||||
import cn from "classnames"
|
||||
|
||||
export function TaskDiv({task}: {task: TaskWithId}) {
|
||||
const {send} = useBoardContext()
|
||||
|
||||
const toggleStatus = useCallback(() => {
|
||||
if(task.status === "Unfinished") {
|
||||
send({"Task": [task.id, {...task, status: "Complete"}]})
|
||||
}
|
||||
else if(task.status === "Complete") {
|
||||
send({"Task": [task.id, {...task, status: "Unfinished"}]})
|
||||
}
|
||||
}, [send, task])
|
||||
|
||||
return (
|
||||
<div onClick={toggleStatus} tabIndex={0} className={cn({
|
||||
"panel": true,
|
||||
[style.taskDiv]: true,
|
||||
[style.taskPriorityHighest]: task.priority === "Highest",
|
||||
[style.taskPriorityHigh]: task.priority === "High",
|
||||
[style.taskPriorityNormal]: task.priority === "Normal",
|
||||
[style.taskPriorityLow]: task.priority === "Low",
|
||||
[style.taskPriorityLowest]: task.priority === "Lowest",
|
||||
[style.taskImportanceHighest]: task.importance === "Highest",
|
||||
[style.taskImportanceHigh]: task.importance === "High",
|
||||
[style.taskImportanceNormal]: task.importance === "Normal",
|
||||
[style.taskImportanceLow]: task.importance === "Low",
|
||||
[style.taskImportanceLowest]: task.importance === "Lowest",
|
||||
[style.taskStatusUnfinished]: task.status === "Unfinished",
|
||||
[style.taskStatusInProgress]: task.status === "InProgress",
|
||||
[style.taskStatusComplete]: task.status === "Complete",
|
||||
})}>
|
||||
<div className={style.taskIcon}>
|
||||
<TaskIconEl icon={task.icon} style={task.status === "Complete" ? "solid" : "regular"}/>
|
||||
</div>
|
||||
<div className={cn({
|
||||
[style.taskDescription]: true,
|
||||
[style.taskDescriptionComplete]: task.status === "Complete",
|
||||
})}>
|
||||
{task.text}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
.taskGroupColumn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
15
todoblue/src/app/board/[board]/TaskGroupColumn.tsx
Normal file
15
todoblue/src/app/board/[board]/TaskGroupColumn.tsx
Normal file
|
@ -0,0 +1,15 @@
|
|||
import {TaskDiv} from "@/app/board/[board]/TaskDiv"
|
||||
import {TaskGroup} from "@/app/board/[board]/useBoardTaskArranger"
|
||||
import style from "./TaskGroupColumn.module.css"
|
||||
|
||||
|
||||
export function TaskGroupColumn({taskGroup}: {taskGroup: TaskGroup}) {
|
||||
return (
|
||||
<div className={style.taskGroupColumn}>
|
||||
<h3>
|
||||
{taskGroup.name}
|
||||
</h3>
|
||||
{taskGroup.tasks.map(task => <TaskDiv task={task}/>)}
|
||||
</div>
|
||||
)
|
||||
}
|
106
todoblue/src/app/board/[board]/TaskIconEl.tsx
Normal file
106
todoblue/src/app/board/[board]/TaskIconEl.tsx
Normal file
|
@ -0,0 +1,106 @@
|
|||
import {TaskIcon} from "@/app/board/[board]/Types"
|
||||
import {SizeProp} from "@fortawesome/fontawesome-svg-core"
|
||||
import {
|
||||
faUser as faUserSolid,
|
||||
faImage as faImageSolid,
|
||||
faEnvelope as faEnvelopeSolid,
|
||||
faStar as faStarSolid,
|
||||
faHeart as faHeartSolid,
|
||||
faComment as faCommentSolid,
|
||||
faFaceSmile as faFaceSmileSolid,
|
||||
faFile as faFileSolid,
|
||||
faBell as faBellSolid,
|
||||
faBookmark as faBookmarkSolid,
|
||||
faEye as faEyeSolid,
|
||||
faHand as faHandSolid,
|
||||
faPaperPlane as faPaperPlaneSolid,
|
||||
faHandshake as faHandshakeSolid,
|
||||
faSun as faSunSolid,
|
||||
faClock as faClockSolid,
|
||||
faCircle as faCircleSolid,
|
||||
faSquare as faSquareSolid,
|
||||
faBuilding as faBuildingSolid,
|
||||
faFlag as faFlagSolid,
|
||||
faMoon as faMoonSolid,
|
||||
} from "@fortawesome/free-solid-svg-icons"
|
||||
import {
|
||||
faUser as faUserRegular,
|
||||
faImage as faImageRegular,
|
||||
faEnvelope as faEnvelopeRegular,
|
||||
faStar as faStarRegular,
|
||||
faHeart as faHeartRegular,
|
||||
faComment as faCommentRegular,
|
||||
faFaceSmile as faFaceSmileRegular,
|
||||
faFile as faFileRegular,
|
||||
faBell as faBellRegular,
|
||||
faBookmark as faBookmarkRegular,
|
||||
faEye as faEyeRegular,
|
||||
faHand as faHandRegular,
|
||||
faPaperPlane as faPaperPlaneRegular,
|
||||
faHandshake as faHandshakeRegular,
|
||||
faSun as faSunRegular,
|
||||
faClock as faClockRegular,
|
||||
faCircle as faCircleRegular,
|
||||
faSquare as faSquareRegular,
|
||||
faBuilding as faBuildingRegular,
|
||||
faFlag as faFlagRegular,
|
||||
faMoon as faMoonRegular,
|
||||
} from "@fortawesome/free-regular-svg-icons"
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||
|
||||
|
||||
export const ICONS = {
|
||||
solid: {
|
||||
"User": faUserSolid,
|
||||
"Image": faImageSolid,
|
||||
"Envelope": faEnvelopeSolid,
|
||||
"Star": faStarSolid,
|
||||
"Heart": faHeartSolid,
|
||||
"Comment": faCommentSolid,
|
||||
"FaceSmile": faFaceSmileSolid,
|
||||
"File": faFileSolid,
|
||||
"Bell": faBellSolid,
|
||||
"Bookmark": faBookmarkSolid,
|
||||
"Eye": faEyeSolid,
|
||||
"Hand": faHandSolid,
|
||||
"PaperPlane": faPaperPlaneSolid,
|
||||
"Handshake": faHandshakeSolid,
|
||||
"Sun": faSunSolid,
|
||||
"Clock": faClockSolid,
|
||||
"Circle": faCircleSolid,
|
||||
"Square": faSquareSolid,
|
||||
"Building": faBuildingSolid,
|
||||
"Flag": faFlagSolid,
|
||||
"Moon": faMoonSolid,
|
||||
},
|
||||
regular: {
|
||||
"User": faUserRegular,
|
||||
"Image": faImageRegular,
|
||||
"Envelope": faEnvelopeRegular,
|
||||
"Star": faStarRegular,
|
||||
"Heart": faHeartRegular,
|
||||
"Comment": faCommentRegular,
|
||||
"FaceSmile": faFaceSmileRegular,
|
||||
"File": faFileRegular,
|
||||
"Bell": faBellRegular,
|
||||
"Bookmark": faBookmarkRegular,
|
||||
"Eye": faEyeRegular,
|
||||
"Hand": faHandRegular,
|
||||
"PaperPlane": faPaperPlaneRegular,
|
||||
"Handshake": faHandshakeRegular,
|
||||
"Sun": faSunRegular,
|
||||
"Clock": faClockRegular,
|
||||
"Circle": faCircleRegular,
|
||||
"Square": faSquareRegular,
|
||||
"Building": faBuildingRegular,
|
||||
"Flag": faFlagRegular,
|
||||
"Moon": faMoonRegular,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function TaskIconEl({icon, style, size}: {icon: TaskIcon, style: "solid" | "regular", size?: SizeProp}) {
|
||||
return (
|
||||
<FontAwesomeIcon icon={ICONS[style][icon]} size={size}/>
|
||||
)
|
||||
}
|
|
@ -1,17 +1,30 @@
|
|||
"use client";
|
||||
|
||||
import {TaskWithId} from "@/app/board/[board]/types"
|
||||
import {TaskIconEl} from "@/app/board/[board]/TaskIconEl"
|
||||
import {BoardAction} from "@/app/board/[board]/Types"
|
||||
import {TaskIcon, TaskWithId} from "@/app/board/[board]/types"
|
||||
import {useBoardWebSocket} from "@/app/board/[board]/useBoardWebSocket"
|
||||
import {GroupSortingFunction, TaskGroup, TaskGroupingFunction, TaskSortingFunction, useBoardTaskArranger} from "@/app/board/[board]/useBoardTaskArranger"
|
||||
import {GroupNamingFunction, GroupSortingFunction, TaskGroup, TaskGroupingFunction, TaskSortingFunction, useBoardTaskArranger} from "@/app/board/[board]/useBoardTaskArranger"
|
||||
import {useBoardTitleEditor} from "@/app/board/[board]/useBoardTitleEditor"
|
||||
import {useCycleState} from "@/app/useCycleState"
|
||||
import {faBell, faBookmark, faBuilding, faCircle, faClock, faComment, faEnvelope, faEye, faFaceSmile, faFile, faFlag, faHand, faHandshake, faHeart, faImage, faMoon, faPaperPlane, faSquare, faStar, faSun, faUser, IconDefinition} from "@fortawesome/free-solid-svg-icons"
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||
import {Dispatch, SetStateAction} from "react"
|
||||
|
||||
function groupTasksByIcon(a: TaskWithId) {return a.icon}
|
||||
function sortGroupsByKey(a: TaskGroup, b: TaskGroup) {return a.key.localeCompare(b.key)}
|
||||
|
||||
const TASK_GROUPERS: [TaskGroupingFunction, GroupSortingFunction][] = [
|
||||
[groupTasksByIcon, sortGroupsByKey],
|
||||
function nameToFontAwesomeIcon(a: string) {
|
||||
let icon = a as TaskIcon;
|
||||
return <>
|
||||
<TaskIconEl icon={icon} style={"solid"}/>
|
||||
|
||||
{a}
|
||||
</>
|
||||
}
|
||||
|
||||
const TASK_GROUPERS: [TaskGroupingFunction, GroupSortingFunction, GroupNamingFunction][] = [
|
||||
[groupTasksByIcon, sortGroupsByKey, nameToFontAwesomeIcon],
|
||||
]
|
||||
|
||||
function sortTasksByText(a: TaskWithId, b: TaskWithId) {return a.text.localeCompare(b.text)}
|
||||
|
@ -36,15 +49,16 @@ export interface UseBoardReturns {
|
|||
previousSorter: () => void,
|
||||
editTitle: string,
|
||||
setEditTitle: Dispatch<SetStateAction<string>>,
|
||||
send: (action: BoardAction) => void,
|
||||
}
|
||||
|
||||
export function useBoard(name: string): UseBoardReturns {
|
||||
const {state: {title, tasksById}, send, websocketState} = useBoardWebSocket(name);
|
||||
|
||||
const {value: [taskGrouper, groupSorter], move: moveGrouper, next: nextGrouper, previous: previousGrouper} = useCycleState(TASK_GROUPERS);
|
||||
const {value: [taskGrouper, groupSorter, groupNamer], move: moveGrouper, next: nextGrouper, previous: previousGrouper} = useCycleState(TASK_GROUPERS);
|
||||
const {value: taskSorter, move: moveSorter, next: nextSorter, previous: previousSorter} = useCycleState(TASK_SORTERS);
|
||||
|
||||
const {taskGroups} = useBoardTaskArranger(tasksById, taskGrouper, groupSorter, taskSorter);
|
||||
const {taskGroups} = useBoardTaskArranger(tasksById, taskGrouper, groupSorter, groupNamer, taskSorter);
|
||||
const {isEditingTitle, stopEditingTitle, startEditingTitle, toggleEditingTitle, editTitle, setEditTitle} = useBoardTitleEditor(title, send);
|
||||
|
||||
return {
|
||||
|
@ -63,5 +77,6 @@ export function useBoard(name: string): UseBoardReturns {
|
|||
previousSorter,
|
||||
editTitle,
|
||||
setEditTitle,
|
||||
send,
|
||||
}
|
||||
}
|
|
@ -1,18 +1,20 @@
|
|||
"use client";
|
||||
|
||||
import {Task, TaskWithId} from "@/app/board/[board]/types"
|
||||
import {useMemo} from "react"
|
||||
import {ReactNode, useMemo} from "react"
|
||||
|
||||
export type TaskGroup = {
|
||||
key: string,
|
||||
name: ReactNode,
|
||||
tasks: TaskWithId[],
|
||||
}
|
||||
|
||||
export type TaskGroupingFunction = (a: TaskWithId) => string
|
||||
export type TaskSortingFunction = (a: TaskWithId, b: TaskWithId) => number;
|
||||
export type GroupSortingFunction = (a: TaskGroup, b: TaskGroup) => number;
|
||||
export type GroupNamingFunction = (a: string) => ReactNode;
|
||||
export type TaskSortingFunction = (a: TaskWithId, b: TaskWithId) => number;
|
||||
|
||||
export function arrangeBoardTasks(tasksById: { [p: string]: Task }, taskGrouper: TaskGroupingFunction, groupSorter: GroupSortingFunction, taskSorter: TaskSortingFunction): TaskGroup[] {
|
||||
export function arrangeBoardTasks(tasksById: { [p: string]: Task }, taskGrouper: TaskGroupingFunction, groupSorter: GroupSortingFunction, groupNamer: GroupNamingFunction, taskSorter: TaskSortingFunction): TaskGroup[] {
|
||||
const groupsByKey: {[group: string]: TaskWithId[]} = {}
|
||||
|
||||
for(const [id, task] of Object.entries(tasksById)) {
|
||||
|
@ -31,7 +33,8 @@ export function arrangeBoardTasks(tasksById: { [p: string]: Task }, taskGrouper:
|
|||
const groups: TaskGroup[] = []
|
||||
|
||||
for(const [key, tasks] of Object.entries(groupsByKey)) {
|
||||
groups.push({key, tasks})
|
||||
const name = groupNamer(key);
|
||||
groups.push({key, name, tasks})
|
||||
}
|
||||
|
||||
groups.sort(groupSorter)
|
||||
|
@ -40,8 +43,8 @@ export function arrangeBoardTasks(tasksById: { [p: string]: Task }, taskGrouper:
|
|||
}
|
||||
|
||||
|
||||
export function useBoardTaskArranger(tasksById: { [p: string]: Task }, taskGrouper: TaskGroupingFunction, groupSorter: GroupSortingFunction, taskSorter: TaskSortingFunction) {
|
||||
const taskGroups = useMemo(() => arrangeBoardTasks(tasksById, taskGrouper, groupSorter, taskSorter), [tasksById, taskGrouper, taskSorter, groupSorter])
|
||||
export function useBoardTaskArranger(tasksById: { [p: string]: Task }, taskGrouper: TaskGroupingFunction, groupSorter: GroupSortingFunction, groupNamer: GroupNamingFunction, taskSorter: TaskSortingFunction) {
|
||||
const taskGroups = useMemo(() => arrangeBoardTasks(tasksById, taskGrouper, groupSorter, groupNamer, taskSorter), [tasksById, taskGrouper, taskSorter, groupSorter])
|
||||
|
||||
return {taskGroups};
|
||||
}
|
||||
|
|
|
@ -2,6 +2,6 @@ import {useMemo} from "react"
|
|||
|
||||
|
||||
export function useBoardWebSocketURL(name: string) {
|
||||
const webSocketURL = useMemo(() => `ws://127.0.0.1:8080/board/${name}/ws`, [name]);
|
||||
const webSocketURL = useMemo(() => `${process.env.NEXT_PUBLIC_API_BASE_URL}/board/${name}/ws`, [name]);
|
||||
return {webSocketURL}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ export default function RootLayout({children}: { children: ReactNode }) {
|
|||
<p>
|
||||
© <a href="https://steffo.eu">Stefano Pigozzi</a> -
|
||||
<a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPL 3.0</a> -
|
||||
<a href="https://github.com/Steffo99/todocolors">GitHub</a>
|
||||
<a href="https://github.com/Steffo99/todocolors">GitHub</a> -
|
||||
Using {process.env.NEXT_PUBLIC_API_BASE_URL}
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
|
|
Loading…
Reference in a new issue