From 2ad220e525628c0adb125b3ff266046cc0425a2a Mon Sep 17 00:00:00 2001 From: misterkirill Date: Fri, 11 Jul 2025 00:30:47 +0500 Subject: [PATCH] feat: add title to the editor state --- src/app/{actions.ts => actions/auth.ts} | 0 src/app/actions/blocks.ts | 23 +++ src/components/Header.tsx | 2 +- src/components/editor/Editor.tsx | 15 +- src/components/forms/AuthForm.tsx | 2 +- src/lib/editorReducer.ts | 201 ++++++++++++++---------- 6 files changed, 155 insertions(+), 88 deletions(-) rename src/app/{actions.ts => actions/auth.ts} (100%) create mode 100644 src/app/actions/blocks.ts diff --git a/src/app/actions.ts b/src/app/actions/auth.ts similarity index 100% rename from src/app/actions.ts rename to src/app/actions/auth.ts diff --git a/src/app/actions/blocks.ts b/src/app/actions/blocks.ts new file mode 100644 index 0000000..a2c18fb --- /dev/null +++ b/src/app/actions/blocks.ts @@ -0,0 +1,23 @@ +"use server"; + +import { eq } from "drizzle-orm"; +import { blocksTable } from "@/lib/db/schema"; +import { db } from "@/lib/db"; + +export async function updateBlock({ + id, + tag, + lines, +}: { + id: string; + tag?: string; + lines?: string[]; +}) { + await db + .update(blocksTable) + .set({ + ...(tag !== undefined ? { tag } : {}), + ...(lines !== undefined ? { lines } : {}), + }) + .where(eq(blocksTable.id, id)); +} diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 3de09a0..bb3f47c 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,6 +1,6 @@ import Link from "next/link"; import { CircleQuestionMark, List, Plus, UserRound, UserRoundMinus } from "lucide-react"; -import { logOut } from "@/app/actions"; +import { logOut } from "@/app/actions/auth"; import { getAuth } from "@/lib/auth"; import HeaderButton from "./ui/HeaderButton"; diff --git a/src/components/editor/Editor.tsx b/src/components/editor/Editor.tsx index 7f3feb7..ae99aec 100644 --- a/src/components/editor/Editor.tsx +++ b/src/components/editor/Editor.tsx @@ -1,6 +1,6 @@ "use client"; -import { useReducer } from "react"; +import { ChangeEvent, useReducer } from "react"; import { Copy, Plus } from "lucide-react"; import { v4 as uuidv4 } from "uuid"; import { editorReducer, IBlock } from "@/lib/editorReducer"; @@ -25,7 +25,14 @@ const defaultBlocks = [ ]; export default function Editor(props: EditorProps) { - const [state, dispatch] = useReducer(editorReducer, props.defaultBlocks || defaultBlocks); + const [state, dispatch] = useReducer(editorReducer, { + title: props.defaultTitle || "Untitled", + blocks: props.defaultBlocks || defaultBlocks, + }); + + const handleUpdateTitle = (e: ChangeEvent) => { + dispatch({ type: "update_title", title: e.target.value }); + } const handleAddBlock = () => { dispatch({ type: "add_block" }); @@ -37,8 +44,8 @@ export default function Editor(props: EditorProps) { return (
- - {state.map((block) => )} + + {state.blocks.map((block) => )}
} /> } title="Copy note to clipboard" /> diff --git a/src/components/forms/AuthForm.tsx b/src/components/forms/AuthForm.tsx index fca0b99..c0cb815 100644 --- a/src/components/forms/AuthForm.tsx +++ b/src/components/forms/AuthForm.tsx @@ -1,7 +1,7 @@ "use client"; import { useActionState } from "react"; -import { login, register } from "@/app/actions"; +import { login, register } from "@/app/actions/auth"; export default function AuthForm({ isRegister = false }: { isRegister?: boolean }) { const [state, formAction] = useActionState(isRegister ? register : login, null); diff --git a/src/lib/editorReducer.ts b/src/lib/editorReducer.ts index 09ed1b4..62be492 100644 --- a/src/lib/editorReducer.ts +++ b/src/lib/editorReducer.ts @@ -12,7 +12,10 @@ export type IBlock = { lines: ILine[]; }; -type EditorState = IBlock[]; +type EditorState = { + title: string; + blocks: IBlock[]; +}; export type Action = | { type: "add_block" } @@ -20,6 +23,7 @@ export type Action = | { type: "delete_block", blockId: string } | { type: "add_line", blockId: string } | { type: "delete_line", blockId: string } + | { type: "update_title", title: string } | { type: "update_line_text"; blockId: string; lineId: string; text: string } | { type: "update_tag"; blockId: string; tag: string } | { type: "move_block_up", blockId: string } @@ -28,24 +32,33 @@ export type Action = export function editorReducer(state: EditorState, action: Action): EditorState { switch (action.type) { - case "add_block": - return [ + case "update_title": + return { ...state, - { - id: uuidv4(), - tag: "", - locked: false, - lines: Array.from({ length: 4 }, () => ({ + title: action.title, + }; + + case "add_block": + return { + ...state, + blocks: [ + ...state.blocks, + { id: uuidv4(), - text: "", - })), - } - ]; + tag: "", + locked: false, + lines: Array.from({ length: 4 }, () => ({ + id: uuidv4(), + text: "", + })), + } + ] + }; case "copy": let copyText = ""; - state.forEach((block) => { + state.blocks.forEach((block) => { if (block.tag !== "") { copyText += `[${block.tag}]\n`; } @@ -62,92 +75,116 @@ export function editorReducer(state: EditorState, action: Action): EditorState { return state; case "delete_block": - return state.filter((block) => block.id !== action.blockId); + return { + ...state, + blocks: state.blocks.filter((block) => block.id !== action.blockId), + }; case "add_line": - return state.map((block) => { - if (block.id === action.blockId) { - return { - ...block, - lines: [...block.lines, { id: uuidv4(), text: "" }], - }; - } else { - return block; - } - }); + return { + ...state, + blocks: state.blocks.map((block) => { + if (block.id === action.blockId) { + return { + ...block, + lines: [...block.lines, { id: uuidv4(), text: "" }], + }; + } else { + return block; + } + }), + }; case "delete_line": - return state.map((block) => { - if (block.id === action.blockId && block.lines.length > 0) { - return { - ...block, - lines: block.lines.slice(0, -1), - }; - } else { - return block; - } - }); + return { + ...state, + blocks: state.blocks.map((block) => { + if (block.id === action.blockId && block.lines.length > 0) { + return { + ...block, + lines: block.lines.slice(0, -1), + }; + } else { + return block; + } + }), + }; case "update_line_text": - return state.map((block) => { - if (block.id === action.blockId) { - return { - ...block, - lines: block.lines.map((line) => { - if (line.id === action.lineId) { - return { - ...line, - text: action.text, - }; - } else { - return line; - } - }), - }; - } else { - return block; - } - }); + return { + ...state, + blocks: state.blocks.map((block) => { + if (block.id === action.blockId) { + return { + ...block, + lines: block.lines.map((line) => { + if (line.id === action.lineId) { + return { + ...line, + text: action.text, + }; + } else { + return line; + } + }), + }; + } else { + return block; + } + }), + }; case "update_tag": - return state.map((block) => { - if (block.id === action.blockId) { - return { - ...block, - tag: action.tag, - }; - } else { - return block; - } - }); + return { + ...state, + blocks: state.blocks.map((block) => { + if (block.id === action.blockId) { + return { + ...block, + tag: action.tag, + }; + } else { + return block; + } + }), + }; case "move_block_up": { - const index = state.findIndex((b) => b.id === action.blockId); + const index = state.blocks.findIndex((b) => b.id === action.blockId); if (index <= 0) return state; - const newState = [...state]; - [newState[index - 1], newState[index]] = [newState[index], newState[index - 1]]; - return newState; + const newBlocks = [...state.blocks]; + [newBlocks[index - 1], newBlocks[index]] = [newBlocks[index], newBlocks[index - 1]]; + return { + ...state, + blocks: newBlocks, + }; } case "move_block_down": { - const index = state.findIndex((b) => b.id === action.blockId); - if (index === state.length - 1) return state; - const newState = [...state]; - [newState[index], newState[index + 1]] = [newState[index + 1], newState[index]]; - return newState; + const index = state.blocks.findIndex((b) => b.id === action.blockId); + if (index === state.blocks.length - 1) return state; + const newBlocks = [...state.blocks]; + [newBlocks[index], newBlocks[index + 1]] = [newBlocks[index + 1], newBlocks[index]]; + return { + ...state, + blocks: newBlocks, + }; } case "toggle_lock": - return state.map((block) => { - if (block.id === action.blockId) { - return { - ...block, - locked: !block.locked, - }; - } else { - return block; - } - }); + return { + ...state, + blocks: state.blocks.map((block) => { + if (block.id === action.blockId) { + return { + ...block, + locked: !block.locked, + }; + } else { + return block; + } + }), + }; default: return state;