feat: add title to the editor state
This commit is contained in:
parent
8b1de14f79
commit
2ad220e525
23
src/app/actions/blocks.ts
Normal file
23
src/app/actions/blocks.ts
Normal file
@ -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));
|
||||
}
|
@ -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";
|
||||
|
||||
|
@ -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<HTMLInputElement>) => {
|
||||
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 (
|
||||
<div className="flex flex-col items-center px-4 max-w-2xl w-full gap-4">
|
||||
<input className="font-bold text-xl w-full text-center focus:outline-none" defaultValue={props.defaultTitle || "Untitled"} />
|
||||
{state.map((block) => <Block key={block.id} block={block} dispatch={dispatch} /> )}
|
||||
<input className="font-bold text-xl w-full text-center focus:outline-none" defaultValue={state.title} onChange={handleUpdateTitle} />
|
||||
{state.blocks.map((block) => <Block key={block.id} block={block} dispatch={dispatch} /> )}
|
||||
<div className="flex gap-2">
|
||||
<IconOnlyButton onClick={handleAddBlock} icon={<Plus size={24} />} />
|
||||
<IconOnlyButton onClick={handleCopy} icon={<Copy size={24} />} title="Copy note to clipboard" />
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user