Add a file tree UI and corresponding composable for local file management. Introduce TTS menu and player components for voice synthesis integration. Add new EditorView and DocsView routes and update SettingsPanel view switching. Enhance Mermaid plugin with improved styling and action buttons.
507 lines
15 KiB
CSS
507 lines
15 KiB
CSS
:root {
|
||
font-family: 'Noto Sans', 'Segoe UI', Helvetica, Arial, sans-serif;
|
||
line-height: 1.5;
|
||
font-weight: 400;
|
||
font-synthesis: none;
|
||
text-rendering: optimizeLegibility;
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
}
|
||
|
||
:root,
|
||
:root[data-theme='light'] {
|
||
color-scheme: light;
|
||
--app-bg: #f4f6fb;
|
||
--app-text: #1f2937;
|
||
--panel-bg: rgba(255, 255, 255, 0.5);
|
||
--panel-border: #d7deea;
|
||
--panel-shadow: 0 8px 24px rgba(16, 24, 40, 0.12);
|
||
--btn-bg: rgba(255, 255, 255, 0.5);
|
||
--btn-fg: #5b6470;
|
||
--btn-hover-bg: #4a90d9;
|
||
--btn-hover-fg: #ffffff;
|
||
--btn-disabled-bg: rgba(207, 213, 223, 0.5);
|
||
--btn-disabled-fg: #8a92a0;
|
||
--overlay-bg: rgba(15, 23, 42, 0.3);
|
||
--tooltip-bg: #111827;
|
||
--tooltip-fg: #f9fafb;
|
||
--muted-text: #6b7280;
|
||
--danger-text: #dc2626;
|
||
--scrollbar-thumb: #d4dae4;
|
||
--scrollbar-thumb-hover: #bbc4d2;
|
||
--focus-ring: #3b82f6;
|
||
--toggle-bg-start: rgba(255, 248, 221, 0.5);
|
||
--toggle-bg-end: rgba(242, 244, 255, 0.5);
|
||
--toggle-thumb-bg: #ffffff;
|
||
--toggle-sun: #f59e0b;
|
||
--toggle-moon: #475569;
|
||
--ghost-text: #7d8796;
|
||
--ghost-code-bg: rgba(15, 23, 42, 0.06);
|
||
--code-inline-bg: rgba(15, 23, 42, 0.06);
|
||
--code-block-bg: #f8fafc;
|
||
--code-block-border: rgba(148, 163, 184, 0.28);
|
||
--code-text: #0f172a;
|
||
--mermaid-max-height: 480px;
|
||
--mermaid-mobile-max-height: 320px;
|
||
--mermaid-glass-bg: rgba(255, 255, 255, 0.55);
|
||
--mermaid-glass-border: rgba(180, 200, 230, 0.5);
|
||
--mermaid-glass-border-hover: rgba(59, 130, 246, 0.45);
|
||
--mermaid-glass-shadow: 0 4px 24px rgba(15, 23, 42, 0.08), 0 1px 4px rgba(15, 23, 42, 0.05);
|
||
--mermaid-glass-shadow-hover: 0 8px 32px rgba(59, 130, 246, 0.12), 0 2px 8px rgba(15, 23, 42, 0.08);
|
||
--mermaid-btn-bg: rgba(255, 255, 255, 0.8);
|
||
--mermaid-btn-hover-bg: rgba(239, 246, 255, 0.95);
|
||
--mermaid-btn-fg: #374151;
|
||
--mermaid-btn-border: rgba(180, 200, 230, 0.6);
|
||
|
||
--crepe-color-background: #ffffff;
|
||
--crepe-color-on-background: #000000;
|
||
--crepe-color-surface: #f7f7f7;
|
||
--crepe-color-surface-low: #ededed;
|
||
--crepe-color-on-surface: #1c1c1c;
|
||
--crepe-color-on-surface-variant: #4d4d4d;
|
||
--crepe-color-outline: #a8a8a8;
|
||
--crepe-color-primary: #333333;
|
||
--crepe-color-secondary: #cfcfcf;
|
||
--crepe-color-on-secondary: #000000;
|
||
--crepe-color-inverse: #f0f0f0;
|
||
--crepe-color-on-inverse: #1a1a1a;
|
||
--crepe-color-inline-code: #ba1a1a;
|
||
--crepe-color-error: #ba1a1a;
|
||
--crepe-color-hover: #e0e0e0;
|
||
--crepe-color-selected: #d5d5d5;
|
||
--crepe-color-inline-area: #cacaca;
|
||
}
|
||
|
||
:root[data-theme='dark'] {
|
||
color-scheme: dark;
|
||
--app-bg: #0f1117;
|
||
--app-text: #e5e7eb;
|
||
--panel-bg: rgba(26, 30, 39, 0.5);
|
||
--panel-border: #2f3644;
|
||
--panel-shadow: 0 10px 26px rgba(0, 0, 0, 0.5);
|
||
--btn-bg: rgba(34, 40, 52, 0.5);
|
||
--btn-fg: #d2d8e4;
|
||
--btn-hover-bg: #6ea8ff;
|
||
--btn-hover-fg: #0d1117;
|
||
--btn-disabled-bg: rgba(46, 52, 65, 0.5);
|
||
--btn-disabled-fg: #7a8498;
|
||
--overlay-bg: rgba(2, 6, 23, 0.65);
|
||
--tooltip-bg: #f8fafc;
|
||
--tooltip-fg: #0f172a;
|
||
--muted-text: #aeb6c5;
|
||
--danger-text: #f87171;
|
||
--scrollbar-thumb: #40485a;
|
||
--scrollbar-thumb-hover: #5f6980;
|
||
--focus-ring: #60a5fa;
|
||
--toggle-bg-start: rgba(45, 49, 64, 0.5);
|
||
--toggle-bg-end: rgba(31, 36, 48, 0.5);
|
||
--toggle-thumb-bg: #dbe3f2;
|
||
--toggle-sun: #fbbf24;
|
||
--toggle-moon: #e2e8f0;
|
||
--ghost-text: #95a0b4;
|
||
--ghost-code-bg: rgba(226, 232, 240, 0.12);
|
||
--code-inline-bg: rgba(30, 41, 59, 0.92);
|
||
--code-block-bg: rgba(15, 23, 42, 0.92);
|
||
--code-block-border: rgba(71, 85, 105, 0.55);
|
||
--code-text: #e2e8f0;
|
||
--mermaid-max-height: 480px;
|
||
--mermaid-mobile-max-height: 320px;
|
||
--mermaid-glass-bg: rgba(20, 28, 44, 0.6);
|
||
--mermaid-glass-border: rgba(60, 80, 120, 0.4);
|
||
--mermaid-glass-border-hover: rgba(96, 165, 250, 0.45);
|
||
--mermaid-glass-shadow: 0 4px 24px rgba(0, 0, 0, 0.3), 0 1px 4px rgba(0, 0, 0, 0.2);
|
||
--mermaid-glass-shadow-hover: 0 8px 32px rgba(96, 165, 250, 0.15), 0 2px 8px rgba(0, 0, 0, 0.3);
|
||
--mermaid-btn-bg: rgba(40, 52, 75, 0.85);
|
||
--mermaid-btn-hover-bg: rgba(55, 70, 100, 0.95);
|
||
--mermaid-btn-fg: #c9d6e8;
|
||
--mermaid-btn-border: rgba(70, 95, 140, 0.55);
|
||
|
||
--crepe-color-background: #1a1a1a;
|
||
--crepe-color-on-background: #e6e6e6;
|
||
--crepe-color-surface: #121212;
|
||
--crepe-color-surface-low: #1c1c1c;
|
||
--crepe-color-on-surface: #d1d1d1;
|
||
--crepe-color-on-surface-variant: #a9a9a9;
|
||
--crepe-color-outline: #757575;
|
||
--crepe-color-primary: #b5b5b5;
|
||
--crepe-color-secondary: #4d4d4d;
|
||
--crepe-color-on-secondary: #d6d6d6;
|
||
--crepe-color-inverse: #e5e5e5;
|
||
--crepe-color-on-inverse: #2a2a2a;
|
||
--crepe-color-inline-code: #ff6666;
|
||
--crepe-color-error: #ff6666;
|
||
--crepe-color-hover: #232323;
|
||
--crepe-color-selected: #2f2f2f;
|
||
--crepe-color-inline-area: #2b2b2b;
|
||
}
|
||
|
||
:root[data-theme='light'] .milkdown {
|
||
--crepe-color-background: transparent;
|
||
--crepe-color-on-background: #000000;
|
||
--crepe-color-surface: rgba(247, 247, 247, 0.5);
|
||
--crepe-color-surface-low: rgba(237, 237, 237, 0.5);
|
||
--crepe-color-on-surface: #1c1c1c;
|
||
--crepe-color-on-surface-variant: #4d4d4d;
|
||
--crepe-color-outline: #a8a8a8;
|
||
--crepe-color-primary: #333333;
|
||
--crepe-color-secondary: #cfcfcf;
|
||
--crepe-color-on-secondary: #000000;
|
||
--crepe-color-inverse: #f0f0f0;
|
||
--crepe-color-on-inverse: #1a1a1a;
|
||
--crepe-color-inline-code: #ba1a1a;
|
||
--crepe-color-error: #ba1a1a;
|
||
--crepe-color-hover: #e0e0e0;
|
||
--crepe-color-selected: #d5d5d5;
|
||
--crepe-color-inline-area: #cacaca;
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown {
|
||
--crepe-color-background: transparent;
|
||
--crepe-color-on-background: #e6e6e6;
|
||
--crepe-color-surface: rgba(18, 18, 18, 0.5);
|
||
--crepe-color-surface-low: rgba(28, 28, 28, 0.5);
|
||
--crepe-color-on-surface: #d1d1d1;
|
||
--crepe-color-on-surface-variant: #a9a9a9;
|
||
--crepe-color-outline: #757575;
|
||
--crepe-color-primary: #b5b5b5;
|
||
--crepe-color-secondary: #4d4d4d;
|
||
--crepe-color-on-secondary: #d6d6d6;
|
||
--crepe-color-inverse: #e5e5e5;
|
||
--crepe-color-on-inverse: #2a2a2a;
|
||
--crepe-color-inline-code: #ff6666;
|
||
--crepe-color-error: #ff6666;
|
||
--crepe-color-hover: #232323;
|
||
--crepe-color-selected: #2f2f2f;
|
||
--crepe-color-inline-area: #2b2b2b;
|
||
}
|
||
|
||
html,
|
||
body {
|
||
margin: 0;
|
||
padding: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow-x: hidden;
|
||
overflow-y: auto;
|
||
background: var(--app-bg);
|
||
color: var(--app-text);
|
||
}
|
||
|
||
body {
|
||
min-width: 320px;
|
||
}
|
||
|
||
#app {
|
||
width: 100vw;
|
||
height: 100vh;
|
||
margin: 0;
|
||
padding: 0;
|
||
max-width: none;
|
||
background: var(--app-bg);
|
||
color: var(--app-text);
|
||
}
|
||
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
box-sizing: border-box;
|
||
transition:
|
||
background-color 220ms ease,
|
||
color 220ms ease,
|
||
border-color 220ms ease,
|
||
box-shadow 220ms ease;
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
transition: none !important;
|
||
}
|
||
}
|
||
|
||
/* ── Mermaid diagram blocks ─────────────────────────────────────────── */
|
||
.mermaid-block {
|
||
position: relative;
|
||
display: block;
|
||
width: 100%;
|
||
max-width: 100%;
|
||
margin: 1.25em 0;
|
||
padding: 0;
|
||
background: var(--mermaid-glass-bg);
|
||
border: 1px solid var(--mermaid-glass-border);
|
||
border-radius: 16px;
|
||
box-shadow: var(--mermaid-glass-shadow);
|
||
backdrop-filter: blur(12px);
|
||
-webkit-backdrop-filter: blur(12px);
|
||
transition: border-color 240ms ease, box-shadow 240ms ease;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.mermaid-block:hover {
|
||
border-color: var(--mermaid-glass-border-hover);
|
||
box-shadow: var(--mermaid-glass-shadow-hover);
|
||
}
|
||
|
||
/* 悬浮控制栏:右上角,hover 时渐现 */
|
||
.mermaid-controls {
|
||
position: absolute;
|
||
top: 10px;
|
||
right: 10px;
|
||
z-index: 10;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
opacity: 0;
|
||
transform: translateY(-4px);
|
||
transition: opacity 200ms ease, transform 200ms ease;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.mermaid-block:hover .mermaid-controls {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
pointer-events: auto;
|
||
}
|
||
|
||
.mermaid-action-btn {
|
||
appearance: none;
|
||
border: 1px solid var(--mermaid-btn-border);
|
||
background: var(--mermaid-btn-bg);
|
||
color: var(--mermaid-btn-fg);
|
||
cursor: pointer;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 5px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
line-height: 1;
|
||
backdrop-filter: blur(8px);
|
||
-webkit-backdrop-filter: blur(8px);
|
||
box-shadow: 0 1px 4px rgba(0,0,0,0.15), inset 0 1px 0 rgba(255,255,255,0.1);
|
||
transition: background 160ms ease, border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease;
|
||
}
|
||
|
||
.mermaid-zoom-btn {
|
||
width: 30px;
|
||
height: 30px;
|
||
padding: 0;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.mermaid-download-btn {
|
||
height: 30px;
|
||
padding: 0 12px;
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.mermaid-action-btn:hover:not([disabled]) {
|
||
background: var(--mermaid-btn-hover-bg);
|
||
border-color: var(--focus-ring);
|
||
box-shadow: 0 0 0 3px rgba(59,130,246,0.18), 0 2px 8px rgba(0,0,0,0.2);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.mermaid-action-btn:active:not([disabled]) {
|
||
transform: translateY(0);
|
||
box-shadow: 0 1px 4px rgba(0,0,0,0.15);
|
||
}
|
||
|
||
.mermaid-action-btn[disabled] {
|
||
opacity: 0.35;
|
||
cursor: not-allowed;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.mermaid-inner {
|
||
display: block;
|
||
width: 100%;
|
||
max-height: var(--mermaid-max-height);
|
||
overflow: auto;
|
||
padding: 20px;
|
||
background: transparent;
|
||
}
|
||
|
||
.mermaid-inner::-webkit-scrollbar { width: 6px; height: 6px; }
|
||
.mermaid-inner::-webkit-scrollbar-thumb {
|
||
background-color: var(--scrollbar-thumb);
|
||
border-radius: 3px;
|
||
}
|
||
.mermaid-inner::-webkit-scrollbar-thumb:hover {
|
||
background-color: var(--scrollbar-thumb-hover);
|
||
}
|
||
|
||
.mermaid-image {
|
||
display: block;
|
||
width: auto;
|
||
height: auto;
|
||
max-width: 100%;
|
||
margin: 0 auto;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.mermaid-inner svg { display: block; margin: 0 auto; }
|
||
|
||
/* 三点弹跳加载动画 */
|
||
.mermaid-loading {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
padding: 36px;
|
||
}
|
||
|
||
.mermaid-loading span {
|
||
display: inline-block;
|
||
width: 7px;
|
||
height: 7px;
|
||
border-radius: 50%;
|
||
background: var(--muted-text, #6b7280);
|
||
animation: mermaid-bounce 1.2s ease-in-out infinite;
|
||
}
|
||
.mermaid-loading span:nth-child(2) { animation-delay: 0.2s; }
|
||
.mermaid-loading span:nth-child(3) { animation-delay: 0.4s; }
|
||
|
||
@keyframes mermaid-bounce {
|
||
0%, 80%, 100% { transform: scale(0.55); opacity: 0.35; }
|
||
40% { transform: scale(1); opacity: 1; }
|
||
}
|
||
|
||
.mermaid-error {
|
||
margin: 12px;
|
||
padding: 12px 16px;
|
||
background: rgba(220, 38, 38, 0.08);
|
||
border: 1px solid var(--danger-text, #dc2626);
|
||
border-radius: 8px;
|
||
color: var(--danger-text, #dc2626);
|
||
font-size: 12px;
|
||
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Mono', monospace;
|
||
white-space: pre-wrap;
|
||
word-break: break-word;
|
||
}
|
||
|
||
:root .milkdown .katex {
|
||
color: var(--crepe-color-on-background);
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .katex .mord,
|
||
:root[data-theme='dark'] .milkdown .katex .mbin,
|
||
:root[data-theme='dark'] .milkdown .katex .mrel,
|
||
:root[data-theme='dark'] .milkdown .katex .minner {
|
||
color: var(--crepe-color-on-background);
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .katex .mord.text {
|
||
color: var(--crepe-color-on-background);
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .cm-editor,
|
||
:root[data-theme='dark'] .milkdown .cm-scroller {
|
||
background-color: var(--code-block-bg);
|
||
color: var(--code-text);
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .cm-gutters {
|
||
background-color: var(--code-block-bg);
|
||
color: var(--crepe-color-on-surface-variant);
|
||
border-right: 1px solid var(--code-block-border);
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .cm-activeLine {
|
||
background-color: rgba(255, 255, 255, 0.05);
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .cm-activeLineGutter {
|
||
background-color: rgba(255, 255, 255, 0.08);
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .cm-selectionBackground,
|
||
:root[data-theme='dark'] .milkdown .cm-selectionBackground::selection {
|
||
background-color: rgba(59, 130, 246, 0.25);
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .cm-cursor {
|
||
border-left-color: var(--crepe-color-on-background);
|
||
}
|
||
|
||
:root .milkdown .ProseMirror pre,
|
||
:root .milkdown .ProseMirror code {
|
||
background: var(--code-inline-bg);
|
||
color: var(--code-text);
|
||
border: 1px solid var(--code-block-border);
|
||
}
|
||
|
||
:root .milkdown .ProseMirror pre {
|
||
padding: 12px 16px;
|
||
border-radius: 8px;
|
||
background: var(--code-block-bg);
|
||
}
|
||
|
||
:root .milkdown .ProseMirror pre code {
|
||
background: none;
|
||
border: none;
|
||
padding: 0;
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.comment,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.prolog,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.doctype,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.cdata {
|
||
color: #6b7280;
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.punctuation {
|
||
color: #9ca3af;
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.property,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.tag,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.boolean,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.number,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.constant,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.symbol,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.deleted {
|
||
color: #f472b6;
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.selector,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.attr-name,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.string,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.char,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.builtin,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.inserted {
|
||
color: #a78bfa;
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.operator,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.entity,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.url,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .language-css .token.string,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .style .token.string {
|
||
color: #60a5fa;
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.atrule,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.attr-value,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.keyword {
|
||
color: #34d399;
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.function,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.class-name {
|
||
color: #fbbf24;
|
||
}
|
||
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.regex,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.important,
|
||
:root[data-theme='dark'] .milkdown .ProseMirror pre code .token.variable {
|
||
color: #fb923c;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.mermaid-inner {
|
||
max-height: var(--mermaid-mobile-max-height);
|
||
}
|
||
}
|