feat: add line saves

This commit is contained in:
Kirill Siukhin 2025-07-15 23:54:31 +05:00
parent 5da589c331
commit ed28943b54
5 changed files with 61 additions and 10 deletions

View File

@ -89,7 +89,6 @@ export async function moveUp(formData: FormData) {
const block = await getBlock(blockId);
if (!block) return;
// Найти блок, который перед текущим
const siblings = await getBlocks(block.noteId);
const currentIndex = siblings.findIndex((b) => b.id === block.id);
if (currentIndex <= 0) return;
@ -136,3 +135,18 @@ export async function moveDown(formData: FormData) {
revalidatePath("/notes/[id]", "page");
}
export async function setLines(blockId: string, lines: string[]) {
console.log(lines)
await db
.update(blocksTable)
.set({ lines })
.where(eq(blocksTable.id, blockId));
}
export async function setTag(blockId: string, tag: string) {
await db
.update(blocksTable)
.set({ tag })
.where(eq(blocksTable.id, blockId));
}

View File

@ -4,8 +4,8 @@ import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { desc, eq, and } from "drizzle-orm";
import { blocksTable, INote, notesTable, usersTable } from "@/lib/db/schema";
import { db } from "@/lib/db";
import { requireAuth } from "./auth";
import { db } from "@/lib/db";
export async function createNote() {
const user = await requireAuth();
@ -45,3 +45,11 @@ export async function deleteNote(formData: FormData) {
.where(and(eq(notesTable.id, noteId), eq(notesTable.authorId, user.id)));
revalidatePath("/notes");
}
export async function setTitle(noteId: string, title: string) {
await db
.update(notesTable)
.set({ title })
.where(eq(notesTable.id, noteId));
revalidatePath("/notes/[id]", "page");
}

View File

@ -1,10 +1,24 @@
import { ChangeEvent, useState } from "react";
import { ArrowDown, ArrowUp, LockOpen, Lock, Minus, Plus, X } from "lucide-react";
import { addLine, changeLock, deleteBlock, deleteLine, moveDown, moveUp } from "@/app/actions/blocks";
import { addLine, changeLock, deleteBlock, deleteLine, moveDown, moveUp, setLines } from "@/app/actions/blocks";
import { useDebounce } from "@/lib/hooks/useDebounce";
import { IBlock } from "@/lib/db/schema";
import IconOnlyButton from "../ui/IconOnlyButton";
import LineInput from "./LineInput";
export default function Block({ block }: { block: IBlock }) {
const [lines, setLinesState] = useState(block.lines);
useDebounce(() => {
setLines(block.id, lines);
}, [lines]);
const lineChangeHandler = (i: number, e: ChangeEvent<HTMLInputElement>) => {
const newLines = [...lines];
newLines[i] = e.target.value;
setLinesState(newLines);
}
return (
<div className="flex flex-col gap-2 w-full">
<div className="border-2 border-neutral-800 rounded-lg p-3 w-full">
@ -16,7 +30,7 @@ export default function Block({ block }: { block: IBlock }) {
disabled={block.isLocked}
/>
{block.lines.map((line, i) => (
<LineInput key={i} defaultValue={line} disabled={block.isLocked} />
<LineInput key={i} defaultValue={line} disabled={block.isLocked} onChange={(e) => lineChangeHandler(i, e)} />
))}
<div className="flex items-center mx-2 mt-2">
<div className="flex gap-1 mr-4">

View File

@ -1,11 +1,14 @@
"use client";
import { useState } from "react";
import { Copy, Plus } from "lucide-react";
import { v4 as uuidv4 } from "uuid";
import { IBlock, INote } from "@/lib/db/schema";
import { createBlock } from "@/app/actions/blocks";
import IconOnlyButton from "../ui/IconOnlyButton";
import Block from "./Block";
import { useDebounce } from "@/lib/hooks/useDebounce";
import { setTitle } from "@/app/actions/notes";
const defaultNoteId = uuidv4();
@ -35,6 +38,8 @@ export default function Editor({
note?: INote;
blocks?: IBlock[];
}) {
const [title, setTitleState] = useState(note.title);
const copyHandler = () => {
let copyText = "";
blocks.forEach((block) => {
@ -46,11 +51,16 @@ export default function Editor({
navigator.clipboard.writeText(copyText);
}
useDebounce(() => {
setTitle(note.id, title);
}, [title]);
return (
<div className="flex flex-col items-center max-w-2xl w-full gap-4">
<input
className="font-bold text-xl w-full text-center focus:outline-none"
defaultValue={note.title}
onChange={(e) => setTitleState(e.target.value)}
value={title}
/>
{blocks.map((block) => <Block key={block.id} block={block} /> )}
<div className="flex gap-2">

View File

@ -1,10 +1,15 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect } from "react";
import { DependencyList, useEffect, useState } from "react";
export function useDebounce(callback: () => void, deps: DependencyList) {
const [isFirstTime, setIsFirstTime] = useState(true);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useDebounce(callback: () => void, deps: any[]) {
useEffect(() => {
const timeout = setTimeout(callback, 1000);
return () => clearTimeout(timeout);
if (isFirstTime) {
setIsFirstTime(false);
} else {
const timeout = setTimeout(callback, 1000);
return () => clearTimeout(timeout);
}
}, deps);
}