/
DME
/
Notes
Обзор
Документация
Войти
/
DME
/
Notes
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/components/note-editor.tsx
169 строк
5 KB
Karasique333
Commit
19 июн 2025, 15:09
19 июн 2025, 15:09
d96c829
Код
Авторство
О чём код?
'use client' import { ChevronLeft, Clock, Tag } from 'lucide-react' import Link from 'next/link' import { usePathname, useRouter } from 'next/navigation' import React, { useState } from 'react' import toast from 'react-hot-toast' import { Button } from './ui/button' import { Input } from './ui/input' import { Separator } from './ui/separator' import { Textarea } from './ui/textarea' import { api } from '@/trpc/react' import Checklist from '@/components/Checklist'; import ImageUploader from '@/components/ImageUploader'; export default function NoteEditor() { const [title, setTitle] = useState('') const [tags, setTags] = useState('') const [content, setContent] = useState('') const [checklist, setChecklist] = useState<{content: string; completed: boolean;}[]>([]); const [images, setImages] = useState<string[]>([]); // base64 строка или пути const router = useRouter() const utils = api.useUtils() const createNote = api.note.create.useMutation({ onSuccess: async (data) => { await utils.note.invalidate() await utils.note.getTags.invalidate() await utils.note.getAll.invalidate() await utils.note.getTags.fetch() toast.success('Заметка сохранена!') router.push(`/all-notes/${data?.id}`) }, }) const handleSave = () => { if (!title.trim() || !content.trim()) { toast.error('Введите заголовок и содержание!') return } const tagsArray = tags.split(',').map((tag: string) => tag.trim()) createNote.mutate({ title, tags: tagsArray, content, checklist, images, }) } const handleCancel = () => { setTitle('') setTags('') setContent('') toast.success('Изменения отменены.') } return ( <div className="flex h-full w-full flex-col"> <NoteTopHeader onCancel={handleCancel} onSave={handleSave} /> <Separator className="my-4 lg:hidden" /> <div className="flex flex-1 flex-col gap-4 pb-24"> {/* Title */} <Input value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Заголовок" className="border-none px-0 font-bold tracking-[-0.5px] shadow-none placeholder:text-2xl/7 placeholder:text-neutral-950 dark:text-white dark:placeholder:text-white" /> {/* Tags */} <div className="flex flex-col gap-3 text-neutral-700 dark:text-neutral-300"> <div className="flex items-center"> <div className="flex items-center gap-1.5"> <Tag className="h-4 w-4" /> <h6 className="text-xs font-normal">Теги</h6> </div> <Input value={tags} onChange={(e) => setTags(e.target.value)} placeholder="Введите через запятую" className="flex-1 border-none text-base font-normal capitalize shadow-none" /> </div> {/* Last Edited */} <div className="flex"> <div className="flex items-center gap-1.5"> <Clock className="h-4 w-4" /> <h6 className="w-[115px] text-xs font-normal">Редактировано</h6> </div> <p className="text-sm font-normal text-neutral-400"> Пока не сохранено </p> </div> </div> <Separator className="my-4 text-neutral-200 dark:text-neutral-800" /> {/* Content */} <div className="h-full text-neutral-800 dark:text-neutral-100"> <Textarea value={content} onChange={(e) => setContent(e.target.value)} placeholder="Содержание" className="h-full resize-none text-sm font-normal" /> </div> {/* Checklist */} <Checklist checklist={checklist} setChecklist={setChecklist} /> {/* Image uploader */} <ImageUploader images={images} setImages={setImages} /> {/* Action Buttons */} <div className="mt-4 hidden gap-4 lg:flex"> <Button onClick={handleSave}>Сохранить</Button> <Button variant="secondary" onClick={handleCancel}> Отмена </Button> </div> </div> </div> ) } function NoteTopHeader({ onCancel, onSave, }: { onCancel: () => void onSave: () => void }) { const pathname = usePathname() const rootPath = pathname.split('/')[1] return ( <div className="flex items-center justify-between border-b border-neutral-200 bg-white pb-3 text-neutral-600 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-300 lg:hidden"> <Link className="inline-flex items-center gap-1" href={`/${rootPath}`}> <ChevronLeft className="h-4 w-4" /> Go Back </Link> <div className="flex items-center gap-4"> {/* Cancel Button */} <button className="text-sm text-neutral-600 dark:text-neutral-300" onClick={onCancel} > Отменить </button> {/* Save Note Button */} <button className="text-sm text-blue-500" onClick={onSave}> Сохранить </button> </div> </div> ) }