diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 9efd56c..3f6c72e 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -10,9 +10,22 @@ All notable changes to this project will be documented in this file. - Link to openrouter.ai/models for browsing available models - Conditional "Show free models only" filter - only displays when free models exist - Unit tests for `get_models_list_status()` function +- IBM Plex Sans and Plex Mono fonts for improved typography +- CSS design tokens for consistent spacing, shadows, and transitions +- Skip link for keyboard navigation (accessibility) +- ARIA landmarks, roles, and live regions throughout HTML +- Focus-visible states on all interactive elements +- Mobile responsive layout with bottom drawer sidebar +- Hamburger menu toggle for mobile navigation +- Message slide-in animations and modal transitions ### Changed - Model Selection UI now educates users about model list curation +- Primary accent color changed from blue to warm orange (#ea580c) +- Help icons converted to buttons with 44px touch targets (WCAG compliance) +- Sidebar now scrollable to access all sections including RAG +- Settings tabs horizontally scrollable on mobile +- Info box styling aligned with orange accent theme ## 2026-02-02 diff --git a/chat_rag_explorer/static/script.js b/chat_rag_explorer/static/script.js index fb78cb4..ba50c1d 100644 --- a/chat_rag_explorer/static/script.js +++ b/chat_rag_explorer/static/script.js @@ -49,6 +49,42 @@ document.addEventListener('DOMContentLoaded', () => { const submitButton = chatForm.querySelector('button'); // Settings link navigates directly (chat is preserved in sessionStorage) + // Mobile sidebar toggle + const sidebarToggle = document.getElementById('sidebar-toggle'); + const sidebar = document.getElementById('sidebar'); + const sidebarOverlay = document.getElementById('sidebar-overlay'); + + if (sidebarToggle && sidebar) { + sidebarToggle.addEventListener('click', () => { + const isOpen = sidebar.classList.toggle('open'); + sidebarToggle.setAttribute('aria-expanded', isOpen); + if (sidebarOverlay) { + sidebarOverlay.classList.toggle('visible', isOpen); + } + AppLogger.debug('Sidebar toggled', { isOpen }); + }); + + // Close sidebar when clicking overlay + if (sidebarOverlay) { + sidebarOverlay.addEventListener('click', () => { + sidebar.classList.remove('open'); + sidebarToggle.setAttribute('aria-expanded', 'false'); + sidebarOverlay.classList.remove('visible'); + }); + } + + // Close sidebar on escape key + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && sidebar.classList.contains('open')) { + sidebar.classList.remove('open'); + sidebarToggle.setAttribute('aria-expanded', 'false'); + if (sidebarOverlay) { + sidebarOverlay.classList.remove('visible'); + } + } + }); + } + // API key status tracking let apiKeyConfigured = true; // Assume configured until we check const apiKeyBanner = document.getElementById('api-key-banner'); diff --git a/chat_rag_explorer/static/style.css b/chat_rag_explorer/static/style.css index 95d9ff5..a5372b2 100644 --- a/chat_rag_explorer/static/style.css +++ b/chat_rag_explorer/static/style.css @@ -1,13 +1,77 @@ +/* ===== Design Tokens ===== */ +/* Import IBM Plex Sans - distinctive, readable, open-source font */ +@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap'); + :root { - --bg-color: #f4f4f9; + /* Warm neutrals */ + --bg-color: #f8f7f4; --chat-bg: #ffffff; - --primary-color: #007bff; - --user-msg-bg: #007bff; + --surface: #f3f2ef; + --surface-elevated: #ffffff; + + /* Primary accent - Warm Orange */ + --primary-color: #ea580c; + --primary-hover: #c2410c; + --primary-light: #fff7ed; + --primary-dark: #9a3412; + + /* Legacy alias for backwards compatibility */ + --user-msg-bg: var(--primary-color); --user-msg-text: #ffffff; - --bot-msg-bg: #e9ecef; - --bot-msg-text: #333333; + --bot-msg-bg: #f3f2ef; + --bot-msg-text: #1f2937; --input-bg: #ffffff; - --border-color: #ddd; + --border-color: #e5e2db; + + /* Semantic colors */ + --success: #16a34a; + --success-light: #dcfce7; + --error: #dc2626; + --error-light: #fee2e2; + --warning: #d97706; + --warning-light: #fef3c7; + + /* Text hierarchy */ + --text-primary: #1f2937; + --text-secondary: #6b7280; + --text-muted: #9ca3af; + + /* Typography scale */ + --font-sans: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + --font-mono: 'IBM Plex Mono', 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace; + + /* Font sizes */ + --text-xs: 0.75rem; + --text-sm: 0.875rem; + --text-base: 1rem; + --text-lg: 1.125rem; + --text-xl: 1.25rem; + + /* Spacing */ + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-5: 1.25rem; + --space-6: 1.5rem; + --space-8: 2rem; + + /* Border radius */ + --radius-sm: 0.375rem; + --radius-md: 0.5rem; + --radius-lg: 0.75rem; + --radius-xl: 1rem; + --radius-full: 9999px; + + /* Shadows */ + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); + --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04); + --shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.04); + + /* Transitions */ + --transition-fast: 150ms ease; + --transition-normal: 200ms ease; + --transition-slow: 300ms ease; } * { @@ -16,11 +80,65 @@ padding: 0; } +/* ===== Accessibility ===== */ + +/* Skip link - hidden until focused */ +.skip-link { + position: absolute; + top: -100px; + left: 0; + padding: var(--space-3) var(--space-4); + background: var(--primary-color); + color: white; + text-decoration: none; + font-weight: 600; + z-index: 10000; + border-radius: 0 0 var(--radius-md) 0; + transition: top var(--transition-fast); +} + +.skip-link:focus { + top: 0; + outline: 2px solid var(--primary-dark); + outline-offset: 2px; +} + +.skip-link:not(:focus) { + clip: rect(0, 0, 0, 0); + overflow: hidden; +} + +/* Visually hidden class for screen readers */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* Global focus-visible styles */ +:focus-visible { + outline: 2px solid var(--primary-color); + outline-offset: 2px; +} + +/* Remove default focus outline in favor of focus-visible */ +:focus:not(:focus-visible) { + outline: none; +} + body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + font-family: var(--font-sans); background-color: var(--bg-color); + color: var(--text-primary); height: 100vh; overflow: hidden; + line-height: 1.6; } .main-layout { @@ -36,32 +154,34 @@ body { display: flex; flex-direction: column; height: 100%; - box-shadow: 0 0 10px rgba(0,0,0,0.1); + box-shadow: var(--shadow-lg); max-width: none; /* Occupy remaining space */ } .sidebar { width: 300px; - background-color: #f8f9fa; + background-color: var(--surface); border-left: 1px solid var(--border-color); - padding: 1.5rem; + padding: var(--space-6); display: flex; flex-direction: column; - gap: 2rem; - overflow: visible; + gap: var(--space-6); + overflow-y: auto; + overflow-x: hidden; } .sidebar h3 { - font-size: 0.9rem; + font-size: var(--text-xs); + font-weight: 600; text-transform: uppercase; - color: #666; - margin-bottom: 1rem; + color: var(--text-secondary); + margin-bottom: var(--space-4); letter-spacing: 0.05rem; } .sidebar-section { - border-bottom: 1px solid #eee; - padding-bottom: 1.5rem; + border-bottom: 1px solid var(--border-color); + padding-bottom: var(--space-6); } .sidebar-section:last-child { @@ -76,13 +196,13 @@ body { } .metric .label { - color: #555; + color: var(--text-secondary); } .metric .value { font-weight: 600; - color: #222; - font-family: "SFMono-Regular", Consolas, monospace; + color: var(--text-primary); + font-family: var(--font-mono); } .metric-link { @@ -96,29 +216,32 @@ body { .value-link { text-decoration: none; - color: #222; + color: var(--text-primary); + transition: color var(--transition-fast); } .value-link:hover { + color: var(--primary-color); text-decoration: underline; } .small { - font-size: 0.85rem; - color: #888; + font-size: var(--text-sm); + color: var(--text-muted); line-height: 1.4; } header { - padding: 1rem; + padding: var(--space-4); border-bottom: 1px solid var(--border-color); text-align: center; - background-color: #fff; + background-color: var(--surface-elevated); } header h1 { - font-size: 1.2rem; - color: #333; + font-size: var(--text-lg); + font-weight: 600; + color: var(--text-primary); } /* API Key Warning Banner */ @@ -217,10 +340,22 @@ header h1 { .message { max-width: 80%; - padding: 0.8rem 1rem; - border-radius: 1rem; - line-height: 1.5; + padding: 0.875rem 1.125rem; + border-radius: var(--radius-lg); + line-height: 1.6; word-wrap: break-word; + animation: messageSlideIn 0.25s ease-out; +} + +@keyframes messageSlideIn { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } } /* Markdown Styling */ @@ -250,11 +385,11 @@ header h1 { } .message .content code { - font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; + font-family: var(--font-mono); font-size: 0.9em; background-color: rgba(0, 0, 0, 0.05); padding: 0.2rem 0.4rem; - border-radius: 0.2rem; + border-radius: var(--radius-sm); } .message .content pre code { @@ -279,16 +414,19 @@ header h1 { .message.user { align-self: flex-end; - background-color: var(--user-msg-bg); + background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-hover) 100%); color: var(--user-msg-text); - border-bottom-right-radius: 0.2rem; + border-bottom-right-radius: var(--radius-sm); + box-shadow: var(--shadow-sm); } .message.bot { align-self: flex-start; background-color: var(--bot-msg-bg); color: var(--bot-msg-text); - border-bottom-left-radius: 0.2rem; + border-bottom-left-radius: var(--radius-sm); + box-shadow: var(--shadow-md); + border: 1px solid var(--border-color); } .input-area { @@ -304,15 +442,18 @@ header h1 { #message-input { flex: 1; - padding: 0.8rem; + padding: 0.875rem 1rem; border: 1px solid var(--border-color); - border-radius: 0.5rem; - font-size: 1rem; + border-radius: var(--radius-md); + font-size: var(--text-base); + font-family: var(--font-sans); outline: none; + transition: border-color var(--transition-fast), box-shadow var(--transition-fast); } #message-input:focus { border-color: var(--primary-color); + box-shadow: 0 0 0 3px rgba(234, 88, 12, 0.1); } button { @@ -320,14 +461,20 @@ button { background-color: var(--primary-color); color: white; border: none; - border-radius: 0.5rem; - font-size: 1rem; + border-radius: var(--radius-md); + font-size: var(--text-base); + font-weight: 500; cursor: pointer; - transition: background-color 0.2s; + transition: background-color var(--transition-fast), transform var(--transition-fast), box-shadow var(--transition-fast); +} + +button:hover:not(:disabled) { + transform: translateY(-1px); + box-shadow: var(--shadow-md); } button:hover { - background-color: #0056b3; + background-color: var(--primary-hover); } button:disabled { @@ -335,6 +482,11 @@ button:disabled { cursor: not-allowed; } +button:focus-visible { + outline: 2px solid var(--primary-dark); + outline-offset: 2px; +} + /* Navigation */ .header-content { display: flex; @@ -368,26 +520,31 @@ button:disabled { display: inline-flex; align-items: center; justify-content: center; - width: 3.375rem; - height: 3.375rem; - background: #f5f5f5; - border: 1px solid #ddd; - border-radius: 0.5rem; - color: #555; - font-size: 1.875rem; + width: 2.75rem; + height: 2.75rem; + background: var(--surface); + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + color: var(--text-secondary); + font-size: 1.5rem; padding: 0; cursor: pointer; - transition: all 0.2s; + transition: all var(--transition-fast); line-height: 1; text-decoration: none; } .icon-btn:hover { color: var(--primary-color); - background: #e8f4ff; + background: var(--primary-light); border-color: var(--primary-color); } +.icon-btn:focus-visible { + outline: 2px solid var(--primary-color); + outline-offset: 2px; +} + /* Settings Page */ .settings-layout { display: flex; @@ -403,8 +560,8 @@ button:disabled { width: 100%; max-width: 800px; background-color: var(--chat-bg); - border-radius: 0.5rem; - box-shadow: 0 0 10px rgba(0,0,0,0.1); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); height: fit-content; } @@ -492,7 +649,12 @@ button:disabled { .select-wrapper select:focus { outline: none; border-color: var(--primary-color); - box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1); + box-shadow: 0 0 0 3px rgba(234, 88, 12, 0.15); +} + +.select-wrapper select:focus-visible { + outline: 2px solid var(--primary-color); + outline-offset: -2px; } .select-wrapper select:disabled { @@ -519,16 +681,18 @@ button:disabled { } .model-details { - margin-top: 1rem; - padding: 1rem; - background-color: #f8f9fa; - border-radius: 0.5rem; - font-size: 0.9rem; + margin-top: var(--space-4); + padding: var(--space-4); + background-color: var(--surface); + border-radius: var(--radius-md); + border: 1px solid var(--border-color); + font-size: var(--text-sm); display: none; } .model-details.visible { display: block; + animation: fadeSlideIn 0.2s ease-out; } .model-details .detail-row { @@ -547,8 +711,8 @@ button:disabled { .model-details .detail-value { font-weight: 500; - color: #333; - font-family: "SFMono-Regular", Consolas, monospace; + color: var(--text-primary); + font-family: var(--font-mono); } .model-details .description { @@ -602,19 +766,38 @@ button:disabled { z-index: 1000; align-items: center; justify-content: center; + backdrop-filter: blur(2px); } .modal-overlay.visible { display: flex; + animation: overlayFadeIn 0.2s ease-out; +} + +@keyframes overlayFadeIn { + from { opacity: 0; } + to { opacity: 1; } } .modal { - background: #fff; - padding: 1.5rem 2rem; - border-radius: 0.5rem; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); + background: var(--surface-elevated); + padding: var(--space-6) var(--space-8); + border-radius: var(--radius-lg); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18), 0 2px 8px rgba(0, 0, 0, 0.08); max-width: 400px; width: 90%; + animation: modalSlideIn 0.2s ease-out; +} + +@keyframes modalSlideIn { + from { + opacity: 0; + transform: scale(0.95) translateY(-10px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } } .modal-message { @@ -654,7 +837,7 @@ button:disabled { } .modal-btn-ok:hover { - background-color: #0056b3; + background-color: var(--primary-hover); } /* Parameter Controls */ @@ -680,10 +863,10 @@ button:disabled { } .param-value { - font-family: "SFMono-Regular", Consolas, monospace; - font-size: 0.85rem; + font-family: var(--font-mono); + font-size: var(--text-sm); font-weight: 600; - color: #333; + color: var(--text-primary); min-width: 2.5rem; text-align: right; } @@ -711,7 +894,7 @@ button:disabled { } .param-control input[type="range"]::-webkit-slider-thumb:hover { - background: #0056b3; + background: var(--primary-hover); } .param-control input[type="range"]::-moz-range-thumb { @@ -784,8 +967,13 @@ button:disabled { .tab-btn.active { color: #fff; - background: linear-gradient(135deg, var(--primary-color) 0%, #0056b3 100%); - box-shadow: 0 2px 8px rgba(0, 123, 255, 0.35); + background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%); + box-shadow: 0 2px 8px rgba(234, 88, 12, 0.35); +} + +.tab-btn:focus-visible { + outline: 2px solid var(--primary-color); + outline-offset: 2px; } .tab-panels { @@ -812,19 +1000,21 @@ button:disabled { } .toolbar-btn { - padding: 0.75rem 1rem; - font-size: 0.9rem; - border-radius: 0.5rem; + padding: var(--space-3) var(--space-4); + font-size: var(--text-sm); + font-weight: 500; + border-radius: var(--radius-md); border: 1px solid var(--border-color); - background: #fff; - color: #333; + background: var(--surface-elevated); + color: var(--text-primary); cursor: pointer; - transition: all 0.2s; + transition: all var(--transition-fast); } .toolbar-btn:hover { - background: #f5f5f5; - border-color: #bbb; + background: var(--surface); + border-color: var(--text-muted); + transform: translateY(-1px); } .toolbar-btn.danger { @@ -854,26 +1044,36 @@ button:disabled { .text-input:focus { outline: none; border-color: var(--primary-color); - box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1); + box-shadow: 0 0 0 3px rgba(234, 88, 12, 0.15); +} + +.text-input:focus-visible { + outline: 2px solid var(--primary-color); + outline-offset: -2px; } .prompt-textarea { width: 100%; min-height: 200px; - padding: 0.75rem; - font-size: 0.95rem; - font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; + padding: var(--space-3); + font-size: var(--text-sm); + font-family: var(--font-mono); border: 1px solid var(--border-color); - border-radius: 0.5rem; - background-color: #fff; + border-radius: var(--radius-md); + background-color: var(--surface-elevated); resize: vertical; - line-height: 1.5; + line-height: 1.6; } .prompt-textarea:focus { outline: none; border-color: var(--primary-color); - box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1); + box-shadow: 0 0 0 3px rgba(234, 88, 12, 0.15); +} + +.prompt-textarea:focus-visible { + outline: 2px solid var(--primary-color); + outline-offset: -2px; } .save-btn { @@ -888,7 +1088,7 @@ button:disabled { } .save-btn:hover:not(:disabled) { - background-color: #0056b3; + background-color: var(--primary-hover); } .save-btn:disabled { @@ -984,11 +1184,11 @@ button:disabled { } .api-key-status code { - font-family: "SFMono-Regular", Consolas, monospace; - background: #e9ecef; + font-family: var(--font-mono); + background: var(--surface); padding: 0.25rem 0.5rem; - border-radius: 0.25rem; - font-size: 0.85rem; + border-radius: var(--radius-sm); + font-size: var(--text-sm); } .field-hint { @@ -1159,8 +1359,8 @@ button:disabled { .details-meta-value { font-weight: 600; - font-family: "SFMono-Regular", Consolas, monospace; - color: #333; + font-family: var(--font-mono); + color: var(--text-primary); } .details-section { @@ -1237,7 +1437,7 @@ button:disabled { margin-left: auto; font-size: 0.7rem; color: #718096; - font-family: "SFMono-Regular", Consolas, monospace; + font-family: var(--font-mono); } .details-rag-meta { @@ -1282,7 +1482,7 @@ button:disabled { .details-rag-settings strong { color: #2d3748; - font-family: "SFMono-Regular", Consolas, monospace; + font-family: var(--font-mono); } /* RAG callout for filtered/missing results in details modal */ @@ -1321,11 +1521,11 @@ button:disabled { .details-message-content { padding: 0.85rem; - font-size: 0.875rem; + font-size: var(--text-sm); line-height: 1.55; white-space: pre-wrap; word-wrap: break-word; - font-family: "SFMono-Regular", Consolas, monospace; + font-family: var(--font-mono); max-height: 200px; overflow-y: auto; } @@ -1533,10 +1733,10 @@ button:disabled { } .sample-record-id { - font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; - font-size: 0.8rem; - color: #666; - margin-bottom: 0.5rem; + font-family: var(--font-mono); + font-size: var(--text-xs); + color: var(--text-secondary); + margin-bottom: var(--space-2); word-break: break-all; } @@ -1602,30 +1802,59 @@ button:disabled { color: #dc3545; } -/* Help Icons */ +/* Help Icons - 44px minimum touch target per WCAG */ .help-icon { display: inline-flex; align-items: center; justify-content: center; - width: 1rem; - height: 1rem; - font-size: 0.7rem; + width: 1.25rem; + height: 1.25rem; + /* Touch target achieved via padding/margin */ + min-width: 44px; + min-height: 44px; + margin: -12px; + padding: 12px; + font-size: var(--text-xs); font-weight: 600; - color: #888; - background: #f0f0f0; - border: 1px solid #ddd; + color: var(--text-muted); + background: transparent; + border: none; border-radius: 50%; cursor: help; - transition: all 0.2s; + transition: color var(--transition-fast), background-color var(--transition-fast); text-decoration: none; - margin-right: 0.35rem; flex-shrink: 0; + position: relative; +} + +.help-icon::before { + content: ''; + position: absolute; + width: 1.25rem; + height: 1.25rem; + background: var(--surface); + border: 1px solid var(--border-color); + border-radius: 50%; + z-index: -1; + transition: all var(--transition-fast); } .help-icon:hover { color: var(--primary-color); +} + +.help-icon:hover::before { border-color: var(--primary-color); - background: #e8f4ff; + background: var(--primary-light); +} + +.help-icon:focus-visible { + outline: none; +} + +.help-icon:focus-visible::before { + outline: 2px solid var(--primary-color); + outline-offset: 2px; } /* Tooltip container */ @@ -1641,18 +1870,18 @@ button:disabled { position: absolute; bottom: calc(100% + 8px); left: 0; - background: #333; + background: var(--text-primary); color: #fff; - padding: 0.6rem 0.8rem; - border-radius: 0.375rem; - font-size: 0.8rem; - line-height: 1.4; + padding: var(--space-3) var(--space-4); + border-radius: var(--radius-md); + font-size: var(--text-xs); + line-height: 1.5; white-space: normal; width: 230px; text-align: left; z-index: 1000; - box-shadow: 0 2px 8px rgba(0,0,0,0.2); - transition: opacity 0.2s, visibility 0.2s; + box-shadow: var(--shadow-lg); + transition: opacity var(--transition-fast), visibility var(--transition-fast); } .tooltip-content::after { @@ -1661,7 +1890,7 @@ button:disabled { top: 100%; left: 10px; border: 6px solid transparent; - border-top-color: #333; + border-top-color: var(--text-primary); } .tooltip-wrapper:hover .tooltip-content { @@ -1757,12 +1986,12 @@ button:disabled { } #error-details { - background-color: #f8f9fa; - border: 1px solid #dee2e6; - border-radius: 0.375rem; - padding: 1rem; - font-size: 0.75rem; - font-family: "SFMono-Regular", Consolas, monospace; + background-color: var(--surface); + border: 1px solid var(--border-color); + border-radius: var(--radius-sm); + padding: var(--space-4); + font-size: var(--text-xs); + font-family: var(--font-mono); overflow-x: auto; white-space: pre-wrap; word-break: break-word; @@ -1848,9 +2077,9 @@ button:disabled { } .wizard-step.step-active .step-number { - background: linear-gradient(135deg, var(--primary-color) 0%, #0056b3 100%); + background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%); color: #fff; - box-shadow: 0 2px 8px rgba(0, 123, 255, 0.4); + box-shadow: 0 2px 8px rgba(234, 88, 12, 0.4); } .step-title { @@ -2069,9 +2298,9 @@ button:disabled { } .test-connection-btn:hover { - background: linear-gradient(135deg, var(--primary-color) 0%, #0056b3 100%); + background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%); color: #fff; - box-shadow: 0 2px 8px rgba(0, 123, 255, 0.3); + box-shadow: 0 2px 8px rgba(234, 88, 12, 0.3); } .test-connection-btn:disabled { @@ -2120,11 +2349,11 @@ button:disabled { } .save-btn-enhanced:not(:disabled) { - background: linear-gradient(135deg, var(--primary-color) 0%, #0056b3 100%); + background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%); } .save-btn-enhanced:not(:disabled):hover { - box-shadow: 0 4px 12px rgba(0, 123, 255, 0.4); + box-shadow: 0 4px 12px rgba(234, 88, 12, 0.4); transform: translateY(-1px); } @@ -2447,11 +2676,11 @@ button:disabled { } .help-message code { - background: #f6f8fa; + background: var(--surface); padding: 2px 6px; - border-radius: 3px; - font-family: 'Monaco', 'Consolas', monospace; - font-size: 0.85rem; + border-radius: var(--radius-sm); + font-family: var(--font-mono); + font-size: var(--text-sm); } .help-message ol { @@ -2511,25 +2740,33 @@ button:disabled { .info-box-content code { background: rgba(0, 0, 0, 0.08); padding: 2px 6px; - border-radius: 3px; - font-family: 'SF Mono', 'Monaco', 'Consolas', monospace; + border-radius: var(--radius-sm); + font-family: var(--font-mono); font-size: 0.85em; } /* Active state - when .models_list exists and is filtering */ .info-box-active { - background: #e8f4fd; - border: 1px solid #b8daff; - color: #004085; + background: var(--primary-light); + border: 1px solid rgba(234, 88, 12, 0.3); + color: var(--primary-dark); } .info-box-active .info-icon-circle { - background: #004085; + background: var(--primary-color); color: #fff; } .info-box-active .info-box-content code { - background: rgba(0, 64, 133, 0.12); + background: rgba(234, 88, 12, 0.12); +} + +.info-box-active .info-box-content a { + color: var(--primary-color); +} + +.info-box-active .info-box-content a:hover { + color: var(--primary-hover); } /* Neutral state - when .models_list does not exist */ @@ -2547,3 +2784,244 @@ button:disabled { .info-box-neutral .info-box-content code { background: rgba(0, 0, 0, 0.06); } + +/* ===== Responsive Layout ===== */ + +/* Sidebar toggle button - hidden on desktop */ +.sidebar-toggle { + display: none; +} + +/* Mobile-first: < 768px */ +@media (max-width: 767px) { + /* Main layout becomes single column */ + .main-layout { + flex-direction: column; + position: relative; + } + + /* App container takes full width */ + .app-container, + main.app-container { + width: 100%; + height: 100vh; + } + + /* Show sidebar toggle button */ + .sidebar-toggle { + display: flex; + position: relative; + } + + .hamburger-icon { + font-size: 1.25rem; + } + + /* Sidebar becomes a bottom drawer */ + .sidebar { + position: fixed; + bottom: 0; + left: 0; + right: 0; + width: 100%; + max-height: 70vh; + background-color: var(--surface-elevated); + border-left: none; + border-top: 1px solid var(--border-color); + box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.15); + border-radius: var(--radius-lg) var(--radius-lg) 0 0; + transform: translateY(100%); + transition: transform var(--transition-slow); + z-index: 100; + overflow-y: auto; + padding: var(--space-4); + gap: var(--space-4); + } + + .sidebar.open { + transform: translateY(0); + } + + /* Sidebar overlay when open */ + .sidebar-overlay { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.3); + z-index: 99; + } + + .sidebar-overlay.visible { + display: block; + } + + /* Header adjustments */ + .header-content { + padding: 0 var(--space-2); + } + + .header-content h1 { + font-size: var(--text-base); + } + + /* Chat area adjustments */ + .chat-history { + padding: var(--space-3); + } + + .message { + max-width: 90%; + } + + /* Input area sticky at bottom */ + .input-area { + padding: var(--space-3); + position: sticky; + bottom: 0; + background: var(--surface-elevated); + } + + #message-input { + font-size: 16px; /* Prevent iOS zoom */ + } + + /* Settings page adjustments */ + .settings-layout { + padding: var(--space-3); + } + + .settings-container { + border-radius: var(--radius-md); + } + + .settings-container header { + padding: var(--space-3) var(--space-4); + } + + .settings-content { + padding: var(--space-4); + } + + /* Settings tabs become scrollable pills */ + .settings-tabs { + flex-wrap: nowrap; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + scrollbar-width: none; + gap: var(--space-2); + padding: var(--space-2); + } + + .settings-tabs::-webkit-scrollbar { + display: none; + } + + .tab-btn { + flex: 0 0 auto; + white-space: nowrap; + padding: var(--space-3) var(--space-4); + font-size: var(--text-sm); + } + + /* Wizard step adjustments */ + .wizard-step { + padding-left: var(--space-8); + margin-left: var(--space-3); + } + + .step-number { + left: calc(-1 * var(--space-8)); + width: 1.75rem; + height: 1.75rem; + font-size: var(--text-xs); + } + + .step-content { + padding: var(--space-4); + } + + /* Form elements */ + .prompt-toolbar { + flex-direction: column; + gap: var(--space-3); + } + + .prompt-toolbar .select-wrapper { + width: 100%; + } + + .toolbar-btn { + width: 100%; + } + + /* RAG mode radios stack better */ + .mode-radio-group { + gap: var(--space-3); + } + + /* Modal adjustments */ + .modal { + width: 95%; + max-width: none; + margin: var(--space-4); + } + + .details-modal { + max-height: 90vh; + } + + /* API key banner */ + .api-key-banner { + padding: var(--space-3); + } + + .banner-content { + flex-direction: column; + gap: var(--space-2); + } + + .banner-icon { + font-size: 1.5rem; + } +} + +/* Tablet: 768px - 1024px */ +@media (min-width: 768px) and (max-width: 1024px) { + /* Sidebar narrower */ + .sidebar { + width: 260px; + padding: var(--space-4); + gap: var(--space-6); + } + + .sidebar h3 { + font-size: 0.7rem; + } + + .metric { + font-size: var(--text-sm); + } + + /* Settings adjustments */ + .settings-container { + max-width: 700px; + } +} + +/* Large screens: > 1200px */ +@media (min-width: 1200px) { + .sidebar { + width: 320px; + } + + .settings-container { + max-width: 900px; + } + + .message { + max-width: 70%; + } +} diff --git a/chat_rag_explorer/templates/index.html b/chat_rag_explorer/templates/index.html index 06a2f63..07399c7 100644 --- a/chat_rag_explorer/templates/index.html +++ b/chat_rag_explorer/templates/index.html @@ -7,14 +7,20 @@
+ + Skip to chat + -