/* Tiptap Editor - Typora-inspired, theme-aware */ .tiptap-editor { position: relative; width: 100%; height: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; font-size: 16px; line-height: 1.75; /* Catppuccin Latte text */ color: #4c4f69; outline: none; } .tiptap-editor .ProseMirror { width: 100%; height: 100%; padding: 24px 32px; outline: none; overflow-y: auto; } .tiptap-editor .ProseMirror-focused { outline: none; } /* Placeholder - shown when document has only one empty paragraph */ .tiptap-editor .ProseMirror p:first-child:last-child:has(br.ProseMirror-trailingBreak:only-child)::before { content: '在此输入内容...'; float: left; /* Latte overlay0 */ color: #9ca0b0; pointer-events: none; height: 0; } /* Typography */ .tiptap-editor h1 { font-size: 2em; font-weight: 700; margin: 1.2em 0 0.6em; line-height: 1.3; /* Latte text */ color: #4c4f69; } .tiptap-editor h2 { font-size: 1.5em; font-weight: 600; margin: 1em 0 0.5em; line-height: 1.35; color: #4c4f69; } .tiptap-editor h3 { font-size: 1.25em; font-weight: 600; margin: 0.8em 0 0.4em; color: #4c4f69; } .tiptap-editor p { margin: 0.6em 0; } .tiptap-editor p:first-child { margin-top: 0; } .tiptap-editor strong { font-weight: 700; color: #4c4f69; } .tiptap-editor em { font-style: italic; } .tiptap-editor s { text-decoration: line-through; opacity: 0.7; } .tiptap-editor code { font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace; font-size: 0.875em; /* Latte surface0 / red */ background: #ccd0da; padding: 0.15em 0.4em; border-radius: 3px; color: #d20f39; } .tiptap-editor pre { /* Latte crust */ background: #dce0e8; border-radius: 6px; padding: 16px; overflow-x: auto; margin: 1em 0; } .tiptap-editor pre code { background: none; padding: 0; color: #4c4f69; font-size: 0.85em; line-height: 1.6; } .tiptap-editor blockquote { /* Latte surface1 / subtext0 */ border-left: 4px solid #bcc0cc; padding-left: 16px; margin: 1em 0; color: #6c6f85; font-style: italic; } .tiptap-editor ul { list-style-type: disc; margin: 0.6em 0; padding-left: 2em; } .tiptap-editor ol { list-style-type: decimal; margin: 0.6em 0; padding-left: 2em; } .tiptap-editor li { margin: 0.2em 0; } .tiptap-editor li > p { margin: 0.2em 0; } .tiptap-editor hr { /* Latte surface1 */ border: none; border-top: 1px solid #bcc0cc; margin: 1.5em 0; } /* Selection */ .tiptap-editor .ProseMirror ::selection { /* Latte surface0 */ background: #ccd0da; } /* Cursor */ .tiptap-editor .ProseMirror-focused .ProseMirror-gapcursor { display: none; } /* ========== Dark Theme (Catppuccin Mocha) ========== */ .dark .tiptap-editor { /* Mocha text */ color: #cdd6f4; } .dark .tiptap-editor h1, .dark .tiptap-editor h2, .dark .tiptap-editor h3, .dark .tiptap-editor strong { color: #cdd6f4; } .dark .tiptap-editor .ProseMirror p.is-editor-empty:first-child::before { /* Mocha overlay0 */ color: #6c7086; } .dark .tiptap-editor code { /* Mocha surface0 / red */ background: #313244; color: #f38ba8; } .dark .tiptap-editor pre { background: #313244; } .dark .tiptap-editor pre code { color: #cdd6f4; } .dark .tiptap-editor blockquote { /* Mocha surface1 / subtext0 */ border-left-color: #45475a; color: #a6adc8; } .dark .tiptap-editor hr { border-top-color: #45475a; } .dark .tiptap-editor a { /* Mocha blue */ color: #89b4fa; } .dark .tiptap-editor .ProseMirror ::selection { background: rgba(30, 102, 245, 0.3); } /* ========== Link ========== */ .tiptap-editor a { /* Latte blue */ color: #1e66f5; text-decoration: none; } .tiptap-editor a:hover { text-decoration: underline; } /* ========== Table ========== */ .tiptap-editor table { border-collapse: collapse; table-layout: fixed; width: 100%; margin: 1em 0; overflow: hidden; /* Latte surface1 */ border: 1px solid #bcc0cc; border-radius: 6px; } .tiptap-editor table td, .tiptap-editor table th { min-width: 80px; border: 1px solid #bcc0cc; padding: 8px 12px; position: relative; vertical-align: top; box-sizing: border-box; } .tiptap-editor table th { /* Latte crust */ background: #dce0e8; font-weight: 600; text-align: left; } .tiptap-editor table .selectedCell { /* Latte surface0 */ background: #ccd0da; } .tiptap-editor table .column-resize-handle { position: absolute; right: -2px; top: 0; bottom: -2px; width: 4px; /* Latte blue */ background-color: #1e66f5; pointer-events: none; } .tiptap-editor .tableWrapper { padding: 1rem 0; overflow-x: auto; } .tiptap-editor .resize-cursor { cursor: ew-resize; cursor: col-resize; } /* ========== Slash Command ========== */ .slash-command { position: fixed; z-index: 9999; /* Latte mantle */ background: #e6e9ef; border: 1px solid #bcc0cc; border-radius: 8px; box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12); padding: 4px; min-width: 260px; max-height: 320px; overflow-y: auto; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; } .slash-command-list { display: flex; flex-direction: column; } .slash-command-item { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-radius: 6px; cursor: pointer; transition: background 0.15s; } .slash-command-item:hover, .slash-command-item.is-selected { /* Latte surface0 */ background: #ccd0da; } .slash-command-item-icon { flex-shrink: 0; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; background: #ccd0da; border-radius: 6px; font-size: 13px; font-weight: 600; /* Latte subtext1 */ color: #5c5f77; } .slash-command-item-text { flex: 1; min-width: 0; } .slash-command-item-title { font-size: 14px; font-weight: 500; color: #4c4f69; line-height: 1.3; } .slash-command-item-desc { font-size: 12px; /* Latte overlay0 */ color: #9ca0b0; line-height: 1.3; } /* ========== Task List (Enhanced) ========== */ .tiptap-editor ul[data-type='taskList'] { list-style: none; padding-left: 0; } .tiptap-editor ul[data-type='taskList'] li { display: flex; align-items: center; gap: 0.5em; margin: 0.3em 0; } .tiptap-editor ul[data-type='taskList'] li > label { flex-shrink: 0; cursor: pointer; user-select: none; /* label 默认 inline,内部 checkbox 是 inline-block 会受 line-height 撑出 基线间距导致 checkbox 在 label 内偏上。用 flex 居中并清零行高, 让 checkbox 严格在 label 盒子中心。 */ display: flex; align-items: center; line-height: 0; } .tiptap-editor ul[data-type='taskList'] li > label input[type='checkbox'] { width: 16px; height: 16px; /* 主强调色 Latte green */ accent-color: #40a02b; cursor: pointer; } .tiptap-editor ul[data-type='taskList'] li > div { flex: 1; } /* task list 项内的段落去掉上下 margin(.tiptap-editor p 默认 .6em 0), 否则 margin 会撑高 div,使 checkbox 与文本垂直中线错位、项间距过大。 */ .tiptap-editor ul[data-type='taskList'] li > div > p { margin: 0; } .tiptap-editor ul[data-type='taskList'] li[data-checked='true'] > div { text-decoration: line-through; opacity: 0.6; } /* ========== Image ========== */ .tiptap-editor img { max-width: 100%; height: auto; border-radius: 6px; margin: 1em 0; display: block; } .tiptap-editor img.ProseMirror-selectednode { /* 主强调色 Latte green */ outline: 2px solid #40a02b; border-radius: 6px; } /* ========== Upload Image Placeholder NodeView ========== */ .upload-image-container { position: relative; display: inline-block; max-width: 100%; } .upload-image-container img { max-width: 100%; height: auto; border-radius: 6px; margin: 1em 0; display: block; /* blur/grayscale 出现与消失的过渡(上传中→成功/失败的 filter 切换) */ transition: filter 0.2s ease; } .upload-image-container.is-error img { opacity: 0.5; filter: grayscale(0.5); } /* 上传中:图片高斯模糊,遮罩文字(spinner/"上传中…")在独立 overlay 层不受影响 */ .upload-image-container.is-uploading { overflow: hidden; } .upload-image-container.is-uploading img { filter: blur(8px); } .upload-image-overlay { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; border-radius: 6px; pointer-events: none; } .upload-image-container.is-error .upload-image-overlay { background: rgba(0, 0, 0, 0.35); pointer-events: auto; } .upload-spinner { width: 28px; height: 28px; border: 3px solid rgba(255, 255, 255, 0.4); border-top-color: #fff; border-radius: 50%; animation: upload-spin 0.8s linear infinite; } @keyframes upload-spin { to { transform: rotate(360deg); } } .upload-overlay-text { color: #fff; font-size: 13px; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); } .upload-error-icon { color: #fff; font-size: 22px; line-height: 1; } .upload-error-msg { color: #fff; font-size: 13px; text-align: center; padding: 0 12px; max-width: 90%; word-break: break-word; } .upload-error-actions { display: flex; gap: 8px; } .upload-btn { padding: 3px 12px; font-size: 12px; border-radius: 4px; border: 1px solid rgba(255, 255, 255, 0.6); background: rgba(255, 255, 255, 0.15); color: #fff; cursor: pointer; } .upload-btn:hover { background: rgba(255, 255, 255, 0.3); } .upload-btn-remove { border-color: rgba(254, 202, 202, 0.7); color: #fecaca; } .upload-btn-remove:hover { background: rgba(239, 68, 68, 0.3); } /* ========== Dark Theme: Table (Mocha) ========== */ .dark .tiptap-editor table { /* Mocha surface1 */ border-color: #45475a; } .dark .tiptap-editor table td, .dark .tiptap-editor table th { border-color: #45475a; color: #cdd6f4; } .dark .tiptap-editor table th { /* Mocha surface0 */ background: #313244; } .dark .tiptap-editor table .selectedCell { background: rgba(30, 102, 245, 0.25); } /* ========== Dark Theme: Slash Command (Mocha) ========== */ .dark .slash-command { /* Mocha mantle */ background: #181825; border-color: #45475a; box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4); } .dark .slash-command-item:hover, .dark .slash-command-item.is-selected { background: #313244; } .dark .slash-command-item-icon { background: #313244; color: #cdd6f4; } .dark .slash-command-item-title { color: #cdd6f4; } .dark .slash-command-item-desc { /* Mocha overlay0 */ color: #6c7086; } /* ========== Dark Theme: Image (Mocha) ========== */ .dark .tiptap-editor img.ProseMirror-selectednode { /* 主强调色 Mocha green */ outline-color: #a6e3a1; } .dark .upload-image-container.is-error img { opacity: 0.45; } .dark .upload-btn { border-color: rgba(200, 200, 200, 0.4); } .dark .upload-btn-remove { border-color: rgba(239, 68, 68, 0.5); } /* ========== Dark Theme: Task List (Mocha) ========== */ .dark .tiptap-editor ul[data-type='taskList'] li > label input[type='checkbox'] { /* 主强调色 Mocha green */ accent-color: #a6e3a1; } /* ========== Source Toggle Button ========== */ .tiptap-toggle-btn { position: absolute; top: 12px; right: 12px; z-index: 10; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; border: none; border-radius: 6px; /* Latte text 半透明底 */ background: rgba(76, 79, 105, 0.05); color: #6c6f85; font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace; font-size: 13px; font-weight: 600; line-height: 1; cursor: pointer; opacity: 0.55; transition: opacity 0.15s, background 0.15s; } .tiptap-toggle-btn:hover { opacity: 1; background: rgba(76, 79, 105, 0.1); } .dark .tiptap-toggle-btn { /* Mocha text 半透明底 */ background: rgba(205, 214, 244, 0.06); color: #6c7086; } .dark .tiptap-toggle-btn:hover { background: rgba(205, 214, 244, 0.12); } /* ========== Source Textarea ========== */ .tiptap-source-textarea { position: absolute; inset: 0; width: 100%; height: 100%; padding: 24px 32px; box-sizing: border-box; border: none; background: transparent; /* Latte text */ color: #4c4f69; font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace; font-size: 14px; line-height: 1.7; resize: none; outline: none; overflow-y: auto; z-index: 5; } .tiptap-source-textarea::placeholder { /* Latte overlay0 */ color: #9ca0b0; } .dark .tiptap-source-textarea { /* Mocha text */ color: #cdd6f4; } .dark .tiptap-source-textarea::placeholder { /* Mocha overlay0 */ color: #6c7086; }