diff --git a/docker-compose.yml b/docker-compose.yml index cfe7911..85f5361 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,7 +40,7 @@ services: - NODE_ENV=production - NEXT_TELEMETRY_DISABLED=1 volumes: - - uploads-data:/app/public/uploads + - uploads-data:/app/data/uploads - backup-data:/app/data/backups depends_on: postgres: diff --git a/memento-note/app/actions/notes.ts b/memento-note/app/actions/notes.ts index c90c4a5..8da91fd 100644 --- a/memento-note/app/actions/notes.ts +++ b/memento-note/app/actions/notes.ts @@ -2,7 +2,7 @@ import { revalidatePath } from 'next/cache' import prisma from '@/lib/prisma' -import { Note, CheckItem } from '@/lib/types' +import { Note, CheckItem, NoteType } from '@/lib/types' import { auth } from '@/auth' import { getAIProvider } from '@/lib/ai/factory' import { parseNote as parseNoteUtil, cosineSimilarity, calculateRRFK, detectQueryType, getSearchWeights } from '@/lib/utils' @@ -626,7 +626,7 @@ export async function createNote(data: { title?: string content: string color?: string - type?: 'text' | 'checklist' + type?: NoteType checkItems?: CheckItem[] labels?: string[] images?: string[] @@ -637,8 +637,8 @@ export async function createNote(data: { size?: 'small' | 'medium' | 'large' autoGenerated?: boolean aiProvider?: string - notebookId?: string | undefined // Assign note to a notebook if provided - skipRevalidation?: boolean // Option to prevent full page refresh for smooth optimistic UI updates + notebookId?: string | undefined + skipRevalidation?: boolean }) { const session = await auth(); if (!session?.user?.id) throw new Error('Unauthorized'); @@ -659,7 +659,7 @@ export async function createNote(data: { title: data.title || null, content: data.content, color: data.color || 'default', - type: data.type || 'text', + type: data.type || 'richtext', checkItems: data.checkItems ? JSON.stringify(data.checkItems) : null, labels: null, // set by syncNoteLabels below images: data.images ? JSON.stringify(data.images) : null, @@ -799,7 +799,7 @@ export async function updateNote(id: string, data: { color?: string isPinned?: boolean isArchived?: boolean - type?: 'text' | 'checklist' + type?: NoteType checkItems?: CheckItem[] | null labels?: string[] | null images?: string[] | null diff --git a/memento-note/app/globals.css b/memento-note/app/globals.css index 29b7dfb..2b3f120 100644 --- a/memento-note/app/globals.css +++ b/memento-note/app/globals.css @@ -502,4 +502,473 @@ direction: ltr; unicode-bidi: embed; display: inline-block; -} \ No newline at end of file +} + +/* ============================================ + Notion-like Rich Text Editor (TipTap) + ============================================ */ + +/* --- Editor Wrapper --- */ +.notion-editor-wrapper { + position: relative; +} + +/* --- ProseMirror Base --- */ +.notion-editor-wrapper .ProseMirror { + outline: none; + min-height: 120px; + padding: 4px 0; + font-size: 0.9375rem; + line-height: 1.7; + caret-color: var(--primary); +} + +.notion-editor-wrapper .ProseMirror > *:first-child { margin-top: 0; } + +/* Placeholder */ +.notion-editor-wrapper .ProseMirror p.is-editor-empty:first-child::before, +.notion-editor-wrapper .ProseMirror p.is-empty::before { + content: attr(data-placeholder); + float: left; + color: var(--muted-foreground); + pointer-events: none; + height: 0; + opacity: 0.4; + font-style: italic; +} + +/* --- Paragraphs --- */ +.notion-editor-wrapper .ProseMirror p { margin: 0.2em 0; } + +/* --- Headings (Notion style — clean, sans-serif) --- */ +.notion-editor-wrapper .ProseMirror h1 { + font-size: 1.75rem; + font-weight: 700; + margin: 1.2em 0 0.2em; + line-height: 1.25; + letter-spacing: -0.02em; +} +.notion-editor-wrapper .ProseMirror h2 { + font-size: 1.375rem; + font-weight: 600; + margin: 1em 0 0.15em; + line-height: 1.3; + letter-spacing: -0.01em; +} +.notion-editor-wrapper .ProseMirror h3 { + font-size: 1.125rem; + font-weight: 600; + margin: 0.8em 0 0.1em; + line-height: 1.35; +} + +/* --- Lists --- */ +.notion-editor-wrapper .ProseMirror ul { + list-style-type: disc; + padding-left: 1.5rem; + margin: 0.25em 0; +} +.notion-editor-wrapper .ProseMirror ol { + list-style-type: decimal; + padding-left: 1.5rem; + margin: 0.25em 0; +} +.notion-editor-wrapper .ProseMirror li > p { margin: 0.1em 0; } +.notion-editor-wrapper .ProseMirror li > ul, +.notion-editor-wrapper .ProseMirror li > ol { margin: 0.1em 0; } + +/* --- Task / Todo List --- */ +.notion-editor-wrapper .ProseMirror ul[data-type="taskList"] { + list-style: none; + padding-left: 0; +} +.notion-editor-wrapper .ProseMirror ul[data-type="taskList"] li { + display: flex; + align-items: flex-start; + gap: 0.4rem; + margin: 0.2em 0; +} +.notion-editor-wrapper .ProseMirror ul[data-type="taskList"] li > label { + display: flex; + align-items: center; + cursor: pointer; + margin-top: 2px; +} +.notion-editor-wrapper .ProseMirror ul[data-type="taskList"] li > label input[type="checkbox"] { + -webkit-appearance: none; appearance: none; + width: 16px; height: 16px; + border: 2px solid var(--border); + border-radius: 4px; + cursor: pointer; + display: grid; place-content: center; + transition: all 0.15s ease; + background: transparent; + flex-shrink: 0; +} +.notion-editor-wrapper .ProseMirror ul[data-type="taskList"] li > label input[type="checkbox"]:checked { + background: var(--primary); + border-color: var(--primary); +} +.notion-editor-wrapper .ProseMirror ul[data-type="taskList"] li > label input[type="checkbox"]::before { + content: ""; width: 10px; height: 10px; + transform: scale(0); + transition: 120ms transform ease-in-out; + box-shadow: inset 1em 1em white; + clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); +} +.notion-editor-wrapper .ProseMirror ul[data-type="taskList"] li > label input[type="checkbox"]:checked::before { transform: scale(1); } +.notion-editor-wrapper .ProseMirror ul[data-type="taskList"] li[data-checked="true"] > div > p { + color: var(--muted-foreground); + text-decoration: line-through; +} + +/* --- Blockquote --- */ +.notion-editor-wrapper .ProseMirror blockquote { + border-left: 3px solid var(--primary); + padding: 0.25em 0 0.25em 1em; + margin: 0.4em 0; + color: var(--muted-foreground); + font-style: italic; + background: oklch(0.5 0 0 / 0.03); + border-radius: 0 4px 4px 0; +} + +/* --- Code --- */ +.notion-editor-wrapper .ProseMirror code { + background: var(--muted); + padding: 0.15em 0.4em; + border-radius: 4px; + font-size: 0.85em; + font-family: var(--font-mono, ui-monospace, monospace); + color: var(--foreground); +} +.notion-editor-wrapper .ProseMirror pre { + background: var(--muted); + border-radius: 8px; + padding: 0.85rem 1rem; + margin: 0.5em 0; + overflow-x: auto; + border: 1px solid var(--border); +} +.notion-editor-wrapper .ProseMirror pre code { + background: none; + padding: 0; + border-radius: 0; + font-size: 0.8125rem; + line-height: 1.6; +} + +/* --- Horizontal Rule --- */ +.notion-editor-wrapper .ProseMirror hr { + border: none; + border-top: 1px solid var(--border); + margin: 0.75em 0; +} + +/* --- Strong / Marks --- */ +.notion-editor-wrapper .ProseMirror strong { font-weight: 600; } + +/* --- Images --- */ +.notion-editor-wrapper .ProseMirror img { + border-radius: 8px; + max-width: 100%; + height: auto; + display: block; + margin: 0.5em 0; + transition: filter 0.15s ease; +} +.notion-editor-wrapper .ProseMirror img:hover { filter: brightness(95%); } +.notion-editor-wrapper .ProseMirror img.ProseMirror-selectednode { + outline: 2px solid var(--primary); + outline-offset: 2px; +} + +/* --- Links --- */ +.notion-editor-wrapper .ProseMirror a { + color: var(--primary); + text-decoration: underline; + text-underline-offset: 2px; + cursor: pointer; +} +.notion-editor-wrapper .ProseMirror a:hover { + opacity: 0.8; +} + +/* --- Highlight --- */ +.notion-editor-wrapper .ProseMirror mark { + background: oklch(0.85 0.12 90); + border-radius: 2px; + padding: 0 1px; +} +.dark .notion-editor-wrapper .ProseMirror mark { + background: oklch(0.4 0.1 90); +} + +/* ============================================ + Bubble Menu (floating toolbar on selection) + ============================================ */ +.notion-bubble-menu { + background: var(--popover); + border: 1px solid var(--border); + border-radius: 10px; + box-shadow: 0 4px 16px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04); + padding: 2px; + display: flex; + align-items: center; + gap: 0; + z-index: 100; +} +.dark .notion-bubble-menu { + box-shadow: 0 4px 16px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.06); +} + +.notion-bubble-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 30px; + height: 30px; + border-radius: 6px; + border: none; + background: transparent; + color: var(--foreground); + cursor: pointer; + transition: all 0.12s ease; +} +.notion-bubble-btn:hover { + background: var(--accent); +} +.notion-bubble-btn-active { + background: var(--accent); + color: var(--primary); +} + +/* AI submenu inside bubble */ +.notion-ai-submenu { + position: absolute; + top: 100%; + right: 0; + margin-top: 4px; + background: var(--popover); + border: 1px solid var(--border); + border-radius: 8px; + box-shadow: 0 8px 24px rgba(0,0,0,0.12); + padding: 4px; + min-width: 150px; + z-index: 110; +} +.dark .notion-ai-submenu { + box-shadow: 0 8px 24px rgba(0,0,0,0.5); +} +.notion-ai-subitem { + display: flex; + align-items: center; + gap: 8px; + width: 100%; + padding: 7px 10px; + border: none; + background: transparent; + border-radius: 6px; + cursor: pointer; + font-size: 0.8125rem; + color: var(--foreground); + transition: background 0.1s ease; +} +.notion-ai-subitem:hover { + background: var(--accent); +} + +/* Inline input inside bubble menu (link editor) */ +.notion-inline-input { + background: transparent; + border: none; + outline: none; + font-size: 0.8125rem; + color: var(--foreground); + width: 200px; + min-width: 120px; +} +.notion-inline-input::placeholder { + color: var(--muted-foreground); + opacity: 0.6; +} + +/* Image insert overlay */ +.notion-overlay { + position: fixed; + inset: 0; + z-index: 9999; + display: flex; + align-items: center; + justify-content: center; + background: rgba(0,0,0,0.3); +} +.dark .notion-overlay { + background: rgba(0,0,0,0.6); +} +.notion-image-modal { + background: var(--popover); + border: 1px solid var(--border); + border-radius: 12px; + box-shadow: 0 16px 48px rgba(0,0,0,0.15); + padding: 20px; + width: 400px; + max-width: 90vw; +} +.dark .notion-image-modal { + box-shadow: 0 16px 48px rgba(0,0,0,0.5); +} +.notion-modal-input { + width: 100%; + padding: 8px 12px; + border: 1px solid var(--border); + border-radius: 8px; + background: var(--background); + color: var(--foreground); + font-size: 0.8125rem; + outline: none; + transition: border-color 0.15s ease; +} +.notion-modal-input:focus { + border-color: var(--primary); +} +.notion-modal-input::placeholder { + color: var(--muted-foreground); + opacity: 0.5; +} +.notion-modal-btn { + padding: 6px 14px; + border-radius: 6px; + font-size: 0.8125rem; + border: 1px solid var(--border); + background: transparent; + color: var(--foreground); + cursor: pointer; + transition: background 0.1s ease; +} +.notion-modal-btn:hover { + background: var(--accent); +} +.notion-modal-btn-primary { + background: var(--primary); + color: var(--primary-foreground); + border-color: var(--primary); +} +.notion-modal-btn-primary:hover { + opacity: 0.9; + background: var(--primary); +} + +/* ============================================ + Slash Command Menu + ============================================ */ +.notion-slash-menu { + position: fixed; + z-index: 9999; + background: var(--popover); + border: 1px solid var(--border); + border-radius: 8px; + box-shadow: 0 4px 24px rgba(0,0,0,0.1); + padding: 4px; + min-width: 300px; + max-height: 340px; + overflow-y: auto; + scrollbar-width: thin; +} +.dark .notion-slash-menu { + box-shadow: 0 4px 24px rgba(0,0,0,0.5); +} + +.notion-slash-section + .notion-slash-section { + border-top: 1px solid var(--border); + margin-top: 4px; + padding-top: 4px; +} + +.notion-slash-label { + padding: 6px 8px 2px; + font-size: 11px; + font-weight: 600; + color: var(--muted-foreground); + user-select: none; +} + +.notion-slash-item { + display: flex; + align-items: center; + gap: 8px; + width: 100%; + padding: 4px 8px; + border: none; + background: transparent; + border-radius: 4px; + cursor: pointer; + text-align: left; + color: var(--foreground); + transition: background 0.1s ease; +} +.notion-slash-item:hover, +.notion-slash-item-selected { + background: var(--accent); +} + +.notion-slash-icon { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + border: 1px solid var(--border); + border-radius: 4px; + background: var(--background); + color: var(--muted-foreground); + flex-shrink: 0; +} +.notion-slash-icon-ai { + background: oklch(0.95 0.05 270); + border-color: oklch(0.8 0.08 270); + color: oklch(0.55 0.15 270); +} +.dark .notion-slash-icon-ai { + background: oklch(0.25 0.05 270); + border-color: oklch(0.4 0.08 270); + color: oklch(0.75 0.15 270); +} + +.notion-slash-loading { + display: flex; + align-items: center; + gap: 6px; + padding: 8px 10px; + font-size: 13px; + color: var(--muted-foreground); +} + +.notion-slash-title { + font-size: 13px; + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 0 1 auto; +} +.notion-slash-desc { + font-size: 11px; + color: var(--muted-foreground); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 1 1 auto; + text-align: right; +} + +/* ============================================ + Note Card Rich Text Preview + ============================================ */ +.rt-preview { font-size: 0.875rem; line-height: 1.6; } +.rt-preview h1 { font-size: 1.3rem; font-weight: 700; margin: 0.3em 0; } +.rt-preview h2 { font-size: 1.1rem; font-weight: 600; margin: 0.3em 0; } +.rt-preview h3 { font-size: 1rem; font-weight: 600; margin: 0.3em 0; } +.rt-preview p { margin: 0.2em 0; } +.rt-preview ul, .rt-preview ol { padding-left: 1.25rem; margin: 0.2em 0; } +.rt-preview blockquote { border-left: 3px solid var(--border); padding-left: 0.75rem; color: var(--muted-foreground); margin: 0.3em 0; } \ No newline at end of file diff --git a/memento-note/components/note-actions.tsx b/memento-note/components/note-actions.tsx index 74d56dc..ed1003d 100644 --- a/memento-note/components/note-actions.tsx +++ b/memento-note/components/note-actions.tsx @@ -19,6 +19,10 @@ import { Trash2, RotateCcw, History, + AlignLeft, + FileCode2, + PenLine, + ListChecks, } from "lucide-react" import { cn } from "@/lib/utils" import { NOTE_COLORS } from "@/lib/types" @@ -38,6 +42,7 @@ interface NoteActionsProps { onDelete: () => void onShareCollaborators?: () => void isMarkdown?: boolean + noteType?: string onToggleMarkdown?: () => void isTrashView?: boolean onRestore?: () => void @@ -62,6 +67,7 @@ export function NoteActions({ onDelete, onShareCollaborators, isMarkdown = false, + noteType = 'text', onToggleMarkdown, isTrashView, onRestore, @@ -170,19 +176,22 @@ export function NoteActions({ - {/* Markdown Toggle */} - {onToggleMarkdown && ( - - )} + {onToggleMarkdown && (() => { + const iconMap: Record = { text: AlignLeft, markdown: FileCode2, richtext: PenLine, checklist: ListChecks } + const TypeIcon = iconMap[noteType] || FileText + return ( + + ) + })()} {/* More Options */} diff --git a/memento-note/components/note-card.tsx b/memento-note/components/note-card.tsx index 862c069..5502843 100644 --- a/memento-note/components/note-card.tsx +++ b/memento-note/components/note-card.tsx @@ -1,6 +1,6 @@ 'use client' -import { Note, NOTE_COLORS, NoteColor } from '@/lib/types' +import { Note, NOTE_COLORS, NoteColor, NoteType } from '@/lib/types' import { Card } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' @@ -20,7 +20,7 @@ import { AlertDialogHeader, AlertDialogTitle, } from '@/components/ui/alert-dialog' -import { Pin, Bell, GripVertical, X, Link2, FolderOpen, StickyNote, LucideIcon, Folder, Briefcase, FileText, Zap, BarChart3, Globe, Sparkles, Book, Heart, Crown, Music, Building2, LogOut, Trash2 } from 'lucide-react' +import { Pin, Bell, GripVertical, X, Link2, FolderOpen, StickyNote, LucideIcon, Folder, Briefcase, FileText, Zap, BarChart3, Globe, Sparkles, Book, Heart, Crown, Music, Building2, LogOut, Trash2, AlignLeft, FileCode2, PenLine, ListChecks } from 'lucide-react' import { useState, useEffect, useTransition, useOptimistic, memo } from 'react' import { useSession } from 'next-auth/react' import { useRouter, useSearchParams } from 'next/navigation' @@ -83,6 +83,13 @@ function getDateLocale(language: string): Locale { return localeMap[language] || enUS } +const NOTE_TYPE_ICONS: Record = { + text: AlignLeft, + markdown: FileCode2, + richtext: PenLine, + checklist: ListChecks, +} + // Map icon names to lucide-react components const ICON_MAP: Record = { 'folder': Folder, @@ -536,8 +543,12 @@ export const NoteCard = memo(function NoteCard({ {/* Title */} {optimisticNote.title && ( -

- {optimisticNote.title} +

+ {(() => { + const TypeIcon = NOTE_TYPE_ICONS[optimisticNote.type] || AlignLeft + return + })()} + {optimisticNote.title}

)} @@ -608,18 +619,20 @@ export const NoteCard = memo(function NoteCard({ )} {/* Content */} - {optimisticNote.type === 'text' ? ( + {optimisticNote.type === 'checklist' ? ( + + ) : optimisticNote.type === 'richtext' ? ( +
+ ) : (
- ) : ( - )} {/* Labels - using shared LabelBadge component */} diff --git a/memento-note/components/note-editor.tsx b/memento-note/components/note-editor.tsx index 4447476..92537f6 100644 --- a/memento-note/components/note-editor.tsx +++ b/memento-note/components/note-editor.tsx @@ -1,7 +1,7 @@ 'use client' import { useState, useRef, useEffect } from 'react' -import { Note, CheckItem, NOTE_COLORS, NoteColor, LinkMetadata } from '@/lib/types' +import { Note, CheckItem, NOTE_COLORS, NoteColor, LinkMetadata, NoteType } from '@/lib/types' import { Dialog, DialogContent, @@ -23,7 +23,9 @@ import { DropdownMenuSubTrigger, DropdownMenuSubContent, } from '@/components/ui/dropdown-menu' -import { X, Plus, Palette, Image as ImageIcon, Bell, FileText, Eye, Link as LinkIcon, Sparkles, Maximize2, Copy, Wand2, LogOut } from 'lucide-react' +import { NoteTypeSelector } from '@/components/note-type-selector' +import { RichTextEditor } from '@/components/rich-text-editor' +import { X, Plus, Palette, Image as ImageIcon, Bell, Eye, Link as LinkIcon, Sparkles, Maximize2, Copy, Wand2, LogOut } from 'lucide-react' import { updateNote, createNote, cleanupOrphanedImages, leaveSharedNote } from '@/app/actions/notes' import { fetchLinkMetadata } from '@/app/actions/scrape' import { cn } from '@/lib/utils' @@ -85,8 +87,9 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps) const [size, setSize] = useState(note.size || 'small') const [isSaving, setIsSaving] = useState(false) const [removedImageUrls, setRemovedImageUrls] = useState([]) - const [isMarkdown, setIsMarkdown] = useState(note.isMarkdown || false) - const [showMarkdownPreview, setShowMarkdownPreview] = useState(note.isMarkdown || false) + const [noteType, setNoteType] = useState(note.type) + const isMarkdown = noteType === 'markdown' + const [showMarkdownPreview, setShowMarkdownPreview] = useState(note.type === 'markdown') const fileInputRef = useRef(null) // Update context notebookId when note changes @@ -96,9 +99,9 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps) // Auto-tagging hook - use local state for live suggestions as user types const { suggestions, isAnalyzing } = useAutoTagging({ - content: note.type === 'text' ? content : '', + content: noteType !== 'checklist' ? content : '', notebookId: note.notebookId, - enabled: note.type === 'text' && autoLabelingEnabled + enabled: noteType !== 'checklist' && autoLabelingEnabled }) // Reminder state @@ -466,7 +469,7 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps) // Set the transformed markdown content and enable markdown mode setContent(data.transformedText) - setIsMarkdown(true) + setNoteType('markdown') setShowMarkdownPreview(false) toast.success(t('ai.transformSuccess')) @@ -523,14 +526,15 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps) try { await updateNote(note.id, { title: title.trim() || null, - content: note.type === 'text' ? content : '', - checkItems: note.type === 'checklist' ? checkItems : null, + content: noteType !== 'checklist' ? content : '', + checkItems: noteType === 'checklist' ? checkItems : null, labels, images, links, color, reminder: currentReminder, - isMarkdown, + isMarkdown: noteType === 'markdown', + type: noteType, size, }) @@ -588,12 +592,12 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps) title: `${title || t('notes.untitled')} (${t('notes.copy')})`, content: content, color: color, - type: note.type, checkItems: checkItems, labels: labels, images: images, links: links, - isMarkdown: isMarkdown, + isMarkdown: noteType === 'markdown', + type: noteType, size: size, }) toast.success(t('notes.copySuccess')) @@ -697,7 +701,13 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps) )} {/* Content or Checklist */} - {note.type === 'text' ? ( + {noteType === 'richtext' ? ( + + ) : noteType === 'text' || noteType === 'markdown' ? (
{showMarkdownPreview && isMarkdown ? ( - {/* Markdown toggle */} - {note.type === 'text' && ( - - )} + { setNoteType(newType); if (newType !== 'markdown') setShowMarkdownPreview(false) }} /> - {/* Markdown preview toggle */} - {isMarkdown && ( + {noteType === 'markdown' && ( - + compact + /> - {isMarkdown && ( + {noteType === 'markdown' && ( )} - {note.type === 'text' && aiAssistantEnabled && ( + {noteType !== 'checklist' && aiAssistantEnabled && ( - {t('notes.markdown')} - )} + { setType(newType); if (newType !== 'markdown') setShowMarkdownPreview(false) }} /> - {type === 'text' && isMarkdown && ( + {type === 'markdown' && ( + + + {types.map((type) => { + const Icon = TYPE_ICONS[type] + const isActive = type === value + return ( + onChange(type)} + className={cn('gap-2 cursor-pointer', isActive && 'bg-accent')} + > +
+ + {t(TYPE_I18N_KEYS[type])} +
+ {isActive && } +
+ ) + })} +
+ + ) +} + +export { TYPE_ICONS, TYPE_I18N_KEYS } diff --git a/memento-note/components/rich-text-editor.tsx b/memento-note/components/rich-text-editor.tsx new file mode 100644 index 0000000..2c9b798 --- /dev/null +++ b/memento-note/components/rich-text-editor.tsx @@ -0,0 +1,451 @@ +'use client' + +import { useEffect, useRef, useState, useCallback, forwardRef, useImperativeHandle } from 'react' +import { useEditor, EditorContent } from '@tiptap/react' +import { BubbleMenu } from '@tiptap/react/menus' +import StarterKit from '@tiptap/starter-kit' +import Underline from '@tiptap/extension-underline' +import Placeholder from '@tiptap/extension-placeholder' +import TiptapLink from '@tiptap/extension-link' +import Highlight from '@tiptap/extension-highlight' +import Image from '@tiptap/extension-image' +import TextAlign from '@tiptap/extension-text-align' +import TaskList from '@tiptap/extension-task-list' +import TaskItem from '@tiptap/extension-task-item' +import Superscript from '@tiptap/extension-superscript' +import Subscript from '@tiptap/extension-subscript' +import Typography from '@tiptap/extension-typography' +import type { Editor } from '@tiptap/core' +import type { EditorState } from '@tiptap/pm/state' +import { + Bold, Italic, Underline as UnderlineIcon, Strikethrough, Code, + Heading1, Heading2, Heading3, List, ListOrdered, CheckSquare, + Quote, CodeXml, Minus, ImageIcon, Type, Highlighter, Link as LinkIcon, + Sparkles, Wand2, Scissors, Lightbulb, X, Check, ExternalLink, + FileText, Pilcrow, MessageSquare, AlignLeft, AlignCenter, AlignRight, +} from 'lucide-react' +import { cn } from '@/lib/utils' + +export interface RichTextEditorHandle { + getEditor: () => Editor | null +} + +interface RichTextEditorProps { + content?: string + onChange?: (content: string) => void + className?: string + placeholder?: string +} + +type SlashItem = { + title: string + description: string + icon: typeof Bold + category?: string + isImage?: boolean + isAi?: boolean + aiOption?: 'clarify' | 'shorten' | 'improve' + command: (editor: Editor) => void +} + +const slashCommands: SlashItem[] = [ + { title: 'Text', description: 'Just start writing with plain text', icon: Pilcrow, category: 'Basic blocks', command: (e) => e.chain().focus().setParagraph().run() }, + { title: 'Heading 1', description: 'Big section heading', icon: Heading1, category: 'Basic blocks', command: (e) => e.chain().focus().toggleHeading({ level: 1 }).run() }, + { title: 'Heading 2', description: 'Medium section heading', icon: Heading2, category: 'Basic blocks', command: (e) => e.chain().focus().toggleHeading({ level: 2 }).run() }, + { title: 'Heading 3', description: 'Small section heading', icon: Heading3, category: 'Basic blocks', command: (e) => e.chain().focus().toggleHeading({ level: 3 }).run() }, + { title: 'Bullet List', description: 'Create a simple bullet list', icon: List, category: 'Basic blocks', command: (e) => e.chain().focus().toggleBulletList().run() }, + { title: 'Numbered List', description: 'Create a list with numbering', icon: ListOrdered, category: 'Basic blocks', command: (e) => e.chain().focus().toggleOrderedList().run() }, + { title: 'To-do List', description: 'Track tasks with checkboxes', icon: CheckSquare, category: 'Basic blocks', command: (e) => e.chain().focus().toggleTaskList().run() }, + { title: 'Quote', description: 'Capture a quote', icon: Quote, category: 'Basic blocks', command: (e) => e.chain().focus().toggleBlockquote().run() }, + { title: 'Code Block', description: 'Capture a code snippet', icon: CodeXml, category: 'Basic blocks', command: (e) => e.chain().focus().toggleCodeBlock().run() }, + { title: 'Divider', description: 'Visually divide blocks', icon: Minus, category: 'Basic blocks', command: (e) => e.chain().focus().setHorizontalRule().run() }, + { title: 'Image', description: 'Embed an image from URL', icon: ImageIcon, category: 'Media', isImage: true, command: () => {} }, + { title: 'Clarify', description: 'Make text clearer and easier to understand', icon: Lightbulb, category: 'AI', isAi: true, aiOption: 'clarify', command: () => {} }, + { title: 'Shorten', description: 'Make text more concise', icon: Scissors, category: 'AI', isAi: true, aiOption: 'shorten', command: () => {} }, + { title: 'Improve', description: 'Improve writing style and flow', icon: Wand2, category: 'AI', isAi: true, aiOption: 'improve', command: () => {} }, +] + +async function aiReformulate(text: string, option: 'clarify' | 'shorten' | 'improve'): Promise { + const res = await fetch('/api/ai/reformulate', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ text, option }), + }) + const data = await res.json() + if (!res.ok) throw new Error(data.error || 'AI failed') + return data.reformulatedText || data.text || text +} + +function useImageInsert() { + const [open, setOpen] = useState(false) + const editorRef = useRef(null) + + const requestInsert = useCallback((editor: Editor) => { + editorRef.current = editor + setOpen(true) + }, []) + + const confirm = useCallback((url: string) => { + if (url.trim() && editorRef.current) { + editorRef.current.chain().focus().setImage({ src: url.trim() }).run() + } + setOpen(false) + editorRef.current = null + }, []) + + const cancel = useCallback(() => { + setOpen(false) + editorRef.current = null + }, []) + + return { open, requestInsert, confirm, cancel } +} + +export const RichTextEditor = forwardRef( + function RichTextEditor({ content, onChange, className, placeholder }, ref) { + const imageInsert = useImageInsert() + + const editor = useEditor({ + extensions: [ + StarterKit.configure({ heading: { levels: [1, 2, 3] }, link: false, underline: false }), + Underline, + TiptapLink.configure({ openOnClick: false, autolink: true }), + Highlight.configure({ multicolor: false }), + Image.configure({ inline: false, allowBase64: true }), + TextAlign.configure({ types: ['heading', 'paragraph'] }), + TaskList, + TaskItem.configure({ nested: true }), + Superscript, + Subscript, + Typography, + Placeholder.configure({ placeholder: placeholder || "Type '/' for commands..." }), + ], + content: content || '', + immediatelyRender: false, + editorProps: { + attributes: { class: 'notion-editor' }, + }, + onUpdate: ({ editor: e }) => { + onChange?.(e.getHTML()) + }, + }) + + useImperativeHandle(ref, () => ({ getEditor: () => editor }), [editor]) + + return ( +
+ {editor && ( + { + const { from, to } = state.selection + return from !== to && !e.isActive('codeBlock') + }} + > + + + )} + + {editor && } + + + + {imageInsert.open && ( + + )} +
+ ) + } +) + +function ImageModal({ onConfirm, onCancel }: { onConfirm: (url: string) => void; onCancel: () => void }) { + const [url, setUrl] = useState('') + const [preview, setPreview] = useState(null) + const [error, setError] = useState('') + const inputRef = useRef(null) + + useEffect(() => { inputRef.current?.focus() }, []) + + const handleConfirm = () => { + if (!url.trim()) return + if (!/^https?:\/\/.+/i.test(url.trim())) { setError('Please enter a valid URL'); return } + onConfirm(url.trim()) + } + + return ( +
+
e.stopPropagation()}> +
Insert image
+ { setUrl(e.target.value); setError(''); setPreview(null) }} + onKeyDown={(e) => { if (e.key === 'Enter') handleConfirm(); if (e.key === 'Escape') onCancel() }} + placeholder="https://example.com/image.png" + className="notion-modal-input" + /> + {url.trim() && !preview && ( + + )} + {preview && ( +
+ { setPreview(null); setError('Failed to load image') }} /> +
+ )} + {error &&
{error}
} +
+ + +
+
+
+ ) +} + +function BubbleToolbar({ editor }: { editor: Editor | null }) { + const [, setTick] = useState(0) + const [aiOpen, setAiOpen] = useState(false) + const [aiLoading, setAiLoading] = useState(false) + const [linkOpen, setLinkOpen] = useState(false) + const [linkUrl, setLinkUrl] = useState('') + const linkInputRef = useRef(null) + + useEffect(() => { + if (!editor) return + const h = () => setTick(t => t + 1) + editor.on('transaction', h) + editor.on('selectionUpdate', h) + return () => { editor.off('transaction', h); editor.off('selectionUpdate', h) } + }, [editor]) + + useEffect(() => { + if (linkOpen && linkInputRef.current) linkInputRef.current.focus() + }, [linkOpen]) + + if (!editor) return null + + const marks = [ + { icon: Bold, active: editor.isActive('bold'), action: () => editor.chain().focus().toggleBold().run() }, + { icon: Italic, active: editor.isActive('italic'), action: () => editor.chain().focus().toggleItalic().run() }, + { icon: UnderlineIcon, active: editor.isActive('underline'), action: () => editor.chain().focus().toggleUnderline().run() }, + { icon: Strikethrough, active: editor.isActive('strike'), action: () => editor.chain().focus().toggleStrike().run() }, + { icon: Code, active: editor.isActive('code'), action: () => editor.chain().focus().toggleCode().run() }, + { icon: Highlighter, active: editor.isActive('highlight'), action: () => editor.chain().focus().toggleHighlight().run() }, + ] + + const handleAI = async (option: 'clarify' | 'shorten' | 'improve') => { + const { from, to } = editor.state.selection + const text = editor.state.doc.textBetween(from, to, ' ') + if (!text || text.split(/\s+/).length < 5) return + setAiLoading(true) + setAiOpen(false) + try { + const result = await aiReformulate(text, option) + editor.chain().focus().insertContentAt({ from, to }, result).run() + } catch (err) { + console.error('AI error:', err) + } finally { + setAiLoading(false) + } + } + + const openLinkEditor = () => { + const existing = editor.getAttributes('link').href || '' + setLinkUrl(existing) + setLinkOpen(true) + setAiOpen(false) + } + + const applyLink = () => { + if (linkUrl.trim()) { + editor.chain().focus().extendMarkRange('link').setLink({ href: linkUrl.trim() }).run() + } else { + editor.chain().focus().extendMarkRange('link').unsetLink().run() + } + setLinkOpen(false) + } + + if (linkOpen) { + return ( +
+ + setLinkUrl(e.target.value)} + onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); applyLink() }; if (e.key === 'Escape') { setLinkOpen(false); editor.chain().focus().run() } }} + placeholder="Paste or type a link..." + className="notion-inline-input" + /> + + {editor.isActive('link') && ( + + )} + +
+ ) + } + + return ( +
+ {marks.map((m, i) => ( + + ))} +
+ + + {aiOpen && ( +
+ + + +
+ )} +
+ ) +} + +function SlashCommandMenu({ editor, onInsertImage }: { editor: Editor; onInsertImage: (editor: Editor) => void }) { + const [isOpen, setIsOpen] = useState(false) + const [query, setQuery] = useState('') + const [selectedIndex, setSelectedIndex] = useState(0) + const [coords, setCoords] = useState({ top: 0, left: 0 }) + const [aiLoading, setAiLoading] = useState(false) + const menuRef = useRef(null) + + const closeMenu = useCallback(() => { setIsOpen(false); setQuery(''); setSelectedIndex(0) }, []) + + const deleteSlashText = useCallback(() => { + const { from, to } = editor.state.selection + const textBefore = editor.state.doc.textBetween(Math.max(0, from - 50), from, '\n') + const slashIdx = textBefore.lastIndexOf('/') + if (slashIdx >= 0) { + const deleteFrom = from - (textBefore.length - slashIdx) + editor.chain().focus().deleteRange({ from: deleteFrom, to }).run() + } + }, [editor]) + + const handleSelect = useCallback(async (item: SlashItem) => { + if (item.isImage) { + deleteSlashText() + closeMenu() + onInsertImage(editor) + } else if (item.isAi && item.aiOption) { + deleteSlashText() + closeMenu() + setAiLoading(true) + try { + const allText = editor.state.doc.textContent + if (!allText || allText.split(/\s+/).length < 5) return + const result = await aiReformulate(allText, item.aiOption) + editor.chain().focus().setContent(result).run() + } catch (err) { + console.error('AI slash error:', err) + } finally { + setAiLoading(false) + } + } else { + deleteSlashText() + item.command(editor) + closeMenu() + } + }, [editor, closeMenu, deleteSlashText, onInsertImage]) + + const filtered = slashCommands.filter(c => c.title.toLowerCase().includes(query.toLowerCase())) + + const categories = filtered.reduce((acc, item) => { + const cat = item.category || 'Basic blocks' + if (!acc[cat]) acc[cat] = [] + acc[cat].push(item) + return acc + }, {} as Record) + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (!isOpen) return + if (e.key === 'ArrowDown') { e.preventDefault(); setSelectedIndex(i => (i + 1) % filtered.length); return } + if (e.key === 'ArrowUp') { e.preventDefault(); setSelectedIndex(i => (i - 1 + filtered.length) % filtered.length); return } + if (e.key === 'Enter') { e.preventDefault(); if (filtered[selectedIndex]) handleSelect(filtered[selectedIndex]); return } + if (e.key === 'Escape') { e.preventDefault(); closeMenu(); return } + } + document.addEventListener('keydown', handleKeyDown, true) + return () => document.removeEventListener('keydown', handleKeyDown, true) + }, [isOpen, selectedIndex, filtered, handleSelect, closeMenu]) + + useEffect(() => { + if (!isOpen) return + const updatePosition = () => { + const { from } = editor.state.selection + const c = editor.view.coordsAtPos(from) + setCoords({ top: c.bottom + 8, left: c.left }) + } + updatePosition() + }, [isOpen, editor, query]) + + useEffect(() => { + const handleClick = () => { if (isOpen) closeMenu() } + document.addEventListener('click', handleClick) + return () => document.removeEventListener('click', handleClick) + }, [isOpen, closeMenu]) + + useEffect(() => { + const handler = () => { + const { from, to, empty } = editor.state.selection + if (!empty) { if (isOpen) closeMenu(); return } + const text = editor.state.doc.textBetween(Math.max(0, from - 50), from, '\n') + const m = text.match(/\/([^\s/]*)$/) + if (m) { setQuery(m[1]); setSelectedIndex(0); if (!isOpen) setIsOpen(true) } + else if (isOpen) closeMenu() + } + editor.on('update', handler) + editor.on('selectionUpdate', handler) + return () => { editor.off('update', handler); editor.off('selectionUpdate', handler) } + }, [editor, isOpen, closeMenu]) + + if (!isOpen || filtered.length === 0) return null + + let flatIndex = -1 + + return ( +
e.stopPropagation()}> + {aiLoading && ( +
+ + AI is thinking... +
+ )} + {!aiLoading && Object.entries(categories).map(([cat, items]) => ( +
+
{cat}
+ {items.map((item) => { + flatIndex++ + const idx = flatIndex + return ( + + ) + })} +
+ ))} +
+ ) +} diff --git a/memento-note/lib/i18n/load-translations.ts b/memento-note/lib/i18n/load-translations.ts index 8a75b73..5c0e9c1 100644 --- a/memento-note/lib/i18n/load-translations.ts +++ b/memento-note/lib/i18n/load-translations.ts @@ -135,6 +135,16 @@ export interface Translations { viewTabsTooltip: string viewModeGroup: string reorderTabs: string + noteType: string + typeText: string + typeMarkdown: string + typeRichText: string + typeChecklist: string + richTextPlaceholder: string + switchTypeTitle: string + switchTypeWarning: string + switchTypeContentPreserved: string + switchType: string } pagination: { previous: string diff --git a/memento-note/lib/types.ts b/memento-note/lib/types.ts index 920d2f6..ad10fc3 100644 --- a/memento-note/lib/types.ts +++ b/memento-note/lib/types.ts @@ -44,6 +44,15 @@ export interface LinkMetadata { siteName?: string; } +export type NoteType = 'text' | 'markdown' | 'richtext' | 'checklist' + +export const NOTE_TYPE_CONFIG: Record = { + text: { icon: 'AlignLeft', label: 'Text' }, + markdown: { icon: 'FileCode2', label: 'Markdown' }, + richtext: { icon: 'PenLine', label: 'Rich Text' }, + checklist: { icon: 'ListChecks', label: 'Checklist' }, +} + export interface Note { id: string; title: string | null; @@ -52,9 +61,9 @@ export interface Note { isPinned: boolean; isArchived: boolean; trashedAt?: Date | null; - type: 'text' | 'checklist'; + type: NoteType; checkItems: CheckItem[] | null; - labels: string[] | null; // DEPRECATED: Array of label names stored as JSON string + labels: string[] | null; images: string[] | null; links: LinkMetadata[] | null; reminder: Date | null; @@ -70,13 +79,11 @@ export interface Note { contentUpdatedAt: Date; sharedWith?: string[]; userId?: string | null; - // Notebook relation (optional - null = "General Notes" / Inbox) notebookId?: string | null; notebook?: Notebook | null; autoGenerated?: boolean | null; aiProvider?: string | null; historyEnabled?: boolean; - // Search result metadata (optional) matchType?: 'exact' | 'related' | null; searchScore?: number | null; } @@ -92,8 +99,7 @@ export interface NoteHistoryEntry { color: string; isPinned: boolean; isArchived: boolean; - type: 'text' | 'checklist'; - checkItems: CheckItem[] | null; + type: NoteType; checkItems: CheckItem[] | null; labels: string[] | null; images: string[] | null; links: LinkMetadata[] | null; diff --git a/memento-note/lib/utils.ts b/memento-note/lib/utils.ts index bbee9f5..a47139e 100644 --- a/memento-note/lib/utils.ts +++ b/memento-note/lib/utils.ts @@ -1,6 +1,6 @@ import { clsx, type ClassValue } from "clsx" import { twMerge } from "tailwind-merge" -import { LABEL_COLORS, LabelColorName, QueryType, Note } from "./types" +import { LABEL_COLORS, LabelColorName, QueryType, Note, NoteType } from "./types" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) @@ -50,8 +50,14 @@ export function asArray(val: unknown, fallback: T[] = []): T[] { * Guarantees array fields are always real arrays or null. */ export function parseNote(dbNote: any): Note { + let noteType: NoteType = dbNote.type || 'text' + if (noteType === 'text' && dbNote.isMarkdown) { + noteType = 'markdown' + } return { ...dbNote, + type: noteType, + isMarkdown: noteType === 'markdown', checkItems: asArray(dbNote.checkItems, null as any) ?? null, labels: asArray(dbNote.labels) || null, images: asArray(dbNote.images) || null, diff --git a/memento-note/locales/ar.json b/memento-note/locales/ar.json index db60312..6d11fa0 100644 --- a/memento-note/locales/ar.json +++ b/memento-note/locales/ar.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "نوع الملاحظة", + "typeText": "نص", + "typeMarkdown": "ماركداون", + "typeRichText": "نص منسق", + "typeChecklist": "قائمة مراجعة", + "richTextPlaceholder": "اكتب ملاحظة...", + "switchTypeTitle": "تغيير نوع الملاحظة؟", + "switchTypeWarning": "قد يفقد بعض التنسيق عند التحويل إلى {type}.", + "switchTypeContentPreserved": "سيتم الحفاظ على المحتوى كنص عادي.", + "switchType": "تحويل إلى {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/de.json b/memento-note/locales/de.json index 177bf98..86d0113 100644 --- a/memento-note/locales/de.json +++ b/memento-note/locales/de.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "Notiztyp", + "typeText": "Text", + "typeMarkdown": "Markdown", + "typeRichText": "Rich Text", + "typeChecklist": "Checkliste", + "richTextPlaceholder": "Notiz erstellen...", + "switchTypeTitle": "Notiztyp ändern?", + "switchTypeWarning": "Formatierung kann beim Wechsel zu {type} verloren gehen.", + "switchTypeContentPreserved": "Dein Inhalt wird als Klartext erhalten.", + "switchType": "Wechseln zu {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/en.json b/memento-note/locales/en.json index ce00981..e2aa42e 100644 --- a/memento-note/locales/en.json +++ b/memento-note/locales/en.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "Note type", + "typeText": "Text", + "typeMarkdown": "Markdown", + "typeRichText": "Rich Text", + "typeChecklist": "Checklist", + "richTextPlaceholder": "Take a note...", + "switchTypeTitle": "Switch note type?", + "switchTypeWarning": "Some formatting may be lost when switching to {type}.", + "switchTypeContentPreserved": "Your content will be preserved as plain text.", + "switchType": "Switch to {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/es.json b/memento-note/locales/es.json index d7411d3..faba4d9 100644 --- a/memento-note/locales/es.json +++ b/memento-note/locales/es.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "Tipo de nota", + "typeText": "Texto", + "typeMarkdown": "Markdown", + "typeRichText": "Texto enriquecido", + "typeChecklist": "Lista de tareas", + "richTextPlaceholder": "Escribe una nota...", + "switchTypeTitle": "¿Cambiar tipo de nota?", + "switchTypeWarning": "Se puede perder formato al cambiar a {type}.", + "switchTypeContentPreserved": "Tu contenido se preservará como texto plano.", + "switchType": "Cambiar a {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/fa.json b/memento-note/locales/fa.json index 650a225..02cf2b9 100644 --- a/memento-note/locales/fa.json +++ b/memento-note/locales/fa.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "نوع یادداشت", + "typeText": "متن", + "typeMarkdown": "مارکداون", + "typeRichText": "متن غنی", + "typeChecklist": "چک‌لیست", + "richTextPlaceholder": "یادداشتی بنویسید...", + "switchTypeTitle": "نوع یادداشت تغییر کند؟", + "switchTypeWarning": "هنگام تغییر به {type} ممکن است برخی قالب‌بندی‌ها از بین بروند.", + "switchTypeContentPreserved": "محتوای شما به عنوان متن ساده حفظ می‌شود.", + "switchType": "تغییر به {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/fr.json b/memento-note/locales/fr.json index f27b83b..807de40 100644 --- a/memento-note/locales/fr.json +++ b/memento-note/locales/fr.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Supprimer la note", "leftShare": "Partage retiré", "dismissed": "Note retirée des récentes", - "generalNotes": "Notes générales" + "generalNotes": "Notes générales", + "noteType": "Type de note", + "typeText": "Texte", + "typeMarkdown": "Markdown", + "typeRichText": "Texte riche", + "typeChecklist": "Liste de tâches", + "richTextPlaceholder": "Prenez une note...", + "switchTypeTitle": "Changer le type de note ?", + "switchTypeWarning": "Certaines mises en forme peuvent être perdues lors du passage en {type}.", + "switchTypeContentPreserved": "Votre contenu sera préservé en texte brut.", + "switchType": "Passer en {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/hi.json b/memento-note/locales/hi.json index d28a17d..60da8a8 100644 --- a/memento-note/locales/hi.json +++ b/memento-note/locales/hi.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "नोट प्रकार", + "typeText": "पाठ", + "typeMarkdown": "मार्कडाउन", + "typeRichText": "रिच टेक्स्ट", + "typeChecklist": "चेकलिस्ट", + "richTextPlaceholder": "एक नोट लिखें...", + "switchTypeTitle": "नोट प्रकार बदलें?", + "switchTypeWarning": "{type} में बदलने पर कुछ फ़ॉर्मेटिंग खो सकती है।", + "switchTypeContentPreserved": "आपकी सामग्री सादे पाठ के रूप में संरक्षित रहेगी।", + "switchType": "{type} में बदलें" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/it.json b/memento-note/locales/it.json index a48c4fd..d6e29aa 100644 --- a/memento-note/locales/it.json +++ b/memento-note/locales/it.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "Tipo di nota", + "typeText": "Testo", + "typeMarkdown": "Markdown", + "typeRichText": "Testo formattato", + "typeChecklist": "Lista di controllo", + "richTextPlaceholder": "Prendi una nota...", + "switchTypeTitle": "Cambiare tipo di nota?", + "switchTypeWarning": "Alcune formattazioni potrebbero andare perse con {type}.", + "switchTypeContentPreserved": "Il contenuto sarà preservato come testo semplice.", + "switchType": "Passa a {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/ja.json b/memento-note/locales/ja.json index 805f544..1ed96f3 100644 --- a/memento-note/locales/ja.json +++ b/memento-note/locales/ja.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "ノートタイプ", + "typeText": "テキスト", + "typeMarkdown": "Markdown", + "typeRichText": "リッチテキスト", + "typeChecklist": "チェックリスト", + "richTextPlaceholder": "メモを取る...", + "switchTypeTitle": "ノートタイプを切り替えますか?", + "switchTypeWarning": "{type} に切り替えると書式が失われる場合があります。", + "switchTypeContentPreserved": "内容はプレーンテキストとして保持されます。", + "switchType": "{type} に切り替え" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/ko.json b/memento-note/locales/ko.json index 767df99..9be7daf 100644 --- a/memento-note/locales/ko.json +++ b/memento-note/locales/ko.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "노트 유형", + "typeText": "텍스트", + "typeMarkdown": "Markdown", + "typeRichText": "리치 텍스트", + "typeChecklist": "체크리스트", + "richTextPlaceholder": "노트를 작성하세요...", + "switchTypeTitle": "노트 유형을 변경하시겠습니까?", + "switchTypeWarning": "{type}(으)로 전환하면 일부 서식이 손실될 수 있습니다.", + "switchTypeContentPreserved": "콘텐츠는 일반 텍스트로 보존됩니다.", + "switchType": "{type}(으)로 전환" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/nl.json b/memento-note/locales/nl.json index bf6cf3a..a1bb284 100644 --- a/memento-note/locales/nl.json +++ b/memento-note/locales/nl.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "Notitietype", + "typeText": "Tekst", + "typeMarkdown": "Markdown", + "typeRichText": "Rich Text", + "typeChecklist": "Checklist", + "richTextPlaceholder": "Maak een notitie...", + "switchTypeTitle": "Notitietype wijzigen?", + "switchTypeWarning": "Opmaak kan verloren gaan bij wijziging naar {type}.", + "switchTypeContentPreserved": "Je inhoud wordt bewaard als platte tekst.", + "switchType": "Wijzigen naar {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/pl.json b/memento-note/locales/pl.json index 198e1c6..3661b4e 100644 --- a/memento-note/locales/pl.json +++ b/memento-note/locales/pl.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "Typ notatki", + "typeText": "Tekst", + "typeMarkdown": "Markdown", + "typeRichText": "Tekst sformatowany", + "typeChecklist": "Lista kontrolna", + "richTextPlaceholder": "Zrób notatkę...", + "switchTypeTitle": "Zmienić typ notatki?", + "switchTypeWarning": "Niektóre formatowanie może zostać utracone przy zmianie na {type}.", + "switchTypeContentPreserved": "Twoja treść zostanie zachowana jako zwykły tekst.", + "switchType": "Zmień na {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/pt.json b/memento-note/locales/pt.json index b070f9c..c257960 100644 --- a/memento-note/locales/pt.json +++ b/memento-note/locales/pt.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "Tipo de nota", + "typeText": "Texto", + "typeMarkdown": "Markdown", + "typeRichText": "Texto rico", + "typeChecklist": "Lista de verificação", + "richTextPlaceholder": "Tome uma nota...", + "switchTypeTitle": "Alterar tipo de nota?", + "switchTypeWarning": "Alguma formatação pode ser perdida ao mudar para {type}.", + "switchTypeContentPreserved": "Seu conteúdo será preservado como texto simples.", + "switchType": "Mudar para {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/ru.json b/memento-note/locales/ru.json index 0e3b8cd..c744052 100644 --- a/memento-note/locales/ru.json +++ b/memento-note/locales/ru.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "Тип заметки", + "typeText": "Текст", + "typeMarkdown": "Markdown", + "typeRichText": "Форматированный текст", + "typeChecklist": "Чек-лист", + "richTextPlaceholder": "Сделайте заметку...", + "switchTypeTitle": "Сменить тип заметки?", + "switchTypeWarning": "Некоторое форматирование может быть потеряно при смене на {type}.", + "switchTypeContentPreserved": "Ваш контент будет сохранён как простой текст.", + "switchType": "Переключить на {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/locales/zh.json b/memento-note/locales/zh.json index f4a110a..437a54d 100644 --- a/memento-note/locales/zh.json +++ b/memento-note/locales/zh.json @@ -201,7 +201,17 @@ "confirmDeleteTitle": "Delete note", "leftShare": "Share removed", "dismissed": "Note dismissed from recent", - "generalNotes": "General Notes" + "generalNotes": "General Notes", + "noteType": "笔记类型", + "typeText": "文本", + "typeMarkdown": "Markdown", + "typeRichText": "富文本", + "typeChecklist": "待办清单", + "richTextPlaceholder": "记笔记...", + "switchTypeTitle": "切换笔记类型?", + "switchTypeWarning": "切换到 {type} 可能会丢失部分格式。", + "switchTypeContentPreserved": "您的内容将保留为纯文本。", + "switchType": "切换到 {type}" }, "pagination": { "previous": "←", diff --git a/memento-note/package-lock.json b/memento-note/package-lock.json index 2fe2eb5..f1abe0d 100644 --- a/memento-note/package-lock.json +++ b/memento-note/package-lock.json @@ -28,6 +28,21 @@ "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-switch": "^1.2.6", "@radix-ui/react-tooltip": "^1.2.8", + "@tiptap/extension-color": "^3.22.5", + "@tiptap/extension-highlight": "^3.22.5", + "@tiptap/extension-image": "^3.22.5", + "@tiptap/extension-placeholder": "^3.22.5", + "@tiptap/extension-subscript": "^3.22.5", + "@tiptap/extension-superscript": "^3.22.5", + "@tiptap/extension-task-item": "^3.22.5", + "@tiptap/extension-task-list": "^3.22.5", + "@tiptap/extension-text-align": "^3.22.5", + "@tiptap/extension-text-style": "^3.22.5", + "@tiptap/extension-typography": "^3.22.5", + "@tiptap/pm": "^3.22.5", + "@tiptap/react": "^3.22.5", + "@tiptap/starter-kit": "^3.22.5", + "@tiptap/suggestion": "^3.22.5", "@types/jsdom": "^28.0.1", "ai": "^6.0.23", "autoprefixer": "^10.4.23", @@ -45,6 +60,7 @@ "next": "^16.1.6", "next-auth": "^5.0.0-beta.30", "nodemailer": "^8.0.4", + "novel": "^1.0.2", "postcss": "^8.5.6", "radix-ui": "^1.4.3", "react": "19.2.3", @@ -59,6 +75,7 @@ "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "tinyld": "^1.3.4", + "tippy.js": "^6.3.7", "vazirmatn": "^33.0.3", "zod": "^4.3.5" }, @@ -352,6 +369,15 @@ "specificity": "bin/cli.js" } }, + "node_modules/@cfcs/core": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@cfcs/core/-/core-0.0.6.tgz", + "integrity": "sha512-FxfJMwoLB8MEMConeXUCqtMGqxdtePQxRBOiGip9ULcYYam3WfCgoY6xdnMaSkYvRvmosp5iuG+TiPofm65+Pw==", + "license": "MIT", + "dependencies": { + "@egjs/component": "^3.0.2" + } + }, "node_modules/@chevrotain/cst-dts-gen": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", @@ -527,6 +553,12 @@ "node": ">=20.19.0" } }, + "node_modules/@daybrush/utils": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@daybrush/utils/-/utils-1.13.0.tgz", + "integrity": "sha512-ALK12C6SQNNHw1enXK+UO8bdyQ+jaWNQ1Af7Z3FNxeAwjYhQT7do+TRE4RASAJ3ObaS2+TJ7TXR3oz2Gzbw0PQ==", + "license": "MIT" + }, "node_modules/@dnd-kit/accessibility": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", @@ -581,6 +613,33 @@ "react": ">=16.8.0" } }, + "node_modules/@egjs/agent": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@egjs/agent/-/agent-2.4.4.tgz", + "integrity": "sha512-cvAPSlUILhBBOakn2krdPnOGv5hAZq92f1YHxYcfu0p7uarix2C6Ia3AVizpS1SGRZGiEkIS5E+IVTLg1I2Iog==", + "license": "MIT" + }, + "node_modules/@egjs/children-differ": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@egjs/children-differ/-/children-differ-1.0.1.tgz", + "integrity": "sha512-DRvyqMf+CPCOzAopQKHtW+X8iN6Hy6SFol+/7zCUiE5y4P/OB8JP8FtU4NxtZwtafvSL4faD5KoQYPj3JHzPFQ==", + "license": "MIT", + "dependencies": { + "@egjs/list-differ": "^1.0.0" + } + }, + "node_modules/@egjs/component": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@egjs/component/-/component-3.0.5.tgz", + "integrity": "sha512-cLcGizTrrUNA2EYE3MBmEDt2tQv1joVP1Q3oDisZ5nw0MZDx2kcgEXM+/kZpfa/PAkFvYVhRUZwytIQWoN3V/w==", + "license": "MIT" + }, + "node_modules/@egjs/list-differ": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@egjs/list-differ/-/list-differ-1.0.1.tgz", + "integrity": "sha512-OTFTDQcWS+1ZREOdCWuk5hCBgYO4OsD30lXcOCyVOAjXMhgL5rBRDnt/otb6Nz8CzU0L/igdcaQBDLWc4t9gvg==", + "license": "MIT" + }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", @@ -1542,6 +1601,7 @@ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", "license": "MIT", + "peer": true, "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" @@ -2638,6 +2698,16 @@ "node": ">=18" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@prisma/client": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.22.0.tgz", @@ -5514,6 +5584,12 @@ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", "license": "MIT" }, + "node_modules/@remirror/core-constants": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", + "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", + "license": "MIT" + }, "node_modules/@rolldown/binding-android-arm64": { "version": "1.0.0-rc.16", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.16.tgz", @@ -5801,6 +5877,34 @@ "dev": true, "license": "MIT" }, + "node_modules/@scena/dragscroll": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scena/dragscroll/-/dragscroll-1.4.0.tgz", + "integrity": "sha512-3O8daaZD9VXA9CP3dra6xcgt/qrm0mg0xJCwiX6druCteQ9FFsXffkF8PrqxY4Z4VJ58fFKEa0RlKqbsi/XnRA==", + "license": "MIT", + "dependencies": { + "@daybrush/utils": "^1.6.0", + "@scena/event-emitter": "^1.0.2" + } + }, + "node_modules/@scena/event-emitter": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@scena/event-emitter/-/event-emitter-1.0.5.tgz", + "integrity": "sha512-AzY4OTb0+7ynefmWFQ6hxDdk0CySAq/D4efljfhtRHCOP7MBF9zUfhKG3TJiroVjASqVgkRJFdenS8ArZo6Olg==", + "license": "MIT", + "dependencies": { + "@daybrush/utils": "^1.1.1" + } + }, + "node_modules/@scena/matrix": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scena/matrix/-/matrix-1.1.1.tgz", + "integrity": "sha512-JVKBhN0tm2Srl+Yt+Ywqu0oLgLcdemDQlD1OxmN9jaCTwaFPZ7tY8n6dhVgMEaR9qcR7r+kAlMXnSfNyYdE+Vg==", + "license": "MIT", + "dependencies": { + "@daybrush/utils": "^1.4.0" + } + }, "node_modules/@stablelib/base64": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", @@ -6106,6 +6210,598 @@ "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, + "node_modules/@tiptap/core": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.22.5.tgz", + "integrity": "sha512-L1lhWz6ujGny8LduTJ7MBWYhzigwOvfUJUrJ7IzOJSuy3+OAzisdGDD1GV7LEO/hU0Hr2Mkm1wajRIHExvS9HQ==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/pm": "3.22.5" + } + }, + "node_modules/@tiptap/extension-blockquote": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.22.5.tgz", + "integrity": "sha512-ajyP5W8fG5Hrru47T/eF3xMKOpNvWofgNJqBTeNuGl02sYxsy9a4EunyFxudsaZP9WW3VOD4SaIWr5+MqpbnOQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-bold": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.22.5.tgz", + "integrity": "sha512-l/uDtpJISiFFyfctvnODNWBN/XPZI1jVZRacTRDDnSn8+x6KQ7G2qgFYueU7KvVJGDFVT39Iio56mcFRG/Pozg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-bubble-menu": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.22.5.tgz", + "integrity": "sha512-yrNlFQQJY5MmhBpmD8tnmaSmyUQrEvgyPKa3bzVeWEhDSG1CW4A0ZSMx3hrA9yFO0HWfw3IJmvSCycEZQBalpQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5", + "@tiptap/pm": "3.22.5" + } + }, + "node_modules/@tiptap/extension-bullet-list": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.22.5.tgz", + "integrity": "sha512-cf54fG9AybU8NgPMv1TOcoqAkELeRc/VpnSCt/rIJZphWQx9nsFmrtkrlCatrIcCaGtNZYwlHlMnC5LVVMu0uA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.22.5" + } + }, + "node_modules/@tiptap/extension-code": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.22.5.tgz", + "integrity": "sha512-mwDNOJC9rYbDu/JcqrN4dbUQRklJU8Fuk2raxD/IvFw9qUIcPCmxQ2XT9UTKmZz/Ju7Kdy72fss6XpgWv6gLAQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-code-block": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.22.5.tgz", + "integrity": "sha512-d123kCfLdJTi4fue1m0+TNFztDkmIRSZGZmGu6H9KqwG5Q7IzjT9o8lzRsz+pXxYqHvqgYmXoEpM6srbzXx/Ag==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5", + "@tiptap/pm": "3.22.5" + } + }, + "node_modules/@tiptap/extension-color": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-3.22.5.tgz", + "integrity": "sha512-4aTygOUlTFBYCvJy67SeKVdXCQw7du3Rj+N5ZutVnDnrpfzUBWsO7f+I+iDS8eMQFbWxVFLlWxGMcTbjtk1a+Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-text-style": "3.22.5" + } + }, + "node_modules/@tiptap/extension-document": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.22.5.tgz", + "integrity": "sha512-8NJERd+pCtvSuEP4C4WMGYmRRCV12ePZL7bC+QUdFlbdXg+kNZS0zZ7hh879tYA0Kidbi8rWWD1Tx+H2ezkmMw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-dropcursor": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.22.5.tgz", + "integrity": "sha512-Mp40DaFrY3sEUVtFqmxrR0BmU4G3k8GCYYNGqNa9OqWv7BrcFDC03V2n3okESDKt4MKkzhQQmypq+ouLy8dLfA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.22.5" + } + }, + "node_modules/@tiptap/extension-floating-menu": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.22.5.tgz", + "integrity": "sha512-dhem4sTPhyQgQ+pFp2Oud4k4FSQz9PVMgeQAC9288SmGwxBkJNveDAw6sKTMrumqDvwkJrtslXIupq9TZYQnzg==", + "license": "MIT", + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@floating-ui/dom": "^1.0.0", + "@tiptap/core": "3.22.5", + "@tiptap/pm": "3.22.5" + } + }, + "node_modules/@tiptap/extension-gapcursor": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.22.5.tgz", + "integrity": "sha512-4WkMu7qqjbsm8hCQS+8X+la1wjriN0SKoRdvpfKH33qM50MB34tYJuGLAO+y7TTh4MMMco3AZCKPBL5JVMqNIg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.22.5" + } + }, + "node_modules/@tiptap/extension-hard-break": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.22.5.tgz", + "integrity": "sha512-n0R2mUVYZU2AVbJhg/WcY9+zx690wVwvsItHJf0DrYbf1tCYHx+PRHUt/AoXk6u8BSmnkb8/FDziS8m3mjfpSg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-heading": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.22.5.tgz", + "integrity": "sha512-hjyEG4947PAhMBfP1G6B0QAh6+y9mp2C5BQmNjprA05/lQzDAT7KFZzNh8ZVp3ol6aICKq/N1gFOW9Dc/9FUOw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-highlight": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-3.22.5.tgz", + "integrity": "sha512-byWruAOKcqRN0OuzVSKqLLrced3M9AZaR2pD1BV3aUZHzMzeBjLBfByh8s4lExH2Z547xQUdHHnUflBQ572I5A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-horizontal-rule": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.22.5.tgz", + "integrity": "sha512-vUV0/ugIbXOc8SJib0h8UMhgcqZXWu/dkEhlswZN4VVven1o5enkfxEiDw+OyIJHi5rUkrdhsQ/KTxG/Xb7X8A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5", + "@tiptap/pm": "3.22.5" + } + }, + "node_modules/@tiptap/extension-image": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-3.22.5.tgz", + "integrity": "sha512-ezMzA6w6UsPesQp6fxTQojI/IkGJLmkwR/VGTimva7sudP3HdSW8k3SGBkjfvp0L2xqUrC/l4nWOchu01A/xtQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-italic": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.22.5.tgz", + "integrity": "sha512-4T8baSiLkeIymTgEwirxDFt5YgYofkP3m1+MGYdGy2HKcOK+1vpvlPhEO1X5qtZngtJW5S4+njKjinRg52A4PA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-link": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.22.5.tgz", + "integrity": "sha512-d671MvF3GPKoS2OVxjIlQ7hIE7MS3hREdR+d4cvnnoiLLD+ZJ6KgDnxmWqF0a1s4qxLWK2KxKRSOIfYGE31QWQ==", + "license": "MIT", + "dependencies": { + "linkifyjs": "^4.3.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5", + "@tiptap/pm": "3.22.5" + } + }, + "node_modules/@tiptap/extension-list": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.22.5.tgz", + "integrity": "sha512-cVO3ZHCgxAWZ4zrFSs81FO2nyCk1wb2EHkpLpW98FzbJLkN9rDkazhW99P3HRWy/CvUldOT+8ecI1YrQtBojMg==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5", + "@tiptap/pm": "3.22.5" + } + }, + "node_modules/@tiptap/extension-list-item": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.22.5.tgz", + "integrity": "sha512-W7uTmyKLhlsvuTPLv+8WwnsY+mlikBFIoLSvVcBaFt4MwpsZ+DeB6KQg02Y7tbtaAnG7rXu9Fvw2QORh2P728A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.22.5" + } + }, + "node_modules/@tiptap/extension-list-keymap": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.22.5.tgz", + "integrity": "sha512-cGUnxJ0y515e1bVHNjUmbx7oWHoEon59w6BA5N2KwV9iW2mZZchlTX4yxJSOX+ixeVRChsa7YwC3Z1jUZ6AMEg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.22.5" + } + }, + "node_modules/@tiptap/extension-ordered-list": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.22.5.tgz", + "integrity": "sha512-OXdh4k4CNrukwiSdWdEQ49uvgnqvR0Z9aNSP4HI5/kZQ/Te1NtRtYCpUrzWyO/7CtjcCisXHti0o9C/TV8YMbQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.22.5" + } + }, + "node_modules/@tiptap/extension-paragraph": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.22.5.tgz", + "integrity": "sha512-52KCto4+XKpnBWpIufspWLyq4UWxAWC72ANPdGuIhbi72NRTabiTbTVN40uwGSPkyakeESG0/vKdWJCVvB4f0g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-placeholder": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.22.5.tgz", + "integrity": "sha512-MZAohQ3FCS763BkhGXgaWRya6WruZjwRwEAkXP8vkxbERzl2OJRjniS4uXCWzAlRb3ttE103SnY7LMdM8FvsXw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "3.22.5" + } + }, + "node_modules/@tiptap/extension-strike": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.22.5.tgz", + "integrity": "sha512-42WrrFK5gOom/0znH85x12Mw5IQ/6O6DWdyUWoRIrNA/qJpuHtU8oVU+bIgU2tuomMGHruRjIzgBQv5sBjEtww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-subscript": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-subscript/-/extension-subscript-3.22.5.tgz", + "integrity": "sha512-dee60jEhXxvaejgTqFCgPDD747S1WDu9sxuwUKvEDyE53xGhqHh25eCDUJ9BGPRa/9UurbGHe0KbXryTsbcaBg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5", + "@tiptap/pm": "3.22.5" + } + }, + "node_modules/@tiptap/extension-superscript": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-superscript/-/extension-superscript-3.22.5.tgz", + "integrity": "sha512-Ta9epX6CY9vOQjZAnY/HY7Lo/ixSrRwdDU8yOhkoO9pkYNA/e8l5xhf1T04qnBQ1+QaOZzpLTYlfQJrHzqcJmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5", + "@tiptap/pm": "3.22.5" + } + }, + "node_modules/@tiptap/extension-task-item": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-task-item/-/extension-task-item-3.22.5.tgz", + "integrity": "sha512-OVJKiq67lU+RiC6slIhhgTJBlP/Vads6MZ7Ld5wxzCtWMdGKDuzQ1dgF7vrMEs7mhSeSH3phNcIdQ5ypYftZ9w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.22.5" + } + }, + "node_modules/@tiptap/extension-task-list": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-task-list/-/extension-task-list-3.22.5.tgz", + "integrity": "sha512-SfZeJSALtFODs0i3fml1TSi4vQ4Uopu0p/LndK+mX5FGNBtNmWiy7Wr5cH03ANfzj8c2EzfGIyH+F2/V0HLK9g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "3.22.5" + } + }, + "node_modules/@tiptap/extension-text": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.22.5.tgz", + "integrity": "sha512-bzpDOdAEo1JeoVZDIyV0oY0jGXkEG+AzF70SzHoRSjOvFDtKWunyXf9eO1OnOr2/fmMcckT2qwUBNBMQplWBzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-text-align": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-3.22.5.tgz", + "integrity": "sha512-LNUinhsZJC+/Vm7ugtghSjqlO64FQuww8oJkHq54Oh135fJ+kY2yBRakYFeH0P0gl4VPJH13AUetLF696CM2UQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-text-style": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-3.22.5.tgz", + "integrity": "sha512-jt63jy8YbhZJUGMxTUzeivLhowGtFp6YbCFrrmZJ7G6IHu8X8LJzO81ksz5nT5l8DKpldGwnINUfA6iE91JIAg==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-typography": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-typography/-/extension-typography-3.22.5.tgz", + "integrity": "sha512-FbBoo7hZNV2q/wa0yL2hVyVjmn0OEA5vzzSep0ExFdOjmPYe+5Us1bsf0G3lutYS9rQfgQrcXBvcGJozU+Agyg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extension-underline": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.22.5.tgz", + "integrity": "sha512-9ut09rJD0iEbS6sk7yd2j6IwuFDLTNmDEGTDLodvqAfi+bq7ddsTDv0YviXoZaA9sdHAdTEVr2ITy2m6WK5jpA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5" + } + }, + "node_modules/@tiptap/extensions": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.22.5.tgz", + "integrity": "sha512-Ifg4MzKCj3uRqe3ieTwYnomu2y4p7EXr2avVSKZYfh12i2dyWe2Gkn1KuZDREANVE+gHqFlQjJRYzhJFwzSCrg==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5", + "@tiptap/pm": "3.22.5" + } + }, + "node_modules/@tiptap/pm": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.22.5.tgz", + "integrity": "sha512-Cr9Mv4igxvI2tKMiahw48sZxva3PfDzypErH8IB82N+9qa9n9ygVMt0BOaDg53hLKxEEVeYr2S/wCcJIVFgBTw==", + "license": "MIT", + "peer": true, + "dependencies": { + "prosemirror-changeset": "^2.3.0", + "prosemirror-commands": "^1.6.2", + "prosemirror-dropcursor": "^1.8.1", + "prosemirror-gapcursor": "^1.3.2", + "prosemirror-history": "^1.4.1", + "prosemirror-keymap": "^1.2.2", + "prosemirror-model": "^1.24.1", + "prosemirror-schema-list": "^1.5.0", + "prosemirror-state": "^1.4.3", + "prosemirror-tables": "^1.6.4", + "prosemirror-transform": "^1.10.2", + "prosemirror-view": "^1.38.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/react": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.22.5.tgz", + "integrity": "sha512-36WHEs+vPmB//V1ff7Ujcnpz7Ey5g8lhpI/0+hoanSbdiPMTQ7qZVWwMovIkMKDlqWVp2fxBgeYM1861jyFzTw==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "fast-equals": "^5.3.3", + "use-sync-external-store": "^1.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "optionalDependencies": { + "@tiptap/extension-bubble-menu": "^3.22.5", + "@tiptap/extension-floating-menu": "^3.22.5" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5", + "@tiptap/pm": "3.22.5", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tiptap/starter-kit": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.22.5.tgz", + "integrity": "sha512-LZ/LYbwH6rnDi5DnRyagkuNsYAVyhM+yJvvz+ZuYA0JkPiTXJV86J5PWSKew8M0gVfMHcNVtKjfQCvViFCeIgw==", + "license": "MIT", + "dependencies": { + "@tiptap/core": "^3.22.5", + "@tiptap/extension-blockquote": "^3.22.5", + "@tiptap/extension-bold": "^3.22.5", + "@tiptap/extension-bullet-list": "^3.22.5", + "@tiptap/extension-code": "^3.22.5", + "@tiptap/extension-code-block": "^3.22.5", + "@tiptap/extension-document": "^3.22.5", + "@tiptap/extension-dropcursor": "^3.22.5", + "@tiptap/extension-gapcursor": "^3.22.5", + "@tiptap/extension-hard-break": "^3.22.5", + "@tiptap/extension-heading": "^3.22.5", + "@tiptap/extension-horizontal-rule": "^3.22.5", + "@tiptap/extension-italic": "^3.22.5", + "@tiptap/extension-link": "^3.22.5", + "@tiptap/extension-list": "^3.22.5", + "@tiptap/extension-list-item": "^3.22.5", + "@tiptap/extension-list-keymap": "^3.22.5", + "@tiptap/extension-ordered-list": "^3.22.5", + "@tiptap/extension-paragraph": "^3.22.5", + "@tiptap/extension-strike": "^3.22.5", + "@tiptap/extension-text": "^3.22.5", + "@tiptap/extension-underline": "^3.22.5", + "@tiptap/extensions": "^3.22.5", + "@tiptap/pm": "^3.22.5" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/suggestion": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-3.22.5.tgz", + "integrity": "sha512-Uv79Ht/o4mx1GWIT65jeQTE67LMrA+K7d8p51XOe9PJw0H0fS3iCdeMJ8tAo3h6QrMJFejdsB7z8jJL9UbAnhA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.22.5", + "@tiptap/pm": "3.22.5" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", @@ -6452,6 +7148,22 @@ "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", "license": "MIT" }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -6461,6 +7173,12 @@ "@types/unist": "*" } }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "license": "MIT" + }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", @@ -6506,7 +7224,6 @@ "version": "19.2.3", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "devOptional": true, "license": "MIT", "peer": true, "peerDependencies": { @@ -6532,6 +7249,12 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -6718,6 +7441,12 @@ "node": ">= 8" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, "node_modules/aria-hidden": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", @@ -7214,6 +7943,12 @@ "node": ">=0.8" } }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT" + }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -7262,6 +7997,25 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-styled": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/css-styled/-/css-styled-1.0.8.tgz", + "integrity": "sha512-tCpP7kLRI8dI95rCh3Syl7I+v7PP+2JYOzWkl0bUEoSbJM+u8ITbutjlQVf0NC2/g4ULROJPi16sfwDIO8/84g==", + "license": "MIT", + "dependencies": { + "@daybrush/utils": "^1.13.0" + } + }, + "node_modules/css-to-mat": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-to-mat/-/css-to-mat-1.1.1.tgz", + "integrity": "sha512-kvpxFYZb27jRd2vium35G7q5XZ2WJ9rWjDUMNT36M3Hc41qCrLXFM5iEKMGXcrPsKfXEN+8l/riB4QzwwwiEyQ==", + "license": "MIT", + "dependencies": { + "@daybrush/utils": "^1.13.0", + "@scena/matrix": "^1.0.0" + } + }, "node_modules/css-tree": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", @@ -8181,6 +8935,21 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-sha256": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", @@ -8221,6 +8990,12 @@ "node": "^14.13.1 || >=16.0.0" } }, + "node_modules/framework-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/framework-utils/-/framework-utils-1.1.0.tgz", + "integrity": "sha512-KAfqli5PwpFJ8o3psRNs8svpMGyCSAe8nmGcjQ0zZBWN2H6dZDnq+ABp3N3hdUmFeMrLtjOCTXD4yplUJIWceg==", + "license": "MIT" + }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -8243,6 +9018,16 @@ "node": ">= 0.6.0" } }, + "node_modules/gesto": { + "version": "1.19.4", + "resolved": "https://registry.npmjs.org/gesto/-/gesto-1.19.4.tgz", + "integrity": "sha512-hfr/0dWwh0Bnbb88s3QVJd1ZRJeOWcgHPPwmiH6NnafDYvhTsxg+SLYu+q/oPNh9JS3V+nlr6fNs8kvPAtcRDQ==", + "license": "MIT", + "dependencies": { + "@daybrush/utils": "^1.13.0", + "@scena/event-emitter": "^1.0.2" + } + }, "node_modules/get-nonce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", @@ -8474,6 +9259,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/html-encoding-sniffer": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", @@ -8904,6 +9699,24 @@ "katex": "cli.js" } }, + "node_modules/keycode": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.1.tgz", + "integrity": "sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg==", + "license": "MIT" + }, + "node_modules/keycon": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/keycon/-/keycon-1.4.0.tgz", + "integrity": "sha512-p1NAIxiRMH3jYfTeXRs2uWbVJ1WpEjpi8ktzUyBJsX7/wn2qu2VRXktneBLNtKNxJmlUYxRi9gOJt1DuthXR7A==", + "license": "MIT", + "dependencies": { + "@cfcs/core": "^0.0.6", + "@daybrush/utils": "^1.7.1", + "@scena/event-emitter": "^1.0.2", + "keycode": "^2.2.0" + } + }, "node_modules/khroma": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", @@ -9192,6 +10005,21 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/linkifyjs": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz", + "integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==", + "license": "MIT" + }, "node_modules/lodash-es": { "version": "4.18.1", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", @@ -9220,6 +10048,22 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/lowlight": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.3.0.tgz", + "integrity": "sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.0.0", + "highlight.js": "~11.11.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/lru-cache": { "version": "11.3.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", @@ -9276,6 +10120,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, "node_modules/markdown-table": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", @@ -9593,6 +10454,12 @@ "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", "license": "CC0-1.0" }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, "node_modules/mermaid": { "version": "11.14.0", "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.14.0.tgz", @@ -10514,6 +11381,661 @@ "node": ">=0.10.0" } }, + "node_modules/novel": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/novel/-/novel-1.0.2.tgz", + "integrity": "sha512-lyMtoBsRCqgrQaNhlc8Ngpp+npJEQjPoGBLcnYlEr8mEf+lXZV7/m6CbEpGRfma+HZQVlU3YJOs4gCmzbLG+ow==", + "license": "Apache-2.0", + "dependencies": { + "@radix-ui/react-slot": "^1.1.1", + "@tiptap/core": "^2.11.2", + "@tiptap/extension-character-count": "^2.11.2", + "@tiptap/extension-code-block-lowlight": "^2.11.2", + "@tiptap/extension-color": "^2.11.2", + "@tiptap/extension-highlight": "^2.11.2", + "@tiptap/extension-horizontal-rule": "^2.11.2", + "@tiptap/extension-image": "^2.11.2", + "@tiptap/extension-link": "^2.11.2", + "@tiptap/extension-placeholder": "^2.11.2", + "@tiptap/extension-task-item": "^2.11.2", + "@tiptap/extension-task-list": "^2.11.2", + "@tiptap/extension-text-style": "^2.11.2", + "@tiptap/extension-underline": "^2.11.2", + "@tiptap/extension-youtube": "^2.11.2", + "@tiptap/pm": "^2.11.2", + "@tiptap/react": "^2.11.2", + "@tiptap/starter-kit": "^2.11.2", + "@tiptap/suggestion": "^2.11.2", + "@types/node": "^22.10.6", + "cmdk": "^1.0.4", + "jotai": "^2.11.0", + "katex": "^0.16.20", + "react-markdown": "^9.0.3", + "react-moveable": "^0.56.0", + "react-tweet": "^3.2.1", + "tippy.js": "^6.3.7", + "tiptap-extension-global-drag-handle": "^0.1.16", + "tunnel-rat": "^0.1.2" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/novel/node_modules/@tiptap/core": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.27.2.tgz", + "integrity": "sha512-ABL1N6eoxzDzC1bYvkMbvyexHacszsKdVPYqhl5GwHLOvpZcv9VE9QaKwDILTyz5voCA0lGcAAXZp+qnXOk5lQ==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-blockquote": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.27.2.tgz", + "integrity": "sha512-oIGZgiAeA4tG3YxbTDfrmENL4/CIwGuP3THtHsNhwRqwsl9SfMk58Ucopi2GXTQSdYXpRJ0ahE6nPqB5D6j/Zw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-bold": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.27.2.tgz", + "integrity": "sha512-bR7J5IwjCGQ0s3CIxyMvOCnMFMzIvsc5OVZKscTN5UkXzFsaY6muUAIqtKxayBUucjtUskm5qZowJITCeCb1/A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-bubble-menu": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.27.2.tgz", + "integrity": "sha512-VkwlCOcr0abTBGzjPXklJ92FCowG7InU8+Od9FyApdLNmn0utRYGRhw0Zno6VgE9EYr1JY4BRnuSa5f9wlR72w==", + "license": "MIT", + "dependencies": { + "tippy.js": "^6.3.7" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-bullet-list": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.27.2.tgz", + "integrity": "sha512-gmFuKi97u5f8uFc/GQs+zmezjiulZmFiDYTh3trVoLRoc2SAHOjGEB7qxdx7dsqmMN7gwiAWAEVurLKIi1lnnw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-character-count": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-character-count/-/extension-character-count-2.27.2.tgz", + "integrity": "sha512-EcQRIvbLbMDDzo7uFqXYgh1CfgedS9sYX4BllktY2OlXLPdNpwo9t8WMK/a7soESNv0Le3WZ5pNvnNhv7Z2YdA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-code": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.27.2.tgz", + "integrity": "sha512-7X9AgwqiIGXoZX7uvdHQsGsjILnN/JaEVtqfXZnPECzKGaWHeK/Ao4sYvIIIffsyZJA8k5DC7ny2/0sAgr2TuA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-code-block": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.27.2.tgz", + "integrity": "sha512-KgvdQHS4jXr79aU3wZOGBIZYYl9vCB7uDEuRFV4so2rYrfmiYMw3T8bTnlNEEGe4RUeAms1i4fdwwvQp9nR1Dw==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-code-block-lowlight": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.27.2.tgz", + "integrity": "sha512-v6NKStBbQ/XCc1NnCi3ObsL1DsxadSIBtUQNA/B+urkPgn5LEy72HAGlf0xwjRaNkAGSaTASLKmc84L5q5zlGQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/extension-code-block": "^2.7.0", + "@tiptap/pm": "^2.7.0", + "highlight.js": "^11", + "lowlight": "^2 || ^3" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-color": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-2.27.2.tgz", + "integrity": "sha512-sOKCP8/2V3sRM3FdWgMe1lFE5ewsWNCRafiVoujS1+TTHGCj4jw6W+LiumBUk7cRI8kXW/rqGWVC4RVdknYUCA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/extension-text-style": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-document": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.27.2.tgz", + "integrity": "sha512-CFhAYsPnyYnosDC4639sCJnBUnYH4Cat9qH5NZWHVvdgtDwu8GZgZn2eSzaKSYXWH1vJ9DSlCK+7UyC3SNXIBA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-dropcursor": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.27.2.tgz", + "integrity": "sha512-oEu/OrktNoQXq1x29NnH/GOIzQZm8ieTQl3FK27nxfBPA89cNoH4mFEUmBL5/OFIENIjiYG3qWpg6voIqzswNw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-floating-menu": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.27.2.tgz", + "integrity": "sha512-GUN6gPIGXS7ngRJOwdSmtBRBDt9Kt9CM/9pSwKebhLJ+honFoNA+Y6IpVyDvvDMdVNgBchiJLs6qA5H97gAePQ==", + "license": "MIT", + "dependencies": { + "tippy.js": "^6.3.7" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-gapcursor": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.27.2.tgz", + "integrity": "sha512-/c9VF1HBxj+AP54XGVgCmD9bEGYc5w5OofYCFQgM7l7PB1J00A4vOke0oPkHJnqnOOyPlFaxO/7N6l3XwFcnKA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-hard-break": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.27.2.tgz", + "integrity": "sha512-kSRVGKlCYK6AGR0h8xRkk0WOFGXHIIndod3GKgWU49APuIGDiXd8sziXsSlniUsWmqgDmDXcNnSzPcV7AQ8YNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-heading": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.27.2.tgz", + "integrity": "sha512-iM3yeRWuuQR/IRQ1djwNooJGfn9Jts9zF43qZIUf+U2NY8IlvdNsk2wTOdBgh6E0CamrStPxYGuln3ZS4fuglw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-highlight": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-2.27.2.tgz", + "integrity": "sha512-ZjlktDdMjruMJFAVz0TbQf0v92Jqkc7Ri1iZJqBXuLid+r+GxUzl2CVAV7qq5yagkGQgvAG+WGsMk880HgR3MA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-history": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.27.2.tgz", + "integrity": "sha512-+hSyqERoFNTWPiZx4/FCyZ/0eFqB9fuMdTB4AC/q9iwu3RNWAQtlsJg5230bf/qmyO6bZxRUc0k8p4hrV6ybAw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-horizontal-rule": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.27.2.tgz", + "integrity": "sha512-WGWUSgX+jCsbtf9Y9OCUUgRZYuwjVoieW5n6mAUohJ9/6gc6sGIOrUpBShf+HHo6WD+gtQjRd+PssmX3NPWMpg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-image": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.27.2.tgz", + "integrity": "sha512-5zL/BY41FIt72azVrCrv3n+2YJ/JyO8wxCcA4Dk1eXIobcgVyIdo4rG39gCqIOiqziAsqnqoj12QHTBtHsJ6mQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-italic": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.27.2.tgz", + "integrity": "sha512-1OFsw2SZqfaqx5Fa5v90iNlPRcqyt+lVSjBwTDzuPxTPFY4Q0mL89mKgkq2gVHYNCiaRkXvFLDxaSvBWbmthgg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-link": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-2.27.2.tgz", + "integrity": "sha512-bnP61qkr0Kj9Cgnop1hxn2zbOCBzNtmawxr92bVTOE31fJv6FhtCnQiD6tuPQVGMYhcmAj7eihtvuEMFfqEPcQ==", + "license": "MIT", + "dependencies": { + "linkifyjs": "^4.3.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-list-item": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.27.2.tgz", + "integrity": "sha512-eJNee7IEGXMnmygM5SdMGDC8m/lMWmwNGf9fPCK6xk0NxuQRgmZHL6uApKcdH6gyNcRPHCqvTTkhEP7pbny/fg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-ordered-list": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.27.2.tgz", + "integrity": "sha512-M7A4tLGJcLPYdLC4CI2Gwl8LOrENQW59u3cMVa+KkwG1hzSJyPsbDpa1DI6oXPC2WtYiTf22zrbq3gVvH+KA2w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-paragraph": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.27.2.tgz", + "integrity": "sha512-elYVn2wHJJ+zB9LESENWOAfI4TNT0jqEN34sMA/hCtA4im1ZG2DdLHwkHIshj/c4H0dzQhmsS/YmNC5Vbqab/A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-placeholder": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.27.2.tgz", + "integrity": "sha512-IjsgSVYJRjpAKmIoapU0E2R4E2FPY3kpvU7/1i7PUYisylqejSJxmtJPGYw0FOMQY9oxnEEvfZHMBA610tqKpg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-strike": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.27.2.tgz", + "integrity": "sha512-HHIjhafLhS2lHgfAsCwC1okqMsQzR4/mkGDm4M583Yftyjri1TNA7lzhzXWRFWiiMfJxKtdjHjUAQaHuteRTZw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-task-item": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-task-item/-/extension-task-item-2.27.2.tgz", + "integrity": "sha512-ZBSqj/dygB/Rp5K9qOxRVwASTZCmKVoTq8C59KvMgD/aFjJxhq/w2dZaWkCUEXEep+NmvJqo0kfeAEMY5UDnGg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-task-list": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-task-list/-/extension-task-list-2.27.2.tgz", + "integrity": "sha512-5nupAewdzZ9F3599oAcaK0WkDH04wdACAVBPM4zG7InlIpkbho3txB7zWmm64OxfhCMIMGKiXY1q0bw9i0QBGQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-text": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.27.2.tgz", + "integrity": "sha512-Xk7nYcigljAY0GO9hAQpZ65ZCxqOqaAlTPDFcKerXmlkQZP/8ndx95OgUb1Xf63kmPOh3xypurGS2is3v0MXSA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-text-style": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.27.2.tgz", + "integrity": "sha512-Omk+uxjJLyEY69KStpCw5fA9asvV+MGcAX2HOxyISDFoLaL49TMrNjhGAuz09P1L1b0KGXo4ml7Q3v/Lfy4WPA==", + "license": "MIT", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-underline": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.27.2.tgz", + "integrity": "sha512-gPOsbAcw1S07ezpAISwoO8f0RxpjcSH7VsHEFDVuXm4ODE32nhvSinvHQjv2icRLOXev+bnA7oIBu7Oy859gWQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/extension-youtube": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/extension-youtube/-/extension-youtube-2.27.2.tgz", + "integrity": "sha512-3l/tfJ8wO8/tALo1tpAfN7TTJQQ00V52XaYamjQPVzPGelm/ECCfSCGQ4oRv8gbyzjUbZkNpkSV1Bj2V7QcGDg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@tiptap/pm": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.27.2.tgz", + "integrity": "sha512-kaEg7BfiJPDQMKbjVIzEPO3wlcA+pZb2tlcK9gPrdDnEFaec2QTF1sXz2ak2IIb2curvnIrQ4yrfHgLlVA72wA==", + "license": "MIT", + "peer": true, + "dependencies": { + "prosemirror-changeset": "^2.3.0", + "prosemirror-collab": "^1.3.1", + "prosemirror-commands": "^1.6.2", + "prosemirror-dropcursor": "^1.8.1", + "prosemirror-gapcursor": "^1.3.2", + "prosemirror-history": "^1.4.1", + "prosemirror-inputrules": "^1.4.0", + "prosemirror-keymap": "^1.2.2", + "prosemirror-markdown": "^1.13.1", + "prosemirror-menu": "^1.2.4", + "prosemirror-model": "^1.23.0", + "prosemirror-schema-basic": "^1.2.3", + "prosemirror-schema-list": "^1.4.1", + "prosemirror-state": "^1.4.3", + "prosemirror-tables": "^1.6.4", + "prosemirror-trailing-node": "^3.0.0", + "prosemirror-transform": "^1.10.2", + "prosemirror-view": "^1.37.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/novel/node_modules/@tiptap/react": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.27.2.tgz", + "integrity": "sha512-0EAs8Cpkfbvben1PZ34JN2Nd79Dhioynm2jML27DBbf1VWPk+FFWFGTMLUT0bu+Np5iVxio8fqV9t0mc4D6thA==", + "license": "MIT", + "dependencies": { + "@tiptap/extension-bubble-menu": "^2.27.2", + "@tiptap/extension-floating-menu": "^2.27.2", + "@types/use-sync-external-store": "^0.0.6", + "fast-deep-equal": "^3", + "use-sync-external-store": "^1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/novel/node_modules/@tiptap/starter-kit": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.27.2.tgz", + "integrity": "sha512-bb0gJvPoDuyRUQ/iuN52j1//EtWWttw+RXAv1uJxfR0uKf8X7uAqzaOOgwjknoCIDC97+1YHwpGdnRjpDkOBxw==", + "license": "MIT", + "dependencies": { + "@tiptap/core": "^2.27.2", + "@tiptap/extension-blockquote": "^2.27.2", + "@tiptap/extension-bold": "^2.27.2", + "@tiptap/extension-bullet-list": "^2.27.2", + "@tiptap/extension-code": "^2.27.2", + "@tiptap/extension-code-block": "^2.27.2", + "@tiptap/extension-document": "^2.27.2", + "@tiptap/extension-dropcursor": "^2.27.2", + "@tiptap/extension-gapcursor": "^2.27.2", + "@tiptap/extension-hard-break": "^2.27.2", + "@tiptap/extension-heading": "^2.27.2", + "@tiptap/extension-history": "^2.27.2", + "@tiptap/extension-horizontal-rule": "^2.27.2", + "@tiptap/extension-italic": "^2.27.2", + "@tiptap/extension-list-item": "^2.27.2", + "@tiptap/extension-ordered-list": "^2.27.2", + "@tiptap/extension-paragraph": "^2.27.2", + "@tiptap/extension-strike": "^2.27.2", + "@tiptap/extension-text": "^2.27.2", + "@tiptap/extension-text-style": "^2.27.2", + "@tiptap/pm": "^2.27.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/novel/node_modules/@tiptap/suggestion": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.27.2.tgz", + "integrity": "sha512-dQyvCIg0hcAVeh4fCIVCxogvbp+bF+GpbUb8sNlgnGrmHXnapGxzkvrlHnvneXZxLk/j7CxmBPKJNnm4Pbx4zw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/novel/node_modules/@types/node": { + "version": "22.19.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz", + "integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/novel/node_modules/react-markdown": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.1.0.tgz", + "integrity": "sha512-xaijuJB0kzGiUdG7nc2MOMDUDBWPyGAjZtUrow9XxUeua8IqeP+VlIfAZ3bphpcLTnSZXz6z9jcVC/TCwbfgdw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/novel/node_modules/react-tweet": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/react-tweet/-/react-tweet-3.3.0.tgz", + "integrity": "sha512-gSIG2169ZK7UH6rBzuU+j1xnQbH3IlOTLEkuGrRiJJTMgETik+h+26yHyyVKrLkzwrOaYPk4K3OtEKycqKgNLw==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.3", + "clsx": "^2.0.0", + "swr": "^2.2.4" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/novel/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -10561,6 +12083,21 @@ "integrity": "sha512-vCseG/EQ6/RcvxhUcGJiHViOgrtz4x0XbZepXvKik66TMGkvbmjeJrKFyBEx6daG5rNyyd14zYXhz0hZVwQFOw==", "license": "MIT" }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", + "license": "MIT" + }, + "node_modules/overlap-area": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/overlap-area/-/overlap-area-1.1.0.tgz", + "integrity": "sha512-3dlJgJCaVeXH0/eZjYVJvQiLVVrPO4U1ZGqlATtx6QGO3b5eNM6+JgUKa7oStBTdYuGTk7gVoABCW6Tp+dhRdw==", + "license": "MIT", + "dependencies": { + "@daybrush/utils": "^1.7.1" + } + }, "node_modules/package-manager-detector": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", @@ -10916,6 +12453,216 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/prosemirror-changeset": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz", + "integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==", + "license": "MIT", + "dependencies": { + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-collab": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz", + "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", + "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz", + "integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-gapcursor": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz", + "integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz", + "integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-inputrules": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz", + "integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-markdown": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.4.tgz", + "integrity": "sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==", + "license": "MIT", + "dependencies": { + "@types/markdown-it": "^14.0.0", + "markdown-it": "^14.0.0", + "prosemirror-model": "^1.25.0" + } + }, + "node_modules/prosemirror-menu": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.3.2.tgz", + "integrity": "sha512-6VgUJTYod0nMBlCaYJGhXGLu7Gt4AvcwcOq0YfJCY/6Uh+3S7UsWhpy6rJFCBFOmonq1hD8KyWOtZhkppd4YPg==", + "license": "MIT", + "dependencies": { + "crelt": "^1.0.0", + "prosemirror-commands": "^1.0.0", + "prosemirror-history": "^1.0.0", + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-model": { + "version": "1.25.4", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz", + "integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==", + "license": "MIT", + "peer": true, + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-schema-basic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz", + "integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.25.0" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", + "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", + "license": "MIT", + "peer": true, + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-tables": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz", + "integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.4", + "prosemirror-state": "^1.4.4", + "prosemirror-transform": "^1.10.5", + "prosemirror-view": "^1.41.4" + } + }, + "node_modules/prosemirror-trailing-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz", + "integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==", + "license": "MIT", + "dependencies": { + "@remirror/core-constants": "3.0.0", + "escape-string-regexp": "^4.0.0" + }, + "peerDependencies": { + "prosemirror-model": "^1.22.1", + "prosemirror-state": "^1.4.2", + "prosemirror-view": "^1.33.8" + } + }, + "node_modules/prosemirror-trailing-node/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz", + "integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-view": { + "version": "1.41.8", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.8.tgz", + "integrity": "sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==", + "license": "MIT", + "peer": true, + "dependencies": { + "prosemirror-model": "^1.20.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -10925,6 +12672,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/pwacompat": { "version": "2.0.17", "resolved": "https://registry.npmjs.org/pwacompat/-/pwacompat-2.0.17.tgz", @@ -11106,6 +12862,16 @@ "node": ">=0.10.0" } }, + "node_modules/react-css-styled": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/react-css-styled/-/react-css-styled-1.1.9.tgz", + "integrity": "sha512-M7fJZ3IWFaIHcZEkoFOnkjdiUFmwd8d+gTh2bpqMOcnxy/0Gsykw4dsL4QBiKsxcGow6tETUa4NAUcmJF+/nfw==", + "license": "MIT", + "dependencies": { + "css-styled": "~1.0.8", + "framework-utils": "^1.1.0" + } + }, "node_modules/react-dom": { "version": "19.2.3", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", @@ -11146,6 +12912,27 @@ "react": ">=18" } }, + "node_modules/react-moveable": { + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/react-moveable/-/react-moveable-0.56.0.tgz", + "integrity": "sha512-FmJNmIOsOA36mdxbrc/huiE4wuXSRlmon/o+/OrfNhSiYYYL0AV5oObtPluEhb2Yr/7EfYWBHTxF5aWAvjg1SA==", + "license": "MIT", + "dependencies": { + "@daybrush/utils": "^1.13.0", + "@egjs/agent": "^2.2.1", + "@egjs/children-differ": "^1.0.1", + "@egjs/list-differ": "^1.0.0", + "@scena/dragscroll": "^1.4.0", + "@scena/event-emitter": "^1.0.5", + "@scena/matrix": "^1.1.1", + "css-to-mat": "^1.1.1", + "framework-utils": "^1.1.0", + "gesto": "^1.19.3", + "overlap-area": "^1.1.0", + "react-css-styled": "^1.1.9", + "react-selecto": "^1.25.0" + } + }, "node_modules/react-remove-scroll": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", @@ -11193,6 +12980,15 @@ } } }, + "node_modules/react-selecto": { + "version": "1.26.3", + "resolved": "https://registry.npmjs.org/react-selecto/-/react-selecto-1.26.3.tgz", + "integrity": "sha512-Ubik7kWSnZyQEBNro+1k38hZaI1tJarE+5aD/qsqCOA1uUBSjgKVBy3EWRzGIbdmVex7DcxznFZLec/6KZNvwQ==", + "license": "MIT", + "dependencies": { + "selecto": "~1.26.3" + } + }, "node_modules/react-style-singleton": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", @@ -11408,6 +13204,12 @@ "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.16" } }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", + "license": "MIT" + }, "node_modules/roughjs": { "version": "4.6.4", "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.4.tgz", @@ -11501,6 +13303,24 @@ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, + "node_modules/selecto": { + "version": "1.26.3", + "resolved": "https://registry.npmjs.org/selecto/-/selecto-1.26.3.tgz", + "integrity": "sha512-gZHgqMy5uyB6/2YDjv3Qqaf7bd2hTDOpPdxXlrez4R3/L0GiEWDCFaUfrflomgqdb3SxHF2IXY0Jw0EamZi7cw==", + "license": "MIT", + "dependencies": { + "@daybrush/utils": "^1.13.0", + "@egjs/children-differ": "^1.0.1", + "@scena/dragscroll": "^1.4.0", + "@scena/event-emitter": "^1.0.5", + "css-styled": "^1.0.8", + "css-to-mat": "^1.1.1", + "framework-utils": "^1.1.0", + "gesto": "^1.19.4", + "keycon": "^1.2.0", + "overlap-area": "^1.1.0" + } + }, "node_modules/semver": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", @@ -11895,6 +13715,21 @@ "node": ">=14.0.0" } }, + "node_modules/tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", + "license": "MIT", + "dependencies": { + "@popperjs/core": "^2.9.0" + } + }, + "node_modules/tiptap-extension-global-drag-handle": { + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/tiptap-extension-global-drag-handle/-/tiptap-extension-global-drag-handle-0.1.18.tgz", + "integrity": "sha512-jwFuy1K8DP3a4bFy76Hpc63w1Sil0B7uZ3mvhQomVvUFCU787Lg2FowNhn7NFzeyok761qY2VG+PZ/FDthWUdg==", + "license": "MIT" + }, "node_modules/tldts": { "version": "7.0.28", "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.28.tgz", @@ -12052,6 +13887,12 @@ "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/ufo": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", @@ -12652,6 +14493,12 @@ "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", "license": "MIT" }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", diff --git a/memento-note/package.json b/memento-note/package.json index 4297aaa..023025f 100644 --- a/memento-note/package.json +++ b/memento-note/package.json @@ -33,6 +33,7 @@ "@dnd-kit/utilities": "^3.2.2", "@excalidraw/excalidraw": "^0.18.0", "@mozilla/readability": "^0.6.0", + "@prisma/client": "^5.22.0", "@radix-ui/react-avatar": "^1.1.11", "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-dialog": "^1.1.15", @@ -44,6 +45,21 @@ "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-switch": "^1.2.6", "@radix-ui/react-tooltip": "^1.2.8", + "@tiptap/extension-color": "^3.22.5", + "@tiptap/extension-highlight": "^3.22.5", + "@tiptap/extension-image": "^3.22.5", + "@tiptap/extension-placeholder": "^3.22.5", + "@tiptap/extension-subscript": "^3.22.5", + "@tiptap/extension-superscript": "^3.22.5", + "@tiptap/extension-task-item": "^3.22.5", + "@tiptap/extension-task-list": "^3.22.5", + "@tiptap/extension-text-align": "^3.22.5", + "@tiptap/extension-text-style": "^3.22.5", + "@tiptap/extension-typography": "^3.22.5", + "@tiptap/pm": "^3.22.5", + "@tiptap/react": "^3.22.5", + "@tiptap/starter-kit": "^3.22.5", + "@tiptap/suggestion": "^3.22.5", "@types/jsdom": "^28.0.1", "ai": "^6.0.23", "autoprefixer": "^10.4.23", @@ -61,6 +77,7 @@ "next": "^16.1.6", "next-auth": "^5.0.0-beta.30", "nodemailer": "^8.0.4", + "novel": "^1.0.2", "postcss": "^8.5.6", "radix-ui": "^1.4.3", "react": "19.2.3", @@ -71,13 +88,13 @@ "remark-math": "^6.0.0", "resend": "^6.12.0", "rss-parser": "^3.13.0", - "sonner": "^2.0.7", "sharp": "^0.34.0", + "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "tinyld": "^1.3.4", + "tippy.js": "^6.3.7", "vazirmatn": "^33.0.3", - "zod": "^4.3.5", - "@prisma/client": "^5.22.0" + "zod": "^4.3.5" }, "devDependencies": { "@playwright/test": "^1.57.0", diff --git a/memento-note/prisma/schema.prisma b/memento-note/prisma/schema.prisma index c535b8d..1dce3be 100644 --- a/memento-note/prisma/schema.prisma +++ b/memento-note/prisma/schema.prisma @@ -119,7 +119,7 @@ model Note { color String @default("default") isPinned Boolean @default(false) isArchived Boolean @default(false) - type String @default("text") + type String @default("richtext") dismissedFromRecent Boolean @default(false) checkItems String? labels String? @@ -129,7 +129,7 @@ model Note { isReminderDone Boolean @default(false) reminderRecurrence String? reminderLocation String? - isMarkdown Boolean @default(false) + isMarkdown Boolean @default(false) // DEPRECATED: use type = 'markdown' instead size String @default("small") sharedWith String? userId String?