/* 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; color: #2c2c2c; 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; color: #999; 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; color: #1a1a1a; } .tiptap-editor h2 { font-size: 1.5em; font-weight: 600; margin: 1em 0 0.5em; line-height: 1.35; color: #1a1a1a; } .tiptap-editor h3 { font-size: 1.25em; font-weight: 600; margin: 0.8em 0 0.4em; color: #1a1a1a; } .tiptap-editor p { margin: 0.6em 0; } .tiptap-editor p:first-child { margin-top: 0; } .tiptap-editor strong { font-weight: 700; color: #1a1a1a; } .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; background: #f3f3f3; padding: 0.15em 0.4em; border-radius: 3px; color: #d73a49; } .tiptap-editor pre { background: #f6f8fa; border-radius: 6px; padding: 16px; overflow-x: auto; margin: 1em 0; } .tiptap-editor pre code { background: none; padding: 0; color: #24292e; font-size: 0.85em; line-height: 1.6; } .tiptap-editor blockquote { border-left: 4px solid #dfe2e5; padding-left: 16px; margin: 1em 0; color: #6a737d; 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 { border: none; border-top: 1px solid #e1e4e8; margin: 1.5em 0; } /* Selection */ .tiptap-editor .ProseMirror ::selection { background: #b4d7ff; } /* Cursor */ .tiptap-editor .ProseMirror-focused .ProseMirror-gapcursor { display: none; } /* ========== Dark Theme ========== */ .dark .tiptap-editor { color: #dadadb; } .dark .tiptap-editor h1, .dark .tiptap-editor h2, .dark .tiptap-editor h3, .dark .tiptap-editor strong { color: #f0f0f0; } .dark .tiptap-editor .ProseMirror p.is-editor-empty:first-child::before { color: #666; } .dark .tiptap-editor code { background: #2e2e33; color: #ff7b72; } .dark .tiptap-editor pre { background: #2e2e33; } .dark .tiptap-editor pre code { color: #dadadb; } .dark .tiptap-editor blockquote { border-left-color: #444; color: #9b9c9d; } .dark .tiptap-editor hr { border-top-color: #333; } .dark .tiptap-editor a { color: #58a6ff; } .dark .tiptap-editor .ProseMirror ::selection { background: #1c4e80; } /* ========== Link ========== */ .tiptap-editor a { color: #0366d6; 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; border: 1px solid #e1e4e8; border-radius: 6px; } .tiptap-editor table td, .tiptap-editor table th { min-width: 80px; border: 1px solid #e1e4e8; padding: 8px 12px; position: relative; vertical-align: top; box-sizing: border-box; } .tiptap-editor table th { background: #f6f8fa; font-weight: 600; text-align: left; } .tiptap-editor table .selectedCell { background: #b4d7ff; } .tiptap-editor table .column-resize-handle { position: absolute; right: -2px; top: 0; bottom: -2px; width: 4px; background-color: #adf; 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; background: #fff; border: 1px solid #e1e4e8; 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 { background: #f0f4ff; } .slash-command-item-icon { flex-shrink: 0; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; background: #f3f3f3; border-radius: 6px; font-size: 13px; font-weight: 600; color: #555; } .slash-command-item-text { flex: 1; min-width: 0; } .slash-command-item-title { font-size: 14px; font-weight: 500; color: #1a1a1a; line-height: 1.3; } .slash-command-item-desc { font-size: 12px; color: #999; 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: flex-start; gap: 0.5em; margin: 0.3em 0; } .tiptap-editor ul[data-type="taskList"] li > label { flex-shrink: 0; margin-top: 0.3em; cursor: pointer; user-select: none; } .tiptap-editor ul[data-type="taskList"] li > label input[type="checkbox"] { width: 16px; height: 16px; accent-color: #0366d6; cursor: pointer; } .tiptap-editor ul[data-type="taskList"] li > div { flex: 1; } .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 { outline: 2px solid #0366d6; 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 ========== */ .dark .tiptap-editor table { border-color: #333; } .dark .tiptap-editor table td, .dark .tiptap-editor table th { border-color: #333; color: #dadadb; } .dark .tiptap-editor table th { background: #2e2e33; } .dark .tiptap-editor table .selectedCell { background: #1c4e80; } /* ========== Dark Theme: Slash Command ========== */ .dark .slash-command { background: #2e2e33; border-color: #444; box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4); } .dark .slash-command-item:hover, .dark .slash-command-item.is-selected { background: #3a3a44; } .dark .slash-command-item-icon { background: #3a3a44; color: #dadadb; } .dark .slash-command-item-title { color: #f0f0f0; } .dark .slash-command-item-desc { color: #888; } /* ========== Dark Theme: Image ========== */ .dark .tiptap-editor img.ProseMirror-selectednode { outline-color: #58a6ff; } .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 ========== */ .dark .tiptap-editor ul[data-type="taskList"] li > label input[type="checkbox"] { accent-color: #58a6ff; } /* ========== 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; background: rgba(0, 0, 0, 0.04); color: #6a737d; 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(0, 0, 0, 0.08); } .dark .tiptap-toggle-btn { background: rgba(255, 255, 255, 0.06); color: #9b9c9d; } .dark .tiptap-toggle-btn:hover { background: rgba(255, 255, 255, 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; color: #2c2c2c; 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 { color: #999; } .dark .tiptap-source-textarea { color: #dadadb; } .dark .tiptap-source-textarea::placeholder { color: #666; }