diff --git a/memento-note/app/globals.css b/memento-note/app/globals.css index b888d86..2a2aa52 100644 --- a/memento-note/app/globals.css +++ b/memento-note/app/globals.css @@ -1222,23 +1222,42 @@ html.font-system * { } /* ============================================ - Slash Command Menu + Slash Command Menu — Premium Design ============================================ */ .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; + border-radius: 12px; + box-shadow: 0 8px 32px rgba(0,0,0,0.12), 0 2px 8px rgba(0,0,0,0.06); + padding: 6px; + min-width: 320px; + max-height: 420px; overflow-y: auto; scrollbar-width: thin; + scrollbar-color: var(--border) transparent; + animation: slash-enter 0.12s ease; +} +@keyframes slash-enter { + from { opacity: 0; transform: translateY(-4px) scale(0.98); } + to { opacity: 1; transform: translateY(0) scale(1); } } .dark .notion-slash-menu { - box-shadow: 0 4px 24px rgba(0,0,0,0.5); + box-shadow: 0 8px 32px rgba(0,0,0,0.5), 0 2px 8px rgba(0,0,0,0.3); +} + +/* Header hint */ +.notion-slash-header { + display: flex; + align-items: center; + gap: 5px; + padding: 5px 10px 6px; + font-size: 10px; + color: var(--muted-foreground); + border-bottom: 1px solid var(--border); + margin-bottom: 4px; + opacity: 0.7; } .notion-slash-section + .notion-slash-section { @@ -1248,62 +1267,79 @@ html.font-system * { } .notion-slash-label { - padding: 6px 8px 2px; - font-size: 11px; - font-weight: 600; + padding: 6px 10px 3px; + font-size: 10.5px; + font-weight: 700; + letter-spacing: 0.06em; + text-transform: uppercase; color: var(--muted-foreground); user-select: none; } +.notion-slash-label-ai { + color: oklch(0.55 0.15 270); +} +.dark .notion-slash-label-ai { + color: oklch(0.72 0.15 270); +} .notion-slash-item { display: flex; align-items: center; - gap: 8px; + gap: 10px; width: 100%; - padding: 4px 8px; + padding: 6px 8px; border: none; background: transparent; - border-radius: 4px; + border-radius: 7px; cursor: pointer; text-align: left; color: var(--foreground); - transition: background 0.1s ease; + transition: background 0.1s ease, transform 0.08s ease; } .notion-slash-item:hover, .notion-slash-item-selected { background: var(--accent); } +.notion-slash-item-selected { + transform: none; +} .notion-slash-icon { display: flex; align-items: center; justify-content: center; - width: 20px; - height: 20px; + width: 30px; + height: 30px; border: 1px solid var(--border); - border-radius: 4px; + border-radius: 7px; background: var(--background); - color: var(--muted-foreground); + color: var(--foreground); flex-shrink: 0; + transition: background 0.1s ease; } -.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-item-selected .notion-slash-icon, +.notion-slash-item:hover .notion-slash-icon { + background: var(--popover); } -.notion-slash-loading { +.notion-slash-icon-ai { + background: oklch(0.95 0.04 270); + border-color: oklch(0.82 0.08 270); + color: oklch(0.52 0.18 270); +} +.dark .notion-slash-icon-ai { + background: oklch(0.22 0.05 270); + border-color: oklch(0.38 0.09 270); + color: oklch(0.75 0.16 270); +} + +/* Stacked title + description */ +.notion-slash-content { display: flex; - align-items: center; - gap: 6px; - padding: 8px 10px; - font-size: 13px; - color: var(--muted-foreground); + flex-direction: column; + flex: 1; + min-width: 0; + gap: 1px; } .notion-slash-title { @@ -1312,7 +1348,7 @@ html.font-system * { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - flex: 0 1 auto; + line-height: 1.3; } .notion-slash-desc { font-size: 11px; @@ -1320,8 +1356,29 @@ html.font-system * { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - flex: 1 1 auto; - text-align: right; + line-height: 1.3; +} + +/* Shortcut badge */ +.notion-slash-shortcut { + font-size: 10px; + font-family: ui-monospace, monospace; + background: var(--muted); + color: var(--muted-foreground); + border: 1px solid var(--border); + border-radius: 4px; + padding: 1px 5px; + flex-shrink: 0; + white-space: nowrap; +} + +.notion-slash-loading { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 12px; + font-size: 13px; + color: var(--muted-foreground); } /* ============================================ diff --git a/memento-note/components/rich-text-editor.tsx b/memento-note/components/rich-text-editor.tsx index 2c9b798..2ce7ad6 100644 --- a/memento-note/components/rich-text-editor.tsx +++ b/memento-note/components/rich-text-editor.tsx @@ -23,6 +23,7 @@ import { Quote, CodeXml, Minus, ImageIcon, Type, Highlighter, Link as LinkIcon, Sparkles, Wand2, Scissors, Lightbulb, X, Check, ExternalLink, FileText, Pilcrow, MessageSquare, AlignLeft, AlignCenter, AlignRight, + Superscript as SuperscriptIcon, Subscript as SubscriptIcon, Expand, } from 'lucide-react' import { cn } from '@/lib/utils' @@ -42,6 +43,7 @@ type SlashItem = { description: string icon: typeof Bold category?: string + shortcut?: string isImage?: boolean isAi?: boolean aiOption?: 'clarify' | 'shorten' | 'improve' @@ -49,20 +51,26 @@ type SlashItem = { } 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: () => {} }, + { title: 'Text', description: 'Plain paragraph', icon: Pilcrow, category: 'Basic blocks', shortcut: '¶', command: (e) => e.chain().focus().setParagraph().run() }, + { title: 'Heading 1', description: 'Big section heading', icon: Heading1, category: 'Basic blocks', shortcut: '#', command: (e) => e.chain().focus().toggleHeading({ level: 1 }).run() }, + { title: 'Heading 2', description: 'Medium section heading', icon: Heading2, category: 'Basic blocks', shortcut: '##', command: (e) => e.chain().focus().toggleHeading({ level: 2 }).run() }, + { title: 'Heading 3', description: 'Small section heading', icon: Heading3, category: 'Basic blocks', shortcut: '###', command: (e) => e.chain().focus().toggleHeading({ level: 3 }).run() }, + { title: 'Bullet List', description: 'Unordered list', icon: List, category: 'Basic blocks', shortcut: '-', command: (e) => e.chain().focus().toggleBulletList().run() }, + { title: 'Numbered List', description: 'Ordered numbered list', icon: ListOrdered, category: 'Basic blocks', shortcut: '1.', command: (e) => e.chain().focus().toggleOrderedList().run() }, + { title: 'To-do List', description: 'Checkboxes for tasks', icon: CheckSquare, category: 'Basic blocks', shortcut: '[]', command: (e) => e.chain().focus().toggleTaskList().run() }, + { title: 'Quote', description: 'Capture a quote', icon: Quote, category: 'Basic blocks', shortcut: '>', command: (e) => e.chain().focus().toggleBlockquote().run() }, + { title: 'Code Block', description: 'Code snippet', icon: CodeXml, category: 'Basic blocks', shortcut: '```', command: (e) => e.chain().focus().toggleCodeBlock().run() }, + { title: 'Divider', description: 'Horizontal separator', icon: Minus, category: 'Basic blocks', shortcut: '---', command: (e) => e.chain().focus().setHorizontalRule().run() }, + { title: 'Image', description: 'Embed image from URL', icon: ImageIcon, category: 'Media', isImage: true, command: () => {} }, + { title: 'Align Left', description: 'Align text left', icon: AlignLeft, category: 'Formatting', command: (e) => e.chain().focus().setTextAlign('left').run() }, + { title: 'Align Center', description: 'Center text', icon: AlignCenter, category: 'Formatting', command: (e) => e.chain().focus().setTextAlign('center').run() }, + { title: 'Align Right', description: 'Align text right', icon: AlignRight, category: 'Formatting', command: (e) => e.chain().focus().setTextAlign('right').run() }, + { title: 'Superscript', description: 'Raise text above baseline', icon: SuperscriptIcon, category: 'Formatting', command: (e) => e.chain().focus().toggleSuperscript().run() }, + { title: 'Subscript', description: 'Lower text below baseline', icon: SubscriptIcon, category: 'Formatting', command: (e) => e.chain().focus().toggleSubscript().run() }, + { title: 'Clarifier', description: 'Rendre le texte plus clair', icon: Lightbulb, category: 'IA Note', isAi: true, aiOption: 'clarify', command: () => {} }, + { title: 'Raccourcir', description: 'Condenser le texte', icon: Scissors, category: 'IA Note', isAi: true, aiOption: 'shorten', command: () => {} }, + { title: 'Améliorer', description: 'Améliorer le style', icon: Wand2, category: 'IA Note', isAi: true, aiOption: 'improve', command: () => {} }, + { title: 'Développer', description: 'Élaborer et enrichir le texte', icon: Expand, category: 'IA Note', isAi: true, aiOption: 'clarify', command: () => {} }, ] async function aiReformulate(text: string, option: 'clarify' | 'shorten' | 'improve'): Promise { @@ -417,30 +425,44 @@ function SlashCommandMenu({ editor, onInsertImage }: { editor: Editor; onInsertI return (
e.stopPropagation()}> + {/* Header hint */} +
+ + Blocs — utilisez ↑↓ pour naviguer, Entrée pour insérer +
{aiLoading && (
- AI is thinking... + IA Note réfléchit...
)} {!aiLoading && Object.entries(categories).map(([cat, items]) => (
-
{cat}
+
+ {cat === 'IA Note' && } + {cat} +
{items.map((item) => { flatIndex++ const idx = flatIndex + const isSelected = idx === selectedIndex return ( ) })}