diff --git a/VERSION b/VERSION index 4b9fcbe..cb0c939 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.1 +0.5.2 diff --git a/src/css/styles.css b/src/css/styles.css index 7c543f1..1afb765 100644 --- a/src/css/styles.css +++ b/src/css/styles.css @@ -1,398 +1,529 @@ /* ========================================== - Chat Switchboard – Styles (v0.5.0) + Chat Switchboard v0.5.2 + Clean utility layout · Open WebUI inspired ========================================== */ :root { - --bg: #0f0f13; - --bg-secondary: #1a1a24; - --bg-tertiary: #252533; - --border: #2a2a3a; - --text: #e4e4ef; - --text-secondary: #8888a0; - --accent: #6c9fff; - --accent-hover: #8ab4ff; - --danger: #e74c3c; - --success: #2ecc71; - --warning: #f39c12; - --radius: 8px; - --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; - --mono: 'SF Mono', 'Fira Code', Consolas, monospace; + --bg: #0e0e10; + --bg-surface: #18181b; + --bg-raised: #222227; + --bg-hover: #2a2a30; + --border: #2e2e35; + --border-light: #3a3a42; + --text: #e8e8ed; + --text-2: #9898a8; + --text-3: #6b6b7b; + --accent: #6c9fff; + --accent-hover: #84b0ff; + --accent-dim: rgba(108,159,255,0.12); + --danger: #ef4444; + --success: #22c55e; + --warning: #eab308; + --radius: 8px; + --radius-lg: 12px; + --sidebar-w: 260px; + --sidebar-rail: 52px; + --font: 'Söhne', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + --mono: 'Söhne Mono', 'SF Mono', 'Fira Code', 'Consolas', monospace; + --transition: 180ms ease; } -* { margin: 0; padding: 0; box-sizing: border-box; } -body { font-family: var(--font); background: var(--bg); color: var(--text); height: 100vh; overflow: hidden; } -a { color: var(--accent); } +*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } +html, body { height: 100%; } +body { font-family: var(--font); background: var(--bg); color: var(--text); overflow: hidden; font-size: 14px; } +a { color: var(--accent); text-decoration: none; } +a:hover { text-decoration: underline; } +::selection { background: var(--accent-dim); } -/* ── Layout ──────────────────────────────── */ +/* ── App Shell ───────────────────────────── */ -#appContainer { display: flex; flex-direction: column; height: 100vh; } - -.header { - display: flex; align-items: center; justify-content: space-between; - padding: 0 1rem; height: 48px; background: var(--bg-secondary); - border-bottom: 1px solid var(--border); flex-shrink: 0; -} -.header-title { font-size: 1rem; font-weight: 600; } -.header-actions { display: flex; align-items: center; gap: 0.5rem; } - -.main { display: flex; flex: 1; overflow: hidden; } +.app { display: flex; height: 100vh; } /* ── Sidebar ─────────────────────────────── */ .sidebar { - width: 260px; background: var(--bg-secondary); border-right: 1px solid var(--border); - display: flex; flex-direction: column; padding: 0.75rem; gap: 0.5rem; flex-shrink: 0; - overflow-y: auto; + width: var(--sidebar-w); background: var(--bg-surface); + border-right: 1px solid var(--border); + display: flex; flex-direction: column; + transition: width var(--transition); + overflow: hidden; flex-shrink: 0; } -.new-chat-btn { width: 100%; } -.chat-history { flex: 1; overflow-y: auto; } +.sidebar.collapsed { width: var(--sidebar-rail); } + +.sidebar-top { + display: flex; flex-direction: column; gap: 2px; + padding: 10px 10px 8px; + border-bottom: 1px solid var(--border); +} + +.sb-btn { + display: flex; align-items: center; gap: 10px; + padding: 8px 10px; border-radius: var(--radius); + background: none; border: none; color: var(--text-2); + cursor: pointer; font-size: 13px; white-space: nowrap; + transition: background var(--transition), color var(--transition); + width: 100%; +} +.sb-btn:hover { background: var(--bg-hover); color: var(--text); } +.sb-btn svg { flex-shrink: 0; } +.sb-label { overflow: hidden; transition: opacity var(--transition); } +.sidebar.collapsed .sb-label { opacity: 0; width: 0; } + +/* Chat list */ +.sidebar-chats { + flex: 1; overflow-y: auto; overflow-x: hidden; + padding: 8px 6px; +} +.sidebar-chats::-webkit-scrollbar { width: 4px; } +.sidebar-chats::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; } + +.chat-group-label { + font-size: 11px; font-weight: 600; color: var(--text-3); + padding: 12px 10px 4px; text-transform: uppercase; letter-spacing: 0.5px; + white-space: nowrap; overflow: hidden; +} +.sidebar.collapsed .chat-group-label { display: none; } .chat-item { - display: flex; align-items: center; padding: 0.5rem 0.75rem; border-radius: var(--radius); - cursor: pointer; font-size: 0.85rem; gap: 0.5rem; transition: background 0.15s; + display: flex; align-items: center; gap: 8px; + padding: 7px 10px; border-radius: var(--radius); + cursor: pointer; font-size: 13px; color: var(--text-2); + transition: background var(--transition); position: relative; + overflow: hidden; } -.chat-item:hover { background: var(--bg-tertiary); } -.chat-item.active { background: var(--bg-tertiary); border-left: 2px solid var(--accent); } +.chat-item:hover { background: var(--bg-hover); color: var(--text); } +.chat-item.active { background: var(--bg-raised); color: var(--text); } .chat-item-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.chat-item-time { + font-size: 10px; color: var(--text-3); flex-shrink: 0; + white-space: nowrap; +} .chat-item-delete { - opacity: 0; background: none; border: none; color: var(--text-secondary); - cursor: pointer; font-size: 0.75rem; padding: 2px 4px; transition: opacity 0.15s; + opacity: 0; position: absolute; right: 6px; background: var(--bg-raised); + border: none; color: var(--text-3); cursor: pointer; font-size: 11px; + padding: 2px 6px; border-radius: 4px; transition: opacity var(--transition); } .chat-item:hover .chat-item-delete { opacity: 1; } +.chat-item:hover .chat-item-time { display: none; } +.sidebar.collapsed .chat-item-title, +.sidebar.collapsed .chat-item-time, +.sidebar.collapsed .chat-item-delete { display: none; } + +.sidebar-empty { + color: var(--text-3); font-size: 12px; text-align: center; padding: 2rem 0.5rem; +} +.sidebar.collapsed .sidebar-empty { display: none; } + +/* User area */ +.sidebar-bottom { + border-top: 1px solid var(--border); + padding: 8px 10px; position: relative; +} + +.user-btn { + display: flex; align-items: center; gap: 10px; + padding: 6px 8px; border-radius: var(--radius); + background: none; border: none; color: var(--text); + cursor: pointer; width: 100%; + transition: background var(--transition); +} +.user-btn:hover { background: var(--bg-hover); } + +.user-avatar { + width: 30px; height: 30px; border-radius: 50%; + background: var(--bg-raised); display: flex; align-items: center; + justify-content: center; font-size: 13px; font-weight: 600; + color: var(--accent); flex-shrink: 0; position: relative; +} +.avatar-dot { + position: absolute; bottom: -1px; right: -1px; + width: 9px; height: 9px; border-radius: 50%; + background: var(--success); border: 2px solid var(--bg-surface); +} +.user-name { font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + +/* Flyout */ +.user-flyout { + display: none; position: absolute; bottom: 100%; left: 8px; right: 8px; + background: var(--bg-raised); border: 1px solid var(--border-light); + border-radius: var(--radius-lg); padding: 4px; margin-bottom: 4px; + box-shadow: 0 -4px 24px rgba(0,0,0,0.5); z-index: 200; +} +.user-flyout.open { display: block; } + +.flyout-item { + display: flex; align-items: center; gap: 10px; + padding: 8px 12px; border-radius: var(--radius); + background: none; border: none; color: var(--text-2); + cursor: pointer; font-size: 13px; width: 100%; + transition: background var(--transition), color var(--transition); +} +.flyout-item:hover { background: var(--bg-hover); color: var(--text); } +.flyout-item svg { flex-shrink: 0; } +.flyout-danger:hover { color: var(--danger); } +.flyout-divider { height: 1px; background: var(--border); margin: 4px 8px; } /* ── Chat Area ───────────────────────────── */ -.chat-area { flex: 1; display: flex; flex-direction: column; min-width: 0; overflow: hidden; } -.chat-messages { flex: 1; overflow-y: auto; padding: 1rem; } +.chat-area { flex: 1; display: flex; flex-direction: column; min-width: 0; background: var(--bg); } -.message { margin-bottom: 1rem; } -.message-inner { display: flex; gap: 0.75rem; max-width: 800px; margin: 0 auto; } -.message-avatar { font-size: 1.25rem; flex-shrink: 0; } -.message-body { flex: 1; min-width: 0; } -.message-head { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.25rem; } -.message-role { font-weight: 600; font-size: 0.85rem; } -.message-time { font-size: 0.7rem; color: var(--text-secondary); } -.message-copy { - background: none; border: none; cursor: pointer; font-size: 0.75rem; - opacity: 0; transition: opacity 0.15s; margin-left: auto; +.model-bar { + display: flex; align-items: center; gap: 6px; + padding: 8px 16px; flex-shrink: 0; } -.message:hover .message-copy { opacity: 0.7; } -.message-text { font-size: 0.9rem; line-height: 1.6; word-wrap: break-word; } - -/* ── Markdown Rendered Content ────────────── */ - -.message-text p { margin: 0.4em 0; } -.message-text p:first-child { margin-top: 0; } -.message-text p:last-child { margin-bottom: 0; } - -.message-text pre { - background: var(--bg-tertiary); padding: 0.75rem; border-radius: var(--radius); - overflow-x: auto; margin: 0.5rem 0; position: relative; font-size: 0.8rem; +.model-bar select { + background: transparent; border: 1px solid transparent; + color: var(--text); font-size: 14px; font-weight: 500; + padding: 4px 8px; border-radius: var(--radius); cursor: pointer; + font-family: var(--font); max-width: 300px; + transition: border-color var(--transition); } -.message-text code { font-family: var(--mono); font-size: 0.85em; background: var(--bg-tertiary); padding: 0.15em 0.35em; border-radius: 3px; } -.message-text pre code { font-size: inherit; background: none; padding: 0; } +.model-bar select:hover { border-color: var(--border); } +.model-bar select:focus { outline: none; border-color: var(--accent); } +.model-bar select option { background: var(--bg-surface); color: var(--text); } + +.icon-btn { + background: none; border: none; color: var(--text-3); cursor: pointer; + padding: 4px; border-radius: 4px; + transition: color var(--transition); +} +.icon-btn:hover { color: var(--text); } + +/* Messages */ +.messages { flex: 1; overflow-y: auto; scroll-behavior: smooth; } +.messages::-webkit-scrollbar { width: 6px; } +.messages::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; } + +.message { padding: 1.25rem 0; } +.message:not(:last-child) { border-bottom: 1px solid rgba(255,255,255,0.03); } + +.msg-inner { max-width: 768px; margin: 0 auto; padding: 0 1.5rem; display: flex; gap: 1rem; } + +.msg-avatar { + width: 28px; height: 28px; border-radius: 50%; + display: flex; align-items: center; justify-content: center; + font-size: 14px; flex-shrink: 0; margin-top: 2px; +} +.message.user .msg-avatar { background: var(--accent-dim); } +.message.assistant .msg-avatar { background: var(--bg-raised); } + +.msg-body { flex: 1; min-width: 0; } +.msg-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; } +.msg-role { font-size: 13px; font-weight: 600; } +.msg-time { font-size: 11px; color: var(--text-3); } +.msg-actions { + margin-left: auto; display: flex; gap: 2px; opacity: 0; + transition: opacity var(--transition); +} +.message:hover .msg-actions { opacity: 1; } +.msg-action-btn { + background: none; border: none; color: var(--text-3); cursor: pointer; + padding: 2px 6px; border-radius: 4px; font-size: 11px; + transition: background var(--transition), color var(--transition); +} +.msg-action-btn:hover { background: var(--bg-hover); color: var(--text); } + +.msg-text { font-size: 14px; line-height: 1.7; } + +/* ── Markdown Content ────────────────────── */ + +.msg-text p { margin: 0.4em 0; } +.msg-text p:first-child { margin-top: 0; } +.msg-text p:last-child { margin-bottom: 0; } + +.msg-text pre { + background: var(--bg-surface); border: 1px solid var(--border); + padding: 0.75rem 1rem; border-radius: var(--radius); + overflow-x: auto; margin: 0.75rem 0; position: relative; + font-size: 13px; +} +.msg-text code { + font-family: var(--mono); font-size: 0.9em; + background: var(--bg-raised); padding: 0.15em 0.4em; + border-radius: 4px; +} +.msg-text pre code { background: none; padding: 0; font-size: inherit; } .copy-code-btn { - position: absolute; top: 4px; right: 4px; background: var(--bg-secondary); - border: 1px solid var(--border); color: var(--text-secondary); border-radius: 4px; - padding: 2px 8px; font-size: 0.7rem; cursor: pointer; opacity: 0; transition: opacity 0.15s; + position: absolute; top: 6px; right: 6px; background: var(--bg-raised); + border: 1px solid var(--border); color: var(--text-3); border-radius: 4px; + padding: 2px 10px; font-size: 11px; cursor: pointer; + opacity: 0; transition: opacity var(--transition); } -.message-text pre:hover .copy-code-btn { opacity: 1; } -.copy-code-btn:hover { background: var(--border); color: var(--text); } +.msg-text pre:hover .copy-code-btn { opacity: 1; } +.copy-code-btn:hover { color: var(--text); border-color: var(--border-light); } -.message-text ul, .message-text ol { margin: 0.4em 0; padding-left: 1.5em; } -.message-text li { margin: 0.2em 0; } -.message-text li > p { margin: 0.2em 0; } +.msg-text ul, .msg-text ol { margin: 0.4em 0; padding-left: 1.5em; } +.msg-text li { margin: 0.2em 0; } +.msg-text li > p { margin: 0.2em 0; } -.message-text blockquote { - border-left: 3px solid var(--accent); padding: 0.25em 0.75em; margin: 0.4em 0; - color: var(--text-secondary); background: var(--bg-tertiary); border-radius: 0 4px 4px 0; +.msg-text blockquote { + border-left: 3px solid var(--accent); padding: 0.25em 0.75em; margin: 0.5em 0; + color: var(--text-2); background: var(--accent-dim); border-radius: 0 var(--radius) var(--radius) 0; } -.message-text a { color: var(--accent); text-decoration: none; } -.message-text a:hover { text-decoration: underline; } +.msg-text hr { border: none; border-top: 1px solid var(--border); margin: 0.75em 0; } -.message-text hr { border: none; border-top: 1px solid var(--border); margin: 0.75em 0; } +.msg-text table { border-collapse: collapse; width: 100%; margin: 0.5em 0; font-size: 13px; } +.msg-text th, .msg-text td { border: 1px solid var(--border); padding: 0.4em 0.7em; text-align: left; } +.msg-text th { background: var(--bg-raised); font-weight: 600; } -.message-text table { border-collapse: collapse; width: 100%; margin: 0.5em 0; font-size: 0.95em; } -.message-text th, .message-text td { border: 1px solid var(--border); padding: 0.35em 0.6em; text-align: left; } -.message-text th { background: var(--bg-tertiary); font-weight: 600; } +.msg-text h1, .msg-text h2, .msg-text h3, .msg-text h4 { margin: 0.75em 0 0.3em; font-weight: 600; } +.msg-text h1 { font-size: 1.4em; } +.msg-text h2 { font-size: 1.2em; } +.msg-text h3 { font-size: 1.05em; } -.message-text img { max-width: 100%; border-radius: 4px; } - -.message-text h1, .message-text h2, .message-text h3, -.message-text h4, .message-text h5, .message-text h6 { - margin: 0.75em 0 0.35em; font-weight: 600; -} -.message-text h1 { font-size: 1.3em; } -.message-text h2 { font-size: 1.15em; } -.message-text h3 { font-size: 1.05em; } - -/* ── Thinking Blocks ─────────────────────── */ +.msg-text a { color: var(--accent); } +.msg-text img { max-width: 100%; border-radius: var(--radius); } +/* Thinking blocks */ .thinking-block { - border: 1px solid rgba(108, 159, 255, 0.15); border-radius: var(--radius); - margin: 0.5rem 0; background: rgba(108, 159, 255, 0.04); + border: 1px solid rgba(108,159,255,0.12); border-radius: var(--radius); + margin: 0.5rem 0; background: rgba(108,159,255,0.03); } .thinking-block summary { - padding: 0.4rem 0.75rem; cursor: pointer; font-size: 0.8rem; - color: var(--text-secondary); user-select: none; + padding: 0.4rem 0.75rem; cursor: pointer; font-size: 12px; + color: var(--text-3); user-select: none; + transition: color var(--transition); } -.thinking-block summary:hover { color: var(--text); } -.thinking-block[open] summary { border-bottom: 1px solid rgba(108, 159, 255, 0.1); } +.thinking-block summary:hover { color: var(--text-2); } +.thinking-block[open] summary { border-bottom: 1px solid rgba(108,159,255,0.08); } .thinking-content { - padding: 0.5rem 0.75rem; font-size: 0.8rem; color: var(--text-secondary); - max-height: 300px; overflow-y: auto; line-height: 1.5; - background: rgba(108, 159, 255, 0.02); + padding: 0.5rem 0.75rem; font-size: 12px; color: var(--text-3); + max-height: 300px; overflow-y: auto; line-height: 1.6; } -.empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: var(--text-secondary); } -.empty-icon { font-size: 3rem; margin-bottom: 1rem; } -.empty-hint { color: var(--text-secondary); font-size: 0.8rem; text-align: center; padding: 1rem; } -.error-hint { color: var(--danger); font-size: 0.8rem; padding: 0.5rem; } -.loading { color: var(--text-secondary); font-size: 0.8rem; padding: 0.5rem; } +/* Empty state */ +.empty-state { + display: flex; flex-direction: column; align-items: center; + justify-content: center; height: 100%; color: var(--text-3); gap: 0.25rem; +} +.empty-logo { font-size: 3rem; margin-bottom: 0.5rem; } +.empty-state h2 { font-size: 1.25rem; font-weight: 600; color: var(--text-2); } +.empty-state p { font-size: 0.85rem; } + +/* Typing indicator */ +.typing-dots { display: flex; gap: 4px; padding: 0.5rem 0; } +.typing-dots span { + width: 6px; height: 6px; border-radius: 50%; background: var(--text-3); + animation: dot-pulse 1.2s infinite; +} +.typing-dots span:nth-child(2) { animation-delay: 0.2s; } +.typing-dots span:nth-child(3) { animation-delay: 0.4s; } +@keyframes dot-pulse { 0%,60%,100% { opacity: 0.4; } 30% { opacity: 1; } } /* ── Input Area ──────────────────────────── */ -.input-area { - border-top: 1px solid var(--border); padding: 0.5rem 1rem 0.75rem; - background: var(--bg-secondary); flex-shrink: 0; +.input-area { padding: 0 1rem 1rem; flex-shrink: 0; } +.input-wrap { + max-width: 768px; margin: 0 auto; + background: var(--bg-surface); border: 1px solid var(--border); + border-radius: var(--radius-lg); padding: 0; + display: flex; align-items: flex-end; + transition: border-color var(--transition); } -.input-bar { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; } -.model-selector { display: flex; align-items: center; gap: 0.5rem; font-size: 0.8rem; } -.model-selector label { color: var(--text-secondary); } -.model-selector select { - background: var(--bg-tertiary); border: 1px solid var(--border); color: var(--text); - padding: 0.25rem 0.5rem; border-radius: 4px; font-size: 0.8rem; max-width: 300px; +.input-wrap:focus-within { border-color: var(--border-light); } + +.input-wrap textarea { + flex: 1; resize: none; background: none; border: none; + color: var(--text); padding: 12px 0 12px 16px; + font-family: var(--font); font-size: 14px; + max-height: 200px; line-height: 1.5; } -.input-row { display: flex; gap: 0.5rem; align-items: flex-end; } -.input-row textarea { - flex: 1; resize: none; background: var(--bg-tertiary); border: 1px solid var(--border); - color: var(--text); padding: 0.5rem 0.75rem; border-radius: var(--radius); - font-family: var(--font); font-size: 0.9rem; max-height: 200px; line-height: 1.5; +.input-wrap textarea:focus { outline: none; } +.input-wrap textarea::placeholder { color: var(--text-3); } + +.input-actions { display: flex; align-items: center; gap: 2px; padding: 6px 8px; } + +.action-btn { + background: none; border: none; color: var(--text-3); cursor: pointer; + padding: 6px; border-radius: var(--radius); + transition: background var(--transition), color var(--transition); + display: flex; align-items: center; justify-content: center; } -.input-row textarea:focus { outline: none; border-color: var(--accent); } -.input-actions { display: flex; gap: 0.25rem; align-items: center; } +.action-btn:hover { background: var(--bg-hover); color: var(--text); } + +.send-btn { color: var(--accent); } +.send-btn:hover { background: var(--accent-dim); color: var(--accent-hover); } +.send-btn:disabled { opacity: 0.3; cursor: not-allowed; } + +.stop-btn { display: none; color: var(--warning); } +.stop-btn.visible { display: flex; } /* ── Buttons ─────────────────────────────── */ button { font-family: var(--font); cursor: pointer; } .btn-primary { - background: var(--accent); color: #fff; border: none; padding: 0.5rem 1rem; - border-radius: var(--radius); font-weight: 600; font-size: 0.85rem; - transition: background 0.15s; + background: var(--accent); color: #fff; border: none; + padding: 8px 16px; border-radius: var(--radius); + font-weight: 500; font-size: 13px; + transition: background var(--transition); } .btn-primary:hover { background: var(--accent-hover); } .btn-primary:disabled { opacity: 0.5; cursor: not-allowed; } .btn-full { width: 100%; } - -.btn-small { font-size: 0.8rem; padding: 0.35rem 0.75rem; } -.btn-danger { background: var(--danger); color: #fff; border: none; border-radius: 4px; } - -.btn-icon { - background: none; border: none; color: var(--text-secondary); font-size: 1rem; - padding: 0.25rem; transition: color 0.15s; +.btn-small { + background: var(--bg-raised); border: 1px solid var(--border); + color: var(--text-2); padding: 6px 12px; border-radius: var(--radius); + font-size: 12px; transition: all var(--transition); } -.btn-icon:hover { color: var(--text); } - -.btn-send { - background: var(--accent); color: #fff; border: none; padding: 0.5rem 1rem; - border-radius: var(--radius); font-weight: 600; font-size: 0.85rem; -} -.btn-send:disabled { opacity: 0.5; } -.btn-stop { display: none; background: var(--warning); color: #000; border: none; padding: 0.5rem 0.75rem; border-radius: var(--radius); font-size: 0.85rem; } -.btn-stop.visible { display: block; } -.btn-regen { background: none; border: 1px solid var(--border); color: var(--text-secondary); border-radius: var(--radius); padding: 0.35rem; } - -/* ── Connection Status ───────────────────── */ - -.connection-status { - display: flex; align-items: center; gap: 0.4rem; font-size: 0.8rem; - color: var(--text-secondary); cursor: pointer; padding: 0.25rem 0.5rem; - border-radius: var(--radius); transition: background 0.15s; -} -.connection-status:hover { background: var(--bg-tertiary); } -.status-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--success); } -.connection-status.online .status-dot { background: var(--success); } - -/* ── Typing Indicator ────────────────────── */ - -.typing-indicator { display: flex; gap: 4px; padding: 0.5rem 0; } -.typing-indicator span { - width: 6px; height: 6px; border-radius: 50%; background: var(--text-secondary); - animation: typing 1.2s infinite; -} -.typing-indicator span:nth-child(2) { animation-delay: 0.2s; } -.typing-indicator span:nth-child(3) { animation-delay: 0.4s; } -@keyframes typing { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-4px); } } - -/* ── Dropdown ────────────────────────────── */ - -.dropdown { position: relative; } -.dropdown-menu { - display: none; position: absolute; top: 100%; right: 0; background: var(--bg-secondary); - border: 1px solid var(--border); border-radius: var(--radius); padding: 0.25rem; - z-index: 100; min-width: 140px; -} -.dropdown-menu.show { display: block; } -.dropdown-menu button { - display: block; width: 100%; text-align: left; background: none; border: none; - color: var(--text); padding: 0.4rem 0.75rem; font-size: 0.8rem; border-radius: 4px; -} -.dropdown-menu button:hover { background: var(--bg-tertiary); } +.btn-small:hover { background: var(--bg-hover); color: var(--text); } +.btn-small.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; } +.btn-danger { background: var(--danger); color: #fff; border: none; border-radius: var(--radius); } /* ── Auth Splash ─────────────────────────── */ .splash { - display: flex; align-items: center; justify-content: center; height: 100vh; - background: var(--bg); + display: flex; align-items: center; justify-content: center; + height: 100vh; background: var(--bg); } .splash-card { - background: var(--bg-secondary); border: 1px solid var(--border); border-radius: 12px; - padding: 2rem; width: 380px; max-width: 90vw; + background: var(--bg-surface); border: 1px solid var(--border); + border-radius: var(--radius-lg); padding: 2rem; + width: 380px; max-width: 90vw; } .splash-brand { text-align: center; margin-bottom: 1.5rem; } .splash-logo { font-size: 3rem; margin-bottom: 0.5rem; } -.splash-brand h1 { font-size: 1.25rem; } -.splash-brand p { color: var(--text-secondary); font-size: 0.85rem; } -.splash-error { color: var(--danger); font-size: 0.8rem; text-align: center; margin-top: 0.5rem; } +.splash-brand h1 { font-size: 1.2rem; font-weight: 600; } +.splash-brand p { color: var(--text-2); font-size: 0.85rem; } +.splash-error { color: var(--danger); font-size: 12px; text-align: center; margin-top: 0.5rem; } -.auth-tabs { display: flex; gap: 0; margin-bottom: 1rem; border-bottom: 1px solid var(--border); } +.auth-tabs { display: flex; margin-bottom: 1rem; border-bottom: 1px solid var(--border); } .auth-tab { - flex: 1; background: none; border: none; color: var(--text-secondary); padding: 0.5rem; - cursor: pointer; border-bottom: 2px solid transparent; font-size: 0.9rem; + flex: 1; background: none; border: none; color: var(--text-3); + padding: 8px; cursor: pointer; font-size: 13px; + border-bottom: 2px solid transparent; + transition: color var(--transition); } .auth-tab.active { color: var(--accent); border-bottom-color: var(--accent); } -.auth-error { color: var(--danger); font-size: 0.8rem; min-height: 1.2em; margin: 0.5rem 0; } +.auth-error { color: var(--danger); font-size: 12px; min-height: 1.2em; margin: 0.5rem 0; } .auth-actions { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 1rem; } /* ── Forms ────────────────────────────────── */ .form-group { margin-bottom: 0.75rem; } -.form-group label { display: block; font-size: 0.8rem; color: var(--text-secondary); margin-bottom: 0.25rem; } +.form-group label { display: block; font-size: 12px; color: var(--text-2); margin-bottom: 4px; font-weight: 500; } .form-group input, .form-group select, .form-group textarea { - width: 100%; background: var(--bg-tertiary); border: 1px solid var(--border); - color: var(--text); padding: 0.5rem 0.75rem; border-radius: var(--radius); - font-family: var(--font); font-size: 0.85rem; + width: 100%; background: var(--bg-raised); border: 1px solid var(--border); + color: var(--text); padding: 8px 12px; border-radius: var(--radius); + font-family: var(--font); font-size: 13px; + transition: border-color var(--transition); } .form-group input:focus, .form-group select:focus, .form-group textarea:focus { outline: none; border-color: var(--accent); } .form-row { display: flex; gap: 0.75rem; } .form-row .form-group { flex: 1; } -.checkbox-label { display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem; cursor: pointer; margin: 0.5rem 0; } +.checkbox-label { display: flex; align-items: center; gap: 8px; font-size: 13px; cursor: pointer; margin: 0.5rem 0; color: var(--text-2); } /* ── Modal ────────────────────────────────── */ .modal-overlay { - position: fixed; inset: 0; background: rgba(0,0,0,0.7); display: none; - align-items: center; justify-content: center; z-index: 1000; + position: fixed; inset: 0; background: rgba(0,0,0,0.6); + display: none; align-items: center; justify-content: center; + z-index: 1000; backdrop-filter: blur(2px); } .modal-overlay.active { display: flex; } .modal { - background: var(--bg-secondary); border-radius: 12px; width: 90%; max-width: 560px; + background: var(--bg-surface); border: 1px solid var(--border); + border-radius: var(--radius-lg); width: 90%; max-width: 520px; max-height: 85vh; display: flex; flex-direction: column; - animation: modalIn 0.2s ease; + animation: modal-in 0.15s ease; } -.modal-wide { max-width: 750px; } -@keyframes modalIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } } +.modal-wide { max-width: 700px; } +@keyframes modal-in { from { opacity: 0; transform: translateY(-8px); } } .modal-header { display: flex; align-items: center; justify-content: space-between; - padding: 1rem 1.25rem; border-bottom: 1px solid var(--border); + padding: 16px 20px; border-bottom: 1px solid var(--border); +} +.modal-header h2 { font-size: 15px; font-weight: 600; } +.modal-close { + background: none; border: none; color: var(--text-3); font-size: 18px; + cursor: pointer; padding: 2px 6px; border-radius: 4px; + transition: color var(--transition); +} +.modal-close:hover { color: var(--text); } +.modal-body { flex: 1; overflow-y: auto; padding: 16px 20px; } +.modal-footer { + padding: 12px 20px; border-top: 1px solid var(--border); + display: flex; justify-content: flex-end; gap: 0.5rem; } -.modal-header h2 { font-size: 1rem; } -.modal-close { background: none; border: none; color: var(--text-secondary); font-size: 1.25rem; cursor: pointer; } -.modal-body { flex: 1; overflow-y: auto; padding: 1rem 1.25rem; } -.modal-footer { padding: 0.75rem 1.25rem; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 0.5rem; } .settings-section { margin-bottom: 1.5rem; padding-bottom: 1rem; border-bottom: 1px solid var(--border); } -.settings-section:last-child { border-bottom: none; } -.settings-section h3 { font-size: 0.9rem; margin-bottom: 0.75rem; color: var(--accent); } - -/* ── Providers ───────────────────────────── */ +.settings-section:last-child { border-bottom: none; margin-bottom: 0; } +.settings-section h3 { font-size: 13px; font-weight: 600; color: var(--text-2); margin-bottom: 12px; text-transform: uppercase; letter-spacing: 0.5px; } +/* Providers */ .provider-row { display: flex; align-items: center; justify-content: space-between; - padding: 0.5rem 0; border-bottom: 1px solid var(--border); + padding: 8px 0; border-bottom: 1px solid var(--border); } -.provider-info { flex: 1; } -.provider-name { font-weight: 600; font-size: 0.85rem; } -.provider-meta { font-size: 0.75rem; color: var(--text-secondary); margin-left: 0.5rem; } -.provider-actions { display: flex; align-items: center; gap: 0.5rem; } -.badge-global { font-size: 0.7rem; color: var(--text-secondary); background: var(--bg-tertiary); padding: 2px 6px; border-radius: 4px; } +.provider-name { font-weight: 500; font-size: 13px; } +.provider-meta { font-size: 11px; color: var(--text-3); margin-left: 8px; } +.provider-actions { display: flex; align-items: center; gap: 8px; } +.badge-global { font-size: 10px; color: var(--text-3); background: var(--bg-raised); padding: 2px 8px; border-radius: 4px; } -/* ── Admin ────────────────────────────────── */ - -.admin-tabs { - display: flex; border-bottom: 1px solid var(--border); padding: 0 1rem; - background: var(--bg-tertiary); -} +/* Admin tabs */ +.admin-tabs { display: flex; border-bottom: 1px solid var(--border); padding: 0 16px; background: var(--bg-raised); } .admin-tab { - padding: 0.5rem 0.75rem; background: none; border: none; color: var(--text-secondary); - cursor: pointer; font-size: 0.8rem; border-bottom: 2px solid transparent; + padding: 8px 12px; background: none; border: none; color: var(--text-3); + cursor: pointer; font-size: 12px; border-bottom: 2px solid transparent; } .admin-tab.active { color: var(--accent); border-bottom-color: var(--accent); } -.admin-user-row { - padding: 0.5rem 0; border-bottom: 1px solid var(--border); font-size: 0.85rem; -} -.admin-user-email { font-size: 0.75rem; color: var(--text-secondary); } -.admin-model-row { - display: flex; align-items: center; gap: 1rem; padding: 0.4rem 0; - border-bottom: 1px solid var(--border); font-size: 0.8rem; -} - -.badge-admin { background: var(--accent); color: #fff; font-size: 0.65rem; padding: 1px 6px; border-radius: 4px; } -.badge-user { background: var(--bg-tertiary); color: var(--text-secondary); font-size: 0.65rem; padding: 1px 6px; border-radius: 4px; } -.badge-inactive { background: var(--danger); color: #fff; font-size: 0.65rem; padding: 1px 6px; border-radius: 4px; } +.admin-user-row { padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 13px; } +.admin-user-email { font-size: 11px; color: var(--text-3); } +.admin-model-row { display: flex; align-items: center; gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--border); font-size: 12px; } +.badge-admin { background: var(--accent); color: #fff; font-size: 10px; padding: 1px 8px; border-radius: 4px; } +.badge-user { background: var(--bg-raised); color: var(--text-3); font-size: 10px; padding: 1px 8px; border-radius: 4px; } +.badge-inactive { background: var(--danger); color: #fff; font-size: 10px; padding: 1px 8px; border-radius: 4px; } +.loading { color: var(--text-3); font-size: 12px; padding: 0.5rem; } +.error-hint { color: var(--danger); font-size: 12px; padding: 0.5rem; } +.empty-hint { color: var(--text-3); font-size: 12px; text-align: center; padding: 1rem; } /* ── Toast ────────────────────────────────── */ .toast-container { position: fixed; bottom: 1rem; left: 50%; transform: translateX(-50%); z-index: 10000; display: flex; flex-direction: column; gap: 0.5rem; } .toast { - background: var(--bg-secondary); border: 1px solid var(--border); border-radius: var(--radius); - padding: 0.5rem 1rem; font-size: 0.85rem; display: flex; align-items: center; gap: 0.5rem; - animation: toastIn 0.3s ease; + background: var(--bg-surface); border: 1px solid var(--border); + border-radius: var(--radius); padding: 8px 16px; font-size: 13px; + display: flex; align-items: center; gap: 8px; + animation: toast-in 0.25s ease; box-shadow: 0 4px 12px rgba(0,0,0,0.3); } .toast.error { border-color: var(--danger); } .toast.warning { border-color: var(--warning); } .toast.success { border-color: var(--success); } -.toast button { background: none; border: none; color: var(--text-secondary); cursor: pointer; } -@keyframes toastIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } +.toast button { background: none; border: none; color: var(--text-3); cursor: pointer; } +@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } } /* ── Debug Modal ─────────────────────────── */ .debug-modal { max-width: 900px; height: 80vh; overflow: hidden; } -.debug-tabs { display: flex; border-bottom: 1px solid var(--border); padding: 0 1rem; background: var(--bg-tertiary); } -.debug-tab { - padding: 0.5rem 0.75rem; background: none; border: none; color: var(--text-secondary); - cursor: pointer; font-size: 0.8rem; border-bottom: 2px solid transparent; -} +.debug-tabs { display: flex; border-bottom: 1px solid var(--border); padding: 0 16px; background: var(--bg-raised); } +.debug-tab { padding: 8px 12px; background: none; border: none; color: var(--text-3); cursor: pointer; font-size: 12px; border-bottom: 2px solid transparent; } .debug-tab.active { color: var(--accent); border-bottom-color: var(--accent); } .debug-modal-body { flex: 1; overflow: hidden; padding: 0 !important; } .debug-tab-content { height: 100%; display: flex; flex-direction: column; } -.debug-toolbar { display: flex; gap: 1rem; padding: 0.4rem 1rem; border-bottom: 1px solid var(--border); font-size: 0.75rem; } -.debug-check { display: flex; align-items: center; gap: 0.3rem; color: var(--text-secondary); cursor: pointer; } -.debug-content { flex: 1; overflow-y: auto; padding: 0.5rem; font-family: var(--mono); font-size: 0.72rem; line-height: 1.5; } -.debug-entry { padding: 1px 0.5rem; border-bottom: 1px solid rgba(128,128,128,0.08); white-space: pre-wrap; word-break: break-all; } -.debug-time { color: var(--text-secondary); opacity: 0.6; font-size: 0.68rem; } +.debug-toolbar { display: flex; gap: 1rem; padding: 6px 12px; border-bottom: 1px solid var(--border); font-size: 11px; } +.debug-check { display: flex; align-items: center; gap: 4px; color: var(--text-3); cursor: pointer; } +.debug-content { flex: 1; overflow-y: auto; padding: 6px; font-family: var(--mono); font-size: 11px; line-height: 1.5; } +.debug-entry { padding: 1px 6px; border-bottom: 1px solid rgba(128,128,128,0.06); white-space: pre-wrap; word-break: break-all; } +.debug-time { color: var(--text-3); opacity: 0.6; font-size: 10px; } .debug-msg { color: var(--text); } -.debug-empty { color: var(--text-secondary); text-align: center; padding: 2rem; } +.debug-empty { color: var(--text-3); text-align: center; padding: 2rem; } .debug-net-entry { border-bottom: 1px solid var(--border); } -.debug-net-entry summary { padding: 0.4rem 0.5rem; cursor: pointer; font-size: 0.75rem; } +.debug-net-entry summary { padding: 6px; cursor: pointer; font-size: 11px; } .debug-net-method { font-weight: bold; color: var(--accent); } .debug-net-url { color: var(--text); word-break: break-all; } -.debug-net-detail { padding: 0.5rem 1rem; font-size: 0.72rem; } -.debug-pre { white-space: pre-wrap; word-break: break-all; max-height: 200px; overflow: auto; padding: 0.5rem; background: rgba(0,0,0,0.2); border-radius: 4px; margin: 0.3rem 0; } -.debug-footer { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 1rem; border-top: 1px solid var(--border); } +.debug-net-detail { padding: 6px 12px; font-size: 11px; } +.debug-pre { white-space: pre-wrap; word-break: break-all; max-height: 200px; overflow: auto; padding: 6px; background: rgba(0,0,0,0.2); border-radius: 4px; margin: 4px 0; } +.debug-footer { display: flex; align-items: center; } /* ── Responsive ──────────────────────────── */ @media (max-width: 768px) { - .sidebar { width: 220px; } - .header-title { font-size: 0.9rem; } -} -@media (max-width: 640px) { - .sidebar { display: none; } + .sidebar { position: fixed; z-index: 100; height: 100%; } + .sidebar.collapsed { width: 0; border: none; } + .msg-inner { padding: 0 1rem; } } diff --git a/src/index.html b/src/index.html index c414102..68cde0e 100644 --- a/src/index.html +++ b/src/index.html @@ -7,65 +7,89 @@ - +
- -