Spaces:
Running on Zero
Running on Zero
Download web/static/index.html from Aniruddha7/QueryLensV2b: direct link, hf CLI and curl.
- Browser
- Download file 49.4 kB
-
https://huggingface.co/spaces/Aniruddha7/QueryLensV2b/resolve/main/web/static/index.html
- Command line
-
hf download hf://spaces/Aniruddha7/QueryLensV2b/web/static/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Aniruddha7/QueryLensV2b/resolve/main/web/static/index.html
49.4 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>QueryLens — Transform natural language into SQL</title> | |
| <link rel="icon" | |
| href='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><rect width="48" height="48" rx="10" fill="%230F151F"/><g stroke="%2322D3EE" stroke-width="2.6" fill="none"><ellipse cx="20" cy="14" rx="10.5" ry="4"/><path d="M9.5 14v20c0 2.2 4.7 4 10.5 4s10.5-1.8 10.5-4V14"/><path d="M9.5 23c0 2.2 4.7 4 10.5 4s10.5-1.8 10.5-4"/></g><circle cx="32.5" cy="27.5" r="8.2" fill="rgba(34,211,238,.18)" stroke="%237DECFB" stroke-width="2.4"/><path d="M38.6 33.6L44.4 39.4" stroke="%237DECFB" stroke-width="2.8" stroke-linecap="round"/></svg>'> | |
| <!-- Fonts --> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link | |
| href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Space+Grotesk:wght@500;600;700&family=JetBrains+Mono:wght@400;600&display=swap" | |
| rel="stylesheet"> | |
| <style> | |
| :root { | |
| /* ── Graphite Halo — professional dark w/ electric cyan ────── */ | |
| --accent: #22D3EE; /* electric cyan (primary) */ | |
| --accent-bright: #7DECFB; | |
| --accent-ink: #05242B; /* text on cyan */ | |
| --accent-soft: rgba(34, 211, 238, 0.12); | |
| --violet: #A78BFA; /* secondary data accent */ | |
| --ocean: #60A5FA; /* info */ | |
| --bg-page: #0A0E15; | |
| --bg-raised: #0E141F; | |
| --panel: #111927; | |
| --panel-inset: #0B101A; | |
| --border: #1F2A3A; | |
| --border-light: #17202D; | |
| --border-strong: #2A3A50; | |
| --text-primary: #E8EEF7; | |
| --text-secondary: #9DAFC4; | |
| --text-tertiary: #64788F; | |
| --success: #34D399; | |
| --warning: #FBBF24; | |
| --error: #F87171; | |
| /* 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; | |
| --space-10: 2.5rem; | |
| /* Shadows — cool, tight, professional */ | |
| --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.35); | |
| --shadow-md: 0 4px 14px -4px rgb(0 0 0 / 0.45), 0 1px 3px -1px rgb(0 0 0 / 0.3); | |
| --shadow-glow: 0 0 18px rgb(34 211 238 / 0.22); | |
| --radius-sm: 8px; | |
| --radius-md: 12px; | |
| --radius-lg: 16px; | |
| --radius-xl: 20px; | |
| --transition-fast: 160ms ease; | |
| --transition-normal: 240ms ease; | |
| } | |
| /* ── Light mode (paper) — same multi-hue system, calmer ambient ── */ | |
| html.light { | |
| --bg-page: #F2F5FA; | |
| --bg-raised: #FFFFFF; | |
| --panel: #FFFFFF; | |
| --panel-inset: #F5F8FC; | |
| --border: #DFE6EF; | |
| --border-light: #EAEFF6; | |
| --border-strong: #C9D4E2; | |
| --text-primary: #172231; | |
| --text-secondary: #4C5D75; | |
| --text-tertiary: #8091A6; | |
| --shadow-sm: 0 1px 2px 0 rgb(16 24 40 / 0.07); | |
| --shadow-md: 0 4px 14px -4px rgb(16 24 40 / 0.12), 0 1px 3px -1px rgb(16 24 40 / 0.08); | |
| --shadow-glow: 0 0 18px rgb(34 211 238 / 0.28); | |
| } | |
| html.light ::-webkit-scrollbar-thumb { background: #C3CEDC; } | |
| html.light ::selection { background: rgb(34 211 238 / .25); color: var(--text-primary); } | |
| html.light body { | |
| background: | |
| radial-gradient(1100px 420px at 50% -220px, rgb(34 211 238 / 0.08), transparent 70%), | |
| radial-gradient(900px 400px at 8% 108%, rgb(167 139 250 / 0.05), transparent 70%), | |
| var(--bg-page); | |
| } | |
| html.light .brand-icon { | |
| background: linear-gradient(150deg, #DFF7FA 0%, #CBEDF5 100%); | |
| border-color: rgb(8 145 178 / .35); | |
| } | |
| html.light .brand-text h1 .lens, | |
| html.light .header-tag, | |
| html.light .profile-btn:hover { color: #0E7490; } | |
| html.light .profile-btn:hover { border-color: rgb(8 145 178 / .45); } | |
| html.light .table-resize-btn:hover { border-color: rgb(8 145 178 / .5); color: #0E7490; } | |
| html.light .answer-table thead th, | |
| html.light .answer-content th { color: #0E7490; } | |
| html.light .answer-table tbody tr:hover td { background: rgb(34 211 238 / .07); } | |
| html.light code.language-sql, html.light pre.sql-content code { color: #24435C; } | |
| html.light .c-cyan { color: #0E7490; background: rgb(14 116 144 / .09); border-color: rgb(14 116 144 / .28); } | |
| html.light .c-violet { color: #7C3AED; background: rgb(124 58 237 / .08); border-color: rgb(124 58 237 / .26); } | |
| html.light .c-emerald { color: #059669; background: rgb(5 150 105 / .09); border-color: rgb(5 150 105 / .28); } | |
| html.light .c-blue { color: #2563EB; background: rgb(37 99 235 / .08); border-color: rgb(37 99 235 / .26); } | |
| html.light .c-amber { color: #B45309; background: rgb(180 83 9 / .09); border-color: rgb(180 83 9 / .28); } | |
| html.light .c-rose { color: #DB2777; background: rgb(219 39 119 / .08); border-color: rgb(219 39 119 / .26); } | |
| html.light .btn-outline-violet { color: #7C3AED; } | |
| html.light .btn-outline-violet:hover { background: rgb(124 58 237 / .08); border-color: rgb(124 58 237 / .7); color: #6D28D9; } | |
| html.light .btn-outline-rose { color: #DB2777; } | |
| html.light .btn-outline-rose:hover { background: rgb(219 39 119 / .08); border-color: rgb(219 39 119 / .7); color: #9D174D; } | |
| html.light .btn-outline-amber { color: #B45309; } | |
| html.light .btn-outline-amber:hover { background: rgb(180 83 9 / .08); border-color: rgb(180 83 9 / .7); color: #92400E; } | |
| html.light .profile-btn.primary { border-color: rgb(5 150 105 / .55); color: #059669; } | |
| html.light .profile-btn.primary:hover { background: rgb(5 150 105 / .09); border-color: #059669; color: #047857; } | |
| html.light .db-badge { color: #059669; background: rgb(5 150 105 / .09); border-color: rgb(5 150 105 / .30); } | |
| /* ── Theme toggle (header) ─────────────────────────────────── */ | |
| .header-right { display: inline-flex; align-items: center; gap: 10px; } | |
| .theme-toggle { | |
| width: 34px; height: 34px; border-radius: var(--radius-sm); | |
| display: inline-flex; align-items: center; justify-content: center; | |
| cursor: pointer; color: var(--text-secondary); | |
| background: var(--panel); border: 1px solid var(--border-strong); | |
| transition: color var(--transition-fast), border-color var(--transition-fast), | |
| box-shadow var(--transition-fast); | |
| } | |
| .theme-toggle:hover { color: var(--accent); border-color: rgb(34 211 238 / .45); box-shadow: 0 0 10px rgb(34 211 238 / .25); } | |
| .theme-toggle .icon-moon { display: none; } | |
| html.light .theme-toggle { color: #0E7490; border-color: rgb(8 145 178 / .35); } | |
| html.light .theme-toggle:hover { color: #0E7490; border-color: rgb(8 145 178 / .6); box-shadow: 0 0 10px rgb(8 145 178 / .22); } | |
| html.light .theme-toggle .icon-sun { display: none; } | |
| html.light .theme-toggle .icon-moon { display: inline; } | |
| *, *::before, *::after { box-sizing: border-box; } | |
| html, body { | |
| height: 100%; | |
| margin: 0; | |
| font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| background: | |
| radial-gradient(1100px 420px at 50% -220px, rgb(34 211 238 / 0.07), transparent 70%), | |
| radial-gradient(900px 400px at 8% 108%, rgb(167 139 250 / 0.06), transparent 70%), | |
| var(--bg-page); | |
| color: var(--text-primary); | |
| -webkit-font-smoothing: antialiased; | |
| -moz-osx-font-smoothing: grayscale; | |
| font-size: 15.5px; | |
| line-height: 1.6; | |
| } | |
| h1, h2, h3, h4 { | |
| font-family: 'Space Grotesk', 'Inter', sans-serif; | |
| font-weight: 700; | |
| letter-spacing: -0.015em; | |
| } | |
| ::selection { background: rgba(34, 211, 238, 0.30); color: var(--text-primary); } | |
| ::-webkit-scrollbar { width: 10px; height: 10px; } | |
| ::-webkit-scrollbar-thumb { background: #253349; border-radius: 8px; border: 2px solid var(--bg-page); } | |
| ::-webkit-scrollbar-track { background: transparent; } | |
| /* ── Layout ──────────────────────────────────────────────────── */ | |
| .app-container { | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .header { | |
| background: var(--bg-page); | |
| border-bottom: 1px solid var(--border-light); | |
| position: relative; | |
| } | |
| /* Tron-inspired hairline: a single cyan energy line along the top edge */ | |
| .header::before { | |
| content: ""; | |
| position: absolute; | |
| inset: 0 0 auto 0; | |
| height: 2px; | |
| background: linear-gradient(90deg, | |
| transparent 2%, rgb(34 211 238 / .55) 30%, rgb(34 211 238 / .15) 65%, transparent 98%); | |
| pointer-events: none; | |
| } | |
| /* Header shares exact alignment with .main-content so the brand line | |
| up with the query card edge breaks. */ | |
| .header-content { | |
| max-width: 1240px; | |
| margin: 0 auto; | |
| padding: var(--space-4) var(--space-8); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| gap: var(--space-4); | |
| } | |
| .brand { display: flex; align-items: center; gap: 0.85rem; } | |
| .brand-icon { | |
| width: 42px; height: 42px; | |
| border-radius: var(--radius-md); | |
| background: linear-gradient(150deg, #0F2A35 0%, #123441 100%); | |
| border: 1px solid rgb(34 211 238 / 0.35); | |
| color: var(--accent-bright); | |
| display: grid; place-items: center; | |
| box-shadow: var(--shadow-glow); | |
| } | |
| .brand-text h1 { | |
| margin: 0; font-size: 1.3rem; line-height: 1.2; color: var(--text-primary); | |
| } | |
| .brand-text h1 .lens { color: var(--accent); } | |
| .brand-text p { | |
| margin: 1px 0 0; font-size: 0.82rem; color: var(--text-tertiary); | |
| letter-spacing: 0.01em; | |
| } | |
| .header-tag { | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 0.74rem; | |
| color: var(--accent); | |
| border: 1px solid rgb(34 211 238 / 0.30); | |
| background: var(--accent-soft); | |
| border-radius: 999px; | |
| padding: 0.3rem 0.8rem; | |
| white-space: nowrap; | |
| } | |
| .main-content { | |
| max-width: 1240px; | |
| width: 100%; | |
| margin: 0 auto; | |
| padding: var(--space-6) var(--space-8) var(--space-10); | |
| flex: 1; | |
| } | |
| /* ── Query composer ──────────────────────────────────────────── */ | |
| .query-section { margin-bottom: var(--space-6); } | |
| .query-body { | |
| background: var(--panel); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-lg); | |
| box-shadow: var(--shadow-md); | |
| padding: var(--space-5); | |
| transition: border-color var(--transition-fast), box-shadow var(--transition-fast); | |
| } | |
| .query-body:focus-within { | |
| border-color: rgb(34 211 238 / 0.55); | |
| box-shadow: 0 0 0 3px rgb(34 211 238 / 0.14), var(--shadow-md); | |
| } | |
| .query-textarea { | |
| width: 100%; | |
| min-height: 96px; | |
| border: none; | |
| outline: none; | |
| resize: vertical; | |
| font-family: inherit; | |
| font-size: 1.02rem; | |
| color: var(--text-primary); | |
| background: transparent; | |
| line-height: 1.55; | |
| } | |
| .query-textarea::placeholder { color: var(--text-tertiary); } | |
| .query-controls { | |
| display: flex; align-items: center; gap: var(--space-3); | |
| margin-top: var(--space-3); | |
| padding-top: var(--space-3); | |
| border-top: 1px solid var(--border-light); | |
| flex-wrap: wrap; | |
| } | |
| .mode-select { | |
| font-family: inherit; | |
| font-size: 0.86rem; | |
| color: var(--text-secondary); | |
| background: var(--panel-inset); | |
| border: 1px solid var(--border-strong); | |
| border-radius: var(--radius-sm); | |
| padding: 0.42rem 0.6rem; | |
| cursor: pointer; | |
| } | |
| .btn { | |
| display: inline-flex; align-items: center; gap: 0.45rem; | |
| font-family: inherit; font-size: 0.9rem; font-weight: 600; | |
| border-radius: var(--radius-sm); | |
| padding: 0.5rem 1.05rem; | |
| cursor: pointer; | |
| border: 1px solid transparent; | |
| transition: background var(--transition-fast), border-color var(--transition-fast), | |
| transform var(--transition-fast), opacity var(--transition-fast), | |
| box-shadow var(--transition-fast); | |
| } | |
| .btn:active { transform: translateY(1px); } | |
| .btn:disabled { opacity: 0.55; cursor: not-allowed; } | |
| .btn-primary { | |
| background: var(--accent); | |
| color: var(--accent-ink); | |
| border-color: var(--accent); | |
| box-shadow: 0 0 14px rgb(34 211 238 / 0.25); | |
| } | |
| .btn-primary:hover:not(:disabled) { | |
| background: var(--accent-bright); | |
| border-color: var(--accent-bright); | |
| box-shadow: 0 0 20px rgb(34 211 238 / 0.4); | |
| } | |
| .btn-secondary { | |
| background: transparent; | |
| color: var(--text-secondary); | |
| border-color: var(--border-strong); | |
| } | |
| .btn-secondary:hover:not(:disabled) { | |
| background: var(--accent-soft); | |
| border-color: rgb(34 211 238 / 0.45); | |
| color: var(--text-primary); | |
| } | |
| .status-area { | |
| margin-left: auto; | |
| display: flex; align-items: center; gap: 0.8rem; | |
| font-size: 0.84rem; color: var(--text-tertiary); | |
| } | |
| .spinner { | |
| width: 16px; height: 16px; | |
| border: 2px solid rgb(34 211 238 / 0.25); | |
| border-top-color: var(--accent); | |
| border-radius: 50%; | |
| animation: spin 0.8s linear infinite; | |
| } | |
| @keyframes spin { to { transform: rotate(360deg); } } | |
| .hidden { display: none ; } | |
| /* ── Results grid ────────────────────────────────────────────── */ | |
| .results-grid { | |
| display: grid; | |
| grid-template-columns: minmax(0, 1fr) 340px; | |
| gap: var(--space-6); | |
| align-items: start; | |
| } | |
| @media (max-width: 1020px) { | |
| .results-grid { grid-template-columns: 1fr; } | |
| } | |
| .card { | |
| background: var(--panel); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-lg); | |
| box-shadow: var(--shadow-sm); | |
| overflow: hidden; | |
| } | |
| .card + .card { margin-top: var(--space-6); } | |
| .card-header { | |
| display: flex; align-items: center; gap: 0.5rem; | |
| padding: 0.95rem var(--space-5); | |
| border-bottom: 1px solid var(--border-light); | |
| background: var(--bg-raised); | |
| } | |
| .card-title { | |
| margin: 0; font-size: 0.98rem; color: var(--text-primary); | |
| display: flex; align-items: center; gap: 0.5rem; | |
| font-family: 'Space Grotesk', 'Inter', sans-serif; | |
| } | |
| .card-content { padding: var(--space-5); } | |
| .answer-content { white-space: normal; color: var(--text-primary); } | |
| /* ── Chart box ───────────────────────────────────────────────── */ | |
| .chart-box { | |
| margin-top: var(--space-4); | |
| border: 1px solid var(--border-light); | |
| background: var(--panel-inset); | |
| border-radius: var(--radius-md); | |
| padding: var(--space-3); | |
| } | |
| .chart-pending { | |
| margin-top: var(--space-4); | |
| border: 1px dashed var(--border-strong); | |
| background: var(--panel-inset); | |
| border-radius: var(--radius-md); | |
| padding: var(--space-4) var(--space-3); | |
| font-size: 0.82rem; | |
| color: var(--text-tertiary); | |
| line-height: 1.6; | |
| } | |
| .chart-pending.hidden { display: none; } | |
| #chartCanvas { width: 100%; height: 340px; } | |
| .chart-caption { | |
| margin: 0.4rem 0.2rem 0; | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 0.74rem; color: var(--text-tertiary); | |
| text-align: right; | |
| } | |
| /* ── SQL block ──────────────────────────────────────────────── */ | |
| details summary { outline: none; } | |
| .sql-content { | |
| margin: 0; | |
| background: var(--panel-inset); | |
| border: 1px solid var(--border-light); | |
| border-radius: var(--radius-md); | |
| padding: var(--space-4); | |
| overflow-x: auto; | |
| font-size: 0.87rem; | |
| line-height: 1.6; | |
| } | |
| code.language-sql, pre.sql-content code { | |
| font-family: 'JetBrains Mono', 'Cascadia Code', Consolas, monospace; | |
| color: #D9E7F6; | |
| } | |
| /* ── Agent panels sidebar ───────────────────────────────────── */ | |
| .agent-panels { display: flex; flex-direction: column; gap: var(--space-4); } | |
| .panel { | |
| background: var(--panel); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-lg); | |
| box-shadow: var(--shadow-sm); | |
| overflow: hidden; | |
| } | |
| .panel summary { list-style: none; } | |
| .panel summary::-webkit-details-marker { display: none; } | |
| .panel-header { | |
| display: flex; align-items: center; justify-content: space-between; | |
| padding: 0.8rem var(--space-4); | |
| cursor: pointer; | |
| user-select: none; | |
| } | |
| .panel-header:hover { background: var(--bg-raised); } | |
| .panel-title { | |
| display: flex; align-items: center; gap: 0.5rem; | |
| font-size: 0.84rem; font-weight: 600; color: var(--text-primary); | |
| font-family: 'Space Grotesk', 'Inter', sans-serif; | |
| } | |
| .panel-title .chip svg { width: 14px; height: 14px; } | |
| .panel-content { | |
| padding: 0 var(--space-4) var(--space-4); | |
| font-size: 0.76rem; | |
| color: var(--text-secondary); | |
| max-height: 260px; | |
| overflow-y: auto; | |
| white-space: pre-wrap; | |
| word-break: break-word; | |
| font-family: 'JetBrains Mono', Consolas, monospace; | |
| } | |
| /* ── Database panel ─────────────────────────────────────────── */ | |
| .db-badge { | |
| margin-left: auto; | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 0.7rem; font-weight: 600; | |
| color: #34D399; | |
| background: rgba(52, 211, 153, 0.10); | |
| border: 1px solid rgba(52, 211, 153, 0.3); | |
| border-radius: 999px; | |
| padding: 0.12rem 0.55rem; | |
| } | |
| .profile-list { display: flex; flex-direction: column; gap: 6px; padding: 0 var(--space-4) var(--space-3); } | |
| .profile-item { | |
| display: flex; align-items: center; gap: 0.5rem; | |
| border: 1px solid var(--border); | |
| background: var(--panel-inset); | |
| border-radius: var(--radius-sm); | |
| padding: 0.5rem 0.65rem; | |
| font-size: 0.8rem; | |
| } | |
| .profile-item.active { | |
| border-color: rgba(52, 211, 153, 0.55); | |
| background: rgba(52, 211, 153, 0.08); | |
| } | |
| .profile-name { font-weight: 600; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } | |
| .profile-kind { font-size: 0.68rem; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: 0.04em; } | |
| .profile-actions { margin-left: auto; display: flex; gap: 4px; } | |
| .profile-btn { | |
| border: 1px solid var(--border-strong); | |
| background: var(--panel); | |
| color: var(--text-secondary); | |
| font-size: 0.7rem; font-weight: 600; | |
| border-radius: 4px; padding: 2px 8px; cursor: pointer; | |
| font-family: inherit; | |
| } | |
| .profile-btn:hover { border-color: var(--accent); color: var(--accent); } | |
| .profile-btn.danger:hover { border-color: var(--error); color: var(--error); } | |
| .profile-btn.primary { border-color: rgb(52 211 153 / .55); color: #34d399; } | |
| .profile-btn.primary:hover { background: rgb(52 211 153 / .1); border-color: #34d399; color: #34d399; } | |
| .notes-editor { | |
| border: 1px solid var(--border); | |
| border-top: 2px solid rgb(52 211 153 / .45); | |
| background: var(--panel-inset); | |
| border-radius: var(--radius-sm); | |
| padding: 0.5rem 0.65rem; | |
| display: flex; flex-direction: column; gap: 6px; | |
| } | |
| .notes-editor textarea { | |
| width: 100%; resize: vertical; | |
| background: var(--panel); color: var(--text-primary); | |
| border: 1px solid var(--border-strong); border-radius: 4px; | |
| font-family: inherit; font-size: 0.72rem; line-height: 1.45; | |
| padding: 0.4rem 0.5rem; | |
| } | |
| .notes-editor textarea:focus { outline: none; border-color: rgb(52 211 153 / .55); } | |
| .notes-editor-actions { display: flex; gap: 6px; justify-content: flex-end; } | |
| .profile-dot { | |
| width: 7px; height: 7px; border-radius: 50%; | |
| background: var(--border-strong); flex-shrink: 0; | |
| } | |
| .profile-dot.on { background: var(--success); box-shadow: 0 0 6px rgb(52 211 153 / .6); } | |
| .schema-add { padding: 0 var(--space-4) var(--space-4); border-top: 1px dashed var(--border); padding-top: var(--space-3); } | |
| .schema-add label { | |
| display: block; font-size: 0.72rem; font-weight: 600; | |
| color: var(--text-tertiary); margin: 0.5rem 0 3px; | |
| text-transform: uppercase; letter-spacing: 0.05em; | |
| } | |
| .schema-add input[type="text"] { | |
| width: 100%; font-family: inherit; font-size: 0.8rem; | |
| border: 1px solid var(--border-strong); border-radius: var(--radius-sm); | |
| padding: 0.4rem 0.55rem; color: var(--text-primary); | |
| background: var(--panel-inset); | |
| } | |
| .schema-add input[type="text"]:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px rgb(34 211 238 / .18); } | |
| .schema-add textarea { | |
| width: 100%; font-family: inherit; font-size: 0.8rem; line-height: 1.45; | |
| border: 1px solid var(--border-strong); border-radius: var(--radius-sm); | |
| padding: 0.4rem 0.55rem; color: var(--text-primary); | |
| background: var(--panel-inset); resize: vertical; min-height: 44px; | |
| } | |
| .schema-add textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px rgb(34 211 238 / .18); } | |
| .schema-add-hint { | |
| margin-top: 0.45rem; | |
| font-size: 0.72rem; | |
| color: var(--text-tertiary); | |
| line-height: 1.5; | |
| } | |
| .schema-add .row2 { display: flex; gap: 6px; margin-top: 0.55rem; } | |
| .schema-add .row2 .btn { flex: 1; justify-content: center; padding: 0.42rem 0.5rem; font-size: 0.78rem; } | |
| .schema-tables { padding: 0 var(--space-4) var(--space-4); } | |
| .schema-tables .tbl { | |
| font-size: 0.74rem; color: var(--text-secondary); | |
| border-bottom: 1px dotted var(--border); | |
| padding: 3px 0; | |
| } | |
| .schema-tables .tbl b { color: var(--text-primary); font-weight: 600; } | |
| .schema-tables .tbl .rc { color: var(--text-tertiary); font-size: 0.68rem; } | |
| /* ── Footer ─────────────────────────────────────────────────── */ | |
| .footer { | |
| text-align: center; | |
| padding: var(--space-6); | |
| color: var(--text-tertiary); | |
| font-size: 0.8rem; | |
| border-top: 1px solid var(--border-light); | |
| } | |
| .footer p { margin: 0; } | |
| /* ── Section accent system: one hue family per functional area ── */ | |
| .accent-cyan { border-top: 2px solid rgba(34, 211, 238, 0.55); } | |
| .accent-violet { border-top: 2px solid rgba(167, 139, 250, 0.55); } | |
| .accent-emerald { border-top: 2px solid rgba(52, 211, 153, 0.55); } | |
| .accent-blue { border-top: 2px solid rgba(96, 165, 250, 0.55); } | |
| .accent-amber { border-top: 2px solid rgba(251, 191, 36, 0.55); } | |
| .accent-rose { border-top: 2px solid rgba(244, 114, 182, 0.55); } | |
| .chip { | |
| width: 26px; height: 26px; | |
| border-radius: 8px; | |
| display: grid; place-items: center; | |
| flex-shrink: 0; | |
| border: 1px solid transparent; | |
| } | |
| .c-cyan { color: #22D3EE; background: rgba(34, 211, 238, 0.10); border-color: rgba(34, 211, 238, 0.30); } | |
| .c-violet { color: #A78BFA; background: rgba(167, 139, 250, 0.10); border-color: rgba(167, 139, 250, 0.30); } | |
| .c-emerald { color: #34D399; background: rgba(52, 211, 153, 0.10); border-color: rgba(52, 211, 153, 0.30); } | |
| .c-blue { color: #60A5FA; background: rgba(96, 165, 250, 0.10); border-color: rgba(96, 165, 250, 0.30); } | |
| .c-amber { color: #FBBF24; background: rgba(251, 191, 36, 0.10); border-color: rgba(251, 191, 36, 0.30); } | |
| .c-rose { color: #F472B6; background: rgba(244, 114, 182, 0.10); border-color: rgba(244, 114, 182, 0.30); } | |
| .btn-emerald { | |
| background: #34D399; color: #03130B; border-color: #34D399; | |
| box-shadow: 0 0 14px rgb(52 211 153 / 0.22); | |
| } | |
| .btn-emerald:hover:not(:disabled) { | |
| background: #6EE7B7; border-color: #6EE7B7; | |
| box-shadow: 0 0 20px rgb(52 211 153 / 0.38); | |
| } | |
| .btn-outline-violet, .btn-outline-rose, .btn-outline-amber { | |
| background: transparent; font-weight: 600; | |
| } | |
| .btn-outline-violet { color: #C4B5FD; border-color: rgba(167, 139, 250, 0.45); } | |
| .btn-outline-violet:hover:not(:disabled) { | |
| background: rgba(167, 139, 250, 0.12); border-color: rgba(167, 139, 250, 0.75); color: #DDD6FE; | |
| } | |
| .btn-outline-rose { color: #F9A8D4; border-color: rgba(244, 114, 182, 0.45); } | |
| .btn-outline-rose:hover:not(:disabled) { | |
| background: rgba(244, 114, 182, 0.12); border-color: rgba(244, 114, 182, 0.75); color: #FBCFE8; | |
| } | |
| .btn-outline-amber { color: #FCD34D; border-color: rgba(251, 191, 36, 0.45); } | |
| .btn-outline-amber:hover:not(:disabled) { | |
| background: rgba(251, 191, 36, 0.10); border-color: rgba(251, 191, 36, 0.75); color: #FDE68A; | |
| } | |
| /* ── Result table widget (built by app.js) ──────────────────── */ | |
| .table-wrapper { | |
| margin: 0.8rem 0 0.4rem; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-md); | |
| overflow: hidden; | |
| background: var(--panel-inset); | |
| } | |
| .table-controls { | |
| display: flex; align-items: center; justify-content: space-between; | |
| gap: var(--space-2); | |
| padding: 0.5rem 0.7rem; | |
| border-bottom: 1px solid var(--border-light); | |
| background: var(--bg-raised); | |
| } | |
| .table-info { | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 0.72rem; color: var(--text-tertiary); | |
| } | |
| .table-resize-controls { display: flex; gap: 4px; } | |
| .table-resize-btn { | |
| font-family: inherit; font-size: 0.7rem; font-weight: 600; | |
| color: var(--text-secondary); | |
| background: var(--panel); | |
| border: 1px solid var(--border-strong); | |
| border-radius: 6px; padding: 2px 9px; cursor: pointer; | |
| transition: color var(--transition-fast), border-color var(--transition-fast), | |
| background var(--transition-fast); | |
| } | |
| .table-resize-btn:hover { border-color: rgb(34 211 238 / .5); color: var(--accent-bright); } | |
| .table-resize-btn.active { | |
| color: var(--accent-ink); | |
| background: var(--accent); | |
| border-color: var(--accent); | |
| } | |
| .table-container { overflow-x: auto; } | |
| .answer-table { | |
| border-collapse: collapse; | |
| width: 100%; | |
| font-size: 0.85rem; | |
| } | |
| .answer-table th, .answer-table td { | |
| border-bottom: 1px solid var(--border-light); | |
| text-align: left; | |
| color: var(--text-primary); | |
| } | |
| .answer-table thead th { | |
| background: var(--bg-raised); | |
| font-weight: 600; | |
| color: var(--accent-bright); | |
| border-bottom: 1px solid var(--border-strong); | |
| } | |
| .answer-table tbody tr:hover td { background: rgba(34, 211, 238, 0.05); } | |
| .answer-table.compact th, .answer-table.compact td { padding: 0.25rem 0.7rem; font-size: 0.78rem; } | |
| .answer-table.comfortable th, .answer-table.comfortable td { padding: 0.45rem 0.8rem; } | |
| .answer-table.spacious th, .answer-table.spacious td { padding: 0.75rem 1rem; font-size: 0.9rem; } | |
| .status-text { color: var(--text-tertiary); } | |
| .text-success { color: var(--success); } | |
| .text-warning { color: var(--warning); } | |
| .text-error { color: var(--error); } | |
| /* Markdown tables inside answer */ | |
| .answer-content table { | |
| border-collapse: collapse; | |
| width: 100%; | |
| margin: 0.6rem 0; | |
| font-size: 0.86rem; | |
| } | |
| .answer-content th, .answer-content td { | |
| border: 1px solid var(--border); | |
| padding: 0.4rem 0.7rem; | |
| text-align: left; | |
| } | |
| .answer-content th { | |
| background: var(--bg-raised); | |
| font-weight: 600; | |
| color: var(--accent-bright); | |
| } | |
| .answer-content tr:nth-child(even) td { background: var(--panel-inset); } | |
| </style> | |
| <script> | |
| /* Theme before first paint: avoid a dark flash for light-mode users */ | |
| try { if (localStorage.getItem('ql.theme') === 'light') { document.documentElement.classList.add('light'); } } catch (e) { /* no-op */ } | |
| </script> | |
| </head> | |
| <body> | |
| <div class="app-container"> | |
| <!-- Header --> | |
| <header class="header"> | |
| <div class="header-content"> | |
| <div class="brand"> | |
| <div class="brand-icon"> | |
| <svg width="26" height="26" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| <!-- magnifying lens scanning a database disk stack --> | |
| <g stroke="#22D3EE" stroke-width="2.6" fill="none"> | |
| <ellipse cx="20" cy="14" rx="10.5" ry="4" /> | |
| <path d="M9.5 14v20c0 2.2 4.7 4 10.5 4s10.5-1.8 10.5-4V14" /> | |
| <path d="M9.5 23c0 2.2 4.7 4 10.5 4s10.5-1.8 10.5-4" /> | |
| </g> | |
| <circle cx="32.5" cy="27.5" r="8.2" fill="rgba(34,211,238,.16)" stroke="#7DECFB" stroke-width="2.4" /> | |
| <path d="M38.6 33.6L44.4 39.4" stroke="#7DECFB" stroke-width="2.8" stroke-linecap="round" /> | |
| </svg> | |
| </div> | |
| <div class="brand-text"> | |
| <h1>Query<span class="lens">Lens</span></h1> | |
| <p>Transform natural language into SQL, and documents into insight.</p> | |
| </div> | |
| </div> | |
| <div class="header-right"> | |
| <button id="themeToggle" class="theme-toggle" type="button" aria-label="Switch to light mode" | |
| title="Switch to light mode"> | |
| <svg class="icon-sun" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round"> | |
| <circle cx="12" cy="12" r="4" /> | |
| <path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" /> | |
| </svg> | |
| <svg class="icon-moon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z" /> | |
| </svg> | |
| </button> | |
| <span class="header-tag" id="dbTag">demo_employee</span> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Main Content --> | |
| <main class="main-content"> | |
| <!-- Query Section --> | |
| <section class="query-section"> | |
| <div class="query-body"> | |
| <textarea id="question" class="query-textarea" | |
| placeholder="Ask a question about your data — e.g. “Which department has the highest average salary?” or “Show me sales by month as a chart.”"></textarea> | |
| <div class="query-controls"> | |
| <select id="modeToggle" class="mode-select"> | |
| <option value="text2sql">Text-to-SQL</option> | |
| <option value="ocr_qa">Document Q&A</option> | |
| </select> | |
| <button id="ask" class="btn btn-primary"> | |
| <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" /> | |
| </svg> | |
| Ask | |
| </button> | |
| <button id="recalc" class="btn btn-secondary btn-outline-violet"> | |
| <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <path d="M1 4v6h6" /> | |
| <path d="M23 20v-6h-6" /> | |
| <path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15" /> | |
| </svg> | |
| Re-execute | |
| </button> | |
| <div id="uploadControls" class="hidden" style="display:flex; gap: 0.5rem; align-items: center;"> | |
| <button id="uploadBtn" class="btn btn-secondary btn-outline-rose"> | |
| <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> | |
| <polyline points="17,8 12,3 7,8" /> | |
| <line x1="12" y1="3" x2="12" y2="15" /> | |
| </svg> | |
| Upload Image | |
| </button> | |
| <span id="uploadStatus">No document</span> | |
| </div> | |
| <div class="status-area"> | |
| <div id="spinner" class="spinner hidden"></div> | |
| <span id="spinnerText" class="hidden">Thinking…</span> | |
| <span id="status">Ready</span> | |
| <span id="time"></span> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Results Grid --> | |
| <div class="results-grid"> | |
| <!-- Main Results Column --> | |
| <div class="main-results"> | |
| <!-- Answer Card --> | |
| <div class="card accent-cyan"> | |
| <div class="card-header"> | |
| <h3 class="card-title"> | |
| <span class="chip c-cyan"> | |
| <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <path d="M9 11l3 3L22 4" /> | |
| <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11" /> | |
| </svg> | |
| </span> | |
| Answer | |
| </h3> | |
| </div> | |
| <div class="card-content"> | |
| <div id="answer" class="answer-content">No answer yet — ask something above.</div> | |
| <div id="chartPending" class="chart-pending"> | |
| Charts & analytics render here automatically when a successful query | |
| returns chart-friendly data — try “Show average salary by department”. | |
| </div> | |
| <div id="chartBox" class="chart-box hidden"> | |
| <div id="chartCanvas"></div> | |
| <p class="chart-caption" id="chartCaption"></p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- SQL Card --> | |
| <div class="card accent-violet"> | |
| <details id="sql-details" open> | |
| <summary class="card-header"> | |
| <h3 class="card-title"> | |
| <span class="chip c-violet"> | |
| <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <polyline points="16,18 22,12 16,6" /> | |
| <polyline points="8,6 2,12 8,18" /> | |
| </svg> | |
| </span> | |
| Generated SQL | |
| </h3> | |
| </summary> | |
| <div class="card-content"> | |
| <pre | |
| class="sql-content"><code id="sql" class="language-sql">-- SQL will appear here after the agent crafts a query --</code></pre> | |
| </div> | |
| </details> | |
| </div> | |
| </div> | |
| <!-- Sidebar --> | |
| <div class="agent-panels"> | |
| <!-- Database panel --> | |
| <div class="panel accent-emerald"> | |
| <details open> | |
| <summary class="panel-header"> | |
| <span class="panel-title"> | |
| <span class="chip c-emerald"> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <ellipse cx="12" cy="5" rx="9" ry="3" /> | |
| <path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3" /> | |
| <path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" /> | |
| </svg> | |
| </span> | |
| Database | |
| <span class="db-badge" id="dbBadge">—</span> | |
| </span> | |
| </summary> | |
| <div class="profile-list" id="schemaProfiles"></div> | |
| <div class="schema-add"> | |
| <label for="schemaName">Add a database</label> | |
| <input type="text" id="schemaName" placeholder="Profile name (e.g. sales_2024)"> | |
| <label for="schemaUrl" style="margin-top:0.6rem">Connection URL — or upload a file</label> | |
| <input type="text" id="schemaUrl" | |
| placeholder="postgresql:// · mysql:// · mssql:// · oracle:// · sqlite:///path/file.db"> | |
| <div class="schema-add-hint">PostgreSQL, MySQL, SQL Server, Oracle & SQLite are all supported — paste any of those connection URLs.</div> | |
| <label for="schemaNotes">Schema notes — optional</label> | |
| <textarea id="schemaNotes" rows="2" | |
| placeholder="Optional: what your columns mean — e.g. 'sold_date IS NULL = still in inventory', 'msrp = list price, sale_price = actual', revenue rules, aliases"></textarea> | |
| <div class="row2"> | |
| <button id="schemaAddBtn" class="btn btn-emerald">Connect</button> | |
| <button id="schemaFileBtn" class="btn btn-secondary btn-outline-amber">Upload .sqlite / .csv</button> | |
| </div> | |
| </div> | |
| <div class="schema-tables" id="schemaTables"></div> | |
| </details> | |
| </div> | |
| <!-- Agent panels --> | |
| <div class="panel accent-blue"> | |
| <details open> | |
| <summary class="panel-header"> | |
| <span class="panel-title"> | |
| <span class="chip c-blue"> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <!-- RAM chip / memory module --> | |
| <rect x="4" y="4" width="16" height="16" rx="2" /> | |
| <rect x="9" y="9" width="6" height="6" /> | |
| <line x1="9" y1="1" x2="9" y2="4" /> | |
| <line x1="15" y1="1" x2="15" y2="4" /> | |
| <line x1="9" y1="20" x2="9" y2="23" /> | |
| <line x1="15" y1="20" x2="15" y2="23" /> | |
| <line x1="20" y1="9" x2="23" y2="9" /> | |
| <line x1="20" y1="14" x2="23" y2="14" /> | |
| <line x1="1" y1="9" x2="4" y2="9" /> | |
| <line x1="1" y1="14" x2="4" y2="14" /> | |
| </svg> | |
| </span> | |
| Memory Agent | |
| </span> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <polyline points="6,9 12,15 18,9" /> | |
| </svg> | |
| </summary> | |
| <div id="memory" class="panel-content">—</div> | |
| </details> | |
| </div> | |
| <div class="panel accent-violet"> | |
| <details open> | |
| <summary class="panel-header"> | |
| <span class="panel-title"> | |
| <span class="chip c-violet"> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <!-- terminal: the agent crafts SQL --> | |
| <polyline points="4,17 10,11 4,5" /> | |
| <line x1="12" y1="19" x2="20" y2="19" /> | |
| </svg> | |
| </span> | |
| Query Craft Agent | |
| </span> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <polyline points="6,9 12,15 18,9" /> | |
| </svg> | |
| </summary> | |
| <div id="querycraft" class="panel-content">—</div> | |
| </details> | |
| </div> | |
| <div class="panel accent-rose"> | |
| <details open> | |
| <summary class="panel-header"> | |
| <span class="panel-title"> | |
| <span class="chip c-rose"> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /> | |
| <polyline points="14,2 14,8 20,8" /> | |
| <line x1="16" y1="13" x2="8" y2="13" /> | |
| <line x1="16" y1="17" x2="8" y2="17" /> | |
| <polyline points="10,9 9,9 8,9" /> | |
| </svg> | |
| </span> | |
| Result Presenter Agent | |
| </span> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" | |
| stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <polyline points="6,9 12,15 18,9" /> | |
| </svg> | |
| </summary> | |
| <div id="presenter" class="panel-content">—</div> | |
| </details> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Footer --> | |
| <footer class="footer"> | |
| <p>QueryLens — multi-agent Text-to-SQL & document intelligence</p> | |
| </footer> | |
| </div> | |
| <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script> | |
| <script src="/static/app.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-sql.min.js"></script> | |
| </body> | |
| </html> | |