""" UI 样式模块 - CSS 样式定义 """ CSS = """ :root, .gradio-container { --rosa-bg: #f8fafc; --rosa-surface: #ffffff; --rosa-surface-2: #f1f5f9; --rosa-border: #e2e8f0; --rosa-border-soft: #cbd5e1; --rosa-text: #0f172a; --rosa-text-muted: #475569; --rosa-text-muted-2: #94a3b8; --rosa-code-active-bg: #dbeafe; --rosa-code-active-text: #1d4ed8; --rosa-code-token-bg: #fef3c7; --rosa-code-token-border: #f59e0b; --rosa-card-shadow: none; --rosa-float-bg: #f59e0b; --rosa-float-text: #1f2937; --rosa-legend-text: #475569; /* Code Highlight Colors (Light) */ --rosa-tok-keyword: #7c3aed; --rosa-tok-builtin: #0ea5e9; --rosa-tok-number: #f97316; --rosa-tok-string: #10b981; --rosa-tok-comment: #64748b; --rosa-blue: #3b82f6; --rosa-sky: #38bdf8; --rosa-violet: #a855f7; --rosa-amber: #f59e0b; --rosa-cyan: #06b6d4; --rosa-green: #22c55e; --rosa-green-soft: rgba(34, 197, 94, 0.16); --rosa-red: #ef4444; --rosa-red-soft: rgba(239, 68, 68, 0.14); --rosa-blue-soft: rgba(59, 130, 246, 0.08); --rosa-violet-soft: rgba(168, 85, 247, 0.08); } .rosa-theme-dark, :root.rosa-theme-dark { --rosa-bg: #0b1220; --rosa-surface: #0f172a; --rosa-surface-2: #1e293b; --rosa-border: #334155; --rosa-border-soft: #475569; --rosa-text: #f1f5f9; --rosa-text-muted: #cbd5e1; --rosa-text-muted-2: #94a3b8; --rosa-code-active-bg: rgba(59, 130, 246, 0.2); --rosa-code-active-text: #bfdbfe; --rosa-code-token-bg: rgba(245, 158, 11, 0.2); --rosa-code-token-border: #fbbf24; --rosa-card-shadow: 0 10px 28px rgba(0, 0, 0, 0.5); --rosa-float-bg: #fbbf24; --rosa-float-text: #111827; --rosa-legend-text: #cbd5e1; /* Code Highlight Colors (Dark) */ --rosa-tok-keyword: #c4b5fd; --rosa-tok-builtin: #7dd3fc; --rosa-tok-number: #fdba74; --rosa-tok-string: #6ee7b7; --rosa-tok-comment: #94a3b8; --rosa-blue: #60a5fa; --rosa-sky: #7dd3fc; --rosa-violet: #c084fc; --rosa-amber: #fbbf24; --rosa-cyan: #67e8f9; --rosa-green: #4ade80; --rosa-green-soft: rgba(74, 222, 128, 0.2); --rosa-red: #f87171; --rosa-red-soft: rgba(248, 113, 113, 0.2); --rosa-blue-soft: rgba(96, 165, 250, 0.2); --rosa-violet-soft: rgba(192, 132, 252, 0.2); } body, .gradio-container { background: var(--rosa-bg) !important; color: var(--rosa-text) !important; } .rosa-theme-dark { color-scheme: dark; } /* 覆盖 Gradio 内置 CSS 变量 */ :root, .gradio-container, .rosa-theme-dark, .rosa-theme-dark .gradio-container { --body-background-fill: var(--rosa-bg) !important; --block-background-fill: var(--rosa-surface) !important; --block-border-color: var(--rosa-border) !important; --block-label-background-fill: var(--rosa-surface) !important; --block-label-text-color: var(--rosa-text) !important; --block-title-text-color: var(--rosa-text) !important; --input-background-fill: var(--rosa-surface-2) !important; --input-border-color: var(--rosa-border) !important; --input-text-color: var(--rosa-text) !important; --body-text-color: var(--rosa-text) !important; --body-text-color-subdued: var(--rosa-text-muted) !important; --background-fill-primary: var(--rosa-surface) !important; --background-fill-secondary: var(--rosa-surface-2) !important; --border-color-primary: var(--rosa-border) !important; --border-color-accent: var(--rosa-blue) !important; --color-accent: var(--rosa-blue) !important; --color-accent-soft: var(--rosa-blue-soft) !important; --button-primary-background-fill: var(--rosa-blue) !important; --button-primary-text-color: #f8fafc !important; --button-secondary-background-fill: var(--rosa-surface-2) !important; --button-secondary-text-color: var(--rosa-text) !important; --button-secondary-border-color: var(--rosa-border) !important; --neutral-50: var(--rosa-surface) !important; --neutral-100: var(--rosa-surface-2) !important; --neutral-200: var(--rosa-border) !important; --neutral-300: var(--rosa-border-soft) !important; --neutral-400: var(--rosa-text-muted-2) !important; --neutral-500: var(--rosa-text-muted) !important; --neutral-600: var(--rosa-text-muted) !important; --neutral-700: var(--rosa-text) !important; --neutral-800: var(--rosa-text) !important; --neutral-900: var(--rosa-text) !important; --neutral-950: var(--rosa-text) !important; --panel-background-fill: var(--rosa-surface) !important; --checkbox-background-color: var(--rosa-surface-2) !important; --checkbox-border-color: var(--rosa-border) !important; --slider-color: var(--rosa-blue) !important; } /* Gradio 按钮 */ .gradio-container button:not(.secondary), .gradio-container .primary, .gradio-container button[variant="primary"] { background: var(--rosa-blue) !important; color: #f8fafc !important; border: 1px solid var(--rosa-blue) !important; } .gradio-container button.secondary, .gradio-container button:not([variant="primary"]):not(.primary) { background: var(--rosa-surface-2) !important; color: var(--rosa-text) !important; border: 1px solid var(--rosa-border) !important; } /* Gradio 输入框和文本区域 */ .gradio-container input[type="text"], .gradio-container input[type="number"], .gradio-container textarea { background: var(--rosa-surface-2) !important; color: var(--rosa-text) !important; border: 1px solid var(--rosa-border) !important; border-radius: 8px !important; font-family: inherit; } .gradio-container input[readonly], .gradio-container textarea[readonly], .gradio-container textarea[disabled] { background: var(--rosa-surface-2) !important; color: var(--rosa-text) !important; opacity: 1 !important; -webkit-text-fill-color: var(--rosa-text) !important; cursor: text !important; } .gradio-container ::placeholder, .gradio-container input::placeholder, .gradio-container textarea::placeholder { color: var(--rosa-text-muted) !important; opacity: 0.8; } .gradio-container input[type="text"]:focus, .gradio-container input[type="number"]:focus, .gradio-container textarea:focus { outline: none !important; border-color: var(--rosa-blue) !important; box-shadow: 0 0 0 2px var(--rosa-blue-soft) !important; } /* Gradio 滑块 */ .gradio-container input[type="range"] { accent-color: var(--rosa-blue); } .gradio-container .gr-box, .gradio-container .gr-panel, .gradio-container .gr-form { background: var(--rosa-surface) !important; border-color: var(--rosa-border) !important; } /* Gradio 标签 */ .gradio-container label, .gradio-container .label, .gradio-container span.label { color: var(--rosa-text) !important; } /* Gradio 输出框 */ .gradio-container .output-class, .gradio-container .gr-text-output { background: var(--rosa-surface-2) !important; color: var(--rosa-text) !important; border: 1px solid var(--rosa-border) !important; } /* Gradio checkbox */ .gradio-container input[type="checkbox"] { accent-color: var(--rosa-blue); } .page-header { text-align: center; margin-bottom: 18px; color: var(--rosa-text); } .rosa-hidden { display: none !important; } .page-title { font-size: 30px; font-weight: 700; letter-spacing: 0.4px; margin-bottom: 6px; } .page-subtitle { font-size: 14px; color: var(--rosa-text-muted); } .rosa-shell { display: flex; gap: 24px; align-items: flex-start; justify-content: center; flex-wrap: wrap; position: relative; } .rosa-pane { flex: 3 1 520px; min-width: 320px; } .rosa-code-pane { flex: 2 1 320px; min-width: 300px; } .quick-code-details { margin-top: 8px; } .quick-code-details > summary { cursor: pointer; user-select: none; padding: 8px 10px; border: 1px dashed var(--rosa-border-soft); border-radius: 12px; background: var(--rosa-surface); color: var(--rosa-text); font-weight: 600; } .quick-code-details[open] > summary { margin-bottom: 10px; } .quick-code-details > summary::-webkit-details-marker { display: none; } .quick-code-details .rosa-code { max-height: 420px; } #rosa-vis .rosa-card { background: var(--rosa-surface); border-radius: 18px; padding: 24px; color: var(--rosa-text); box-shadow: var(--rosa-card-shadow); border: 1px solid var(--rosa-border); text-align: center; position: relative; } #rosa-vis .rosa-rows { display: flex; flex-direction: column; gap: 20px; align-items: center; } #rosa-vis .rosa-row { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; justify-content: center; width: 100%; } #rosa-vis .rosa-row.k-row { margin-bottom: 0; } #rosa-vis .row-label { min-width: 36px; font-size: 12px; color: var(--rosa-text-muted); text-transform: uppercase; letter-spacing: 0.2px; text-align: center; } #rosa-vis .row-cells { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; max-width: 100%; min-width: 0; } #rosa-vis .cell { width: 30px; height: 30px; border-radius: 8px; background: var(--rosa-surface-2); display: flex; align-items: center; justify-content: center; font-weight: 600; transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.18s ease, color 0.18s ease; color: var(--rosa-text); box-shadow: none; } #rosa-vis .cell.active { background: var(--rosa-blue); color: #f8fafc; box-shadow: none; } #rosa-vis .cell.suffix { background: var(--rosa-sky); color: #0b1220; } #rosa-vis .cell.k-window { background: var(--rosa-violet); color: #0b1220; } #rosa-vis .cell.v-pick { background: var(--rosa-amber); color: #1f2937; } #rosa-vis .cell.out, #rosa-vis .cell.out-fixed { background: var(--rosa-amber); color: #1f2937; } #rosa-vis .cell.filled { box-shadow: none; } #rosa-vis .rosa-overlay { position: absolute; inset: 0; pointer-events: none; z-index: 5; } #rosa-vis .overlay-svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; } #rosa-vis .overlay-box-layer { position: absolute; inset: 0; pointer-events: none; } #rosa-vis .overlay-box { position: absolute; border: 2px solid var(--rosa-blue); border-radius: 10px; box-shadow: 0 6px 16px rgba(15, 23, 42, 0.16); box-sizing: border-box; background: transparent; transition: border-color 0.18s ease, background 0.18s ease; } #rosa-vis .overlay-hover-layer { position: absolute; inset: 0; pointer-events: auto; z-index: 6; } #rosa-vis .overlay-hover-box { position: absolute; background: transparent; pointer-events: auto; cursor: pointer; } #rosa-vis .overlay-box[data-label="t"] { --overlay-label: "t"; } #rosa-vis .overlay-box[data-label="kkk[j:j+w]"] { --overlay-label: "kkk[j:j+w]"; } #rosa-vis .overlay-box.t-box { border-color: var(--rosa-blue); background: var(--rosa-blue-soft); } #rosa-vis .overlay-box.k-box { border-color: var(--rosa-violet); background: var(--rosa-violet-soft); } #rosa-vis .overlay-box.try-match { border-color: var(--rosa-green); background: var(--rosa-green-soft); } #rosa-vis .overlay-box.try-miss { border-color: var(--rosa-red); background: var(--rosa-red-soft); } #rosa-vis .overlay-ray { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; } #rosa-vis .overlay-ray-line { stroke: var(--rosa-cyan); stroke-width: 2; fill: none; stroke-linecap: round; } #rosa-vis .overlay-label { position: absolute; top: -12px; right: 0; font-size: 11px; padding: 0; background: transparent; color: var(--rosa-text); letter-spacing: 0.2px; white-space: nowrap; display: none; } #rosa-vis .overlay-label.t-label { color: var(--rosa-blue); } #rosa-vis .overlay-label.k-label { color: var(--rosa-violet); } .v-float { position: fixed; z-index: 9999; border-radius: 8px; background: var(--rosa-float-bg); color: var(--rosa-float-text); display: flex; align-items: center; justify-content: center; font-weight: 600; box-shadow: 0 10px 24px rgba(15, 23, 42, 0.2); pointer-events: none; transition: transform 0.35s ease, opacity 0.35s ease; opacity: 1; } #rosa-vis .rosa-legend { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 12px; font-size: 12px; color: var(--rosa-legend-text); justify-content: center; } #rosa-vis .legend-item { display: inline-flex; align-items: center; gap: 6px; } #rosa-vis .legend-dot { width: 12px; height: 12px; border-radius: 4px; } #rosa-vis .legend-suffix { background: var(--rosa-sky); } #rosa-vis .legend-window { background: var(--rosa-violet); } #rosa-vis .legend-match { background: var(--rosa-green); } #rosa-vis .legend-v { background: var(--rosa-amber); } #rosa-vis .legend-out { background: var(--rosa-amber); } #rosa-vis .index-row { padding-bottom: 8px; border-bottom: 1px dashed var(--rosa-border); } #rosa-vis .index-cells { gap: 6px; } #rosa-vis .index-cell { width: 30px; text-align: center; font-size: 11px; color: var(--rosa-text-muted-2); font-variant-numeric: tabular-nums; } .rosa-code { background: var(--rosa-surface); border: 1px solid var(--rosa-border); border-radius: 12px; padding: 12px; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 12px; color: var(--rosa-text); max-height: 520px; overflow: auto; } .rosa-code .code-line { display: flex; gap: 10px; padding: 2px 6px; border-radius: 6px; } .rosa-code .line-no { flex: 0 0 36px; width: 36px; text-align: left; color: var(--rosa-text-muted-2); user-select: none; font-variant-numeric: tabular-nums; } .rosa-code .line-text { white-space: pre; flex: 1; } .rosa-code .code-line.active { background: var(--rosa-code-active-bg); color: var(--rosa-code-active-text); } .rosa-code .code-line.active .line-no { color: var(--rosa-code-active-text); } .rosa-code .tok-keyword { color: var(--rosa-tok-keyword); font-weight: 600; } .rosa-code .tok-builtin { color: var(--rosa-tok-builtin); } .rosa-code .tok-number { color: var(--rosa-tok-number); } .rosa-code .tok-string { color: var(--rosa-tok-string); } .rosa-code .tok-comment { color: var(--rosa-tok-comment); font-style: italic; } .rosa-code .code-token { border-bottom: 1px dashed var(--rosa-text-muted-2); padding: 0 1px; } .rosa-code .code-token.active { background: var(--rosa-code-token-bg); border-radius: 4px; border-bottom-color: var(--rosa-code-token-border); } """