mirror of
https://github.com/Steffo99/todocolors.git
synced 2024-11-24 17:24:18 +00:00
Update!
This commit is contained in:
parent
db35005190
commit
d96cb1564e
53 changed files with 4523 additions and 508 deletions
|
@ -1,14 +1,8 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Run server" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
<configuration default="false" name="Run server" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||||
|
<option name="buildProfileId" value="dev" />
|
||||||
<option name="command" value="run" />
|
<option name="command" value="run" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$/todored" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$/todored" />
|
||||||
<option name="emulateTerminal" value="true" />
|
|
||||||
<option name="channel" value="DEFAULT" />
|
|
||||||
<option name="requiredFeatures" value="true" />
|
|
||||||
<option name="allFeatures" value="false" />
|
|
||||||
<option name="withSudo" value="false" />
|
|
||||||
<option name="buildTarget" value="REMOTE" />
|
|
||||||
<option name="backtrace" value="SHORT" />
|
|
||||||
<envs>
|
<envs>
|
||||||
<env name="AXUM_HOST" value="0.0.0.0:8080" />
|
<env name="AXUM_HOST" value="0.0.0.0:8080" />
|
||||||
<env name="REDIS_CONN" value="redis://127.0.0.1:6379/" />
|
<env name="REDIS_CONN" value="redis://127.0.0.1:6379/" />
|
||||||
|
@ -16,6 +10,13 @@
|
||||||
<env name="TODORED_RATE_LIMIT_CONNECTIONS_PER_MINUTE" value="0" />
|
<env name="TODORED_RATE_LIMIT_CONNECTIONS_PER_MINUTE" value="0" />
|
||||||
<env name="TODORED_RATE_LIMIT_MESSAGES_PER_MINUTE" value="0" />
|
<env name="TODORED_RATE_LIMIT_MESSAGES_PER_MINUTE" value="0" />
|
||||||
</envs>
|
</envs>
|
||||||
|
<option name="emulateTerminal" value="true" />
|
||||||
|
<option name="channel" value="DEFAULT" />
|
||||||
|
<option name="requiredFeatures" value="true" />
|
||||||
|
<option name="allFeatures" value="false" />
|
||||||
|
<option name="withSudo" value="false" />
|
||||||
|
<option name="buildTarget" value="REMOTE" />
|
||||||
|
<option name="backtrace" value="SHORT" />
|
||||||
<option name="isRedirectInput" value="false" />
|
<option name="isRedirectInput" value="false" />
|
||||||
<option name="redirectInputPath" value="" />
|
<option name="redirectInputPath" value="" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
|
|
2
todoblue/.gitignore
vendored
2
todoblue/.gitignore
vendored
|
@ -1,5 +1,7 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
.npmrc
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
/node_modules
|
/node_modules
|
||||||
/.pnp
|
/.pnp
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@awesome.me/kit-dfe340c874": "^1.0.10",
|
||||||
"@fortawesome/fontawesome-svg-core": "*",
|
"@fortawesome/fontawesome-svg-core": "*",
|
||||||
"@fortawesome/free-regular-svg-icons": "*",
|
|
||||||
"@fortawesome/free-solid-svg-icons": "*",
|
|
||||||
"@fortawesome/react-fontawesome": "*",
|
"@fortawesome/react-fontawesome": "*",
|
||||||
"@steffo/bluelib": "*",
|
"@steffo/bluelib": "*",
|
||||||
|
"any-date-parser": "^1.5.4",
|
||||||
"classnames": "*",
|
"classnames": "*",
|
||||||
"client-only": "*",
|
"client-only": "*",
|
||||||
"i18next": "*",
|
"i18next": "*",
|
||||||
|
|
|
@ -30,27 +30,6 @@
|
||||||
"taskStatusInProgress": "In progress",
|
"taskStatusInProgress": "In progress",
|
||||||
"taskStatusComplete": "Complete",
|
"taskStatusComplete": "Complete",
|
||||||
"taskStatusJournaled": "Journaled",
|
"taskStatusJournaled": "Journaled",
|
||||||
"taskIconBookmark": "Bookmark",
|
|
||||||
"taskIconCircle": "Circle",
|
|
||||||
"taskIconSquare": "Square",
|
|
||||||
"taskIconHeart": "Heart",
|
|
||||||
"taskIconStar": "Star",
|
|
||||||
"taskIconSun": "Sun",
|
|
||||||
"taskIconMoon": "Moon",
|
|
||||||
"taskIconEye": "Eye",
|
|
||||||
"taskIconHand": "Hand",
|
|
||||||
"taskIconHandshake": "Handshake",
|
|
||||||
"taskIconFaceSmile": "Smile",
|
|
||||||
"taskIconUser": "User",
|
|
||||||
"taskIconComment": "Comment",
|
|
||||||
"taskIconEnvelope": "Envelope",
|
|
||||||
"taskIconFile": "File",
|
|
||||||
"taskIconPaperPlane": "Paper plane",
|
|
||||||
"taskIconBuilding": "Building",
|
|
||||||
"taskIconFlag": "Flag",
|
|
||||||
"taskIconBell": "Bell",
|
|
||||||
"taskIconClock": "Clock",
|
|
||||||
"taskIconImage": "Image",
|
|
||||||
"taskButtonJournal": "Move this task to the Journal",
|
"taskButtonJournal": "Move this task to the Journal",
|
||||||
"taskButtonUnjournal": "Remove this task from the Journal",
|
"taskButtonUnjournal": "Remove this task from the Journal",
|
||||||
"taskButtonDelete": "Delete this task",
|
"taskButtonDelete": "Delete this task",
|
||||||
|
|
|
@ -30,27 +30,6 @@
|
||||||
"taskStatusInProgress": "In corso",
|
"taskStatusInProgress": "In corso",
|
||||||
"taskStatusComplete": "Completato",
|
"taskStatusComplete": "Completato",
|
||||||
"taskStatusJournaled": "Salvato nel Diario",
|
"taskStatusJournaled": "Salvato nel Diario",
|
||||||
"taskIconBookmark": "Segnalibro",
|
|
||||||
"taskIconCircle": "Cerchio",
|
|
||||||
"taskIconSquare": "Quadrato",
|
|
||||||
"taskIconHeart": "Cuore",
|
|
||||||
"taskIconStar": "Stella",
|
|
||||||
"taskIconSun": "Sole",
|
|
||||||
"taskIconMoon": "Luna",
|
|
||||||
"taskIconEye": "Occhio",
|
|
||||||
"taskIconHand": "Mano",
|
|
||||||
"taskIconHandshake": "Stretta di mano",
|
|
||||||
"taskIconFaceSmile": "Sorriso",
|
|
||||||
"taskIconUser": "Utente",
|
|
||||||
"taskIconComment": "Commento",
|
|
||||||
"taskIconEnvelope": "Busta",
|
|
||||||
"taskIconFile": "File",
|
|
||||||
"taskIconPaperPlane": "Aeroplano di carta",
|
|
||||||
"taskIconBuilding": "Edificio",
|
|
||||||
"taskIconFlag": "Bandiera",
|
|
||||||
"taskIconBell": "Campana",
|
|
||||||
"taskIconClock": "Orologio",
|
|
||||||
"taskIconImage": "Immagine",
|
|
||||||
"taskButtonJournal": "Sposta questa attività nel Diario",
|
"taskButtonJournal": "Sposta questa attività nel Diario",
|
||||||
"taskButtonUnjournal": "Rimuovi questa attività dal Diario",
|
"taskButtonUnjournal": "Rimuovi questa attività dal Diario",
|
||||||
"taskButtonDelete": "Elimina questa attività",
|
"taskButtonDelete": "Elimina questa attività",
|
||||||
|
|
|
@ -51,7 +51,7 @@ export function StarredProvider({children}: {children: ReactNode}) {
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const isStarred = useCallback((value: string) => {
|
const isStarred = useCallback((value: string) => {
|
||||||
return starred.indexOf(value) >= 0
|
return starred.includes(value)
|
||||||
}, [starred])
|
}, [starred])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import {useClientTranslation} from "@/app/(i18n)/client"
|
import {useClientTranslation} from "@/app/(i18n)/client"
|
||||||
import {faLock} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import classNames from "classnames"
|
import classNames from "classnames"
|
||||||
import {useRouter} from "next/navigation"
|
import {useRouter} from "next/navigation"
|
||||||
|
@ -71,7 +71,7 @@ export function CreatePrivateBoardPanel({lang}: {lang: string}) {
|
||||||
onSubmit={createBoardValidated}
|
onSubmit={createBoardValidated}
|
||||||
>
|
>
|
||||||
<h3>
|
<h3>
|
||||||
<FontAwesomeIcon icon={faLock} size={"1x"}/>
|
<FontAwesomeIcon icon={fas.faLock} size={"1x"}/>
|
||||||
{" "}
|
{" "}
|
||||||
{t("createPrivateBoardTitle")}
|
{t("createPrivateBoardTitle")}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import {useClientTranslation} from "@/app/(i18n)/client"
|
import {useClientTranslation} from "@/app/(i18n)/client"
|
||||||
import {useLowerKebabifier} from "@/app/(utils)/(kebab)"
|
import {useLowerKebabifier} from "@/app/(utils)/(kebab)"
|
||||||
import {faGlobe} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {useRouter} from "next/navigation"
|
import {useRouter} from "next/navigation"
|
||||||
|
@ -32,7 +32,7 @@ export function CreatePublicBoardPanel({lang}: {lang: string}) {
|
||||||
onSubmit={createBoardValidated}
|
onSubmit={createBoardValidated}
|
||||||
>
|
>
|
||||||
<h3>
|
<h3>
|
||||||
<FontAwesomeIcon icon={faGlobe}/>
|
<FontAwesomeIcon icon={fas.faGlobe}/>
|
||||||
{" "}
|
{" "}
|
||||||
{t("createPublicBoardTitle")}
|
{t("createPublicBoardTitle")}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import {useClientTranslation} from "@/app/(i18n)/client"
|
import {useClientTranslation} from "@/app/(i18n)/client"
|
||||||
import {useLowerKebabifier} from "@/app/(utils)/(kebab)"
|
import {useLowerKebabifier} from "@/app/(utils)/(kebab)"
|
||||||
import {faKey} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {useRouter} from "next/navigation"
|
import {useRouter} from "next/navigation"
|
||||||
|
@ -32,7 +32,7 @@ export function KnownBoardsPanel({lang}: {lang: string}) {
|
||||||
onSubmit={moveToBoardValidated}
|
onSubmit={moveToBoardValidated}
|
||||||
>
|
>
|
||||||
<h3>
|
<h3>
|
||||||
<FontAwesomeIcon icon={faKey}/>
|
<FontAwesomeIcon icon={fas.faKey}/>
|
||||||
{" "}
|
{" "}
|
||||||
{t("existingKnownBoardsTitle")}
|
{t("existingKnownBoardsTitle")}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import {useClientTranslation} from "@/app/(i18n)/client"
|
import {useClientTranslation} from "@/app/(i18n)/client"
|
||||||
import {useStarredConsumer} from "@/app/[lang]/(layout)/(contextStarred)"
|
import {useStarredConsumer} from "@/app/[lang]/(layout)/(contextStarred)"
|
||||||
import {faStar} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
|
@ -66,7 +66,7 @@ export function StarredBoardsPanel({lang}: {lang: string}) {
|
||||||
"box": true,
|
"box": true,
|
||||||
})}>
|
})}>
|
||||||
<h3>
|
<h3>
|
||||||
<FontAwesomeIcon icon={faStar}/>
|
<FontAwesomeIcon icon={fas.faStar}/>
|
||||||
{" "}
|
{" "}
|
||||||
{t("existingStarredBoardsTitle")}
|
{t("existingStarredBoardsTitle")}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import {TaskIcon} from "@/app/[lang]/board/[board]/(api)/(task)/TaskIcon"
|
|
||||||
import {TaskImportance} from "@/app/[lang]/board/[board]/(api)/(task)/TaskImportance"
|
import {TaskImportance} from "@/app/[lang]/board/[board]/(api)/(task)/TaskImportance"
|
||||||
import {TaskPriority} from "@/app/[lang]/board/[board]/(api)/(task)/TaskPriority"
|
|
||||||
|
|
||||||
|
|
||||||
export type Task = {
|
export type Task = {
|
||||||
text: string,
|
text: string,
|
||||||
icon: TaskIcon,
|
icon: string,
|
||||||
importance: TaskImportance,
|
importance: TaskImportance,
|
||||||
priority: TaskPriority,
|
deadline: number | null,
|
||||||
created_on: number | null,
|
created_on: number | null,
|
||||||
started_on: number | null,
|
started_on: number | null,
|
||||||
completed_on: number | null,
|
completed_on: number | null,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,10 +0,0 @@
|
||||||
/**
|
|
||||||
* **Enum** of priority levels a {@link Task} may have.
|
|
||||||
*/
|
|
||||||
export enum TaskPriority {
|
|
||||||
Highest = "Highest",
|
|
||||||
High = "High",
|
|
||||||
Normal = "Normal",
|
|
||||||
Low = "Low",
|
|
||||||
Lowest = "Lowest",
|
|
||||||
}
|
|
|
@ -1,7 +1,4 @@
|
||||||
export {TaskIcon} from "./TaskIcon"
|
|
||||||
export {TaskImportance} from "./TaskImportance"
|
export {TaskImportance} from "./TaskImportance"
|
||||||
export {TaskPriority} from "./TaskPriority"
|
|
||||||
export {TASK_ICON_TO_FONTAWESOME_SOLID, TASK_ICON_TO_FONTAWESOME_REGULAR} from "./taskIconMappings"
|
|
||||||
|
|
||||||
export type {Task} from "./Task"
|
export type {Task} from "./Task"
|
||||||
export type {TaskId} from "./TaskId"
|
export type {TaskId} from "./TaskId"
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
import {faBell as faBellRegular, faBookmark as faBookmarkRegular, faBuilding as faBuildingRegular, faCircle as faCircleRegular, faClock as faClockRegular, faComment as faCommentRegular, faEnvelope as faEnvelopeRegular, faEye as faEyeRegular, faFaceSmile as faFaceSmileRegular, faFile as faFileRegular, faFlag as faFlagRegular, faHand as faHandRegular, faHandshake as faHandshakeRegular, faHeart as faHeartRegular, faImage as faImageRegular, faMoon as faMoonRegular, faPaperPlane as faPaperPlaneRegular, faSquare as faSquareRegular, faStar as faStarRegular, faSun as faSunRegular, faUser as faUserRegular} from "@fortawesome/free-regular-svg-icons"
|
|
||||||
import {faBell as faBellSolid, faBookmark as faBookmarkSolid, faBuilding as faBuildingSolid, faCircle as faCircleSolid, faClock as faClockSolid, faComment as faCommentSolid, faEnvelope as faEnvelopeSolid, faEye as faEyeSolid, faFaceSmile as faFaceSmileSolid, faFile as faFileSolid, faFlag as faFlagSolid, faHand as faHandSolid, faHandshake as faHandshakeSolid, faHeart as faHeartSolid, faImage as faImageSolid, faMoon as faMoonSolid, faPaperPlane as faPaperPlaneSolid, faSquare as faSquareSolid, faStar as faStarSolid, faSun as faSunSolid, faUser as faUserSolid, IconDefinition} from "@fortawesome/free-solid-svg-icons"
|
|
||||||
import {TaskIcon} from "./TaskIcon"
|
|
||||||
|
|
||||||
|
|
||||||
export const TASK_ICON_TO_FONTAWESOME_SOLID: {[T in TaskIcon]: IconDefinition} = {
|
|
||||||
[TaskIcon.User]: faUserSolid,
|
|
||||||
[TaskIcon.Image]: faImageSolid,
|
|
||||||
[TaskIcon.Envelope]: faEnvelopeSolid,
|
|
||||||
[TaskIcon.Star]: faStarSolid,
|
|
||||||
[TaskIcon.Heart]: faHeartSolid,
|
|
||||||
[TaskIcon.Comment]: faCommentSolid,
|
|
||||||
[TaskIcon.FaceSmile]: faFaceSmileSolid,
|
|
||||||
[TaskIcon.File]: faFileSolid,
|
|
||||||
[TaskIcon.Bell]: faBellSolid,
|
|
||||||
[TaskIcon.Bookmark]: faBookmarkSolid,
|
|
||||||
[TaskIcon.Eye]: faEyeSolid,
|
|
||||||
[TaskIcon.Hand]: faHandSolid,
|
|
||||||
[TaskIcon.PaperPlane]: faPaperPlaneSolid,
|
|
||||||
[TaskIcon.Handshake]: faHandshakeSolid,
|
|
||||||
[TaskIcon.Sun]: faSunSolid,
|
|
||||||
[TaskIcon.Clock]: faClockSolid,
|
|
||||||
[TaskIcon.Circle]: faCircleSolid,
|
|
||||||
[TaskIcon.Square]: faSquareSolid,
|
|
||||||
[TaskIcon.Building]: faBuildingSolid,
|
|
||||||
[TaskIcon.Flag]: faFlagSolid,
|
|
||||||
[TaskIcon.Moon]: faMoonSolid,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TASK_ICON_TO_FONTAWESOME_REGULAR: {[T in TaskIcon]: IconDefinition} = {
|
|
||||||
[TaskIcon.User]: faUserRegular,
|
|
||||||
[TaskIcon.Image]: faImageRegular,
|
|
||||||
[TaskIcon.Envelope]: faEnvelopeRegular,
|
|
||||||
[TaskIcon.Star]: faStarRegular,
|
|
||||||
[TaskIcon.Heart]: faHeartRegular,
|
|
||||||
[TaskIcon.Comment]: faCommentRegular,
|
|
||||||
[TaskIcon.FaceSmile]: faFaceSmileRegular,
|
|
||||||
[TaskIcon.File]: faFileRegular,
|
|
||||||
[TaskIcon.Bell]: faBellRegular,
|
|
||||||
[TaskIcon.Bookmark]: faBookmarkRegular,
|
|
||||||
[TaskIcon.Eye]: faEyeRegular,
|
|
||||||
[TaskIcon.Hand]: faHandRegular,
|
|
||||||
[TaskIcon.PaperPlane]: faPaperPlaneRegular,
|
|
||||||
[TaskIcon.Handshake]: faHandshakeRegular,
|
|
||||||
[TaskIcon.Sun]: faSunRegular,
|
|
||||||
[TaskIcon.Clock]: faClockRegular,
|
|
||||||
[TaskIcon.Circle]: faCircleRegular,
|
|
||||||
[TaskIcon.Square]: faSquareRegular,
|
|
||||||
[TaskIcon.Building]: faBuildingRegular,
|
|
||||||
[TaskIcon.Flag]: faFlagRegular,
|
|
||||||
[TaskIcon.Moon]: faMoonRegular,
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {TaskIcon} from "@/app/[lang]/board/[board]/(api)/(task)"
|
import {ICONS} from "@/app/[lang]/board/[board]/(api)/(task)/TaskIcon"
|
||||||
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
||||||
import {TaskEditorIcon} from "@/app/[lang]/board/[board]/(page)/(edit)/(task)/TaskEditorIcon"
|
import {TaskEditorIcon} from "@/app/[lang]/board/[board]/(page)/(edit)/(task)/TaskEditorIcon"
|
||||||
import {TaskEditorInput} from "@/app/[lang]/board/[board]/(page)/(edit)/(task)/TaskEditorInput"
|
import {TaskEditorInput} from "@/app/[lang]/board/[board]/(page)/(edit)/(task)/TaskEditorInput"
|
||||||
|
@ -12,56 +12,33 @@ import {SyntheticEvent, useCallback} from "react"
|
||||||
import style from "./TaskEditor.module.css"
|
import style from "./TaskEditor.module.css"
|
||||||
|
|
||||||
|
|
||||||
const ICON_SEQUENCE = [
|
export function TaskEditor({t, className, editorHook: {input, setInput, task, setTask}}: { t: TFunction, className?: string, editorHook: ReturnType<typeof useTaskEditor> }) {
|
||||||
TaskIcon.Bookmark,
|
|
||||||
TaskIcon.Circle,
|
|
||||||
TaskIcon.Square,
|
|
||||||
TaskIcon.Heart,
|
|
||||||
TaskIcon.Star,
|
|
||||||
TaskIcon.Sun,
|
|
||||||
TaskIcon.Moon,
|
|
||||||
TaskIcon.Eye,
|
|
||||||
TaskIcon.Hand,
|
|
||||||
TaskIcon.Handshake,
|
|
||||||
TaskIcon.FaceSmile,
|
|
||||||
TaskIcon.User,
|
|
||||||
TaskIcon.Comment,
|
|
||||||
TaskIcon.Envelope,
|
|
||||||
TaskIcon.File,
|
|
||||||
TaskIcon.PaperPlane,
|
|
||||||
TaskIcon.Building,
|
|
||||||
TaskIcon.Flag,
|
|
||||||
TaskIcon.Bell,
|
|
||||||
TaskIcon.Clock,
|
|
||||||
TaskIcon.Image,
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
export function TaskEditor({t, className, editorHook: {input, setInput, task, setTask}}: {t: TFunction, className?: string, editorHook: ReturnType<typeof useTaskEditor>}) {
|
|
||||||
const {isReady, sendRequest} = useBoardConsumer()
|
const {isReady, sendRequest} = useBoardConsumer()
|
||||||
|
|
||||||
const nextIcon = useCallback((e: SyntheticEvent<HTMLButtonElement>) => {
|
const nextIcon = useCallback((e: SyntheticEvent<HTMLButtonElement>) => {
|
||||||
if("key" in e && typeof e["key"] === "string") {
|
if("key" in e && typeof e["key"] === "string") {
|
||||||
if(![" "].includes(e.key)) {
|
if(![" "].includes(e.key)) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
let index = ICON_SEQUENCE.indexOf(task.icon) + 1;
|
setTask({...task, icon: ICONS[Math.floor(Math.random() * ICONS.length)]})
|
||||||
if(index === ICON_SEQUENCE.length) index = 0;
|
|
||||||
setTask({...task, icon: ICON_SEQUENCE[index]})
|
|
||||||
}, [task])
|
}, [task])
|
||||||
|
|
||||||
const submitTask = useCallback((e: SyntheticEvent<HTMLInputElement>) => {
|
const submitTask = useCallback((e: SyntheticEvent<HTMLInputElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
if(task.text === "") return
|
if(task.text === "") {
|
||||||
|
return
|
||||||
|
}
|
||||||
sendRequest({"Task": [null, task]})
|
sendRequest({"Task": [null, task]})
|
||||||
setInput(taskToString({...task, text: ""}))
|
setInput(taskToString({...task, text: ""}))
|
||||||
}, [sendRequest, task, setInput])
|
}, [sendRequest, task, setInput])
|
||||||
|
|
||||||
if(!isReady) return null
|
if(!isReady) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -70,7 +47,7 @@ export function TaskEditor({t, className, editorHook: {input, setInput, task, se
|
||||||
<TaskContainer
|
<TaskContainer
|
||||||
role={"form"}
|
role={"form"}
|
||||||
importance={task.importance}
|
importance={task.importance}
|
||||||
priority={task.priority}
|
deadline={task.deadline}
|
||||||
status={TaskSimplifiedStatus.NonExistent}
|
status={TaskSimplifiedStatus.NonExistent}
|
||||||
onSubmit={submitTask}
|
onSubmit={submitTask}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,38 +1,13 @@
|
||||||
import {TaskIcon} from "@/app/[lang]/board/[board]/(api)/(task)"
|
|
||||||
import {TaskIconComponent} from "@/app/[lang]/board/[board]/(page)/(task)/TaskIconComponent"
|
import {TaskIconComponent} from "@/app/[lang]/board/[board]/(page)/(task)/TaskIconComponent"
|
||||||
import {TaskSimplifiedStatus} from "@/app/[lang]/board/[board]/(page)/(task)/TaskSimplifiedStatus"
|
import {TaskSimplifiedStatus} from "@/app/[lang]/board/[board]/(page)/(task)/TaskSimplifiedStatus"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
import {SyntheticEvent} from "react"
|
import {SyntheticEvent} from "react"
|
||||||
|
|
||||||
|
|
||||||
const ICON_TO_KEY = {
|
export function TaskEditorIcon({t, icon, nextIcon}: {t: TFunction, icon: string, nextIcon: (e: SyntheticEvent<HTMLButtonElement>) => void}) {
|
||||||
[TaskIcon.Bookmark]: "taskIconBookmark",
|
|
||||||
[TaskIcon.Circle]: "taskIconCircle",
|
|
||||||
[TaskIcon.Square]: "taskIconSquare",
|
|
||||||
[TaskIcon.Heart]: "taskIconHeart",
|
|
||||||
[TaskIcon.Star]: "taskIconStar",
|
|
||||||
[TaskIcon.Sun]: "taskIconSun",
|
|
||||||
[TaskIcon.Moon]: "taskIconMoon",
|
|
||||||
[TaskIcon.Eye]: "taskIconEye",
|
|
||||||
[TaskIcon.Hand]: "taskIconHand",
|
|
||||||
[TaskIcon.Handshake]: "taskIconHandshake",
|
|
||||||
[TaskIcon.FaceSmile]: "taskIconFaceSmile",
|
|
||||||
[TaskIcon.User]: "taskIconUser",
|
|
||||||
[TaskIcon.Comment]: "taskIconComment",
|
|
||||||
[TaskIcon.Envelope]: "taskIconEnvelope",
|
|
||||||
[TaskIcon.File]: "taskIconFile",
|
|
||||||
[TaskIcon.PaperPlane]: "taskIconPaperPlane",
|
|
||||||
[TaskIcon.Building]: "taskIconBuilding",
|
|
||||||
[TaskIcon.Flag]: "taskIconFlag",
|
|
||||||
[TaskIcon.Bell]: "taskIconBell",
|
|
||||||
[TaskIcon.Clock]: "taskIconClock",
|
|
||||||
[TaskIcon.Image]: "taskIconImage",
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TaskEditorIcon({t, icon, nextIcon}: {t: TFunction, icon: TaskIcon, nextIcon: (e: SyntheticEvent<HTMLButtonElement>) => void}) {
|
|
||||||
return (
|
return (
|
||||||
<TaskIconComponent
|
<TaskIconComponent
|
||||||
title={t(ICON_TO_KEY[icon])}
|
title={icon}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
status={TaskSimplifiedStatus.NonExistent}
|
status={TaskSimplifiedStatus.NonExistent}
|
||||||
onInteract={nextIcon}
|
onInteract={nextIcon}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
export const DEADLINE_GLYPH_START = "["
|
||||||
|
export const DEADLINE_GLYPH_END = "]"
|
||||||
|
|
||||||
|
export const DEADLINE_GLYPH_RE = /\[(.+?)]\s?/
|
||||||
|
|
||||||
|
export const DEADLINE_DEFAULT = null
|
|
@ -1,8 +1,5 @@
|
||||||
import {TaskIcon} from "@/app/[lang]/board/[board]/(api)/(task)"
|
|
||||||
|
|
||||||
|
|
||||||
export const ICON_GLYPH = "#"
|
export const ICON_GLYPH = "#"
|
||||||
|
|
||||||
export const ICON_GLYPH_RE = /#([A-Za-z]+)\s?/
|
export const ICON_GLYPH_RE = /#([A-Za-z0-9-]+)\s?/
|
||||||
|
|
||||||
export const ICON_DEFAULT = TaskIcon.Circle
|
export const ICON_DEFAULT = "Circle"
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import {TaskPriority} from "@/app/[lang]/board/[board]/(api)/(task)"
|
|
||||||
|
|
||||||
|
|
||||||
export const PRIORITY_GLYPH = "/"
|
|
||||||
|
|
||||||
export const PRIORITY_GLYPH_RE = /\/([1-5])\s?/
|
|
||||||
|
|
||||||
export const PRIORITY_DEFAULT = TaskPriority.Normal
|
|
|
@ -1,8 +1,12 @@
|
||||||
import {Task, TaskIcon, TaskImportance, TaskPriority} from "@/app/[lang]/board/[board]/(api)/(task)"
|
import {Task, TaskImportance} from "@/app/[lang]/board/[board]/(api)/(task)"
|
||||||
import {ICON_GLYPH_RE} from "@/app/[lang]/board/[board]/(page)/(edit)/icon"
|
import {DEADLINE_GLYPH_RE} from "@/app/[lang]/board/[board]/(page)/(edit)/deadline"
|
||||||
|
import {ICON_DEFAULT, ICON_GLYPH_RE} from "@/app/[lang]/board/[board]/(page)/(edit)/icon"
|
||||||
import {IMPORTANCE_GLYPH_RE} from "@/app/[lang]/board/[board]/(page)/(edit)/importance"
|
import {IMPORTANCE_GLYPH_RE} from "@/app/[lang]/board/[board]/(page)/(edit)/importance"
|
||||||
import {PRIORITY_GLYPH_RE} from "@/app/[lang]/board/[board]/(page)/(edit)/priority"
|
import {default as dateParser} from "any-date-parser"
|
||||||
|
|
||||||
|
// ahhh i love typescript shenanigans
|
||||||
|
// @ts-ignore
|
||||||
|
const DATE_FROM_STRING = dateParser.fromString;
|
||||||
|
|
||||||
const VALUE_TO_TASK_IMPORTANCE = {
|
const VALUE_TO_TASK_IMPORTANCE = {
|
||||||
"1": TaskImportance.Highest,
|
"1": TaskImportance.Highest,
|
||||||
|
@ -12,61 +16,28 @@ const VALUE_TO_TASK_IMPORTANCE = {
|
||||||
"5": TaskImportance.Lowest,
|
"5": TaskImportance.Lowest,
|
||||||
}
|
}
|
||||||
|
|
||||||
const VALUE_TO_TASK_PRIORITY = {
|
export function stringToTask(text: string, lang: string): Task {
|
||||||
"1": TaskPriority.Highest,
|
|
||||||
"2": TaskPriority.High,
|
|
||||||
"3": TaskPriority.Normal,
|
|
||||||
"4": TaskPriority.Low,
|
|
||||||
"5": TaskPriority.Lowest,
|
|
||||||
}
|
|
||||||
|
|
||||||
const VALUE_TO_TASK_ICON = {
|
|
||||||
"bookmark": TaskIcon.Bookmark,
|
|
||||||
"circle": TaskIcon.Circle,
|
|
||||||
"square": TaskIcon.Square,
|
|
||||||
"heart": TaskIcon.Heart,
|
|
||||||
"star": TaskIcon.Star,
|
|
||||||
"sun": TaskIcon.Sun,
|
|
||||||
"moon": TaskIcon.Moon,
|
|
||||||
"eye": TaskIcon.Eye,
|
|
||||||
"hand": TaskIcon.Hand,
|
|
||||||
"handshake": TaskIcon.Handshake,
|
|
||||||
"facesmile": TaskIcon.FaceSmile,
|
|
||||||
"smile": TaskIcon.FaceSmile,
|
|
||||||
"user": TaskIcon.User,
|
|
||||||
"comment": TaskIcon.Comment,
|
|
||||||
"envelope": TaskIcon.Envelope,
|
|
||||||
"file": TaskIcon.File,
|
|
||||||
"paperplane": TaskIcon.PaperPlane,
|
|
||||||
"plane": TaskIcon.PaperPlane,
|
|
||||||
"building": TaskIcon.Building,
|
|
||||||
"flag": TaskIcon.Flag,
|
|
||||||
"bell": TaskIcon.Bell,
|
|
||||||
"clock": TaskIcon.Clock,
|
|
||||||
"image": TaskIcon.Image,
|
|
||||||
}
|
|
||||||
|
|
||||||
export function stringToTask(text: string): Task {
|
|
||||||
const priorityMatch = PRIORITY_GLYPH_RE.exec(text)
|
|
||||||
const importanceMatch = IMPORTANCE_GLYPH_RE.exec(text)
|
const importanceMatch = IMPORTANCE_GLYPH_RE.exec(text)
|
||||||
const iconMatch = ICON_GLYPH_RE.exec(text)
|
const iconMatch = ICON_GLYPH_RE.exec(text)
|
||||||
|
const deadlineMatch = DEADLINE_GLYPH_RE.exec(text)
|
||||||
|
|
||||||
const priority: TaskPriority = VALUE_TO_TASK_PRIORITY[priorityMatch?.[1]?.trim() as "1"|"2"|"3"|"4"|"5" ?? "3"]
|
|
||||||
const importance: TaskImportance = VALUE_TO_TASK_IMPORTANCE[importanceMatch?.[1]?.trim() as "1"|"2"|"3"|"4"|"5" ?? "3"]
|
const importance: TaskImportance = VALUE_TO_TASK_IMPORTANCE[importanceMatch?.[1]?.trim() as "1"|"2"|"3"|"4"|"5" ?? "3"]
|
||||||
// @ts-ignore
|
const icon: string = iconMatch?.[1]?.trim() ?? ICON_DEFAULT
|
||||||
const icon: TaskIcon = VALUE_TO_TASK_ICON[iconMatch?.[1]?.toLowerCase()?.trim()] ?? TaskIcon.Circle
|
const deadlineGroup: string | undefined = deadlineMatch?.[1]?.trim()
|
||||||
|
const deadlineDate: Date | undefined = deadlineGroup === undefined ? undefined : DATE_FROM_STRING(deadlineGroup, lang) ?? undefined
|
||||||
|
const deadline: number | null = (deadlineDate?.getTime?.()) ?? null
|
||||||
|
|
||||||
// TODO: Splice so the regexes aren't executed twice
|
// TODO: Splice so the regexes aren't executed twice
|
||||||
text = text.replace(PRIORITY_GLYPH_RE, "")
|
|
||||||
text = text.replace(IMPORTANCE_GLYPH_RE, "")
|
text = text.replace(IMPORTANCE_GLYPH_RE, "")
|
||||||
text = text.replace(ICON_GLYPH_RE, "")
|
text = text.replace(ICON_GLYPH_RE, "")
|
||||||
|
text = text.replace(DEADLINE_GLYPH_RE, "")
|
||||||
text = text.trim()
|
text = text.trim()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
text,
|
text,
|
||||||
priority,
|
|
||||||
importance,
|
importance,
|
||||||
icon,
|
icon,
|
||||||
|
deadline,
|
||||||
created_on: + new Date(),
|
created_on: + new Date(),
|
||||||
started_on: null,
|
started_on: null,
|
||||||
completed_on: null,
|
completed_on: null,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Task, TaskImportance, TaskPriority} from "@/app/[lang]/board/[board]/(api)/(task)"
|
import {Task, TaskImportance} from "@/app/[lang]/board/[board]/(api)/(task)"
|
||||||
|
import {DEADLINE_DEFAULT, DEADLINE_GLYPH_END, DEADLINE_GLYPH_START} from "@/app/[lang]/board/[board]/(page)/(edit)/deadline"
|
||||||
import {ICON_DEFAULT, ICON_GLYPH} from "@/app/[lang]/board/[board]/(page)/(edit)/icon"
|
import {ICON_DEFAULT, ICON_GLYPH} from "@/app/[lang]/board/[board]/(page)/(edit)/icon"
|
||||||
import {IMPORTANCE_DEFAULT, IMPORTANCE_GLYPH} from "@/app/[lang]/board/[board]/(page)/(edit)/importance"
|
import {IMPORTANCE_DEFAULT, IMPORTANCE_GLYPH} from "@/app/[lang]/board/[board]/(page)/(edit)/importance"
|
||||||
import {PRIORITY_DEFAULT, PRIORITY_GLYPH} from "@/app/[lang]/board/[board]/(page)/(edit)/priority"
|
|
||||||
|
|
||||||
|
|
||||||
const TASK_IMPORTANCE_TO_VALUE = {
|
const TASK_IMPORTANCE_TO_VALUE = {
|
||||||
|
@ -12,17 +12,25 @@ const TASK_IMPORTANCE_TO_VALUE = {
|
||||||
[TaskImportance.Lowest]: "5",
|
[TaskImportance.Lowest]: "5",
|
||||||
}
|
}
|
||||||
|
|
||||||
const TASK_PRIORITY_TO_VALUE = {
|
export function taskToString(t: Task, lang: string): string {
|
||||||
[TaskPriority.Highest]: "1",
|
const intlDate = Intl.DateTimeFormat(lang, {
|
||||||
[TaskPriority.High]: "2",
|
year: "numeric",
|
||||||
[TaskPriority.Normal]: "3",
|
month: "short",
|
||||||
[TaskPriority.Low]: "4",
|
day: "2-digit",
|
||||||
[TaskPriority.Lowest]: "5",
|
hour: "2-digit",
|
||||||
}
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
})
|
||||||
|
|
||||||
export function taskToString(t: Task): string {
|
|
||||||
let s = ""
|
let s = ""
|
||||||
|
|
||||||
|
if(t.deadline !== DEADLINE_DEFAULT) {
|
||||||
|
s += DEADLINE_GLYPH_START
|
||||||
|
s += intlDate.format(new Date(t.deadline))
|
||||||
|
s += DEADLINE_GLYPH_END
|
||||||
|
s += " "
|
||||||
|
}
|
||||||
|
|
||||||
if(t.icon !== ICON_DEFAULT) {
|
if(t.icon !== ICON_DEFAULT) {
|
||||||
s += ICON_GLYPH
|
s += ICON_GLYPH
|
||||||
s += t.icon
|
s += t.icon
|
||||||
|
@ -35,12 +43,6 @@ export function taskToString(t: Task): string {
|
||||||
s += " "
|
s += " "
|
||||||
}
|
}
|
||||||
|
|
||||||
if(t.priority !== PRIORITY_DEFAULT) {
|
|
||||||
s += PRIORITY_GLYPH
|
|
||||||
s += TASK_PRIORITY_TO_VALUE[t.priority]
|
|
||||||
s += " "
|
|
||||||
}
|
|
||||||
|
|
||||||
s += t.text
|
s += t.text
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
||||||
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
||||||
import {faUsers} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
|
@ -16,7 +16,7 @@ export function ConnectedClientsButton({t}: {t: TFunction}) {
|
||||||
title={t("privacyButtonTitle")}
|
title={t("privacyButtonTitle")}
|
||||||
className={cn(style.block, style.singleBlock)}
|
className={cn(style.block, style.singleBlock)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faUsers} size={"2xs"}/>
|
<FontAwesomeIcon icon={fas.faUsers} size={"2xs"}/>
|
||||||
|
|
||||||
{clients.length}
|
{clients.length}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
||||||
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
||||||
import {faObjectGroup} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
|
@ -17,7 +17,7 @@ export function CycleGroupingButton({t, next}: {t: TFunction, next: () => void})
|
||||||
onClick={next}
|
onClick={next}
|
||||||
className={cn(style.block, style.singleBlock)}
|
className={cn(style.block, style.singleBlock)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faObjectGroup}/>
|
<FontAwesomeIcon icon={fas.faObjectGroup}/>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
||||||
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
||||||
import {faArrowDownWideShort} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
|
@ -17,7 +17,7 @@ export function CycleSortingButton({t, next}: {t: TFunction, next: () => void})
|
||||||
onClick={next}
|
onClick={next}
|
||||||
className={cn(style.block, style.singleBlock)}
|
className={cn(style.block, style.singleBlock)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faArrowDownWideShort}/>
|
<FontAwesomeIcon icon={fas.faArrowDownWideShort}/>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
||||||
import {faHouse} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
|
@ -17,7 +17,7 @@ export function NavigateHomeButton({t}: {t: TFunction}) {
|
||||||
onClick={goHome}
|
onClick={goHome}
|
||||||
className={cn(style.block, style.singleBlock)}
|
className={cn(style.block, style.singleBlock)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faHouse}/>
|
<FontAwesomeIcon icon={fas.faHouse}/>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
||||||
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
||||||
import {useBoardMetadataEditor} from "@/app/[lang]/board/[board]/(page)/useBoardMetadataEditor"
|
import {useBoardMetadataEditor} from "@/app/[lang]/board/[board]/(page)/useBoardMetadataEditor"
|
||||||
import {faFloppyDisk, faPencil} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
|
@ -19,7 +19,7 @@ export function ToggleEditingButton({t, metadataHook}: {t: TFunction, metadataHo
|
||||||
onClick={metadataHook.toggleEditingMetadata}
|
onClick={metadataHook.toggleEditingMetadata}
|
||||||
className={cn(style.block, style.singleBlock)}
|
className={cn(style.block, style.singleBlock)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={metadataHook.isEditingMetadata ? faFloppyDisk : faPencil}/>
|
<FontAwesomeIcon icon={fas[metadataHook.isEditingMetadata ? "faFloppyDisk" : "faPencil"]}/>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {LockBoardRequest} from "@/app/[lang]/board/[board]/(api)/(request)"
|
import {LockBoardRequest} from "@/app/[lang]/board/[board]/(api)/(request)"
|
||||||
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
||||||
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
||||||
import {faLock, faLockOpen} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
|
@ -25,7 +25,7 @@ export function ToggleLockedButton({t}: {t: TFunction}) {
|
||||||
onClick={toggleLock}
|
onClick={toggleLock}
|
||||||
className={cn(style.block, style.singleBlock)}
|
className={cn(style.block, style.singleBlock)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={locked ? faLock : faLockOpen}/>
|
<FontAwesomeIcon icon={fas[locked ? "faLock" : "faLockOpen"]}/>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import {useStarredConsumer} from "@/app/[lang]/(layout)/(contextStarred)"
|
import {useStarredConsumer} from "@/app/[lang]/(layout)/(contextStarred)"
|
||||||
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
||||||
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
||||||
import {faStar as faStarRegular} from "@fortawesome/free-regular-svg-icons"
|
import {far, fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {faStar as faStarSolid} from "@fortawesome/free-solid-svg-icons"
|
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
|
@ -19,7 +20,7 @@ export function ToggleStarredButton({t}: {t: TFunction}) {
|
||||||
onClick={() => toggleStarred(boardName)}
|
onClick={() => toggleStarred(boardName)}
|
||||||
className={cn(style.block, style.singleBlock)}
|
className={cn(style.block, style.singleBlock)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={thisIsStarred ? faStarSolid : faStarRegular}/>
|
<FontAwesomeIcon icon={(thisIsStarred ? fas : far)["faStar"]}/>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {TrimBoardRequest} from "@/app/[lang]/board/[board]/(api)/(request)"
|
import {TrimBoardRequest} from "@/app/[lang]/board/[board]/(api)/(request)"
|
||||||
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
||||||
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
import style from "@/app/[lang]/board/[board]/(page)/(header)/BoardHeaderButtons.module.css"
|
||||||
import {faScissors} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
|
@ -25,7 +25,7 @@ export function TrimButton({t}: {t: TFunction}) {
|
||||||
onClick={requestTrim}
|
onClick={requestTrim}
|
||||||
className={cn(style.block, style.singleBlock)}
|
className={cn(style.block, style.singleBlock)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faScissors}/>
|
<FontAwesomeIcon icon={fas.faScissors}/>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {IconDefinition} from "@fortawesome/free-solid-svg-icons"
|
import {IconDefinition} from "@fortawesome/fontawesome-svg-core"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {SyntheticEvent} from "react"
|
import {SyntheticEvent} from "react"
|
||||||
|
|
|
@ -45,31 +45,39 @@
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
.taskPriorityHighest {
|
.taskDeadlineHour {
|
||||||
border: 4px solid hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.45);
|
border: 4px hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.45);
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.taskPriorityHigh {
|
.taskDeadlineDay {
|
||||||
border: 3px solid hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.25);
|
border: 3px hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.25);
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.taskPriorityNormal {
|
.taskDeadlineWeek {
|
||||||
border: 2px solid hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.15);
|
border: 2px hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.15);
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.taskPriorityLow {
|
.taskDeadlineMonth {
|
||||||
border: 1px solid hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.15);
|
border: 1px hsl(var(--bhsl-current-hue) var(--bhsl-current-saturation) var(--bhsl-current-lightness) / 0.15);
|
||||||
padding: 7px;
|
padding: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.taskPriorityLowest {
|
.taskDeadlineNone {
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.taskDeadlineIncoming {
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.taskDeadlinePast {
|
||||||
|
border-style: dashed;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes inProgress {
|
@keyframes inProgress {
|
||||||
0%, 100% {
|
0%, 100% {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {TaskImportance, TaskPriority} from "@/app/[lang]/board/[board]/(api)/(task)"
|
import {TaskImportance} from "@/app/[lang]/board/[board]/(api)/(task)"
|
||||||
import {TaskSimplifiedStatus} from "@/app/[lang]/board/[board]/(page)/(task)/TaskSimplifiedStatus"
|
import {TaskSimplifiedStatus} from "@/app/[lang]/board/[board]/(page)/(task)/TaskSimplifiedStatus"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {ComponentPropsWithoutRef} from "react"
|
import {ComponentPropsWithoutRef} from "react"
|
||||||
|
@ -9,12 +9,16 @@ export type TaskContainerProps = {
|
||||||
className?: string,
|
className?: string,
|
||||||
role: "article" | "form",
|
role: "article" | "form",
|
||||||
importance: TaskImportance,
|
importance: TaskImportance,
|
||||||
priority: TaskPriority,
|
deadline: number | null,
|
||||||
status: TaskSimplifiedStatus,
|
status: TaskSimplifiedStatus,
|
||||||
} & ComponentPropsWithoutRef<"article">
|
} & ComponentPropsWithoutRef<"article">
|
||||||
|
|
||||||
|
|
||||||
export function TaskContainer({role, className, importance, priority, status, ...props}: TaskContainerProps) {
|
export function TaskContainer({role, className, importance, deadline, status, ...props}: TaskContainerProps) {
|
||||||
|
const now = + new Date();
|
||||||
|
const delta = deadline === null ? null : deadline - now
|
||||||
|
const deltaAbs = delta === null ? null : Math.abs(delta)
|
||||||
|
|
||||||
const fullProps = {
|
const fullProps = {
|
||||||
className: cn({
|
className: cn({
|
||||||
"panel": true,
|
"panel": true,
|
||||||
|
@ -25,11 +29,13 @@ export function TaskContainer({role, className, importance, priority, status, ..
|
||||||
[style.taskImportanceNormal]: importance === TaskImportance.Normal,
|
[style.taskImportanceNormal]: importance === TaskImportance.Normal,
|
||||||
[style.taskImportanceLow]: importance === TaskImportance.Low,
|
[style.taskImportanceLow]: importance === TaskImportance.Low,
|
||||||
[style.taskImportanceLowest]: importance === TaskImportance.Lowest,
|
[style.taskImportanceLowest]: importance === TaskImportance.Lowest,
|
||||||
[style.taskPriorityHighest]: priority === TaskPriority.Highest,
|
[style.taskDeadlineNone]: deadline === null,
|
||||||
[style.taskPriorityHigh]: priority === TaskPriority.High,
|
[style.taskDeadlineHour]: deltaAbs !== null && deltaAbs < 60 * 60 * 1000,
|
||||||
[style.taskPriorityNormal]: priority === TaskPriority.Normal,
|
[style.taskDeadlineDay]: deltaAbs !== null && 60 * 60 * 1000 <= deltaAbs && deltaAbs < 24 * 60 * 60 * 1000,
|
||||||
[style.taskPriorityLow]: priority === TaskPriority.Low,
|
[style.taskDeadlineWeek]: deltaAbs !== null && 24 * 60 * 60 * 1000 <= deltaAbs && deltaAbs < 7 * 24 * 60 * 60 * 1000,
|
||||||
[style.taskPriorityLowest]: priority === TaskPriority.Lowest,
|
[style.taskDeadlineMonth]: deltaAbs !== null && deltaAbs >= 7 * 24 * 60 * 60 * 1000,
|
||||||
|
[style.taskDeadlineIncoming]: delta !== null && delta > 0,
|
||||||
|
[style.taskDeadlinePast]: delta !== null && delta < 0,
|
||||||
[style.taskStatusNonExistent]: status === TaskSimplifiedStatus.NonExistent,
|
[style.taskStatusNonExistent]: status === TaskSimplifiedStatus.NonExistent,
|
||||||
[style.taskStatusUnfinished]: status === TaskSimplifiedStatus.Unfinished,
|
[style.taskStatusUnfinished]: status === TaskSimplifiedStatus.Unfinished,
|
||||||
[style.taskStatusInProgress]: status === TaskSimplifiedStatus.InProgress,
|
[style.taskStatusInProgress]: status === TaskSimplifiedStatus.InProgress,
|
||||||
|
|
|
@ -2,3 +2,7 @@
|
||||||
border-radius: var(--b-border-radius);
|
border-radius: var(--b-border-radius);
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.taskDescriptionSource {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
|
@ -4,14 +4,16 @@ import style from "./TaskDescription.module.css"
|
||||||
|
|
||||||
type TaskDescriptionProps = {
|
type TaskDescriptionProps = {
|
||||||
className?: string,
|
className?: string,
|
||||||
|
isSource?: boolean,
|
||||||
text: string,
|
text: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TaskDescription({className, text}: TaskDescriptionProps) {
|
export function TaskDescription({className, isSource, text}: TaskDescriptionProps) {
|
||||||
return (
|
return (
|
||||||
<div className={cn({
|
<div className={cn({
|
||||||
"taskDescription": true,
|
"taskDescription": true,
|
||||||
[style.taskDescription]: true,
|
[style.taskDescription]: true,
|
||||||
|
[style.taskDescriptionSource]: isSource,
|
||||||
}, className)} tabIndex={0}>
|
}, className)} tabIndex={0}>
|
||||||
{text}
|
{text}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {TASK_ICON_TO_FONTAWESOME_REGULAR, TASK_ICON_TO_FONTAWESOME_SOLID, TaskIcon} from "@/app/[lang]/board/[board]/(api)/(task)"
|
|
||||||
import {TaskSimplifiedStatus} from "@/app/[lang]/board/[board]/(page)/(task)/TaskSimplifiedStatus"
|
import {TaskSimplifiedStatus} from "@/app/[lang]/board/[board]/(page)/(task)/TaskSimplifiedStatus"
|
||||||
|
import {fal, far, fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
|
import {IconPack} from "@fortawesome/fontawesome-svg-core"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {SyntheticEvent} from "react"
|
import {SyntheticEvent} from "react"
|
||||||
|
@ -9,11 +10,18 @@ import style from "./TaskIconComponent.module.css"
|
||||||
type TaskIconProps = {
|
type TaskIconProps = {
|
||||||
className?: string,
|
className?: string,
|
||||||
title: string,
|
title: string,
|
||||||
icon: TaskIcon,
|
icon: string,
|
||||||
status: TaskSimplifiedStatus,
|
status: TaskSimplifiedStatus,
|
||||||
onInteract?: (e: SyntheticEvent<HTMLButtonElement>) => void,
|
onInteract?: (e: SyntheticEvent<HTMLButtonElement>) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const STATUS_TO_PREFIX: {[t in TaskSimplifiedStatus]: IconPack} = {
|
||||||
|
[TaskSimplifiedStatus.Unfinished]: fal,
|
||||||
|
[TaskSimplifiedStatus.InProgress]: far,
|
||||||
|
[TaskSimplifiedStatus.Complete]: fas,
|
||||||
|
[TaskSimplifiedStatus.Journaled]: fas,
|
||||||
|
[TaskSimplifiedStatus.NonExistent]: far,
|
||||||
|
}
|
||||||
|
|
||||||
export function TaskIconComponent({className, title, icon, status, onInteract}: TaskIconProps) {
|
export function TaskIconComponent({className, title, icon, status, onInteract}: TaskIconProps) {
|
||||||
const clickable = !!onInteract;
|
const clickable = !!onInteract;
|
||||||
|
@ -32,7 +40,7 @@ export function TaskIconComponent({className, title, icon, status, onInteract}:
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
size={"lg"}
|
size={"lg"}
|
||||||
icon={[TaskSimplifiedStatus.Complete, TaskSimplifiedStatus.Journaled].includes(status) ? TASK_ICON_TO_FONTAWESOME_SOLID[icon] : TASK_ICON_TO_FONTAWESOME_REGULAR[icon]}
|
icon={STATUS_TO_PREFIX[status][`fa${icon}`]}
|
||||||
beatFade={status === TaskSimplifiedStatus.InProgress}
|
beatFade={status === TaskSimplifiedStatus.InProgress}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import {ColumningMode} from "@/app/[lang]/board/[board]/(page)/(view)/(columning)/ColumningMode"
|
import {ColumningMode} from "@/app/[lang]/board/[board]/(page)/(view)/(columning)/ColumningMode"
|
||||||
import {faTableColumns, faTableList} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
|
import {IconDefinition} from "@fortawesome/fontawesome-svg-core"
|
||||||
|
|
||||||
|
|
||||||
export const COLUMNING_MODE_TO_ICON = {
|
export const COLUMNING_MODE_TO_ICON: {[m in ColumningMode]: IconDefinition} = {
|
||||||
[ColumningMode.SingleColumn]: faTableList,
|
[ColumningMode.SingleColumn]: fas.faTableList,
|
||||||
[ColumningMode.MultiColumn]: faTableColumns,
|
[ColumningMode.MultiColumn]: fas.faTableColumns,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
export enum GroupingMode {
|
export enum GroupingMode {
|
||||||
ByImportance,
|
ByImportance,
|
||||||
ByPriority,
|
|
||||||
ByStatus,
|
ByStatus,
|
||||||
ByIcon,
|
ByIcon,
|
||||||
Journal,
|
Journal,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {TaskIcon, TaskImportance, TaskPriority} from "@/app/[lang]/board/[board]/(api)/(task)"
|
import {TaskImportance} from "@/app/[lang]/board/[board]/(api)/(task)"
|
||||||
|
import {ICONS} from "@/app/[lang]/board/[board]/(api)/(task)/TaskIcon"
|
||||||
import {GroupingMode} from "@/app/[lang]/board/[board]/(page)/(view)/(grouping)/GroupingMode"
|
import {GroupingMode} from "@/app/[lang]/board/[board]/(page)/(view)/(grouping)/GroupingMode"
|
||||||
import {TaskGroup} from "@/app/[lang]/board/[board]/(page)/(view)/(grouping)/TaskGroup"
|
import {TaskGroup} from "@/app/[lang]/board/[board]/(page)/(view)/(grouping)/TaskGroup"
|
||||||
|
|
||||||
|
@ -11,14 +12,6 @@ const TASK_IMPORTANCE_TO_VALUE = {
|
||||||
[TaskImportance.Lowest]: 5,
|
[TaskImportance.Lowest]: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
const TASK_PRIORITY_TO_VALUE = {
|
|
||||||
[TaskPriority.Highest]: 1,
|
|
||||||
[TaskPriority.High]: 2,
|
|
||||||
[TaskPriority.Normal]: 3,
|
|
||||||
[TaskPriority.Low]: 4,
|
|
||||||
[TaskPriority.Lowest]: 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
const TASK_STATUS_TO_VALUE = {
|
const TASK_STATUS_TO_VALUE = {
|
||||||
"Journaled": 3,
|
"Journaled": 3,
|
||||||
"Complete": 2,
|
"Complete": 2,
|
||||||
|
@ -26,45 +19,18 @@ const TASK_STATUS_TO_VALUE = {
|
||||||
"Unfinished": 0,
|
"Unfinished": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
const TASK_ICON_TO_VALUE = {
|
|
||||||
[TaskIcon.Bookmark]: 1,
|
|
||||||
[TaskIcon.Circle]: 2,
|
|
||||||
[TaskIcon.Square]: 3,
|
|
||||||
[TaskIcon.Heart]: 4,
|
|
||||||
[TaskIcon.Star]: 5,
|
|
||||||
[TaskIcon.Sun]: 6,
|
|
||||||
[TaskIcon.Moon]: 7,
|
|
||||||
[TaskIcon.Eye]: 8,
|
|
||||||
[TaskIcon.Hand]: 9,
|
|
||||||
[TaskIcon.Handshake]: 10,
|
|
||||||
[TaskIcon.FaceSmile]: 11,
|
|
||||||
[TaskIcon.User]: 12,
|
|
||||||
[TaskIcon.Comment]: 13,
|
|
||||||
[TaskIcon.Envelope]: 14,
|
|
||||||
[TaskIcon.File]: 15,
|
|
||||||
[TaskIcon.PaperPlane]: 16,
|
|
||||||
[TaskIcon.Building]: 17,
|
|
||||||
[TaskIcon.Flag]: 18,
|
|
||||||
[TaskIcon.Bell]: 19,
|
|
||||||
[TaskIcon.Clock]: 20,
|
|
||||||
[TaskIcon.Image]: 21,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GROUPING_MODE_TO_GROUP_SORTER_FUNCTION = {
|
export const GROUPING_MODE_TO_GROUP_SORTER_FUNCTION = {
|
||||||
[GroupingMode.ByImportance]: function sortGroupsByImportance(a: TaskGroup<TaskImportance>, b: TaskGroup<TaskImportance>): number {
|
[GroupingMode.ByImportance]: function sortGroupsByImportance(a: TaskGroup<TaskImportance>, b: TaskGroup<TaskImportance>): number {
|
||||||
return TASK_IMPORTANCE_TO_VALUE[a.k] - TASK_IMPORTANCE_TO_VALUE[b.k]
|
return TASK_IMPORTANCE_TO_VALUE[a.k] - TASK_IMPORTANCE_TO_VALUE[b.k]
|
||||||
},
|
},
|
||||||
[GroupingMode.ByPriority]: function sortGroupsByPriority(a: TaskGroup<TaskPriority>, b: TaskGroup<TaskPriority>): number {
|
|
||||||
return TASK_PRIORITY_TO_VALUE[a.k] - TASK_PRIORITY_TO_VALUE[b.k]
|
|
||||||
},
|
|
||||||
[GroupingMode.ByStatus]: function sortGroupsByStatus(a: TaskGroup<string>, b: TaskGroup<string>): number {
|
[GroupingMode.ByStatus]: function sortGroupsByStatus(a: TaskGroup<string>, b: TaskGroup<string>): number {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return TASK_STATUS_TO_VALUE[a.k] - TASK_STATUS_TO_VALUE[b.k]
|
return TASK_STATUS_TO_VALUE[a.k] - TASK_STATUS_TO_VALUE[b.k]
|
||||||
},
|
},
|
||||||
[GroupingMode.ByIcon]: function sortGroupsByIcon(a: TaskGroup<TaskIcon>, b: TaskGroup<TaskIcon>): number {
|
[GroupingMode.ByIcon]: function sortGroupsByIcon(a: TaskGroup<string>, b: TaskGroup<string>): number {
|
||||||
return TASK_ICON_TO_VALUE[a.k] - TASK_ICON_TO_VALUE[b.k]
|
return ICONS.indexOf(a.k as any) - ICONS.indexOf(b.k as any)
|
||||||
},
|
},
|
||||||
[GroupingMode.Journal]: function sortGroupsAlphabetically(a: TaskGroup<TaskIcon>, b: TaskGroup<TaskIcon>): number {
|
[GroupingMode.Journal]: function sortGroupsAlphabetically(a: TaskGroup<string>, b: TaskGroup<string>): number {
|
||||||
return b.k.localeCompare(a.k)
|
return b.k.localeCompare(a.k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,19 @@
|
||||||
import {TaskIcon, TaskImportance, TaskPriority} from "@/app/[lang]/board/[board]/(api)/(task)"
|
import {TaskImportance} from "@/app/[lang]/board/[board]/(api)/(task)"
|
||||||
import {TaskWithId} from "@/app/[lang]/board/[board]/(page)/(task)/TaskWithId"
|
import {TaskWithId} from "@/app/[lang]/board/[board]/(page)/(task)/TaskWithId"
|
||||||
import {GroupingMode} from "@/app/[lang]/board/[board]/(page)/(view)/(grouping)/GroupingMode"
|
import {GroupingMode} from "@/app/[lang]/board/[board]/(page)/(view)/(grouping)/GroupingMode"
|
||||||
|
|
||||||
|
|
||||||
export const GROUPING_MODE_TO_TASK_GROUPER_FUNCTION = {
|
export const GROUPING_MODE_TO_TASK_GROUPER_FUNCTION = {
|
||||||
[GroupingMode.ByImportance]: function groupTasksByImportance(t: TaskWithId): TaskImportance | null {
|
[GroupingMode.ByImportance]: function groupTasksByImportance(t: TaskWithId): TaskImportance | null {
|
||||||
if(t[1].journaled_on) return null
|
if(t[1].journaled_on) return null
|
||||||
return t[1].importance
|
return t[1].importance
|
||||||
},
|
},
|
||||||
[GroupingMode.ByPriority]: function groupTasksByPriority(t: TaskWithId): TaskPriority | null {
|
|
||||||
if(t[1].journaled_on) return null
|
|
||||||
return t[1].priority
|
|
||||||
},
|
|
||||||
[GroupingMode.ByStatus]: function groupTasksByStatus(t: TaskWithId): string | null {
|
[GroupingMode.ByStatus]: function groupTasksByStatus(t: TaskWithId): string | null {
|
||||||
if(t[1].journaled_on) return null
|
if(t[1].journaled_on) return null
|
||||||
else if(t[1].completed_on) return "Complete"
|
else if(t[1].completed_on) return "Complete"
|
||||||
else if(t[1].started_on) return "InProgress"
|
else if(t[1].started_on) return "InProgress"
|
||||||
else return "Unfinished"
|
else return "Unfinished"
|
||||||
},
|
},
|
||||||
[GroupingMode.ByIcon]: function groupTasksByIcon(t: TaskWithId): TaskIcon | null {
|
[GroupingMode.ByIcon]: function groupTasksByIcon(t: TaskWithId): string | null {
|
||||||
if(t[1].journaled_on) return null
|
if(t[1].journaled_on) return null
|
||||||
return t[1].icon
|
return t[1].icon
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {TASK_ICON_TO_FONTAWESOME_REGULAR, TaskIcon, TaskImportance, TaskPriority} from "@/app/[lang]/board/[board]/(api)/(task)"
|
import {TaskImportance} from "@/app/[lang]/board/[board]/(api)/(task)"
|
||||||
import style from "@/app/[lang]/board/[board]/(page)/(task)/TaskContainer.module.css"
|
import style from "@/app/[lang]/board/[board]/(page)/(task)/TaskContainer.module.css"
|
||||||
import {GroupingMode} from "@/app/[lang]/board/[board]/(page)/(view)/(grouping)/GroupingMode"
|
import {GroupingMode} from "@/app/[lang]/board/[board]/(page)/(view)/(grouping)/GroupingMode"
|
||||||
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
import {ReactNode} from "react"
|
import {ReactNode} from "react"
|
||||||
|
@ -48,41 +49,6 @@ export const GROUPING_MODE_TO_TITLE_COMPONENT: {[key in GroupingMode]: (t: Title
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
[GroupingMode.ByPriority]: function TitleFromPriority({t, k}: { t: TFunction, k: TaskPriority }): ReactNode {
|
|
||||||
switch(k) {
|
|
||||||
case TaskPriority.Highest:
|
|
||||||
return (
|
|
||||||
<span className={style.taskPriorityHighestColumnHeader}>
|
|
||||||
{t("taskPriorityHighest")}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
case TaskPriority.High:
|
|
||||||
return (
|
|
||||||
<span className={style.taskPriorityHighColumnHeader}>
|
|
||||||
{t("taskPriorityHigh")}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
case TaskPriority.Normal:
|
|
||||||
return (
|
|
||||||
<span className={style.taskPriorityNormalColumnHeader}>
|
|
||||||
{t("taskPriorityNormal")}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
case TaskPriority.Low:
|
|
||||||
return (
|
|
||||||
<span className={style.taskPriorityLowColumnHeader}>
|
|
||||||
{t("taskPriorityLow")}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
case TaskPriority.Lowest:
|
|
||||||
return (
|
|
||||||
<span className={style.taskPriorityLowestColumnHeader}>
|
|
||||||
{t("taskPriorityLowest")}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
[GroupingMode.ByStatus]: function TitleFromStatus({t, k}: { t: TFunction, k: string }): ReactNode {
|
[GroupingMode.ByStatus]: function TitleFromStatus({t, k}: { t: TFunction, k: string }): ReactNode {
|
||||||
switch(k) {
|
switch(k) {
|
||||||
case "Unfinished":
|
case "Unfinished":
|
||||||
|
@ -106,12 +72,12 @@ export const GROUPING_MODE_TO_TITLE_COMPONENT: {[key in GroupingMode]: (t: Title
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
[GroupingMode.ByIcon]: function TitleFromIcon({k}: { t: TFunction, k: TaskIcon }): ReactNode {
|
[GroupingMode.ByIcon]: function TitleFromIcon({k}: { t: TFunction, k: string }): ReactNode {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
<FontAwesomeIcon icon={TASK_ICON_TO_FONTAWESOME_REGULAR[k]}/>
|
<FontAwesomeIcon icon={fas[`fa${k}`]}/>
|
||||||
|
|
||||||
{TaskIcon[k]}
|
{k}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export enum SortingMode {
|
export enum SortingMode {
|
||||||
ByPriority,
|
|
||||||
ByImportance,
|
ByImportance,
|
||||||
|
ByDeadline,
|
||||||
ByIcon,
|
ByIcon,
|
||||||
ByText,
|
ByText,
|
||||||
ByStatus,
|
ByStatus,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {TaskIcon, TaskImportance, TaskPriority} from "@/app/[lang]/board/[board]/(api)/(task)"
|
import {TaskImportance} from "@/app/[lang]/board/[board]/(api)/(task)"
|
||||||
|
import {ICONS} from "@/app/[lang]/board/[board]/(api)/(task)/TaskIcon"
|
||||||
import {TaskWithId} from "@/app/[lang]/board/[board]/(page)/(task)/TaskWithId"
|
import {TaskWithId} from "@/app/[lang]/board/[board]/(page)/(task)/TaskWithId"
|
||||||
import {SortingMode} from "@/app/[lang]/board/[board]/(page)/(view)/(sorting)/SortingMode"
|
import {SortingMode} from "@/app/[lang]/board/[board]/(page)/(view)/(sorting)/SortingMode"
|
||||||
|
|
||||||
|
@ -11,38 +12,6 @@ const TASK_IMPORTANCE_TO_VALUE = {
|
||||||
[TaskImportance.Lowest]: 5,
|
[TaskImportance.Lowest]: 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
const TASK_PRIORITY_TO_VALUE = {
|
|
||||||
[TaskPriority.Highest]: 1,
|
|
||||||
[TaskPriority.High]: 2,
|
|
||||||
[TaskPriority.Normal]: 3,
|
|
||||||
[TaskPriority.Low]: 4,
|
|
||||||
[TaskPriority.Lowest]: 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
const TASK_ICON_TO_VALUE = {
|
|
||||||
[TaskIcon.Bookmark]: 1,
|
|
||||||
[TaskIcon.Circle]: 2,
|
|
||||||
[TaskIcon.Square]: 3,
|
|
||||||
[TaskIcon.Heart]: 4,
|
|
||||||
[TaskIcon.Star]: 5,
|
|
||||||
[TaskIcon.Sun]: 6,
|
|
||||||
[TaskIcon.Moon]: 7,
|
|
||||||
[TaskIcon.Eye]: 8,
|
|
||||||
[TaskIcon.Hand]: 9,
|
|
||||||
[TaskIcon.Handshake]: 10,
|
|
||||||
[TaskIcon.FaceSmile]: 11,
|
|
||||||
[TaskIcon.User]: 12,
|
|
||||||
[TaskIcon.Comment]: 13,
|
|
||||||
[TaskIcon.Envelope]: 14,
|
|
||||||
[TaskIcon.File]: 15,
|
|
||||||
[TaskIcon.PaperPlane]: 16,
|
|
||||||
[TaskIcon.Building]: 17,
|
|
||||||
[TaskIcon.Flag]: 18,
|
|
||||||
[TaskIcon.Bell]: 19,
|
|
||||||
[TaskIcon.Clock]: 20,
|
|
||||||
[TaskIcon.Image]: 21,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function getTaskSorter(sortingModes: SortingMode[]) {
|
export function getTaskSorter(sortingModes: SortingMode[]) {
|
||||||
return (a: TaskWithId, b: TaskWithId) => {
|
return (a: TaskWithId, b: TaskWithId) => {
|
||||||
|
@ -61,13 +30,13 @@ const SORTING_MODE_TO_SORTING_FUNCTION = {
|
||||||
return a[1].text.localeCompare(b[1].text)
|
return a[1].text.localeCompare(b[1].text)
|
||||||
},
|
},
|
||||||
[SortingMode.ByIcon]: function sortTasksByIcon(a: TaskWithId, b: TaskWithId) {
|
[SortingMode.ByIcon]: function sortTasksByIcon(a: TaskWithId, b: TaskWithId) {
|
||||||
return TASK_ICON_TO_VALUE[a[1].icon] - TASK_ICON_TO_VALUE[b[1].icon]
|
return ICONS.indexOf(a[1].icon as any) - ICONS.indexOf(b[1].icon as any)
|
||||||
},
|
},
|
||||||
[SortingMode.ByImportance]: function sortTasksByImportance(a: TaskWithId, b: TaskWithId) {
|
[SortingMode.ByImportance]: function sortTasksByImportance(a: TaskWithId, b: TaskWithId) {
|
||||||
return TASK_IMPORTANCE_TO_VALUE[a[1].importance] - TASK_IMPORTANCE_TO_VALUE[b[1].importance]
|
return TASK_IMPORTANCE_TO_VALUE[a[1].importance] - TASK_IMPORTANCE_TO_VALUE[b[1].importance]
|
||||||
},
|
},
|
||||||
[SortingMode.ByPriority]: function sortTasksByPriority(a: TaskWithId, b: TaskWithId) {
|
[SortingMode.ByDeadline]: function sortTasksByPriority(a: TaskWithId, b: TaskWithId) {
|
||||||
return TASK_PRIORITY_TO_VALUE[a[1].priority] - TASK_PRIORITY_TO_VALUE[b[1].priority]
|
return (a[1].deadline ?? -1) - (b[1].deadline ?? -1)
|
||||||
},
|
},
|
||||||
[SortingMode.ByStatus]: function sortTasksByStatus(a: TaskWithId, b: TaskWithId) {
|
[SortingMode.ByStatus]: function sortTasksByStatus(a: TaskWithId, b: TaskWithId) {
|
||||||
if(a[1].journaled_on && !b[1].journaled_on) return 1;
|
if(a[1].journaled_on && !b[1].journaled_on) return 1;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {ModifyTaskBoardRequest} from "@/app/[lang]/board/[board]/(api)/(request)"
|
import {ModifyTaskBoardRequest} from "@/app/[lang]/board/[board]/(api)/(request)"
|
||||||
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
||||||
|
import {taskToString} from "@/app/[lang]/board/[board]/(page)/(edit)/taskToString"
|
||||||
import {TaskActions} from "@/app/[lang]/board/[board]/(page)/(task)/TaskActions"
|
import {TaskActions} from "@/app/[lang]/board/[board]/(page)/(task)/TaskActions"
|
||||||
import {TaskContainer} from "@/app/[lang]/board/[board]/(page)/(task)/TaskContainer"
|
import {TaskContainer} from "@/app/[lang]/board/[board]/(page)/(task)/TaskContainer"
|
||||||
import {TaskDescription} from "@/app/[lang]/board/[board]/(page)/(task)/TaskDescription"
|
import {TaskDescription} from "@/app/[lang]/board/[board]/(page)/(task)/TaskDescription"
|
||||||
|
@ -12,7 +13,7 @@ import {TFunction} from "i18next"
|
||||||
import {Dispatch, KeyboardEvent, PointerEvent, SetStateAction, SyntheticEvent, useCallback, useState} from "react"
|
import {Dispatch, KeyboardEvent, PointerEvent, SetStateAction, SyntheticEvent, useCallback, useState} from "react"
|
||||||
|
|
||||||
|
|
||||||
export function TaskViewer({t, taskWithId: [id, task], setEditorInput}: {t: TFunction, taskWithId: TaskWithId, setEditorInput: Dispatch<SetStateAction<string>>}) {
|
export function TaskViewer({lang, t, taskWithId: [id, task], setEditorInput}: {lang: string, t: TFunction, taskWithId: TaskWithId, setEditorInput: Dispatch<SetStateAction<string>>}) {
|
||||||
const [isFlipped, setFlipped] = useState<boolean>(false)
|
const [isFlipped, setFlipped] = useState<boolean>(false)
|
||||||
const {sendRequest, boardState: {locked}} = useBoardConsumer()
|
const {sendRequest, boardState: {locked}} = useBoardConsumer()
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ export function TaskViewer({t, taskWithId: [id, task], setEditorInput}: {t: TFun
|
||||||
<TaskContainer
|
<TaskContainer
|
||||||
role={"article"}
|
role={"article"}
|
||||||
importance={task.importance}
|
importance={task.importance}
|
||||||
priority={task.priority}
|
deadline={task.deadline}
|
||||||
status={status}
|
status={status}
|
||||||
onKeyDown={toggleFlipOnKeyDown}
|
onKeyDown={toggleFlipOnKeyDown}
|
||||||
onPointerEnter={flipOnPointerEnter}
|
onPointerEnter={flipOnPointerEnter}
|
||||||
|
@ -138,12 +139,13 @@ export function TaskViewer({t, taskWithId: [id, task], setEditorInput}: {t: TFun
|
||||||
>
|
>
|
||||||
<TaskViewerIcon
|
<TaskViewerIcon
|
||||||
t={t}
|
t={t}
|
||||||
icon={task.icon}
|
icon={task.icon as any}
|
||||||
status={status}
|
status={status}
|
||||||
onInteract={status === TaskSimplifiedStatus.Journaled ? undefined : toggleStatus}
|
onInteract={status === TaskSimplifiedStatus.Journaled ? undefined : toggleStatus}
|
||||||
/>
|
/>
|
||||||
<TaskDescription
|
<TaskDescription
|
||||||
text={task.text}
|
isSource={isFlipped}
|
||||||
|
text={isFlipped ? taskToString(task, lang) : task.text}
|
||||||
/>
|
/>
|
||||||
{sideElements}
|
{sideElements}
|
||||||
</TaskContainer>
|
</TaskContainer>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import {TaskIcon} from "@/app/[lang]/board/[board]/(api)/(task)"
|
|
||||||
import {TaskIconComponent} from "@/app/[lang]/board/[board]/(page)/(task)/TaskIconComponent"
|
import {TaskIconComponent} from "@/app/[lang]/board/[board]/(page)/(task)/TaskIconComponent"
|
||||||
import {TaskSimplifiedStatus} from "@/app/[lang]/board/[board]/(page)/(task)/TaskSimplifiedStatus"
|
import {TaskSimplifiedStatus} from "@/app/[lang]/board/[board]/(page)/(task)/TaskSimplifiedStatus"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
|
@ -15,7 +14,7 @@ const TASK_STATUS_TO_I18N_KEY: {[key in TaskSimplifiedStatus]: string} = {
|
||||||
export type TaskViewerIconProps = {
|
export type TaskViewerIconProps = {
|
||||||
t: TFunction,
|
t: TFunction,
|
||||||
status: TaskSimplifiedStatus,
|
status: TaskSimplifiedStatus,
|
||||||
icon: TaskIcon,
|
icon: string,
|
||||||
onInteract?: Parameters<typeof TaskIconComponent>[0]["onInteract"]
|
onInteract?: Parameters<typeof TaskIconComponent>[0]["onInteract"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {UpdateTaskBoardChange} from "@/app/[lang]/board/[board]/(api)/(change)"
|
||||||
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoard)"
|
||||||
import {TaskButton} from "@/app/[lang]/board/[board]/(page)/(task)/TaskButton"
|
import {TaskButton} from "@/app/[lang]/board/[board]/(page)/(task)/TaskButton"
|
||||||
import {TaskWithId} from "@/app/[lang]/board/[board]/(page)/(task)/TaskWithId"
|
import {TaskWithId} from "@/app/[lang]/board/[board]/(page)/(task)/TaskWithId"
|
||||||
import {faBookBookmark} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
import {SyntheticEvent, useCallback} from "react"
|
import {SyntheticEvent, useCallback} from "react"
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export function TaskViewerJournalButton({t, taskWithId: [id, task]}: {t: TFuncti
|
||||||
return (
|
return (
|
||||||
<TaskButton
|
<TaskButton
|
||||||
title={t("taskButtonJournal")}
|
title={t("taskButtonJournal")}
|
||||||
icon={faBookBookmark}
|
icon={fas.faBookBookmark}
|
||||||
onInteract={locked ? undefined : toggleJournalTask}
|
onInteract={locked ? undefined : toggleJournalTask}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {useBoardConsumer} from "@/app/[lang]/board/[board]/(layout)/(contextBoar
|
||||||
import {taskToString} from "@/app/[lang]/board/[board]/(page)/(edit)/taskToString"
|
import {taskToString} from "@/app/[lang]/board/[board]/(page)/(edit)/taskToString"
|
||||||
import {TaskButton} from "@/app/[lang]/board/[board]/(page)/(task)/TaskButton"
|
import {TaskButton} from "@/app/[lang]/board/[board]/(page)/(task)/TaskButton"
|
||||||
import {TaskWithId} from "@/app/[lang]/board/[board]/(page)/(task)/TaskWithId"
|
import {TaskWithId} from "@/app/[lang]/board/[board]/(page)/(task)/TaskWithId"
|
||||||
import {faTrashArrowUp} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
import {Dispatch, SetStateAction, SyntheticEvent, useCallback} from "react"
|
import {Dispatch, SetStateAction, SyntheticEvent, useCallback} from "react"
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export function TaskViewerRecreateButton({t, taskWithId: [id, task], setEditorIn
|
||||||
return (
|
return (
|
||||||
<TaskButton
|
<TaskButton
|
||||||
title={t("taskButtonRecreate")}
|
title={t("taskButtonRecreate")}
|
||||||
icon={faTrashArrowUp}
|
icon={fas.faTrashArrowUp}
|
||||||
onInteract={locked ? undefined : recreateTask}
|
onInteract={locked ? undefined : recreateTask}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,38 +4,39 @@ import {GroupingMode} from "@/app/[lang]/board/[board]/(page)/(view)/(grouping)"
|
||||||
import {SortingMode} from "@/app/[lang]/board/[board]/(page)/(view)/(sorting)"
|
import {SortingMode} from "@/app/[lang]/board/[board]/(page)/(view)/(sorting)"
|
||||||
import {BoardViewer} from "@/app/[lang]/board/[board]/(page)/(view)/BoardViewer"
|
import {BoardViewer} from "@/app/[lang]/board/[board]/(page)/(view)/BoardViewer"
|
||||||
import {SplashWithIcon} from "@/app/[lang]/board/[board]/(page)/(view)/SplashWithIcon"
|
import {SplashWithIcon} from "@/app/[lang]/board/[board]/(page)/(view)/SplashWithIcon"
|
||||||
import {faAsterisk, faGear, faLink, faLinkSlash} from "@fortawesome/free-solid-svg-icons"
|
import {fas} from "@awesome.me/kit-dfe340c874/icons"
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import {TFunction} from "i18next"
|
import {TFunction} from "i18next"
|
||||||
import {Dispatch, SetStateAction} from "react"
|
import {Dispatch, SetStateAction} from "react"
|
||||||
|
|
||||||
|
|
||||||
export function BoardMain({t, className, columning, sorting, grouping, setEditorInput}: {t: TFunction, className?: string, columning: ColumningMode, grouping: GroupingMode, sorting: SortingMode[], setEditorInput: Dispatch<SetStateAction<string>>}) {
|
export function BoardMain({lang, t, className, columning, sorting, grouping, setEditorInput}: {lang: string, t: TFunction, className?: string, columning: ColumningMode, grouping: GroupingMode, sorting: SortingMode[], setEditorInput: Dispatch<SetStateAction<string>>}) {
|
||||||
const {webSocketState, webSocketBackoffMs, boardState} = useBoardConsumer()
|
const {webSocketState, webSocketBackoffMs, boardState} = useBoardConsumer()
|
||||||
|
|
||||||
switch(webSocketState) {
|
switch(webSocketState) {
|
||||||
case undefined:
|
case undefined:
|
||||||
return <SplashWithIcon
|
return <SplashWithIcon
|
||||||
icon={<FontAwesomeIcon size={"4x"} icon={faGear} beatFade/>}
|
icon={<FontAwesomeIcon size={"4x"} icon={fas.faGear} beatFade/>}
|
||||||
text={t("boardPreparing")}
|
text={t("boardPreparing")}
|
||||||
className={className}
|
className={className}
|
||||||
/>
|
/>
|
||||||
case WebSocket.CONNECTING:
|
case WebSocket.CONNECTING:
|
||||||
return <SplashWithIcon
|
return <SplashWithIcon
|
||||||
icon={<FontAwesomeIcon size={"4x"} icon={faLink} beatFade/>}
|
icon={<FontAwesomeIcon size={"4x"} icon={fas.faLink} beatFade/>}
|
||||||
text={t("boardConnecting")}
|
text={t("boardConnecting")}
|
||||||
className={className}
|
className={className}
|
||||||
/>
|
/>
|
||||||
case WebSocket.OPEN:
|
case WebSocket.OPEN:
|
||||||
if(Object.keys(boardState.tasks).length === 0) {
|
if(Object.keys(boardState.tasks).length === 0) {
|
||||||
return <SplashWithIcon
|
return <SplashWithIcon
|
||||||
icon={<FontAwesomeIcon size={"4x"} icon={faAsterisk}/>}
|
icon={<FontAwesomeIcon size={"4x"} icon={fas.faAsterisk}/>}
|
||||||
text={t("boardEmpty")}
|
text={t("boardEmpty")}
|
||||||
className={className}
|
className={className}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return <BoardViewer
|
return <BoardViewer
|
||||||
|
lang={lang}
|
||||||
t={t}
|
t={t}
|
||||||
columning={columning}
|
columning={columning}
|
||||||
sorting={sorting}
|
sorting={sorting}
|
||||||
|
@ -46,13 +47,13 @@ export function BoardMain({t, className, columning, sorting, grouping, setEditor
|
||||||
}
|
}
|
||||||
case WebSocket.CLOSING:
|
case WebSocket.CLOSING:
|
||||||
return <SplashWithIcon
|
return <SplashWithIcon
|
||||||
icon={<FontAwesomeIcon size={"4x"} icon={faLinkSlash} beatFade/>}
|
icon={<FontAwesomeIcon size={"4x"} icon={fas.faLinkSlash} beatFade/>}
|
||||||
text={t("boardDisconnecting")}
|
text={t("boardDisconnecting")}
|
||||||
className={className}
|
className={className}
|
||||||
/>
|
/>
|
||||||
case WebSocket.CLOSED:
|
case WebSocket.CLOSED:
|
||||||
return <SplashWithIcon
|
return <SplashWithIcon
|
||||||
icon={<FontAwesomeIcon size={"4x"} icon={faLinkSlash}/>}
|
icon={<FontAwesomeIcon size={"4x"} icon={fas.faLinkSlash}/>}
|
||||||
text={t("boardDisconnected", { retryingInSeconds: Math.ceil((webSocketBackoffMs ?? 0) / 1000).toString() })}
|
text={t("boardDisconnected", { retryingInSeconds: Math.ceil((webSocketBackoffMs ?? 0) / 1000).toString() })}
|
||||||
className={className}
|
className={className}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {Dispatch, SetStateAction} from "react"
|
||||||
import style from "./BoardViewer.module.css"
|
import style from "./BoardViewer.module.css"
|
||||||
|
|
||||||
|
|
||||||
export function BoardViewer({className, t, columning, grouping, sorting, setEditorInput}: {className?: string, t: TFunction, columning: ColumningMode, grouping: GroupingMode, sorting: SortingMode[], setEditorInput: Dispatch<SetStateAction<string>>}) {
|
export function BoardViewer({className, lang, t, columning, grouping, sorting, setEditorInput}: {className?: string, t: TFunction, lang: string, columning: ColumningMode, grouping: GroupingMode, sorting: SortingMode[], setEditorInput: Dispatch<SetStateAction<string>>}) {
|
||||||
const {boardState: {tasks}} = useBoardConsumer()
|
const {boardState: {tasks}} = useBoardConsumer()
|
||||||
const {taskGroups} = useBoardTasksArranger(tasks, grouping, sorting);
|
const {taskGroups} = useBoardTasksArranger(tasks, grouping, sorting);
|
||||||
|
|
||||||
|
@ -22,12 +22,12 @@ export function BoardViewer({className, t, columning, grouping, sorting, setEdit
|
||||||
[style.boardMainTaskGroupsMultiColumn]: columning === ColumningMode.MultiColumn,
|
[style.boardMainTaskGroupsMultiColumn]: columning === ColumningMode.MultiColumn,
|
||||||
[style.boardMainTaskGroupsSingleColumn]: columning === ColumningMode.SingleColumn,
|
[style.boardMainTaskGroupsSingleColumn]: columning === ColumningMode.SingleColumn,
|
||||||
})}>
|
})}>
|
||||||
{taskGroups.map((tg) => <BoardViewerColumn t={t} taskGroup={tg} key={tg.k} grouping={grouping} setEditorInput={setEditorInput}/>)}
|
{taskGroups.map((tg) => <BoardViewerColumn lang={lang} t={t} taskGroup={tg} key={tg.k} grouping={grouping} setEditorInput={setEditorInput}/>)}
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BoardViewerColumn({t, grouping, taskGroup, setEditorInput}: {t: TFunction, grouping: GroupingMode, taskGroup: TaskGroup<string | number>, setEditorInput: Dispatch<SetStateAction<string>>}) {
|
export function BoardViewerColumn({lang, t, grouping, taskGroup, setEditorInput}: {lang: string, t: TFunction, grouping: GroupingMode, taskGroup: TaskGroup<string | number>, setEditorInput: Dispatch<SetStateAction<string>>}) {
|
||||||
const ColumnTitle = GROUPING_MODE_TO_TITLE_COMPONENT[grouping]
|
const ColumnTitle = GROUPING_MODE_TO_TITLE_COMPONENT[grouping]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -36,7 +36,7 @@ export function BoardViewerColumn({t, grouping, taskGroup, setEditorInput}: {t:
|
||||||
<ColumnTitle t={t} k={taskGroup.k}/>
|
<ColumnTitle t={t} k={taskGroup.k}/>
|
||||||
</h3>
|
</h3>
|
||||||
<div className={style.boardColumnContents}>
|
<div className={style.boardColumnContents}>
|
||||||
{taskGroup.tasks.map((task: TaskWithId) => <TaskViewer t={t} taskWithId={task} key={task[0]} setEditorInput={setEditorInput}/>)}
|
{taskGroup.tasks.map((task: TaskWithId) => <TaskViewer lang={lang} t={t} taskWithId={task} key={task[0]} setEditorInput={setEditorInput}/>)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,7 +15,7 @@ export function BoardPage({lang}: {lang: string}) {
|
||||||
const internationalization = useClientTranslation(lang, "board")
|
const internationalization = useClientTranslation(lang, "board")
|
||||||
const metadataHook = useBoardMetadataEditor()
|
const metadataHook = useBoardMetadataEditor()
|
||||||
const layoutHook = useBoardLayoutEditor()
|
const layoutHook = useBoardLayoutEditor()
|
||||||
const editorHook = useTaskEditor()
|
const editorHook = useTaskEditor(lang)
|
||||||
|
|
||||||
const t = internationalization.t as TFunction
|
const t = internationalization.t as TFunction
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ export function BoardPage({lang}: {lang: string}) {
|
||||||
layoutHook={layoutHook}
|
layoutHook={layoutHook}
|
||||||
/>
|
/>
|
||||||
<BoardMain
|
<BoardMain
|
||||||
|
lang={lang}
|
||||||
t={t}
|
t={t}
|
||||||
className={style.pageMain}
|
className={style.pageMain}
|
||||||
columning={layoutHook.columningHook.value}
|
columning={layoutHook.columningHook.value}
|
||||||
|
|
|
@ -19,7 +19,6 @@ export function useBoardLayoutEditor() {
|
||||||
ColumningMode.MultiColumn,
|
ColumningMode.MultiColumn,
|
||||||
])
|
])
|
||||||
const groupingHook = useCycler(useLocalStorage<number | undefined>(localStorageKeyGrouping, undefined), [
|
const groupingHook = useCycler(useLocalStorage<number | undefined>(localStorageKeyGrouping, undefined), [
|
||||||
GroupingMode.ByPriority,
|
|
||||||
GroupingMode.ByImportance,
|
GroupingMode.ByImportance,
|
||||||
GroupingMode.ByStatus,
|
GroupingMode.ByStatus,
|
||||||
GroupingMode.ByIcon,
|
GroupingMode.ByIcon,
|
||||||
|
@ -28,7 +27,7 @@ export function useBoardLayoutEditor() {
|
||||||
const sortingHook = useCycler(useLocalStorage<number | undefined>(localStorageKeySorting, undefined), [
|
const sortingHook = useCycler(useLocalStorage<number | undefined>(localStorageKeySorting, undefined), [
|
||||||
[
|
[
|
||||||
SortingMode.ByStatus,
|
SortingMode.ByStatus,
|
||||||
SortingMode.ByPriority,
|
SortingMode.ByDeadline,
|
||||||
SortingMode.ByImportance,
|
SortingMode.ByImportance,
|
||||||
SortingMode.ByText,
|
SortingMode.ByText,
|
||||||
SortingMode.ByIcon,
|
SortingMode.ByIcon,
|
||||||
|
@ -37,7 +36,7 @@ export function useBoardLayoutEditor() {
|
||||||
[
|
[
|
||||||
SortingMode.ByStatus,
|
SortingMode.ByStatus,
|
||||||
SortingMode.ByImportance,
|
SortingMode.ByImportance,
|
||||||
SortingMode.ByPriority,
|
SortingMode.ByDeadline,
|
||||||
SortingMode.ByText,
|
SortingMode.ByText,
|
||||||
SortingMode.ByIcon,
|
SortingMode.ByIcon,
|
||||||
SortingMode.ByCreation,
|
SortingMode.ByCreation,
|
||||||
|
@ -53,7 +52,7 @@ export function useBoardLayoutEditor() {
|
||||||
SortingMode.ByCreation,
|
SortingMode.ByCreation,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
SortingMode.ByPriority,
|
SortingMode.ByDeadline,
|
||||||
SortingMode.ByImportance,
|
SortingMode.ByImportance,
|
||||||
SortingMode.ByText,
|
SortingMode.ByText,
|
||||||
SortingMode.ByIcon,
|
SortingMode.ByIcon,
|
||||||
|
@ -61,7 +60,7 @@ export function useBoardLayoutEditor() {
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
SortingMode.ByImportance,
|
SortingMode.ByImportance,
|
||||||
SortingMode.ByPriority,
|
SortingMode.ByDeadline,
|
||||||
SortingMode.ByText,
|
SortingMode.ByText,
|
||||||
SortingMode.ByIcon,
|
SortingMode.ByIcon,
|
||||||
SortingMode.ByCreation,
|
SortingMode.ByCreation,
|
||||||
|
|
|
@ -4,12 +4,12 @@ import {taskToString} from "@/app/[lang]/board/[board]/(page)/(edit)/taskToStrin
|
||||||
import {useCallback, useMemo, useState} from "react"
|
import {useCallback, useMemo, useState} from "react"
|
||||||
|
|
||||||
|
|
||||||
export function useTaskEditor() {
|
export function useTaskEditor(lang: string) {
|
||||||
const [input, setInput] = useState<string>("")
|
const [input, setInput] = useState<string>("")
|
||||||
const task = useMemo(() => stringToTask(input), [input])
|
const task = useMemo(() => stringToTask(input, lang), [input, lang])
|
||||||
|
|
||||||
const setTask = useCallback((t: Task) => {
|
const setTask = useCallback((t: Task) => {
|
||||||
setInput(taskToString(t))
|
setInput(taskToString(t, lang))
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -2,6 +2,13 @@
|
||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@awesome.me/kit-dfe340c874@^1.0.10":
|
||||||
|
version "1.0.10"
|
||||||
|
resolved "https://npm.fontawesome.com/@awesome.me/kit-dfe340c874/-/1.0.10/kit-dfe340c874-1.0.10.tgz#a09e8b5a92ab9d58e703008f5adde7aaeaf6f629"
|
||||||
|
integrity sha512-q8cIvNP/0xULSNs5XqusIa4pTgI9pvMubNZIQQWIDM8yacpYt1wM54jOceq0g3tGTzl1HummO4oN5Xdfbm8gww==
|
||||||
|
dependencies:
|
||||||
|
"@fortawesome/fontawesome-common-types" "^6.6.0"
|
||||||
|
|
||||||
"@babel/runtime@^7.23.2":
|
"@babel/runtime@^7.23.2":
|
||||||
version "7.25.6"
|
version "7.25.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2"
|
||||||
|
@ -9,35 +16,21 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.14.0"
|
regenerator-runtime "^0.14.0"
|
||||||
|
|
||||||
"@fortawesome/fontawesome-common-types@6.6.0":
|
"@fortawesome/fontawesome-common-types@6.6.0", "@fortawesome/fontawesome-common-types@^6.6.0":
|
||||||
version "6.6.0"
|
version "6.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz#31ab07ca6a06358c5de4d295d4711b675006163f"
|
resolved "https://npm.fontawesome.com/@fortawesome/fontawesome-common-types/-/6.6.0/fontawesome-common-types-6.6.0.tgz#31ab07ca6a06358c5de4d295d4711b675006163f"
|
||||||
integrity sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==
|
integrity sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==
|
||||||
|
|
||||||
"@fortawesome/fontawesome-svg-core@*":
|
"@fortawesome/fontawesome-svg-core@*":
|
||||||
version "6.6.0"
|
version "6.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz#2a24c32ef92136e98eae2ff334a27145188295ff"
|
resolved "https://npm.fontawesome.com/@fortawesome/fontawesome-svg-core/-/6.6.0/fontawesome-svg-core-6.6.0.tgz#2a24c32ef92136e98eae2ff334a27145188295ff"
|
||||||
integrity sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==
|
integrity sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@fortawesome/fontawesome-common-types" "6.6.0"
|
"@fortawesome/fontawesome-common-types" "6.6.0"
|
||||||
|
|
||||||
"@fortawesome/free-regular-svg-icons@*":
|
|
||||||
version "6.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.6.0.tgz#fc49a947ac8dfd20403c9ea5f37f0919425bdf04"
|
|
||||||
integrity sha512-Yv9hDzL4aI73BEwSEh20clrY8q/uLxawaQ98lekBx6t9dQKDHcDzzV1p2YtBGTtolYtNqcWdniOnhzB+JPnQEQ==
|
|
||||||
dependencies:
|
|
||||||
"@fortawesome/fontawesome-common-types" "6.6.0"
|
|
||||||
|
|
||||||
"@fortawesome/free-solid-svg-icons@*":
|
|
||||||
version "6.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz#061751ca43be4c4d814f0adbda8f006164ec9f3b"
|
|
||||||
integrity sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==
|
|
||||||
dependencies:
|
|
||||||
"@fortawesome/fontawesome-common-types" "6.6.0"
|
|
||||||
|
|
||||||
"@fortawesome/react-fontawesome@*":
|
"@fortawesome/react-fontawesome@*":
|
||||||
version "0.2.2"
|
version "0.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz#68b058f9132b46c8599875f6a636dad231af78d4"
|
resolved "https://npm.fontawesome.com/@fortawesome/react-fontawesome/-/0.2.2/react-fontawesome-0.2.2.tgz#68b058f9132b46c8599875f6a636dad231af78d4"
|
||||||
integrity sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==
|
integrity sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==
|
||||||
dependencies:
|
dependencies:
|
||||||
prop-types "^15.8.1"
|
prop-types "^15.8.1"
|
||||||
|
@ -142,6 +135,11 @@
|
||||||
"@types/prop-types" "*"
|
"@types/prop-types" "*"
|
||||||
csstype "^3.0.2"
|
csstype "^3.0.2"
|
||||||
|
|
||||||
|
any-date-parser@^1.5.4:
|
||||||
|
version "1.5.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/any-date-parser/-/any-date-parser-1.5.4.tgz#3c462f3a419b7147a88a8c7cab91da4193ff680b"
|
||||||
|
integrity sha512-S4gl9UmXNk9XXSQxp5w5harUD6aM0fepyL3dZM/B3znX57sWf792hS2UvvCFIHECfpsqfKbQ+cqWBky4AKyRIg==
|
||||||
|
|
||||||
busboy@1.6.0:
|
busboy@1.6.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
|
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
|
||||||
|
|
Loading…
Reference in a new issue