Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>AI Chat Hub</title> | |
| <link | |
| href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" | |
| rel="stylesheet"> | |
| <style> | |
| :root { | |
| --bg-primary: #0a0a0f; | |
| --bg-secondary: #12121a; | |
| --bg-tertiary: #1a1a24; | |
| --bg-hover: #22222e; | |
| --border-color: #2a2a3a; | |
| --text-primary: #f0f0f5; | |
| --text-secondary: #8888a0; | |
| --text-muted: #555566; | |
| --accent-primary: #6366f1; | |
| --accent-secondary: #8b5cf6; | |
| --accent-gradient: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #a855f7 100%); | |
| --success: #10b981; | |
| --error: #ef4444; | |
| --warning: #f59e0b; | |
| --shadow-lg: 0 25px 50px -12px rgba(0, 0, 0, 0.5); | |
| --shadow-md: 0 10px 30px -5px rgba(0, 0, 0, 0.3); | |
| --radius-sm: 8px; | |
| --radius-md: 12px; | |
| --radius-lg: 16px; | |
| --radius-xl: 24px; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; | |
| background: var(--bg-primary); | |
| color: var(--text-primary); | |
| min-height: 100vh; | |
| overflow: hidden; | |
| } | |
| /* Animated Background */ | |
| .bg-pattern { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| pointer-events: none; | |
| z-index: 0; | |
| opacity: 0.4; | |
| background: | |
| radial-gradient(circle at 20% 20%, rgba(99, 102, 241, 0.15) 0%, transparent 50%), | |
| radial-gradient(circle at 80% 80%, rgba(139, 92, 246, 0.15) 0%, transparent 50%), | |
| radial-gradient(circle at 50% 50%, rgba(168, 85, 247, 0.08) 0%, transparent 70%); | |
| } | |
| .app-container { | |
| display: flex; | |
| height: 100vh; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| /* Sidebar */ | |
| .sidebar { | |
| width: 280px; | |
| background: var(--bg-secondary); | |
| border-right: 1px solid var(--border-color); | |
| display: flex; | |
| flex-direction: column; | |
| transition: transform 0.3s ease; | |
| } | |
| .sidebar-header { | |
| padding: 20px; | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| font-size: 1.25rem; | |
| font-weight: 700; | |
| background: var(--accent-gradient); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .logo-icon { | |
| width: 36px; | |
| height: 36px; | |
| background: var(--accent-gradient); | |
| border-radius: var(--radius-sm); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 1.2rem; | |
| -webkit-text-fill-color: white; | |
| } | |
| .sidebar-nav { | |
| padding: 16px 12px; | |
| flex: 1; | |
| overflow-y: auto; | |
| } | |
| .nav-section { | |
| margin-bottom: 24px; | |
| } | |
| .nav-section-title { | |
| font-size: 0.7rem; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| letter-spacing: 0.1em; | |
| color: var(--text-muted); | |
| padding: 0 12px; | |
| margin-bottom: 8px; | |
| } | |
| .nav-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| padding: 12px; | |
| border-radius: var(--radius-md); | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| color: var(--text-secondary); | |
| font-size: 0.9rem; | |
| font-weight: 500; | |
| } | |
| .nav-item:hover { | |
| background: var(--bg-hover); | |
| color: var(--text-primary); | |
| } | |
| .nav-item.active { | |
| background: rgba(99, 102, 241, 0.15); | |
| color: var(--accent-primary); | |
| } | |
| .nav-item svg { | |
| width: 20px; | |
| height: 20px; | |
| flex-shrink: 0; | |
| } | |
| .nav-item-badge { | |
| margin-left: auto; | |
| background: var(--accent-primary); | |
| color: white; | |
| font-size: 0.7rem; | |
| padding: 2px 8px; | |
| border-radius: 10px; | |
| font-weight: 600; | |
| } | |
| /* Main Content */ | |
| .main-content { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| min-width: 0; | |
| } | |
| /* Header */ | |
| .header { | |
| height: 64px; | |
| background: var(--bg-secondary); | |
| border-bottom: 1px solid var(--border-color); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 0 24px; | |
| } | |
| .header-left { | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| } | |
| .model-selector { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| padding: 8px 16px; | |
| background: var(--bg-tertiary); | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--radius-md); | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| } | |
| .model-selector:hover { | |
| border-color: var(--accent-primary); | |
| } | |
| .model-selector-icon { | |
| width: 24px; | |
| height: 24px; | |
| border-radius: 6px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 0.8rem; | |
| font-weight: 700; | |
| color: white; | |
| } | |
| .model-selector-text { | |
| font-weight: 500; | |
| font-size: 0.9rem; | |
| } | |
| .model-selector-arrow { | |
| color: var(--text-muted); | |
| transition: transform 0.2s ease; | |
| } | |
| .header-right { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .header-btn { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: var(--radius-sm); | |
| background: var(--bg-tertiary); | |
| border: 1px solid var(--border-color); | |
| color: var(--text-secondary); | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: all 0.2s ease; | |
| } | |
| .header-btn:hover { | |
| background: var(--bg-hover); | |
| color: var(--text-primary); | |
| border-color: var(--accent-primary); | |
| } | |
| /* Chat Container */ | |
| .chat-container { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| position: relative; | |
| } | |
| .chat-messages { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 24px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 24px; | |
| } | |
| .chat-messages::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| .chat-messages::-webkit-scrollbar-track { | |
| background: transparent; | |
| } | |
| .chat-messages::-webkit-scrollbar-thumb { | |
| background: var(--border-color); | |
| border-radius: 3px; | |
| } | |
| /* Messages */ | |
| .message { | |
| display: flex; | |
| gap: 16px; | |
| max-width: 85%; | |
| animation: messageIn 0.3s ease; | |
| } | |
| @keyframes messageIn { | |
| from { | |
| opacity: 0; | |
| transform: translateY(10px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .message.user { | |
| flex-direction: row-reverse; | |
| align-self: flex-end; | |
| } | |
| .message-avatar { | |
| width: 36px; | |
| height: 36px; | |
| border-radius: var(--radius-sm); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 1rem; | |
| flex-shrink: 0; | |
| } | |
| .message.user .message-avatar { | |
| background: var(--accent-gradient); | |
| } | |
| .message.assistant .message-avatar { | |
| background: var(--bg-tertiary); | |
| border: 1px solid var(--border-color); | |
| } | |
| .message-content { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .message-header { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| margin-bottom: 8px; | |
| } | |
| .message.user .message-header { | |
| flex-direction: row-reverse; | |
| } | |
| .message-name { | |
| font-weight: 600; | |
| font-size: 0.9rem; | |
| } | |
| .message-time { | |
| font-size: 0.75rem; | |
| color: var(--text-muted); | |
| } | |
| .message-text { | |
| background: var(--bg-tertiary); | |
| padding: 16px; | |
| border-radius: var(--radius-md); | |
| border: 1px solid var(--border-color); | |
| line-height: 1.6; | |
| font-size: 0.95rem; | |
| white-space: pre-wrap; | |
| word-break: break-word; | |
| } | |
| .message.user .message-text { | |
| background: rgba(99, 102, 241, 0.15); | |
| border-color: rgba(99, 102, 241, 0.3); | |
| } | |
| .message-text code { | |
| font-family: 'JetBrains Mono', monospace; | |
| background: var(--bg-hover); | |
| padding: 2px 6px; | |
| border-radius: 4px; | |
| font-size: 0.85rem; | |
| } | |
| .message-text pre { | |
| background: var(--bg-hover); | |
| padding: 16px; | |
| border-radius: var(--radius-sm); | |
| overflow-x: auto; | |
| margin-top: 8px; | |
| } | |
| .message-text pre code { | |
| background: none; | |
| padding: 0; | |
| } | |
| /* Typing Indicator */ | |
| .typing-indicator { | |
| display: flex; | |
| gap: 4px; | |
| padding: 16px; | |
| background: var(--bg-tertiary); | |
| border-radius: var(--radius-md); | |
| border: 1px solid var(--border-color); | |
| width: fit-content; | |
| margin: 0 24px; | |
| } | |
| .typing-dot { | |
| width: 8px; | |
| height: 8px; | |
| background: var(--text-muted); | |
| border-radius: 50%; | |
| animation: typing 1.4s infinite; | |
| } | |
| .typing-dot:nth-child(2) { | |
| animation-delay: 0.2s; | |
| } | |
| .typing-dot:nth-child(3) { | |
| animation-delay: 0.4s; | |
| } | |
| @keyframes typing { | |
| 0%, | |
| 60%, | |
| 100% { | |
| transform: translateY(0); | |
| opacity: 0.4; | |
| } | |
| 30% { | |
| transform: translateY(-8px); | |
| opacity: 1; | |
| } | |
| } | |
| /* Chat Input */ | |
| .chat-input-container { | |
| padding: 16px 24px 24px; | |
| background: var(--bg-secondary); | |
| border-top: 1px solid var(--border-color); | |
| } | |
| .chat-input-wrapper { | |
| background: var(--bg-tertiary); | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--radius-lg); | |
| padding: 12px 16px; | |
| display: flex; | |
| align-items: flex-end; | |
| gap: 12px; | |
| transition: all 0.2s ease; | |
| } | |
| .chat-input-wrapper:focus-within { | |
| border-color: var(--accent-primary); | |
| box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15); | |
| } | |
| .chat-input { | |
| flex: 1; | |
| background: transparent; | |
| border: none; | |
| color: var(--text-primary); | |
| font-size: 0.95rem; | |
| font-family: inherit; | |
| resize: none; | |
| max-height: 150px; | |
| line-height: 1.5; | |
| outline: none; | |
| } | |
| .chat-input::placeholder { | |
| color: var(--text-muted); | |
| } | |
| .send-btn { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: var(--radius-sm); | |
| background: var(--accent-gradient); | |
| border: none; | |
| color: white; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: all 0.2s ease; | |
| flex-shrink: 0; | |
| } | |
| .send-btn:hover { | |
| transform: scale(1.05); | |
| box-shadow: 0 4px 15px rgba(99, 102, 241, 0.4); | |
| } | |
| .send-btn:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| transform: none; | |
| box-shadow: none; | |
| } | |
| /* Panels */ | |
| .panel { | |
| position: fixed; | |
| top: 0; | |
| right: -400px; | |
| width: 400px; | |
| height: 100vh; | |
| background: var(--bg-secondary); | |
| border-left: 1px solid var(--border-color); | |
| z-index: 100; | |
| transition: right 0.3s ease; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .panel.open { | |
| right: 0; | |
| } | |
| .panel-overlay { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.5); | |
| z-index: 99; | |
| opacity: 0; | |
| visibility: hidden; | |
| transition: all 0.3s ease; | |
| } | |
| .panel-overlay.visible { | |
| opacity: 1; | |
| visibility: visible; | |
| } | |
| .panel-header { | |
| padding: 20px; | |
| border-bottom: 1px solid var(--border-color); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| } | |
| .panel-title { | |
| font-size: 1.1rem; | |
| font-weight: 600; | |
| } | |
| .panel-close { | |
| width: 32px; | |
| height: 32px; | |
| border-radius: var(--radius-sm); | |
| background: transparent; | |
| border: none; | |
| color: var(--text-secondary); | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: all 0.2s ease; | |
| } | |
| .panel-close:hover { | |
| background: var(--bg-hover); | |
| color: var(--text-primary); | |
| } | |
| .panel-content { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 20px; | |
| } | |
| /* API Key Cards */ | |
| .api-key-list { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; | |
| } | |
| .api-key-card { | |
| background: var(--bg-tertiary); | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--radius-md); | |
| padding: 16px; | |
| transition: all 0.2s ease; | |
| } | |
| .api-key-card:hover { | |
| border-color: var(--accent-primary); | |
| } | |
| .api-key-header { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| margin-bottom: 12px; | |
| } | |
| .api-key-provider { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .provider-icon { | |
| width: 32px; | |
| height: 32px; | |
| border-radius: 8px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-weight: 700; | |
| font-size: 0.8rem; | |
| color: white; | |
| } | |
| .provider-name { | |
| font-weight: 600; | |
| font-size: 0.95rem; | |
| } | |
| .api-key-status { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: var(--success); | |
| } | |
| .api-key-value { | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 0.8rem; | |
| color: var(--text-secondary); | |
| background: var(--bg-hover); | |
| padding: 8px 12px; | |
| border-radius: var(--radius-sm); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| gap: 8px; | |
| } | |
| .api-key-value span { | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| white-space: nowrap; | |
| } | |
| .api-key-actions { | |
| display: flex; | |
| gap: 8px; | |
| margin-top: 12px; | |
| } | |
| .api-key-btn { | |
| flex: 1; | |
| padding: 8px 12px; | |
| border-radius: var(--radius-sm); | |
| font-size: 0.8rem; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| border: 1px solid var(--border-color); | |
| background: transparent; | |
| color: var(--text-secondary); | |
| } | |
| .api-key-btn:hover { | |
| background: var(--bg-hover); | |
| color: var(--text-primary); | |
| } | |
| .api-key-btn.danger:hover { | |
| background: rgba(239, 68, 68, 0.15); | |
| color: var(--error); | |
| border-color: var(--error); | |
| } | |
| /* Add API Key Form */ | |
| .add-key-form { | |
| background: var(--bg-tertiary); | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--radius-md); | |
| padding: 20px; | |
| margin-bottom: 20px; | |
| } | |
| .form-group { | |
| margin-bottom: 16px; | |
| } | |
| .form-label { | |
| display: block; | |
| font-size: 0.85rem; | |
| font-weight: 500; | |
| color: var(--text-secondary); | |
| margin-bottom: 8px; | |
| } | |
| .form-select { | |
| width: 100%; | |
| padding: 10px 14px; | |
| background: var(--bg-secondary); | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--radius-sm); | |
| color: var(--text-primary); | |
| font-size: 0.9rem; | |
| cursor: pointer; | |
| outline: none; | |
| transition: all 0.2s ease; | |
| } | |
| .form-select:focus { | |
| border-color: var(--accent-primary); | |
| } | |
| .form-input { | |
| width: 100%; | |
| padding: 10px 14px; | |
| background: var(--bg-secondary); | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--radius-sm); | |
| color: var(--text-primary); | |
| font-size: 0.9rem; | |
| font-family: 'JetBrains Mono', monospace; | |
| outline: none; | |
| transition: all 0.2s ease; | |
| } | |
| .form-input:focus { | |
| border-color: var(--accent-primary); | |
| } | |
| .form-input::placeholder { | |
| color: var(--text-muted); | |
| } | |
| .form-submit { | |
| width: 100%; | |
| padding: 12px; | |
| background: var(--accent-gradient); | |
| border: none; | |
| border-radius: var(--radius-sm); | |
| color: white; | |
| font-size: 0.9rem; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| } | |
| .form-submit:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 15px rgba(99, 102, 241, 0.4); | |
| } | |
| /* Settings Panel */ | |
| .settings-group { | |
| margin-bottom: 24px; | |
| } | |
| .settings-title { | |
| font-size: 0.8rem; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| letter-spacing: 0.1em; | |
| color: var(--text-muted); | |
| margin-bottom: 12px; | |
| } | |
| .settings-item { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 12px 0; | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| .settings-item:last-child { | |
| border-bottom: none; | |
| } | |
| .settings-label { | |
| font-size: 0.9rem; | |
| color: var(--text-secondary); | |
| } | |
| .settings-value { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .slider { | |
| width: 100px; | |
| height: 4px; | |
| -webkit-appearance: none; | |
| background: var(--border-color); | |
| border-radius: 2px; | |
| outline: none; | |
| } | |
| .slider::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| width: 16px; | |
| height: 16px; | |
| background: var(--accent-primary); | |
| border-radius: 50%; | |
| cursor: pointer; | |
| transition: transform 0.2s ease; | |
| } | |
| .slider::-webkit-slider-thumb:hover { | |
| transform: scale(1.2); | |
| } | |
| .slider-value { | |
| font-size: 0.8rem; | |
| color: var(--text-muted); | |
| min-width: 40px; | |
| text-align: right; | |
| } | |
| /* Toggle Switch */ | |
| .toggle { | |
| position: relative; | |
| width: 48px; | |
| height: 24px; | |
| background: var(--bg-hover); | |
| border-radius: 12px; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| } | |
| .toggle.active { | |
| background: var(--accent-primary); | |
| } | |
| .toggle::after { | |
| content: ''; | |
| position: absolute; | |
| top: 2px; | |
| left: 2px; | |
| width: 20px; | |
| height: 20px; | |
| background: white; | |
| border-radius: 50%; | |
| transition: all 0.2s ease; | |
| } | |
| .toggle.active::after { | |
| left: 26px; | |
| } | |
| /* Empty State */ | |
| .empty-state { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 40px; | |
| text-align: center; | |
| } | |
| .empty-state-icon { | |
| width: 80px; | |
| height: 80px; | |
| background: var(--bg-tertiary); | |
| border-radius: var(--radius-lg); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 2rem; | |
| margin-bottom: 24px; | |
| border: 1px solid var(--border-color); | |
| } | |
| .empty-state-title { | |
| font-size: 1.25rem; | |
| font-weight: 600; | |
| margin-bottom: 8px; | |
| } | |
| .empty-state-text { | |
| color: var(--text-secondary); | |
| font-size: 0.9rem; | |
| max-width: 300px; | |
| } | |
| /* Welcome Screen */ | |
| .welcome-screen { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 40px; | |
| } | |
| .welcome-logo { | |
| width: 80px; | |
| height: 80px; | |
| background: var(--accent-gradient); | |
| border-radius: var(--radius-lg); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 2.5rem; | |
| margin-bottom: 24px; | |
| box-shadow: 0 20px 40px rgba(99, 102, 241, 0.3); | |
| } | |
| .welcome-title { | |
| font-size: 2rem; | |
| font-weight: 700; | |
| margin-bottom: 12px; | |
| background: var(--accent-gradient); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .welcome-subtitle { | |
| color: var(--text-secondary); | |
| font-size: 1rem; | |
| margin-bottom: 32px; | |
| } | |
| .welcome-features { | |
| display: flex; | |
| gap: 24px; | |
| flex-wrap: wrap; | |
| justify-content: center; | |
| } | |
| .welcome-feature { | |
| background: var(--bg-tertiary); | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--radius-md); | |
| padding: 20px; | |
| width: 200px; | |
| text-align: center; | |
| transition: all 0.2s ease; | |
| } | |
| .welcome-feature:hover { | |
| border-color: var(--accent-primary); | |
| transform: translateY(-4px); | |
| } | |
| .welcome-feature-icon { | |
| font-size: 1.5rem; | |
| margin-bottom: 12px; | |
| } | |
| .welcome-feature-title { | |
| font-weight: 600; | |
| font-size: 0.9rem; | |
| margin-bottom: 4px; | |
| } | |
| .welcome-feature-text { | |
| font-size: 0.8rem; | |
| color: var(--text-secondary); | |
| } | |
| /* Toast Notifications */ | |
| .toast-container { | |
| position: fixed; | |
| bottom: 24px; | |
| right: 24px; | |
| z-index: 1000; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .toast { | |
| background: var(--bg-tertiary); | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--radius-md); | |
| padding: 12px 16px; | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| animation: toastIn 0.3s ease; | |
| box-shadow: var(--shadow-lg); | |
| } | |
| @keyframes toastIn { | |
| from { | |
| opacity: 0; | |
| transform: translateX(100%); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateX(0); | |
| } | |
| } | |
| .toast.success { | |
| border-color: var(--success); | |
| } | |
| .toast.error { | |
| border-color: var(--error); | |
| } | |
| .toast-icon { | |
| font-size: 1.2rem; | |
| } | |
| .toast-message { | |
| font-size: 0.9rem; | |
| } | |
| /* Mobile Responsive */ | |
| @media (max-width: 768px) { | |
| .sidebar { | |
| position: fixed; | |
| left: -280px; | |
| z-index: 200; | |
| } | |
| .sidebar.open { | |
| left: 0; | |
| } | |
| .panel { | |
| width: 100%; | |
| right: -100%; | |
| } | |
| .welcome-features { | |
| flex-direction: column; | |
| } | |
| .welcome-feature { | |
| width: 100%; | |
| } | |
| .message { | |
| max-width: 95%; | |
| } | |
| } | |
| /* Provider Colors */ | |
| .provider-openai { | |
| background: linear-gradient(135deg, #10a37f 0%, #1a7f5a 100%); | |
| color: white; | |
| } | |
| .provider-anthropic { | |
| background: linear-gradient(135deg, #d97757 0%, #c45f3d 100%); | |
| color: white; | |
| } | |
| .provider-google { | |
| background: linear-gradient(135deg, #4285f4 0%, #3367d6 100%); | |
| color: white; | |
| } | |
| .provider-mistral { | |
| background: linear-gradient(135deg, #ff7000 0%, #e55a00 100%); | |
| color: white; | |
| } | |
| .provider-cohere { | |
| background: linear-gradient(135deg, #395941 0%, #2a4531 100%); | |
| color: white; | |
| } | |
| .provider-xai { | |
| background: linear-gradient(135deg, #000 0%, #333 100%); | |
| color: white; | |
| } | |
| .provider-ollama { | |
| background: linear-gradient(135deg, #5a5a5a 0%, #3a3a3a 100%); | |
| color: white; | |
| } | |
| /* Markdown Styles */ | |
| .markdown-content h1 { | |
| font-size: 1.5em; | |
| margin: 0.5em 0; | |
| } | |
| .markdown-content h2 { | |
| font-size: 1.3em; | |
| margin: 0.5em 0; | |
| } | |
| .markdown-content h3 { | |
| font-size: 1.1em; | |
| margin: 0.5em 0; | |
| } | |
| .markdown-content p { | |
| margin: 0.5em 0; | |
| } | |
| .markdown-content ul, | |
| .markdown-content ol { | |
| margin: 0.5em 0; | |
| padding-left: 1.5em; | |
| } | |
| .markdown-content li { | |
| margin: 0.25em 0; | |
| } | |
| .markdown-content blockquote { | |
| border-left: 3px solid var(--accent-primary); | |
| padding-left: 1em; | |
| margin: 0.5em 0; | |
| color: var(--text-secondary); | |
| } | |
| .markdown-content a { | |
| color: var(--accent-primary); | |
| } | |
| /* Mobile menu button */ | |
| .mobile-menu-btn { | |
| display: none; | |
| } | |
| @media (max-width: 768px) { | |
| .mobile-menu-btn { | |
| display: flex; | |
| } | |
| } | |
| /* Scrollbar */ | |
| ::-webkit-scrollbar { | |
| width: 6px; | |
| height: 6px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: transparent; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: var(--border-color); | |
| border-radius: 3px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: var(--text-muted); | |
| } | |
| /* Footer */ | |
| .footer { | |
| padding: 12px 24px; | |
| border-top: 1px solid var(--border-color); | |
| text-align: center; | |
| font-size: 0.75rem; | |
| color: var(--text-muted); | |
| } | |
| .footer a { | |
| color: var(--accent-primary); | |
| text-decoration: none; | |
| font-weight: 500; | |
| } | |
| .footer a:hover { | |
| text-decoration: underline; | |
| } | |
| /* Model Dropdown */ | |
| .model-dropdown { | |
| position: absolute; | |
| top: 100%; | |
| left: 0; | |
| right: 0; | |
| background: var(--bg-secondary); | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--radius-md); | |
| box-shadow: var(--shadow-lg); | |
| z-index: 50; | |
| max-height: 300px; | |
| overflow-y: auto; | |
| display: none; | |
| } | |
| .model-dropdown.open { | |
| display: block; | |
| } | |
| .model-dropdown-item { | |
| padding: 12px 16px; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| transition: all 0.2s ease; | |
| } | |
| .model-dropdown-item:hover { | |
| background: var(--bg-hover); | |
| } | |
| .model-dropdown-item.selected { | |
| background: rgba(99, 102, 241, 0.15); | |
| } | |
| .model-dropdown-icon { | |
| width: 28px; | |
| height: 28px; | |
| border-radius: 6px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 0.7rem; | |
| font-weight: 700; | |
| color: white; | |
| } | |
| .model-dropdown-info { | |
| flex: 1; | |
| } | |
| .model-dropdown-name { | |
| font-weight: 500; | |
| font-size: 0.9rem; | |
| } | |
| .model-dropdown-desc { | |
| font-size: 0.75rem; | |
| color: var(--text-muted); | |
| } | |
| .model-selector-wrapper { | |
| position: relative; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="bg-pattern"></div> | |
| <div class="app-container"> | |
| <!-- Sidebar --> | |
| <aside class="sidebar" id="sidebar"> | |
| <div class="sidebar-header"> | |
| <div class="logo"> | |
| <div class="logo-icon">🤖</div> | |
| <span>AI Chat Hub</span> | |
| </div> | |
| </div> | |
| <nav class="sidebar-nav"> | |
| <div class="nav-section"> | |
| <div class="nav-section-title">Chat</div> | |
| <div class="nav-item active" data-view="chat"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path> | |
| </svg> | |
| <span>New Chat</span> | |
| </div> | |
| <div class="nav-item" data-view="history"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <circle cx="12" cy="12" r="10"></circle> | |
| <polyline points="12 6 12 12 16 14"></polyline> | |
| </svg> | |
| <span>History</span> | |
| </div> | |
| </div> | |
| <div class="nav-section"> | |
| <div class="nav-section-title">Configuration</div> | |
| <div class="nav-item" data-panel="api-keys"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path | |
| d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"> | |
| </path> | |
| </svg> | |
| <span>API Keys</span> | |
| <span class="nav-item-badge" id="api-key-count">0</span> | |
| </div> | |
| <div class="nav-item" data-panel="settings"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <circle cx="12" cy="12" r="3"></circle> | |
| <path | |
| d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"> | |
| </path> | |
| </svg> | |
| <span>Settings</span> | |
| </div> | |
| </div> | |
| </nav> | |
| <div class="footer"> | |
| Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a> | |
| </div> | |
| </aside> | |
| <!-- Main Content --> | |
| <main class="main-content"> | |
| <header class="header"> | |
| <div class="header-left"> | |
| <button class="header-btn mobile-menu-btn" id="mobile-menu-btn"> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <line x1="3" y1="12" x2="21" y2="12"></line> | |
| <line x1="3" y1="6" x2="21" y2="6"></line> | |
| <line x1="3" y1="18" x2="21" y2="18"></line> | |
| </svg> | |
| </button> | |
| <div class="model-selector-wrapper"> | |
| <div class="model-selector" id="model-selector"> | |
| <div class="model-selector-icon provider-openai" id="current-model-icon">O</div> | |
| <span class="model-selector-text" id="current-model-name">Select Model</span> | |
| <svg class="model-selector-arrow" width="16" height="16" viewBox="0 0 24 24" fill="none" | |
| stroke="currentColor" stroke-width="2"> | |
| <polyline points="6 9 12 15 18 9"></polyline> | |
| </svg> | |
| </div> | |
| <div class="model-dropdown" id="model-dropdown"></div> | |
| </div> | |
| </div> | |
| <div class="header-right"> | |
| <button class="header-btn" id="clear-chat-btn" title="Clear Chat"> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <polyline points="3 6 5 6 21 6"></polyline> | |
| <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path> | |
| </svg> | |
| </button> | |
| </div> | |
| </header> | |
| <div class="chat-container"> | |
| <!-- Welcome Screen --> | |
| <div class="welcome-screen" id="welcome-screen"> | |
| <div class="welcome-logo">💬</div> | |
| <h1 class="welcome-title">AI Chat Hub</h1> | |
| <p class="welcome-subtitle">Connect your API keys and start chatting with AI models</p> | |
| <div class="welcome-features"> | |
| <div class="welcome-feature"> | |
| <div class="welcome-feature-icon">🔑</div> | |
| <div class="welcome-feature-title">Multiple Providers</div> | |
| <div class="welcome-feature-text">OpenAI, Anthropic, Google, Mistral & more</div> | |
| </div> | |
| <div class="welcome-feature"> | |
| <div class="welcome-feature-icon">⚡</div> | |
| <div class="welcome-feature-title">Fast Responses</div> | |
| <div class="welcome-feature-text">Streamed responses in real-time</div> | |
| </div> | |
| <div class="welcome-feature"> | |
| <div class="welcome-feature-icon">🔒</div> | |
| <div class="welcome-feature-title">Secure & Private</div> | |
| <div class="welcome-feature-text">Your keys stay on your device</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Chat Messages --> | |
| <div class="chat-messages" id="chat-messages" style="display: none;"></div> | |
| <!-- Typing Indicator --> | |
| <div class="typing-indicator" id="typing-indicator" style="display: none;"> | |
| <div class="typing-dot"></div> | |
| <div class="typing-dot"></div> | |
| <div class="typing-dot"></div> | |
| </div> | |
| <!-- Chat Input --> | |
| <div class="chat-input-container"> | |
| <div class="chat-input-wrapper"> | |
| <textarea class="chat-input" id="chat-input" placeholder="Message AI Chat Hub..." rows="1"></textarea> | |
| <button class="send-btn" id="send-btn"> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <line x1="22" y1="2" x2="11" y2="13"></line> | |
| <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon> | |
| </svg> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| </div> | |
| <!-- Panel Overlay --> | |
| <div class="panel-overlay" id="panel-overlay"></div> | |
| <!-- API Keys Panel --> | |
| <div class="panel" id="api-keys-panel"> | |
| <div class="panel-header"> | |
| <h2 class="panel-title">API Keys</h2> | |
| <button class="panel-close" data-close-panel> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <line x1="18" y1="6" x2="6" y2="18"></line> | |
| <line x1="6" y1="6" x2="18" y2="18"></line> |