diff --git a/.gitignore b/.gitignore index 7f9b52d..370aa7a 100644 --- a/.gitignore +++ b/.gitignore @@ -31,4 +31,5 @@ FIXES_APPLIED.md .cursor/ .agents/ skills-lock.json -graphify-out/ \ No newline at end of file +graphify-out/ +.superpowers/ \ No newline at end of file diff --git a/docs/html/editor-file-views.html b/docs/html/editor-file-views.html index 9264f01..3777384 100644 --- a/docs/html/editor-file-views.html +++ b/docs/html/editor-file-views.html @@ -102,69 +102,38 @@

Simple flow for teams

WHERE created_at >= NOW() - INTERVAL '7 days' GROUP BY day ORDER BY day; -
-
✓ 7 rows in 43ms · demo_db
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
day orders revenue
2026-04-0714218,420.00
2026-04-0815821,340.50
2026-04-0913117,890.00
2026-04-1017724,110.25
2026-04-1119127,905.40
2026-04-1216822,490.00
2026-04-1318226,331.75
-
- -
-

Execution Insight

-

Suggestion: add an index on orders(created_at) and keep daily aggregation in a materialized - view for dashboard latency under 100ms.

-
-
- 📊 Revenue by Day — Bar Chart - Chart.js -
-
- +
+

Click Run to execute this cell — the results table and chart appear below.

+
+
+
✓ 7 rows · demo_db
+ + + + + + + + + +
day orders revenue
+
+
+

Execution Insight

+

Suggestion: add an index on orders(created_at) and keep daily aggregation in a materialized + view for dashboard latency under 100ms.

+
+
+
+ 📊 Revenue by Day — Bar Chart + Chart.js +
+
+ +
+
diff --git a/docs/html/minimized-overview.html b/docs/html/minimized-overview.html index faa7f58..4f577c9 100644 --- a/docs/html/minimized-overview.html +++ b/docs/html/minimized-overview.html @@ -3,6 +3,7 @@ + @@ -10,79 +11,370 @@
-
-

VS Code Marketplace --

-
- + + +
+ +
+ +

+ PostgreSQL work
+ without + context + switching. +

+ +

Connect to a demo database, run a notebook query, watch results chart, + and ask the AI assistant why the query is slow — all inside VS Code.

+ +
+ + Install from Marketplace +
+ +
+
+ + Marketplace installs +
+
+ + Current release +
+
+ AI + SQL + Schema aware workflows +
+
-

Powerful PostgreSQL Management Inside VS Code

-

Write SQL, manage PostgreSQL databases, and leverage AI — all without - leaving VS Code. Interactive SQL notebooks (.pgsql), live dashboards, schema explorer, and AI-assisted query - optimization with OpenAI, Anthropic Claude, Gemini, and GitHub Models.

-
-
- ⬇ Install Now - -
-
-
- - - - - + +
+ +
+

+ Interactive workspace + +

+ +
+ + + + + + + + +
+ +
+ + PgStudio Workspace · Demo Project + +
+ + + +
+ Plan insight + Index recommendation +
+ +
+ +
+
-
-- Real-time database insights
-SELECT
-  date_trunc('day', created_at) AS day,
-  COUNT(*) AS users,
-  SUM(amount) AS revenue
-FROM orders
-WHERE created_at >= NOW() - INTERVAL '7 days'
-GROUP BY day ORDER BY day;
-
✓ 7 rows in 45ms
-
- + +
+ +

+ + Below: capabilities, pricing, install everywhere +

+ + + +
+ +

Everything PgStudio does for you

+

50+ capabilities across 5 areas — all inside VS Code, zero browser tabs required.

+
+ + + + + + +
+ + +
+
+ +
+
Capability
+

Capability

+

+
+ +
+
+ +
+
+
+ + + +
+ +

Simple, transparent pricing

+

No hidden fees, no surprise charges. The extension is free and open source today.

+
+
+
Community
+
For individual developers and small teams
+
$0 / forever
+
    +
  • SQL notebooks with inline results
  • +
  • Database explorer for PostgreSQL objects
  • +
  • AI assistant including GitHub Models (no API key)
  • +
  • Environment safety labels and risk signals
  • +
  • Export CSV, JSON, Excel
  • +
  • Community support via GitHub
  • +
+ Install Free +
+
+
Teams roadmap
+
Commercial tiers are not sold yet — follow progress on GitHub.
+
TBD
+
    +
  • Everything in Community
  • +
  • Optional cloud sync for shared connection profiles (planned)
  • +
  • Org-wide governance and audit hooks (planned)
  • +
  • Prioritized support channel (planned)
  • +
+ Track on GitHub → +
+
+
+ + + +
+ +

Available everywhere

+

Install in under a minute from your preferred marketplace.

+ +
+ + + + + +

PgStudio helps developers query PostgreSQL in VS Code with notebooks, explorer navigation, schema tools, AI-assisted SQL generation, EXPLAIN analysis, and performance optimization workflows.

@@ -96,4 +388,4 @@

PgStudio capabilities

  • Production safety controls with environment labels and read-only mode
  • - \ No newline at end of file + diff --git a/docs/index.html b/docs/index.html index 284924e..c79d350 100644 --- a/docs/index.html +++ b/docs/index.html @@ -30,7 +30,7 @@ - + + diff --git a/docs/js/bootstrap.js b/docs/js/bootstrap.js index 47d791c..a77d724 100644 --- a/docs/js/bootstrap.js +++ b/docs/js/bootstrap.js @@ -1,14 +1,80 @@ +function wireLandingChrome() { + document.getElementById("btn-landing-home")?.addEventListener("click", () => { + const minimized = document.body.classList.contains("editor-minimized"); + if (minimized) { + document.querySelector(".hero-shell")?.scrollTo({ top: 0, behavior: "smooth" }); + window.scrollTo({ top: 0, behavior: "smooth" }); + return; + } + setEditorMinimizedState(true); + }); + + document.getElementById("btn-landing-live-demo")?.addEventListener("click", () => { + setEditorMinimizedState(false); + openFile("query"); + switchSidebarPanel("pgstudio"); + }); + + document.querySelectorAll("[data-landing-open-demo]").forEach((node) => { + node.addEventListener("click", (e) => { + e.preventDefault(); + setEditorMinimizedState(false); + openFile("query"); + switchSidebarPanel("pgstudio"); + }); + }); +} + +function wireEditorLayoutToggles() { + const wb = document.querySelector(".workbench"); + const btnExplorer = document.getElementById("btn-toggle-explorer-sidebar"); + const btnAssistant = document.getElementById("btn-toggle-assistant-sidebar"); + if (!wb || !btnExplorer || !btnAssistant) return; + + function syncLayoutToggleUi() { + const leftHidden = wb.classList.contains("panel-left-hidden"); + const rightHidden = wb.classList.contains("panel-right-hidden"); + btnExplorer.setAttribute("aria-pressed", leftHidden ? "true" : "false"); + btnAssistant.setAttribute("aria-pressed", rightHidden ? "true" : "false"); + btnExplorer.setAttribute("title", leftHidden ? "Show Explorer sidebar" : "Hide Explorer sidebar"); + btnAssistant.setAttribute("title", rightHidden ? "Show SQL Assistant" : "Hide SQL Assistant"); + } + + btnExplorer.addEventListener("click", (e) => { + e.stopPropagation(); + wb.classList.toggle("panel-left-hidden"); + if (wb.classList.contains("panel-left-hidden")) { + wb.classList.remove("show-left"); + } + syncLayoutToggleUi(); + }); + + btnAssistant.addEventListener("click", (e) => { + e.stopPropagation(); + wb.classList.toggle("panel-right-hidden"); + if (wb.classList.contains("panel-right-hidden")) { + wb.classList.remove("show-right"); + } + syncLayoutToggleUi(); + }); + + syncLayoutToggleUi(); +} + function initializeDesktopExperience() { wireThemeToggle(); wireTour(); + wireLandingChrome(); wireWindowControls(); wireActivityBar(); + wireEditorLayoutToggles(); wireNavigation(); wireTabClose(); wireSearch(); wireQueryRunAnimation(); wireQueryToolbarActions(); wireFeatureCards(); + if (typeof wireCapabilityModal === "function") wireCapabilityModal(); wireConnectionSimulation(); wireAssistant(); hydrateMarketplaceStats(); @@ -16,11 +82,18 @@ function initializeDesktopExperience() { preloadAssistantConversation(); openFile("query"); - window.setTimeout(renderRevenueChart, 500); - document.addEventListener("click", (e) => { const tab = e.target.closest("[data-open='query']"); if (tab) window.setTimeout(animateSqlTyping, 200); + // On first workbench interaction: schedule context node fade and suppress command palette + if (e.target.closest(".shell")) { + if (!document.body.classList.contains("nodes-faded")) { + window.setTimeout(() => document.body.classList.add("nodes-faded"), 6000); + } + if (!document.body.classList.contains("shell-engaged")) { + document.body.classList.add("shell-engaged"); + } + } }); } @@ -60,7 +133,8 @@ function wireMobileUiToggles() { if (btnCloseEditor && body) { btnCloseEditor.addEventListener("click", () => { - body.classList.toggle("editor-minimized"); + const nextMinimized = !body.classList.contains("editor-minimized"); + setEditorMinimizedState(nextMinimized); }); } diff --git a/docs/js/landing-capabilities.js b/docs/js/landing-capabilities.js new file mode 100644 index 0000000..31b4709 --- /dev/null +++ b/docs/js/landing-capabilities.js @@ -0,0 +1,382 @@ +// Landing-page capability modal +// Wires the "Everything PgStudio does for you" cards to a single +// element and populates it on click. + +const CAPABILITY_DETAILS = { + notebooks: { + icon: "📓", + eyebrow: "Workflow", + title: "SQL Notebooks", + tagline: + "Author multi-cell .pgsql notebooks that mix queries, markdown, and inline results. Save them, version them, share them.", + sections: [ + { + heading: "Run & iterate", + items: [ + "Multi-statement cells — execute several statements in one cell with streaming NOTICE output.", + "Dollar-quote-aware splitter — safely runs functions, DO blocks, and stored procedures.", + "Failure strategies — stop on first error, continue, or rollback the whole cell.", + "Per-cell transactions — savepoints, manual commit/rollback, auto-rollback on error.", + ], + }, + { + heading: "Inspect results", + items: [ + "Inline result tables with sort, filter, and column resize.", + "Charts — bar, line, pie rendered with Chart.js directly inside the notebook.", + "EXPLAIN visualizer — read query plans without leaving the cell.", + "Export — CSV, JSON, Excel (XLSX) in a single click.", + ], + }, + { + heading: "Stay productive", + items: [ + "SQL completions — schema-aware identifiers, keywords, snippets.", + "Saved queries with tags and a queryable history.", + "Markdown cells for runbooks, postmortems, and shareable analysis.", + "Git-friendly — .pgsql is plain text, diffs cleanly in PRs.", + ], + }, + { + heading: "Status & safety", + items: [ + "Status bar shows connection, database, transaction state, and risk indicator.", + "Risk scoring on destructive statements before you hit run.", + "Notebook export — render the whole notebook to standalone HTML.", + ], + }, + ], + tags: [".pgsql", "Multi-statement", "Charts", "EXPLAIN", "CSV / JSON / Excel"], + }, + + explorer: { + icon: "🗂️", + eyebrow: "Navigation", + title: "Database Explorer", + tagline: + "A tree view that mirrors your PostgreSQL instance — connections, databases, schemas, and every object PostgreSQL ships.", + sections: [ + { + heading: "Browse everything", + items: [ + "Connections → Databases → Schemas → Objects hierarchy.", + "16+ object types — tables, views, materialized views, indexes, sequences, types, domains, functions, procedures, triggers, partitions, FDWs, extensions, roles, publications, subscriptions.", + "DDL viewer — see the live CREATE statement for any object.", + "Background schema poller auto-refreshes the tree when objects change.", + ], + }, + { + heading: "1-click SQL", + items: [ + "Right-click → generate SELECT, INSERT, UPDATE, DELETE notebooks pre-filled with column lists.", + "ALTER and DROP templates with confirmation prompts.", + "Table properties panel — columns, indexes, constraints, triggers in one view.", + "VACUUM / ANALYZE / REINDEX shortcuts wrapped in safe templates.", + ], + }, + { + heading: "Performance-aware", + items: [ + "Adaptive-TTL cache — 30s / 1m / 5m based on access frequency.", + "Connection pooling keyed by {connection, database}.", + "SSH tunneling with forwarded local ports per connection.", + ], + }, + { + heading: "Connections", + items: [ + "Profile manager — save and switch between connections.", + "Encrypted credentials via VS Code SecretStorage.", + "Environment labels (DEV / STAGE / PROD) attach to every connection.", + ], + }, + ], + tags: ["Tree view", "DDL viewer", "1-click SQL", "SSH tunnel", "SecretStorage"], + }, + + ai: { + icon: "✨", + eyebrow: "Assistance", + title: "AI Assistant", + tagline: + "A schema-aware chat panel that writes, explains, and optimizes SQL — using the model and provider you choose.", + sections: [ + { + heading: "Bring your own model", + items: [ + "OpenAI — GPT-4o, GPT-4o mini, GPT-4 Turbo.", + "Anthropic — Claude 3.5 Sonnet, Haiku, Opus.", + "Google — Gemini 1.5 Pro, Flash.", + "GitHub Models — free tier, no API key required.", + "Local / custom — point at any OpenAI-compatible endpoint.", + ], + }, + { + heading: "Schema-aware prompts", + items: [ + "Auto-injects relevant table and column metadata based on your question.", + "Understands the active connection and database for accurate suggestions.", + "Streaming responses with copy-to-cell action.", + ], + }, + { + heading: "What you can ask", + items: [ + "Generate — “top 10 customers by revenue last quarter”.", + "Explain — paste a query and get a plain-English breakdown.", + "Diagnose — paste an error and get a likely cause + fix.", + "Optimize — suggest indexes and rewrite slow queries.", + ], + }, + { + heading: "Privacy & control", + items: [ + "API keys stored in VS Code SecretStorage — never logged.", + "Model and provider per workspace — pick a different model per project.", + "Conversation history is local; clear it any time.", + ], + }, + ], + tags: ["GPT-4o", "Claude", "Gemini", "GitHub Models", "Schema context", "Streaming"], + }, + + schema: { + icon: "🎨", + eyebrow: "Modeling", + title: "Visual Schema Tools", + tagline: + "Design tables, diff schemas, and import data without leaving VS Code — with safe DDL output you can review before applying.", + sections: [ + { + heading: "Visual table designer", + items: [ + "Add / rename / drop columns with type, nullability, default, and constraints.", + "Foreign keys with referential actions and deferrable options.", + "DDL preview — see the exact CREATE / ALTER before you run it.", + "Generates up + down migrations as paired files.", + ], + }, + { + heading: "ERD diagrams", + items: [ + "Auto-generated from any schema — pan, zoom, export.", + "Shows FK relationships, cardinality, and column types.", + "Click a table in the diagram to open its properties panel.", + ], + }, + { + heading: "Schema diff", + items: [ + "Compare two schemas / databases side by side.", + "Generates a migration script to bring source ↔ target into sync.", + "Highlights destructive changes (drops, type narrowing) with explicit warnings.", + ], + }, + { + heading: "Data import", + items: [ + "CSV / JSON import with guided column mapping.", + "Type inference with overrides per column.", + "Migration framework detection — Flyway, Alembic, golang-migrate, Prisma — and it writes files in their convention.", + ], + }, + ], + tags: ["DDL preview", "ERD", "Schema diff", "CSV / JSON import", "Migration files"], + }, + + safety: { + icon: "🛡️", + eyebrow: "Production", + title: "Safety Controls", + tagline: + "Built for engineers who run queries against real databases. Every dangerous action has a guardrail you can configure.", + sections: [ + { + heading: "Environment awareness", + items: [ + "DEV / STAGE / PROD labels per connection, color-coded everywhere.", + "Status bar indicator shows the current environment at all times.", + "Read-only mode per connection — blocks writes at the executor level.", + ], + }, + { + heading: "Risk scoring", + items: [ + "Static analysis on every cell before run — DROP, TRUNCATE, DELETE/UPDATE without WHERE.", + "Confirmation prompt on high-risk statements (configurable threshold).", + "Risk indicator in the status bar for the current cell.", + ], + }, + { + heading: "Transaction safety", + items: [ + "Per-session transaction state tracked in the kernel.", + "Savepoints with named restore points across cells.", + "Auto-rollback on error — never leave a session in a broken state.", + ], + }, + { + heading: "Credentials & access", + items: [ + "VS Code SecretStorage — passwords are encrypted at rest, never in JSON.", + "SSH tunnels for jump-host access without exposing ports.", + "Schema poller respects connection scope — no cross-database leaks.", + ], + }, + ], + tags: ["DEV / STAGE / PROD", "Read-only", "Risk scoring", "Savepoints", "SecretStorage", "SSH"], + }, + + performance: { + icon: "📊", + eyebrow: "Optimization", + title: "Performance Insights", + tagline: + "Find slow queries, understand why they’re slow, and get specific guidance on how to fix them.", + sections: [ + { + heading: "EXPLAIN visualizer", + items: [ + "EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) parsed and rendered as a node tree.", + "Hot path highlighting — biggest cost contributors flagged.", + "Per-node detail — rows, time, buffers, loops, planning vs execution time.", + ], + }, + { + heading: "Index advisor", + items: [ + "Detects sequential scans on large tables and suggests index candidates.", + "Recommends composite indexes based on WHERE / JOIN / ORDER BY clauses.", + "Generates CREATE INDEX with CONCURRENTLY when safe.", + ], + }, + { + heading: "Performance baselines", + items: [ + "Welford’s online variance tracks rolling mean and stddev per query.", + "Degradation alerts when a query’s p95 drifts beyond baseline.", + "Query analyzer stores a local history you can sort by slowest, most frequent, or recently regressed.", + ], + }, + { + heading: "Live dashboard", + items: [ + "Active sessions, locks, and longest-running queries in real time.", + "Cache hit ratios, dead tuple bloat, and table size trends.", + "Replication lag and WAL position when relevant.", + ], + }, + ], + tags: ["EXPLAIN ANALYZE", "Index advisor", "Baselines", "Welford variance", "Live dashboard"], + }, +}; + +const FOCUSABLE_SELECTOR = + "a[href], button:not([disabled]), input, textarea, select, [tabindex]:not([tabindex='-1'])"; + +let activeTrigger = null; + +function buildBody(detail) { + return detail.sections + .map((section) => { + const items = section.items.map((item) => `
  • ${item}
  • `).join(""); + return ` +
    +

    ${section.heading}

    +
      ${items}
    +
    `; + }) + .join(""); +} + +function buildTags(detail) { + return (detail.tags || []) + .map((tag) => `${tag}`) + .join(""); +} + +function populateModal(modal, detail) { + modal.querySelector("[data-cap-icon]").textContent = detail.icon; + modal.querySelector("[data-cap-eyebrow]").textContent = detail.eyebrow; + modal.querySelector("[data-cap-title]").textContent = detail.title; + modal.querySelector("[data-cap-tagline]").innerHTML = detail.tagline; + modal.querySelector("[data-cap-body]").innerHTML = buildBody(detail); + modal.querySelector("[data-cap-tags]").innerHTML = buildTags(detail); +} + +function openModal(modal, detail, trigger) { + populateModal(modal, detail); + activeTrigger = trigger || null; + + if (typeof modal.showModal === "function") { + if (!modal.open) modal.showModal(); + } else { + modal.setAttribute("open", ""); + modal.classList.add("capability-modal-fallback-open"); + } + + // Focus the close button so ESC and Tab behave predictably. + const closeBtn = modal.querySelector("[data-cap-close]"); + if (closeBtn) closeBtn.focus({ preventScroll: true }); +} + +function closeModal(modal) { + if (typeof modal.close === "function" && modal.open) { + modal.close(); + } else { + modal.removeAttribute("open"); + modal.classList.remove("capability-modal-fallback-open"); + } + + if (activeTrigger && typeof activeTrigger.focus === "function") { + activeTrigger.focus({ preventScroll: true }); + } + activeTrigger = null; +} + +function wireCapabilityModal() { + const modal = document.getElementById("capability-modal"); + const cards = document.querySelectorAll(".feature-card[data-cap]"); + if (!modal || !cards.length) return; + + cards.forEach((card) => { + card.addEventListener("click", () => { + const key = card.getAttribute("data-cap"); + const detail = CAPABILITY_DETAILS[key]; + if (!detail) return; + openModal(modal, detail, card); + }); + }); + + const closeBtn = modal.querySelector("[data-cap-close]"); + closeBtn?.addEventListener("click", () => closeModal(modal)); + + // Click outside the inner card (on the dialog backdrop) closes the modal. + modal.addEventListener("click", (e) => { + if (e.target === modal) closeModal(modal); + }); + + // emits 'cancel' on ESC; restore focus to the trigger. + modal.addEventListener("cancel", () => { + if (activeTrigger && typeof activeTrigger.focus === "function") { + activeTrigger.focus({ preventScroll: true }); + } + activeTrigger = null; + }); + + // Trap focus inside the dialog for browsers without native support. + modal.addEventListener("keydown", (e) => { + if (e.key !== "Tab") return; + const focusable = modal.querySelectorAll(FOCUSABLE_SELECTOR); + if (!focusable.length) return; + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + if (e.shiftKey && document.activeElement === first) { + e.preventDefault(); + last.focus(); + } else if (!e.shiftKey && document.activeElement === last) { + e.preventDefault(); + first.focus(); + } + }); +} diff --git a/docs/js/tour.js b/docs/js/tour.js index 05795d4..1e0b7d7 100644 --- a/docs/js/tour.js +++ b/docs/js/tour.js @@ -3,16 +3,10 @@ let currentTourStep = 0; let pendingTourStartTimer = null; function openEditorViewForTour() { - const shell = document.querySelector(".shell"); - const minimizedOverview = document.getElementById("minimized-overview"); const wasMinimized = document.body.classList.contains("editor-minimized"); - - if (wasMinimized) { - document.body.classList.remove("editor-minimized"); - shell?.setAttribute("aria-hidden", "false"); - minimizedOverview?.setAttribute("aria-hidden", "true"); + if (wasMinimized && typeof setEditorMinimizedState === "function") { + setEditorMinimizedState(false); } - return wasMinimized; } diff --git a/docs/js/visuals.js b/docs/js/visuals.js index 7b8ae98..a60a819 100644 --- a/docs/js/visuals.js +++ b/docs/js/visuals.js @@ -17,47 +17,48 @@ function animateCountUp(el, target, suffix, durationMs) { } // ── Marketplace stats ───────────────────────────────────── -function formatCompactNumber(value) { - if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`; - if (value >= 1e3) return `${(value / 1e3).toFixed(1)}K`; - return `${value}`; -} +const MARKETPLACE_STATS_GUARD = { started: false }; async function hydrateMarketplaceStats() { + if (MARKETPLACE_STATS_GUARD.started) return; + MARKETPLACE_STATS_GUARD.started = true; + try { const res = await fetch("https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery", { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json;api-version=3.0-preview.1" }, body: JSON.stringify({ filters: [{ criteria: [{ filterType: 7, value: "ric-v.postgres-explorer" }] }], flags: 914 }) }); - if (!res.ok) throw new Error(res.status); + if (!res.ok) throw new Error(String(res.status)); const data = await res.json(); const ext = data?.results?.[0]?.extensions?.[0]; - if (!ext) throw new Error("missing"); + if (!ext) throw new Error("missing extension"); const installs = ext.statistics?.find((s) => s.statisticName === "install")?.value ?? 0; const rating = ext.statistics?.find((s) => s.statisticName === "weightedRating")?.value ?? 0; const version = ext.versions?.[0]?.version ?? "0.0.0"; const dlEl = document.getElementById("stat-downloads"); const rtEl = document.getElementById("stat-rating"); + const landingDlEl = document.getElementById("landing-stat-downloads"); const set = (id, v) => { const el = document.getElementById(id); if (el) el.textContent = v; }; set("stat-version", `v${version}`); set("badge-version", `v${version}`); - set("min-overview-version", version); + set("min-overview-version", `v${version}`); - document.querySelectorAll('[itemprop="softwareVersion"]').forEach((el) => { - if (el.tagName === "META") { - el.setAttribute("content", version); - } else { - el.textContent = version; - } - }); + const landingVerMeta = document.getElementById("landing-software-version-meta"); + if (landingVerMeta?.tagName === "META") { + landingVerMeta.setAttribute("content", version); + } window.setTimeout(() => { animateCountUp(dlEl, installs >= 1e3 ? installs / 1e3 : installs, installs >= 1e3 ? "K" : "", 1200); animateCountUp(rtEl, rating, "", 800); + animateCountUp(landingDlEl, installs >= 1e3 ? installs / 1e3 : installs, installs >= 1e3 ? "K" : "", 1200); }, 600); - } catch (e) { console.error("Marketplace stats failed", e); } + } catch (e) { + console.error("Marketplace stats failed", e); + MARKETPLACE_STATS_GUARD.started = false; + } } // ── Revenue bar chart (Chart.js) ────────────────────────── @@ -65,11 +66,17 @@ function renderRevenueChart() { const canvas = document.getElementById("revenue-chart"); if (!canvas || typeof Chart === "undefined") return; - const isDark = document.body.getAttribute("data-theme") === "dark"; - const gridColor = isDark ? "rgba(255,255,255,0.06)" : "rgba(77,94,252,0.08)"; - const textColor = isDark ? "#9ca6d4" : "#667096"; - const barColor = isDark ? "rgba(24,214,255,0.55)" : "rgba(77,94,252,0.62)"; - const barBorder = isDark ? "rgba(24,214,255,0.85)" : "#4d5efc"; + const stack = document.getElementById("query-output-stack"); + if (stack?.classList.contains("query-output-stack--pending")) return; + + const existing = Chart.getChart(canvas); + if (existing) existing.destroy(); + + // Dark-only tokens — aligned with the immersive palette + const gridColor = "rgba(148,163,184,0.1)"; + const textColor = "#9fb0cc"; + const barColor = "rgba(34,211,238,0.55)"; + const barBorder = "#22d3ee"; new Chart(canvas, { type: "bar", @@ -90,11 +97,11 @@ function renderRevenueChart() { plugins: { legend: { display: false }, tooltip: { - backgroundColor: isDark ? "#1c1d4f" : "#ffffff", - borderColor: isDark ? "rgba(24,214,255,0.3)" : "rgba(77,94,252,0.3)", + backgroundColor: "#0d1728", + borderColor: "rgba(34,211,238,0.28)", borderWidth: 1, - titleColor: isDark ? "#eff3ff" : "#14162b", - bodyColor: isDark ? "#9ca6d4" : "#667096", + titleColor: "#f8fbff", + bodyColor: "#9fb0cc", cornerRadius: 6, callbacks: { label: (ctx) => `$${ctx.parsed.y.toLocaleString()}` diff --git a/docs/js/workbench.js b/docs/js/workbench.js index 5450698..332f274 100644 --- a/docs/js/workbench.js +++ b/docs/js/workbench.js @@ -1,3 +1,24 @@ +/** Keeps `.shell` / `#minimized-overview` aria-hidden in sync with `body.editor-minimized`. */ +function setEditorMinimizedState(minimized) { + const shell = document.querySelector(".shell"); + const minimizedOverview = document.getElementById("minimized-overview"); + document.body.classList.toggle("editor-minimized", minimized); + if (shell) { + shell.setAttribute("aria-hidden", minimized ? "true" : "false"); + if (!minimized) { + shell.classList.add("shell-opening"); + shell.addEventListener( + "animationend", + () => shell.classList.remove("shell-opening"), + { once: true } + ); + } + } + if (minimizedOverview) { + minimizedOverview.setAttribute("aria-hidden", minimized ? "false" : "true"); + } +} + function openFile(fileName) { ensureTabExists(fileName); @@ -60,19 +81,10 @@ function wireWindowControls() { const terminalButtons = document.querySelectorAll(".mini-editor-preview button"); if (!closeDot || !shell) return; - const setEditorMinimized = (minimized) => { - document.body.classList.toggle("editor-minimized", minimized); - shell.setAttribute("aria-hidden", minimized ? "true" : "false"); - if (minimizedOverview) minimizedOverview.setAttribute("aria-hidden", minimized ? "false" : "true"); - }; - - let isClosing = false; closeDot.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation() - setEditorMinimized(true); - // if (isClosing) return; - // isClosing = true; + setEditorMinimizedState(true); // shell.classList.add("closing"); // const delayMs = CLOSE_REDIRECT_MIN_MS + Math.random() * (CLOSE_REDIRECT_MAX_MS - CLOSE_REDIRECT_MIN_MS); @@ -84,28 +96,36 @@ function wireWindowControls() { minimizeDot?.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); - setEditorMinimized(true); + setEditorMinimizedState(true); }); maximizeDot?.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); - setEditorMinimized(true); + setEditorMinimizedState(true); }); restoreShortcut?.addEventListener("click", () => { - setEditorMinimized(false); + setEditorMinimizedState(false); }); terminalButtons.forEach((button) => { button.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); - setEditorMinimized(false); + setEditorMinimizedState(false); openFile("query"); switchSidebarPanel("pgstudio"); }); }); + + minimizedOverview?.querySelector(".mini-editor-preview")?.addEventListener("click", (e) => { + const el = e.target; + if (el instanceof Element && el.closest("button")) return; + setEditorMinimizedState(false); + openFile("query"); + switchSidebarPanel("pgstudio"); + }); } // ── Tab close (+ middle-click) ──────────────────────────── @@ -141,21 +161,14 @@ function wireNavigation() { }); } -// ── Theme ───────────────────────────────────────────────── -function applyTheme(theme) { +// ── Theme (dark-only) ───────────────────────────────────── +function applyTheme(_theme) { if (!document.body) return; - document.body.setAttribute("data-theme", theme); - const label = `Theme: ${theme === "light" ? "Light" : "Dark"}`; - const toggle = document.getElementById("theme-toggle"); + // Always dark — any stored or passed theme value is ignored + document.body.setAttribute("data-theme", "dark"); const statusTheme = document.getElementById("sb-theme"); - if (toggle) { - const nextThemeLabel = theme === "dark" ? "light" : "dark"; - toggle.setAttribute("aria-label", `Switch to ${nextThemeLabel} theme`); - toggle.setAttribute("data-tooltip", `Theme: ${theme === "light" ? "Light" : "Dark"}`); - toggle.setAttribute("title", `Switch to ${nextThemeLabel} theme`); - } - if (statusTheme) statusTheme.textContent = label; - // Re-render chart so bar/grid colours match the new theme + if (statusTheme) statusTheme.textContent = "Theme: Dark"; + // Re-render chart with dark tokens unconditionally if (typeof Chart !== "undefined") { const canvas = document.getElementById("revenue-chart"); if (canvas && Chart.getChart(canvas)) { @@ -166,12 +179,9 @@ function applyTheme(theme) { } function wireThemeToggle() { - applyTheme(window.localStorage.getItem(THEME_KEY) === "dark" ? "dark" : "light"); - document.getElementById("theme-toggle")?.addEventListener("click", () => { - const next = document.body.getAttribute("data-theme") === "dark" ? "light" : "dark"; - applyTheme(next); - window.localStorage.setItem(THEME_KEY, next); - }); + applyTheme("dark"); + // Toggle button is hidden via CSS; listener kept for safety but writes nothing + document.getElementById("theme-toggle")?.addEventListener("click", () => applyTheme("dark")); } // ── Search ──────────────────────────────────────────────── @@ -209,15 +219,24 @@ function wireQueryRunAnimation() { const resultBody = document.getElementById("result-body"); const resultMeta = resultContainer?.querySelector(".result-meta"); const insightText = document.getElementById("insight-text"); + const outputStack = document.getElementById("query-output-stack"); if (!runButton || !resultContainer || !resultBody || !resultMeta || !insightText) return; runButton.addEventListener("click", () => { + const hintEl = document.getElementById("query-output-hint"); + const awaitingFirstRun = outputStack?.classList.contains("query-output-stack--pending"); + if (awaitingFirstRun && hintEl) { + hintEl.textContent = "Executing query…"; + } else { + resultMeta.textContent = "Executing query…"; + } + resultContainer.classList.add("running"); - resultMeta.textContent = "Executing query…"; insightText.textContent = "Analyzing scan strategy and aggregations…"; runButton.disabled = true; window.setTimeout(() => { + outputStack?.classList.remove("query-output-stack--pending"); const dataRows = [ ["2026-04-07", 142, "18,420.00"], ["2026-04-08", 158, "21,340.50"], ["2026-04-09", 131, "17,890.00"], ["2026-04-10", 177, "24,110.25"], ["2026-04-11", 191, "27,905.40"], ["2026-04-12", 168, "22,490.00"], @@ -233,6 +252,9 @@ function wireQueryRunAnimation() { resultMeta.textContent = `✓ 7 rows in ${execMs}ms · ecommerce_demo`; insightText.textContent = "Suggestion: add an index on orders(created_at) and keep daily aggregation in a materialized view for dashboard latency under 100ms."; runButton.disabled = false; + window.setTimeout(() => { + if (typeof renderRevenueChart === "function") renderRevenueChart(); + }, 100); }, RUN_RESULT_DELAY_MS); }); @@ -281,9 +303,9 @@ function wireQueryToolbarActions() { function wireFeatureCards() { const detail = document.getElementById("feature-detail"); if (!detail) return; - document.querySelectorAll(".feature-card").forEach((card) => { + document.querySelectorAll(".feature-card[data-feature]").forEach((card) => { card.addEventListener("click", () => { - document.querySelectorAll(".feature-card").forEach((c) => c.classList.remove("active")); + document.querySelectorAll(".feature-card[data-feature]").forEach((c) => c.classList.remove("active")); card.classList.add("active"); const key = card.getAttribute("data-feature"); if (key && FEATURE_DETAILS[key]) detail.textContent = FEATURE_DETAILS[key]; diff --git a/docs/roadmap/phase2-demo-view-redesign.md b/docs/roadmap/phase2-demo-view-redesign.md new file mode 100644 index 0000000..950d48b --- /dev/null +++ b/docs/roadmap/phase2-demo-view-redesign.md @@ -0,0 +1,126 @@ +# Phase 2 — Demo View Redesign Scope + +## Context + +Phase 1 delivered a new dark two-column hero landing page. The full interactive workbench (opened when the user clicks "Open interactive demo") retains its existing visual style. Phase 2 brings that shell into visual alignment with the new landing design. + +**Prerequisite:** Phase 1 landing is live and stable. + +## Objective + +Refresh the visual language of the interactive VS Code shell demo without changing any of its behavior, JS wiring, or content. + +--- + +## Scope Boundaries + +### In scope +- Visual CSS overhaul of the full workbench shell and all its chrome elements +- Topbar, titlebar, activity bar, sidebar, editor region, tabs, breadcrumb, status bar +- Right assistant panel (layout, typography, chat bubbles, action cards) +- Content panels: query cell, result table, insight panel, feature cards, connection form +- Tour overlay and spotlight +- Toast notification +- Mobile responsive tweaks to align with the new dark brand + +### Out of scope +- Any JS behavior changes (wireActivityBar, openFile, wireAssistant, wireTour, etc.) +- Any HTML structural changes that alter element IDs, classes, or `data-*` attributes used by JS +- Content changes to `editor-file-views.html` or `assistant-panel.html` +- SEO metadata or structured data +- Build process or extension TypeScript code + +--- + +## Design Direction + +Pull directly from Phase 1 landing design tokens: + +| Token | Value | +|---|---| +| Shell background | `#0c1528` | +| Sidebar background | `#0d1b30` | +| Border color | `rgba(255,255,255,0.07)` | +| Accent (active tab, highlight) | `#f97316` (orange) | +| Secondary accent | `#3b82f6` (blue) | +| Muted text | `rgba(255,255,255,0.38)` | +| Primary text | `rgba(255,255,255,0.82)` | +| Surface | `rgba(255,255,255,0.04)` | + +Typography: Retain `Google Sans`, `Segoe UI` sans-serif stack. Increase contrast of muted labels by ~10%. + +--- + +## Affected Files + +| File | Change type | +|---|---| +| `docs/styles/base-theme.css` | Add `[data-theme="dark"]`-scoped shell token overrides | +| `docs/styles/workbench-layout.css` | Visual updates to chrome: titlebar, activitybar, sidebar, statusbar, tabs | +| `docs/styles/content-panels.css` | Visual updates to cell, result table, insight panel, feature card, markdown, form | +| `docs/styles/interactive.css` | Visual updates to assistant panel, chat bubbles, tour overlay, toast | +| `docs/html/assistant-panel.html` | Structural clean-up only (no class/ID changes), improve nesting for visual targets | +| `docs/html/editor-file-views.html` | Structural clean-up only (no class/ID changes) | + +--- + +## Implementation Checklist + +### Workbench Chrome +- [ ] Titlebar gradient → flat deep navy with subtle bottom border +- [ ] Window traffic lights (dots) retain exact colors, add hover opacity effect +- [ ] Activity bar: deeper background, active indicator scales to match orange brand +- [ ] Sidebar: border separators at 6% opacity white; header labels match muted token +- [ ] Tab bar: active tab top border stays orange; inactive tab background aligns with `#0d1b30` +- [ ] Breadcrumb: muted separator and filename, match muted token +- [ ] Status bar: keep existing blue; adjust text opacity to 90% white for legibility + +### Editor Region +- [ ] SQL cell border: `rgba(255,255,255,0.07)` +- [ ] Cell lens toolbar: same surface as workbench, action buttons match ghost style +- [ ] Query result table: header background `rgba(255,255,255,0.04)`, row borders at 4% white +- [ ] Insight panel: blue-tinted surface, consistent with landing `mini-wb-insight-bar` style +- [ ] Feature cards: dark surface, hover state with orange border outline + +### SQL Assistant Panel +- [ ] Panel background: `#0c1528` or slightly lighter variant +- [ ] Schema context bar: match `mini-wb-schema-pill` token exactly +- [ ] Action cards: dark surface, icon + label, hover with subtle blue glow +- [ ] Chat bubbles (user): match `mini-chat-user` orange-tinted background +- [ ] Chat bubbles (assistant): match `mini-chat-ai` translucent surface +- [ ] Typing indicator dots: match the new brand accent blue +- [ ] Install CTA link: orange styled, consistent with primary CTA from landing + +### Tour Overlay +- [ ] Spotlight ring: orange accent, `rgba(249,115,22,0.35)` glow +- [ ] Tooltip: dark surface matching shell background, border at 8% white +- [ ] Nav buttons: match ghost button style from landing CTAs + +### Toast +- [ ] Dark surface, orange elephant icon accent, matches workbench shell background + +### Mobile +- [ ] Verify topbar collapse still readable on dark background +- [ ] Mobile workbench panels (show-left, show-right) overlay dark surface properly + +--- + +## Non-Regression Rules for Phase 2 + +- All element IDs remain identical — JS queries must not need changes +- All class names used by JS queries (`.file-view`, `.tab`, `.tree-row`, `.cell`, `.chat-msg`, etc.) must not be renamed or removed +- Only CSS property values change; no structural HTML changes that touch interactive selectors +- After each file change: run a browser smoke test that verifies + 1. Landing opens dark + 2. "Open interactive demo" expands the shell + 3. File navigation (tree row click) switches the editor view + 4. Query run button animates and shows results + 5. AI assistant action cards trigger chat responses + 6. Tour play button starts the tour overlay + 7. Close dot returns to landing + +--- + +## Isolation Strategy + +All Phase 2 CSS overrides should be scoped to `body[data-theme="dark"]` where possible, so that any future light-mode or theme-agnostic path is not silently broken. Use the existing dark-mode selector blocks in each CSS file rather than adding root-level overrides. diff --git a/docs/styles.css b/docs/styles.css index f244d6c..3f7a5d1 100644 --- a/docs/styles.css +++ b/docs/styles.css @@ -1,4 +1,5 @@ @import url("./styles/base-theme.css"); +@import url("./styles/landing-sections.css"); @import url("./styles/workbench-layout.css"); @import url("./styles/content-panels.css"); @import url("./styles/interactive.css"); diff --git a/docs/styles/base-theme.css b/docs/styles/base-theme.css index 5144992..ab64b49 100644 --- a/docs/styles/base-theme.css +++ b/docs/styles/base-theme.css @@ -1,64 +1,49 @@ :root { - /* Light theme: off-white surfaces with blue structure and orange emphasis */ - --vsc-bg: #f8fafc; - --vsc-sidebar: #ffffff; - --vsc-sidebar-bg: #ffffff; - --vsc-shell-bg: #f8fafc; - --vsc-activitybar: #eef2f9; - --vsc-tab-active: #ffffff; - --vsc-tab-inactive: #e2e8f0; - --vsc-statusbar: #1d4ed8; - --vsc-border: #cbd5e1; - --vsc-text: #0f172a; - --vsc-muted: #475569; - --vsc-highlight: #dbeafe; + /* Dark-only immersive palette — single source of truth */ + --vsc-bg: #0d1728; + --vsc-sidebar: #101c32; + --vsc-sidebar-bg: #101c32; + --vsc-shell-bg: #0d1728; + --vsc-activitybar: #0a1220; + --vsc-tab-active: #0d1728; + --vsc-tab-inactive: #101c32; + --vsc-statusbar: #1f3a8a; + --vsc-border: rgba(148, 163, 184, 0.18); + --vsc-text: #f8fbff; + --vsc-muted: #9fb0cc; + --vsc-highlight: rgba(37, 99, 235, 0.18); --vsc-green: #22c55e; - --vsc-blue: #1d4ed8; - --vsc-orange: #ea580c; - --vsc-accent: #1d4ed8; - --vsc-foreground: #0f172a; - --surface: #ffffff; - --site-bg: #f8fafc; - --hero-gradient: linear-gradient(140deg, #eef3ff 0%, #e8f0ff 34%, #f2f6ff 62%, #fff4ec 100%), - radial-gradient(130% 85% at 14% 8%, rgba(59, 130, 246, 0.16) 0%, rgba(59, 130, 246, 0) 58%), - radial-gradient(120% 90% at 88% 92%, rgba(249, 115, 22, 0.12) 0%, rgba(249, 115, 22, 0) 60%); + --vsc-blue: #58a6ff; + --vsc-orange: #ff6b16; + --vsc-accent: #58a6ff; + --vsc-foreground: #f8fbff; + --surface: rgba(14, 24, 45, 0.82); + --site-bg: #0d1728; + /* Single dark canvas shared by landing + interactive demo. Layered atop a solid + base color so no white html-default bleeds through translucent stops. */ + --hero-gradient: + radial-gradient(circle at 18% 18%, rgba(59, 130, 246, 0.24), transparent 34%), + radial-gradient(circle at 84% 28%, rgba(255, 107, 22, 0.2), transparent 32%), + linear-gradient(135deg, #070b14 0%, #0d1728 46%, #15111a 100%); --desktop-topbar-min-height: 48px; --desktop-topbar-padding-y: 9px; --desktop-topbar-padding-x: 16px; - --desktop-topbar-bg: #eef2f9; - --desktop-topbar-border: #cbd5e1; - --desktop-topbar-link: #334155; - --desktop-topbar-link-hover: #0f172a; - --desktop-topbar-intro: #475569; -} - -body[data-theme="dark"] { - /* Dark theme: deep navy surfaces with blue structure and orange execution accents */ - --vsc-bg: #0f1a2e; - --vsc-sidebar: #141f38; - --vsc-sidebar-bg: #141f38; - --vsc-shell-bg: #0f1a2e; - --vsc-activitybar: #131d32; - --vsc-tab-active: #1a2544; - --vsc-tab-inactive: #141f38; - --vsc-statusbar: #1f3a8a; - --vsc-border: #253454; - --vsc-text: #f9fafb; - --vsc-muted: #cbd5f5; - --vsc-highlight: #1a2544; - --vsc-green: #22c55e; - --vsc-blue: #3b82f6; - --vsc-orange: #f97316; - --vsc-accent: #2563eb; - --vsc-foreground: #f9fafb; - --surface: #141f38; - --site-bg: #0f1a2e; - --hero-gradient: radial-gradient(circle at 18% 12%, rgba(37, 99, 235, 0.32) 0%, rgba(15, 26, 46, 0.94) 46%, rgba(249, 115, 22, 0.16) 100%); - --desktop-topbar-bg: #141f38; - --desktop-topbar-border: #253454; - --desktop-topbar-link: #dbe4ff; + --desktop-topbar-bg: #0a1220; + --desktop-topbar-border: rgba(148, 163, 184, 0.12); + --desktop-topbar-link: rgba(255, 255, 255, 0.62); --desktop-topbar-link-hover: #ffffff; - --desktop-topbar-intro: #94a3b8; + --desktop-topbar-intro: #9fb0cc; + /* Landing rail: widest readable column on large displays (avoid ~980px bottleneck) */ + --landing-content-max: min(100vw); + /* Demo window sizing (interactive state): always 90vw × 90vh */ + --demo-shell-w: 90vw; + --demo-shell-h: 90vh; +} + +@supports (height: 100dvh) { + :root { + --demo-shell-h: 90dvh; + } } * { @@ -67,10 +52,13 @@ body[data-theme="dark"] { padding: 0; } +/* Theme toggle hidden — dark is the only theme */ +#theme-toggle { display: none !important; } + body { background: var(--hero-gradient); color: var(--vsc-text); - font-family: "Google Sans", "Google Sans Text", "Product Sans", "Segoe UI", sans-serif; + font-family: Inter, "Google Sans", "Segoe UI", system-ui, sans-serif; height: 100vh; overflow: hidden; } @@ -427,6 +415,99 @@ body[data-theme="dark"] .topbar-icon-btn[data-tooltip]::after { transition: opacity 0.85s ease, transform 0.85s ease, max-height 1.1s ease, min-height 1.1s ease, margin 0.9s ease, border-width 0.75s ease; } +/* Interactive demo: centered shell + AI circuit halo (not full-screen) */ +body:not(.editor-minimized) .site-main { + flex-direction: column; +} + +body:not(.editor-minimized) .hero-shell { + flex: 1 1 auto; + min-height: 0; + overflow: hidden; + padding-bottom: 0; +} + +body:not(.editor-minimized) .demo-shell-stage { + align-items: center; + display: flex; + flex: 1 1 auto; + justify-content: center; + min-height: 0; + padding: 0; + width: 100%; +} + +body:not(.editor-minimized) .demo-shell-frame { + flex-shrink: 0; + height: var(--demo-shell-h); + max-height: var(--demo-shell-h); + max-width: var(--demo-shell-w); + position: relative; + width: var(--demo-shell-w); +} + +/* Floating context pills off in demo mode */ +body:not(.editor-minimized) .ctx-node { + display: none; +} + +/* Glowing halo attached to the shell */ +body:not(.editor-minimized) .demo-shell-halo { + animation: demo-halo-pulse 6s ease-in-out infinite; + background: + radial-gradient(ellipse 70% 60% at 30% 20%, rgba(34, 211, 238, 0.18) 0%, transparent 60%), + radial-gradient(ellipse 60% 55% at 80% 80%, rgba(249, 115, 22, 0.16) 0%, transparent 62%), + radial-gradient(ellipse 80% 70% at 50% 50%, rgba(88, 166, 255, 0.1) 0%, transparent 70%); + border-radius: 24px; + display: block; + filter: blur(28px); + inset: -36px; + opacity: 0.85; + pointer-events: none; + position: absolute; + z-index: 0; +} + +@keyframes demo-halo-pulse { + 0%, 100% { + filter: blur(28px) saturate(1); + opacity: 0.78; + } + + 50% { + filter: blur(36px) saturate(1.18); + opacity: 1; + } +} + +@media (prefers-reduced-motion: reduce) { + body:not(.editor-minimized) .demo-shell-halo { + animation: none; + } +} + +body:not(.editor-minimized) .shell { + border-radius: 12px; + border-width: 1px; + box-shadow: + 0 28px 72px rgba(0, 0, 0, 0.55), + 0 0 0 1px rgba(88, 166, 255, 0.22), + 0 0 36px rgba(34, 211, 238, 0.18), + 0 0 80px rgba(249, 115, 22, 0.1); + flex-shrink: 0; + height: 100%; + max-height: 100%; + max-width: 100%; + min-height: 0; + position: relative; + width: 100%; + z-index: 1; +} + +body:not(.editor-minimized) .shell-orbit { + display: none; +} + .minimized-overview { background: transparent; border: 0; @@ -435,7 +516,7 @@ body[data-theme="dark"] .topbar-icon-btn[data-tooltip]::after { display: block; margin: 0 auto; max-height: 0; - max-width: 980px; + max-width: var(--landing-content-max); opacity: 0; overflow-y: auto; padding: 0 20px; @@ -699,15 +780,6 @@ body.editor-minimized .hero-shell>.hero-subtitle { transform: translateY(-12px); } -body.editor-minimized .minimized-overview { - margin-top: 8px; - max-height: 1400px; - opacity: 1; - padding: 10px 20px 16px; - pointer-events: auto; - transform: translateY(0) scale(1); -} - body.editor-minimized .toast { display: none; } @@ -718,13 +790,14 @@ body.editor-minimized .toast { padding: 8px 2px 12px; } - .minimized-overview h2 { - font-size: clamp(1.6rem, 8.2vw, 2.4rem); + .landing-hero-title { + font-size: clamp(3rem, 5.2vw, 4.75rem); + line-height: 0.95; } .min-lead { font-size: 0.95rem; - line-height: 1.5; + line-height: 1.58; } .min-cta { @@ -736,4 +809,1291 @@ body.editor-minimized .toast { .mini-preview-code { font-size: 12px; } +} + +/* ═══════════════════════════════════════════════════════════ + LANDING HERO REDESIGN + Two-column dark hero (editor-minimized state) + ══════════════════════════════════════════════════════════ */ + +/* Landing-only layout vars; body bg is inherited from base for parity with the demo */ +body.editor-minimized { + --landing-hero-slice-height: calc(100vh - var(--desktop-topbar-min-height)); + --landing-section-min-height: 100vh; + --landing-content-max: min(100vw - 40px, 1600px); +} + +@supports (height: 100dvh) { + body.editor-minimized { + --landing-hero-slice-height: calc(100dvh - var(--desktop-topbar-min-height)); + --landing-section-min-height: 100dvh; + } +} + +/* Scroll lives in .hero-shell; each landing slice is at least one viewport tall */ +body.editor-minimized .site-main { + display: flex; + flex-direction: column; + height: 100vh; + max-height: 100vh; + overflow: hidden; +} + +body.editor-minimized .hero-shell { + flex: 1 1 auto; + min-height: 0; + overflow-x: hidden; + overflow-y: auto; + scroll-snap-type: y proximity; +} + +body.editor-minimized .minimized-overview { + display: flex; + flex-direction: column; + margin-top: 0; + max-height: none; + opacity: 1; + padding: 0; + pointer-events: auto; + transform: none; + width: 100%; +} + +body.editor-minimized .minimized-overview > .section-divider { + flex-shrink: 0; + margin-block: 0; +} + +/* Landing topbar: glass dark */ +body.editor-minimized .desktop-topbar { + background: rgba(6, 13, 26, 0.75); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border-bottom-color: rgba(255, 255, 255, 0.06); +} + +body.editor-minimized .desktop-topbar .hero-intro { + color: rgba(255, 255, 255, 0.5); +} + +body.editor-minimized .desktop-topbar-links a, +body.editor-minimized .desktop-topbar-links button { + color: rgba(255, 255, 255, 0.6); +} + +body.editor-minimized .desktop-topbar-links a:hover, +body.editor-minimized .desktop-topbar-links button:hover { + color: #ffffff; +} + +body.editor-minimized .topbar-icon-btn { + background: rgba(255, 255, 255, 0.06); + border-color: rgba(255, 255, 255, 0.1); + color: rgba(255, 255, 255, 0.65); +} + +body.editor-minimized .landing-nav-install { + align-items: center; + background: linear-gradient(135deg, #ff6b16, #ff8a2a); + border-radius: 8px; + box-shadow: 0 10px 28px rgba(255, 107, 22, 0.25); + color: #fff !important; + display: inline-flex; + font-size: 13px; + font-weight: 700; + margin-left: 6px; + min-height: 38px; + padding: 0 14px; + text-decoration: none; +} + +body.editor-minimized .landing-nav-install:hover { + color: #fff !important; + filter: brightness(1.08); +} + +/* ── Two-column hero layout (editor-forward: wider right rail) ── */ +.hero-layout { + align-items: center; + display: grid; + gap: clamp(28px, 4vw, 48px); + grid-template-columns: minmax(300px, 0.82fr) minmax(340px, 1.18fr); + margin: 0 auto; + max-width: min(var(--landing-content-max), 1220px); + padding: 28px clamp(20px, 4vw, 56px) 20px; + width: 100%; +} + +body.editor-minimized .hero-layout.landing-viewport { + align-content: center; + align-items: center; + box-sizing: border-box; + flex-shrink: 0; + min-height: var(--landing-hero-slice-height); + padding-block: clamp(12px, min(3vh, 32px), 40px); + scroll-margin-top: 0; + scroll-snap-align: start; + scroll-snap-stop: normal; +} + +/* ── Left column ────────────────────────────────────────── */ +.hero-col-left { + align-items: flex-start; + box-sizing: border-box; + display: flex; + flex-direction: column; + justify-content: flex-start; + text-align: left; + width: 100%; +} + +body.editor-minimized .hero-col-left { + --landing-hero-copy-max: 620px; +} + +body.editor-minimized .hero-col-left .landing-hero-title, +body.editor-minimized .hero-col-left .min-lead, +body.editor-minimized .hero-col-left .minimized-actions, +body.editor-minimized .hero-col-left .hero-kpi-strip { + box-sizing: border-box; + max-width: var(--landing-hero-copy-max); + text-align: left; + width: 100%; +} + +body.editor-minimized .hero-col-left .hero-kpi-strip { + max-width: var(--landing-hero-copy-max); +} + +.hero-trust-badge { + align-items: center; + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 99px; + color: rgba(255, 255, 255, 0.55); + display: inline-flex; + font-size: 11px; + font-weight: 500; + gap: 7px; + margin-bottom: 28px; + padding: 5px 14px 5px 10px; + width: fit-content; +} + +.badge-pulse { + animation: landing-kicker-pulse 1.6s ease-in-out infinite; + background: var(--vsc-green); + border-radius: 50%; + box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.2); + flex-shrink: 0; + height: 7px; + width: 7px; +} + +@keyframes landing-kicker-pulse { + 0%, 100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.35); } + 50% { box-shadow: 0 0 0 7px rgba(34, 197, 94, 0); } +} + +body.editor-minimized .hero-col-left .landing-hero-title { + color: #f8fbff; + font-size: clamp(3rem, 4.4vw, 4.45rem); + font-weight: 800; + hyphens: none; + letter-spacing: -0.032em; + line-height: 0.98; + margin: 0 0 22px; + text-align: left; +} + +.hero-line { + display: block; +} + +.hero-line--primary { + color: #f8fbff; + font-weight: 800; +} + +body.editor-minimized .hero-col-left .hero-line--accent { + color: #ff7a1a; + display: block; + font-weight: 800; + line-height: 1.01; +} + +/* Legacy spans (if present elsewhere) */ +.hero-title-primary { + color: #ffffff; + font-weight: 800; +} + +.hero-title-accent { + color: #ff7f24; + font-weight: 800; +} + +body.editor-minimized .hero-col-left .min-lead { + color: rgba(203, 213, 225, 0.88); + font-size: 1.05rem; + font-weight: 400; + line-height: 1.62; + margin: 0 0 30px; + max-width: 620px; +} + +/* ── CTAs ───────────────────────────────────────────────── */ +body.editor-minimized .minimized-actions { + align-items: center; + display: flex; + flex-wrap: wrap; + gap: 14px; + justify-content: flex-start; + margin: 0 0 36px; +} + +body.editor-minimized .min-cta { + appearance: none; + border-style: solid; + border-width: 1px; + border-radius: 10px; + box-sizing: border-box; + cursor: pointer; + display: inline-flex; + font-family: inherit; + font-size: 14px; + font-weight: 600; + justify-content: center; + line-height: 1.25; + margin: 0; + min-height: 44px; + padding: 11px 22px; + text-align: center; + text-decoration: none; + transition: transform 0.16s ease, filter 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease; +} + +body.editor-minimized button.min-cta { + border-color: transparent; +} + +body.editor-minimized .min-cta.primary { + background: #ff7a1a; + border: 0; + color: #fff; +} + +body.editor-minimized .min-cta.primary:hover { + box-shadow: 0 4px 16px rgba(249, 115, 22, 0.35); + filter: brightness(1.1); +} + +body.editor-minimized .min-cta.secondary { + background: rgba(15, 23, 42, 0.28); + border-color: rgba(148, 163, 184, 0.32); + color: rgba(226, 232, 240, 0.95); +} + +body.editor-minimized .min-cta.secondary:hover { + border-color: rgba(255, 255, 255, 0.4); + color: #fff; +} + +body.editor-minimized .min-cta:hover { + transform: translateY(-1px); +} + +/* ── KPI strip (trust row): horizontal + vertical dividers ─ */ +.hero-kpi-strip { + align-items: stretch; + display: flex; + flex-wrap: nowrap; + gap: 0; + justify-content: flex-start; + margin-top: 6px; + padding-top: 20px; +} + +.hero-kpi-strip .kpi-item { + display: flex; + flex: 1 1 0; + flex-direction: column; + gap: 5px; + min-width: 0; + padding: 0 24px; +} + +.hero-kpi-strip .kpi-item:first-child { + padding-left: 0; +} + +.hero-kpi-strip .kpi-item:last-child { + padding-right: 0; +} + +.hero-kpi-strip .kpi-item + .kpi-item { + border-left: 1px solid rgba(255, 255, 255, 0.1); + margin-left: 24px; + padding-left: 24px; +} + +.kpi-value { + color: #ffffff; + font-size: 20px; + font-weight: 700; + letter-spacing: -0.01em; +} + +.kpi-label { + color: rgba(255, 255, 255, 0.4); + font-size: 12px; + letter-spacing: 0; + text-transform: none; + white-space: normal; +} + +body.editor-minimized .hero-kpi-strip .kpi-value { + font-size: clamp(1.05rem, 2vw, 1.25rem); + font-weight: 700; +} + +/* ── Right column: interactive editor as hero focal point ── */ +.hero-col-right { + display: flex; + flex-direction: column; + justify-content: flex-start; + position: relative; + width: 100%; +} + +.hero-editor-stage { + position: relative; + width: 100%; + z-index: 1; +} + +/* ── Immersive demo stage (orbit, nodes, cmd palette) ──── */ +.hero-editor-stage--immersive { + perspective: 1600px; +} + +.landing-demo-stage { + margin-top: 4px; + min-height: min(560px, 52vh); + position: relative; + transform-style: preserve-3d; +} + +.landing-orbit-ring { + animation: landing-orbit-spin 12s linear infinite; + border: 1px solid rgba(34, 211, 238, 0.12); + border-radius: 50%; + height: min(520px, 48vw); + left: 50%; + pointer-events: none; + position: absolute; + top: 46%; + transform: translate(-50%, -50%) rotateX(66deg); + width: min(520px, 48vw); + z-index: 0; +} + +@keyframes landing-orbit-spin { + from { transform: translate(-50%, -50%) rotateX(66deg) rotateZ(0deg); } + to { transform: translate(-50%, -50%) rotateX(66deg) rotateZ(360deg); } +} + +.landing-float-node { + align-items: center; + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + background: rgba(7, 14, 26, 0.75); + border: 1px solid rgba(148, 163, 184, 0.22); + border-radius: 14px; + box-shadow: 0 18px 42px rgba(0, 0, 0, 0.45); + display: flex; + font-size: 12px; + gap: 8px; + padding: 9px 11px; + pointer-events: none; + position: absolute; + z-index: 4; +} + +.landing-float-node b { + color: var(--vsc-text); + font-weight: 600; +} + +.landing-float-node span { + color: var(--vsc-muted); +} + +.landing-float-node--one { right: 4%; top: 8%; } +.landing-float-node--two { left: 2%; top: 42%; } +.landing-float-node--three { bottom: 14%; right: 10%; } + +.landing-env-dev { color: var(--vsc-green); font-weight: 700; } +.landing-env-prod { color: var(--vsc-orange); font-weight: 700; } + +.landing-cmd-palette { + animation: landing-palette-cycle 7s ease-in-out infinite; + background: rgba(7, 12, 19, 0.92); + border: 1px solid rgba(88, 166, 255, 0.32); + border-radius: 14px; + box-shadow: 0 28px 70px rgba(0, 0, 0, 0.55), 0 0 36px rgba(88, 166, 255, 0.13); + left: 50%; + max-width: min(520px, 94%); + overflow: hidden; + pointer-events: none; + position: absolute; + top: 6%; + transform: translateX(-50%); + width: min(520px, 94%); + z-index: 5; +} + +.landing-cmd-palette-input { + border-bottom: 1px solid var(--vsc-border); + color: #eaf2ff; + font-size: clamp(13px, 1.5vw, 15px); + padding: 13px 16px; +} + +.landing-cmd-gt { + color: var(--vsc-orange); + margin-right: 4px; +} + +.landing-cmd-row { + align-items: center; + color: #bdccef; + display: flex; + font-size: 12px; + gap: 10px; + padding: 10px 16px; +} + +.landing-cmd-row--active { + background: rgba(37, 99, 235, 0.22); + color: #fff; +} + +.landing-cmd-icon { + flex-shrink: 0; + opacity: 0.85; + width: 1.1em; +} + +@keyframes landing-palette-cycle { + 0%, 28% { opacity: 0; transform: translateX(-50%) translateY(-14px) scale(0.96); } + 38%, 74% { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); } + 84%, 100% { opacity: 0; transform: translateX(-50%) translateY(-8px) scale(0.98); } +} + +.landing-demo-stage .mini-wb-preview--hero { + animation: landing-float-workbench 7s ease-in-out infinite; + position: relative; + transform: rotateY(-7deg) rotateX(3deg); + transform-style: preserve-3d; + z-index: 3; +} + +@keyframes landing-float-workbench { + 0%, 100% { transform: rotateY(-7deg) rotateX(3deg) translateY(0); } + 50% { transform: rotateY(-4deg) rotateX(4deg) translateY(-12px); } +} + +.landing-demo-stage .mini-wb-preview--hero:hover { + animation-play-state: paused; +} + +.landing-below-fold-hint { + align-items: center; + color: var(--vsc-muted); + display: flex; + font-size: 12px; + gap: 10px; + justify-content: center; + margin: 0 auto; + max-width: var(--landing-content-max); + padding: 8px 24px 24px; +} + +.landing-scroll-mouse { + border: 1px solid rgba(148, 163, 184, 0.45); + border-radius: 999px; + display: inline-block; + flex-shrink: 0; + height: 28px; + position: relative; + width: 18px; +} + +.landing-scroll-mouse::after { + animation: landing-mouse-dot 1.5s ease-in-out infinite; + background: var(--vsc-orange); + border-radius: 50%; + content: ""; + height: 4px; + left: 6px; + position: absolute; + top: 6px; + width: 4px; +} + +@keyframes landing-mouse-dot { + 0% { opacity: 0; transform: translateY(0); } + 35% { opacity: 1; } + 100% { opacity: 0; transform: translateY(12px); } +} + +@media (prefers-reduced-motion: reduce) { + .landing-orbit-ring, + .landing-cmd-palette, + .landing-demo-stage .mini-wb-preview--hero, + .badge-pulse { + animation: none !important; + } + + .landing-demo-stage .mini-wb-preview--hero { + transform: none; + } +} + +@media (max-width: 1040px) { + .hero-layout { + grid-template-columns: 1fr; + } + + .hero-col-left { + max-width: 640px; + } +} + +@media (max-width: 720px) { + .landing-orbit-ring, + .landing-float-node, + .landing-cmd-palette { + display: none !important; + } + + .landing-demo-stage .mini-wb-preview--hero { + animation: none; + transform: none; + } + + .landing-demo-stage { + min-height: 0; + } + + .hero-kpi-strip { + grid-template-columns: 1fr; + } +} + +.hero-editor-stage::before { + animation: hero-editor-halo 5s ease-in-out infinite; + background: radial-gradient(ellipse 72% 58% at 50% 42%, rgba(37, 99, 235, 0.28) 0%, transparent 62%), + radial-gradient(ellipse 50% 45% at 88% 78%, rgba(249, 115, 22, 0.14) 0%, transparent 55%); + border-radius: 22px; + content: ""; + filter: blur(18px); + inset: -8% -6% -4% -6%; + opacity: 0.85; + pointer-events: none; + position: absolute; + z-index: -1; +} + +@keyframes hero-editor-halo { + 0%, 100% { + opacity: 0.65; + transform: scale(1); + } + + 50% { + opacity: 0.95; + transform: scale(1.02); + } +} + +.hero-editor-caption { + align-items: baseline; + display: flex; + flex-wrap: wrap; + gap: 0.35rem 1rem; + justify-content: space-between; + margin: 0 0 14px; + padding-right: 4px; +} + +.hero-editor-caption-label { + color: rgba(255, 255, 255, 0.88); + font-size: 12px; + font-weight: 600; + letter-spacing: 0.02em; +} + +.hero-editor-caption-hint { + color: rgba(148, 163, 184, 0.85); + font-size: 11px; + font-weight: 500; + letter-spacing: 0.02em; +} + +/* ── Mini workbench preview ─────────────────────────────── */ +.mini-wb-preview { + background: #0c1528; + border: 1px solid rgba(255, 255, 255, 0.09); + border-radius: 14px; + box-shadow: + 0 36px 88px rgba(0, 0, 0, 0.65), + 0 0 0 1px rgba(255, 255, 255, 0.04), + 0 0 70px -20px rgba(37, 99, 235, 0.45), + 0 0 50px -15px rgba(249, 115, 22, 0.18); + cursor: pointer; + max-width: min(100%, 760px); + overflow: hidden; + transition: box-shadow 0.28s ease, transform 0.28s ease, border-color 0.28s ease; + width: 100%; +} + +/* Hero: larger, sharper preview — primary visual */ +.mini-wb-preview--hero { + border-color: rgba(148, 163, 184, 0.24); + border-radius: 18px; + box-shadow: + 0 42px 90px rgba(0, 0, 0, 0.55), + 0 0 0 1px rgba(88, 166, 255, 0.12), + 0 0 70px rgba(88, 166, 255, 0.12); + max-width: min(100%, 920px); +} + +.mini-wb-preview:hover { + box-shadow: + 0 44px 100px rgba(0, 0, 0, 0.72), + 0 0 0 1px rgba(255, 255, 255, 0.07), + 0 0 80px -15px rgba(37, 99, 235, 0.55), + 0 0 60px -10px rgba(249, 115, 22, 0.25); + transform: translateY(-4px); +} + +.mini-wb-preview--hero:hover { + border-color: rgba(96, 165, 250, 0.35); + box-shadow: + 0 56px 120px rgba(0, 0, 0, 0.78), + 0 0 0 1px rgba(96, 165, 250, 0.22), + 0 0 120px -20px rgba(37, 99, 235, 0.6), + 0 0 80px -14px rgba(249, 115, 22, 0.28); + transform: translateY(-6px) scale(1.008); +} + +.landing-demo-stage .mini-wb-preview--hero:hover { + transform: rotateY(-5deg) rotateX(2deg) translateY(-10px) scale(1.01); +} + +/* Titlebar */ +.mini-wb-titlebar { + align-items: center; + background: #0a111e; + border-bottom: 1px solid rgba(255, 255, 255, 0.06); + display: flex; + gap: 10px; + height: 34px; + padding: 0 14px; +} + +.mini-wb-dots { + display: flex; + gap: 5px; +} + +.mini-wb-dots span { + border-radius: 50%; + height: 10px; + width: 10px; +} + +.mini-wb-dots .dot-red { background: #ff5f57; } +.mini-wb-dots .dot-yellow { background: #febc2e; } +.mini-wb-dots .dot-green { background: #28c840; } + +.mini-wb-window-title { + color: rgba(255, 255, 255, 0.38); + font-size: 11px; + letter-spacing: 0.01em; + margin-left: 4px; + white-space: nowrap; +} + +.mini-wb-tab-strip { + display: flex; + margin-left: auto; +} + +.mini-wb-tab { + border-bottom: 2px solid transparent; + color: rgba(255, 255, 255, 0.32); + font-size: 10.5px; + padding: 0 13px; + white-space: nowrap; +} + +.mini-wb-tab.is-active { + border-bottom-color: #f97316; + color: rgba(255, 255, 255, 0.78); +} + +/* Workbench body */ +.mini-wb-body { + display: flex; + height: 320px; + overflow: hidden; +} + +/* Sidebar */ +.mini-wb-sidebar { + background: #0d1b30; + border-right: 1px solid rgba(255, 255, 255, 0.05); + display: flex; + flex-direction: column; + flex-shrink: 0; + overflow: hidden; + padding: 8px 0; + width: 116px; +} + +.mini-wb-sidebar-hdr { + color: rgba(255, 255, 255, 0.28); + font-size: 9px; + font-weight: 600; + letter-spacing: 0.1em; + padding: 4px 10px 6px; +} + +.mini-wb-file-row { + align-items: center; + color: rgba(255, 255, 255, 0.5); + display: flex; + font-size: 10.5px; + gap: 6px; + overflow: hidden; + padding: 3px 10px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.mini-wb-file-row.is-active { + background: rgba(37, 99, 235, 0.18); + border-left: 2px solid #3b82f6; + color: rgba(255, 255, 255, 0.82); + padding-left: 8px; +} + +.mini-wb-file-dot { + border-radius: 50%; + flex-shrink: 0; + height: 6px; + width: 6px; +} + +.mini-wb-file-dot.nb { background: #f97316; } +.mini-wb-file-dot.md { background: #3b82f6; } + +.mini-wb-section-hdr { + color: rgba(255, 255, 255, 0.22); + font-size: 8.5px; + font-weight: 600; + letter-spacing: 0.1em; + margin-top: 8px; + padding: 4px 10px 3px; +} + +.mini-wb-schema-row { + color: rgba(255, 255, 255, 0.38); + font-size: 10px; + overflow: hidden; + padding: 2px 10px 2px 18px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.mini-wb-env-badge { + color: rgba(255, 255, 255, 0.32); + font-size: 8.5px; + line-height: 1.5; + margin-top: auto; + padding: 8px 8px 4px; +} + +.env-label-dev { + background: rgba(34, 197, 94, 0.15); + border-radius: 3px; + color: #22c55e; + font-size: 8px; + font-weight: 700; + padding: 1px 4px; +} + +.env-label-prod { + background: rgba(249, 115, 22, 0.15); + border-radius: 3px; + color: #f97316; + font-size: 8px; + font-weight: 700; + padding: 1px 4px; +} + +/* Center: query result + chart */ +.mini-wb-editor { + border-right: 1px solid rgba(255, 255, 255, 0.04); + display: flex; + flex: 1; + flex-direction: column; + min-width: 0; + overflow: hidden; +} + +.mini-wb-result-table { + border-collapse: collapse; + font-family: "Fira Mono", monospace; + font-size: 9.5px; + margin: 8px 8px 4px; + width: calc(100% - 16px); +} + +.mini-wb-result-table th { + background: rgba(255, 255, 255, 0.04); + color: rgba(255, 255, 255, 0.38); + font-weight: 500; + padding: 4px 7px; + text-align: left; +} + +.mini-wb-result-table td { + border-bottom: 1px solid rgba(255, 255, 255, 0.04); + color: rgba(255, 255, 255, 0.6); + padding: 3px 7px; +} + +/* CSS bar chart */ +.mini-chart { + align-items: flex-end; + border-bottom: 1px solid rgba(255, 255, 255, 0.07); + display: flex; + flex-shrink: 0; + gap: 3px; + height: 62px; + margin: 4px 8px 6px; + padding-bottom: 2px; +} + +.mini-chart-bar { + background: rgba(59, 130, 246, 0.42); + border-radius: 2px 2px 0 0; + border-top: 1px solid rgba(59, 130, 246, 0.85); + flex: 1; + height: var(--bar-h, 50%); + transition: background 0.2s ease; +} + +.mini-wb-preview:hover .mini-chart-bar { + background: rgba(59, 130, 246, 0.58); +} + +.mini-wb-preview--hero .mini-chart-bar { + background: linear-gradient(180deg, rgba(34, 211, 238, 0.86), rgba(14, 165, 233, 0.44)); + border: 1px solid rgba(34, 211, 238, 0.55); + border-radius: 6px 6px 2px 2px; + border-top: 1px solid rgba(34, 211, 238, 0.55); +} + +.mini-wb-preview--hero:hover .mini-chart-bar { + background: linear-gradient(180deg, rgba(34, 211, 238, 0.95), rgba(14, 165, 233, 0.55)); + filter: brightness(1.05); +} + +/* Right: SQL Assistant */ +.mini-wb-assistant { + display: flex; + flex-direction: column; + flex-shrink: 0; + gap: 0; + overflow: hidden; + padding: 8px 8px 0; + width: 195px; +} + +.mini-wb-assistant-hdr { + border-bottom: 1px solid rgba(255, 255, 255, 0.05); + color: rgba(255, 255, 255, 0.28); + font-size: 8.5px; + font-weight: 600; + letter-spacing: 0.1em; + margin-bottom: 7px; + padding-bottom: 6px; +} + +.mini-wb-schema-pill { + background: rgba(37, 99, 235, 0.13); + border: 1px solid rgba(37, 99, 235, 0.22); + border-radius: 4px; + color: rgba(255, 255, 255, 0.42); + font-size: 8.5px; + margin-bottom: 8px; + padding: 3px 7px; +} + +.mini-wb-schema-pill strong { + color: rgba(255, 255, 255, 0.62); +} + +.mini-chat-user { + background: rgba(249, 115, 22, 0.1); + border: 1px solid rgba(249, 115, 22, 0.16); + border-radius: 6px 6px 2px 6px; + color: rgba(255, 255, 255, 0.68); + font-size: 9px; + line-height: 1.45; + margin-bottom: 7px; + padding: 5px 8px; +} + +.mini-chat-ai { + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.07); + border-radius: 2px 6px 6px 6px; + color: rgba(255, 255, 255, 0.55); + flex: 1; + font-size: 9px; + line-height: 1.5; + overflow: hidden; + padding: 5px 8px; +} + +.mini-chat-ai code { + background: rgba(37, 99, 235, 0.22); + border-radius: 3px; + color: #93c5fd; + font-family: "Fira Mono", monospace; + font-size: 8.5px; + padding: 0 3px; +} + +/* Mini workbench CTA button (JS-wired via .mini-editor-preview button) */ +.mini-wb-cta-btn { + background: rgba(249, 115, 22, 0.14); + border: 1px solid rgba(249, 115, 22, 0.28); + border-radius: 5px; + color: #fb923c; + cursor: pointer; + font-family: inherit; + font-size: 9.5px; + font-weight: 600; + margin-top: 7px; + padding: 5px 10px; + text-align: center; + transition: background 0.15s ease; + width: 100%; +} + +.mini-wb-cta-btn:hover { + background: rgba(249, 115, 22, 0.24); + color: #fff; +} + +/* Insight bar at the bottom */ +.mini-wb-insight-bar { + align-items: center; + background: rgba(37, 99, 235, 0.07); + border-top: 1px solid rgba(255, 255, 255, 0.05); + color: rgba(255, 255, 255, 0.32); + display: flex; + font-size: 9.5px; + gap: 6px; + padding: 7px 14px; +} + +.mini-wb-insight-pill { + background: rgba(37, 99, 235, 0.18); + border: 1px solid rgba(37, 99, 235, 0.3); + border-radius: 4px; + color: #60a5fa; + font-size: 9px; + padding: 1px 6px; +} + +/* Hero preview: larger chrome + readable UI (focal interactive mock) */ +.mini-wb-preview--hero .mini-wb-titlebar { + height: 38px; + padding: 0 16px; +} + +.mini-wb-preview--hero .mini-wb-window-title { + font-size: 12px; +} + +.mini-wb-preview--hero .mini-wb-tab { + font-size: 11px; + padding: 0 14px; +} + +.mini-wb-preview--hero .mini-wb-body { + height: clamp(340px, 36vh, 430px); +} + +body.editor-minimized .mini-wb-preview--hero .mini-wb-body { + height: clamp(240px, calc((var(--landing-hero-slice-height) - 8.5rem) * 0.42), 460px); +} + +.mini-wb-preview--hero .mini-wb-sidebar { + padding: 10px 0; + width: 132px; +} + +.mini-wb-preview--hero .mini-wb-sidebar-hdr { + font-size: 9.5px; + padding: 5px 11px 7px; +} + +.mini-wb-preview--hero .mini-wb-file-row { + font-size: 11.5px; + padding: 4px 11px; +} + +.mini-wb-preview--hero .mini-wb-section-hdr { + font-size: 9px; + margin-top: 10px; +} + +.mini-wb-preview--hero .mini-wb-schema-row { + font-size: 10.5px; +} + +.mini-wb-preview--hero .mini-wb-env-badge { + font-size: 9px; +} + +.mini-wb-preview--hero .mini-wb-result-table { + font-size: 10.5px; + margin: 10px 10px 5px; + width: calc(100% - 20px); +} + +.mini-wb-preview--hero .mini-wb-result-table th, +.mini-wb-preview--hero .mini-wb-result-table td { + padding: 5px 8px; +} + +.mini-wb-preview--hero .mini-chart { + gap: 4px; + height: 72px; + margin: 6px 10px 8px; +} + +.mini-wb-preview--hero .mini-wb-assistant { + padding: 10px 10px 0; + width: 218px; +} + +.mini-wb-preview--hero .mini-wb-assistant-hdr { + font-size: 9.5px; + margin-bottom: 8px; +} + +.mini-wb-preview--hero .mini-wb-schema-pill { + font-size: 9.5px; + margin-bottom: 9px; + padding: 4px 8px; +} + +.mini-wb-preview--hero .mini-chat-user { + font-size: 10px; + margin-bottom: 8px; + padding: 6px 9px; +} + +.mini-wb-preview--hero .mini-chat-ai { + font-size: 10px; + line-height: 1.52; + padding: 6px 9px; +} + +.mini-wb-preview--hero .mini-chat-ai code { + font-size: 9.5px; +} + +.mini-wb-preview--hero .mini-wb-cta-btn { + font-size: 10.5px; + margin-top: 8px; + padding: 7px 12px; +} + +.mini-wb-preview--hero .mini-wb-insight-bar { + font-size: 10.5px; + padding: 9px 16px; +} + +.mini-wb-preview--hero .mini-wb-insight-pill { + font-size: 9.5px; +} + +@media (prefers-reduced-motion: reduce) { + .hero-editor-stage::before { + animation: none; + opacity: 0.55; + } + + .mini-wb-preview--hero:hover { + transform: translateY(-4px); + } + + .landing-demo-stage .mini-wb-preview--hero:hover { + transform: translateY(-4px); + } +} + +/* ── Links row below hero ────────────────────────────────── */ +body.editor-minimized .minimized-links { + display: flex; + flex-wrap: wrap; + gap: 8px; + justify-content: center; + margin-top: 12px; + padding: 0 56px 20px; +} + +body.editor-minimized .min-link { + border-color: rgba(255, 255, 255, 0.1); + color: rgba(255, 255, 255, 0.4); +} + +body.editor-minimized .min-link:hover { + background: rgba(255, 255, 255, 0.07); + border-color: rgba(255, 255, 255, 0.2); + color: rgba(255, 255, 255, 0.72); +} + +body.editor-minimized .min-link-home { + background: rgba(37, 99, 235, 0.1); + border-color: rgba(37, 99, 235, 0.28); + color: rgba(255, 255, 255, 0.55); +} + +body.editor-minimized .min-link-home:hover { + background: rgba(37, 99, 235, 0.18); + border-color: rgba(37, 99, 235, 0.5); + color: #fff; +} + +/* ── Responsive ─────────────────────────────────────────── */ +@media (max-width: 1180px) { + .hero-layout { + gap: 36px; + grid-template-columns: minmax(240px, 0.42fr) minmax(280px, 0.58fr); + padding: 32px 36px 16px; + } + + body.editor-minimized .hero-col-left .landing-hero-title { + font-size: clamp(2.7rem, 4.3vw, 3.8rem); + line-height: 0.98; + } + + body.editor-minimized .hero-col-left .min-lead { + font-size: 1.02rem; + line-height: 1.62; + max-width: 620px; + } + + .mini-wb-preview { + max-width: min(100%, 620px); + } + + .mini-wb-preview--hero { + max-width: min(100%, 780px); + } + + .mini-wb-assistant { + width: 165px; + } + + .mini-wb-preview--hero .mini-wb-assistant { + width: 188px; + } + + .mini-wb-preview--hero .mini-wb-body { + height: clamp(300px, 34vh, 380px); + } + + body.editor-minimized .mini-wb-preview--hero .mini-wb-body { + height: clamp(220px, calc((var(--landing-hero-slice-height) - 7.5rem) * 0.4), 400px); + } +} + +@media (max-width: 960px) { + .hero-layout { + grid-template-columns: 1fr; + gap: 28px; + padding: 28px 28px 12px; + } + + .hero-col-right { + display: none; + } + + body.editor-minimized .minimized-links { + padding: 0 24px 16px; + } +} + +@media (max-width: 900px) { + body.editor-minimized .hero-col-left .landing-hero-title { + font-size: clamp(2.35rem, 7vw, 3.15rem); + line-height: 1; + } + + body.editor-minimized .hero-col-left .min-lead { + font-size: 0.96rem; + max-width: 560px; + } +} + +@media (max-width: 640px) { + .hero-layout { + padding: 20px 18px 10px; + } + + body.editor-minimized .hero-col-left .landing-hero-title { + font-size: clamp(1.9rem, 9vw, 2.6rem); + line-height: 1.02; + } + + body.editor-minimized .hero-col-left .min-lead { + font-size: 0.92rem; + line-height: 1.58; + } + + body.editor-minimized .min-cta { + font-size: 13px; + padding: 10px 18px; + } + + .hero-kpi-strip { + align-items: flex-start; + flex-direction: column; + flex-wrap: wrap; + gap: 0; + padding-top: 18px; + } + + .hero-kpi-strip .kpi-item { + padding: 12px 0; + width: 100%; + } + + .hero-kpi-strip .kpi-item + .kpi-item { + border-left: 0; + border-top: 1px solid rgba(148, 163, 184, 0.22); + } } \ No newline at end of file diff --git a/docs/styles/content-panels.css b/docs/styles/content-panels.css index 747b4fb..f4083b9 100644 --- a/docs/styles/content-panels.css +++ b/docs/styles/content-panels.css @@ -23,10 +23,17 @@ background: var(--vsc-orange); } -body[data-theme="dark"] .tour-dot { +.tour-dot { background: rgba(255, 255, 255, 0.2); } +.tour-dot.active { + background: var(--vsc-orange); + box-shadow: 0 0 0 3px rgba(255, 107, 22, 0.3); + transform: scale(1.4); + transition: background 0.25s ease, transform 0.25s ease, box-shadow 0.25s ease; +} + .tour-label { color: var(--vsc-muted); font-size: 10px; @@ -261,9 +268,9 @@ body[data-theme="dark"] .tour-dot { margin: 0; } -body[data-theme="dark"] .doc-tip { +.doc-tip { background: rgba(37, 99, 235, 0.1); - border-color: rgba(249, 115, 22, 0.28); + border-color: rgba(255, 107, 22, 0.28); } @media (max-width: 760px) { diff --git a/docs/styles/interactive.css b/docs/styles/interactive.css index d01a984..5d19750 100644 --- a/docs/styles/interactive.css +++ b/docs/styles/interactive.css @@ -83,7 +83,7 @@ /* ── Right panel (SQL Assistant) ──────────────────────── */ .right-panel { - background: var(--vsc-sidebar); + background: #101c32; border-left: 1px solid var(--vsc-border); display: flex; flex-direction: column; @@ -97,6 +97,16 @@ width: 380px; } +/* Editor toolbar: collapse Explorer (activity + sidebar) / SQL Assistant */ +.workbench.panel-left-hidden .activity-bar, +.workbench.panel-left-hidden .sidebar { + display: none; +} + +.workbench.panel-right-hidden .right-panel { + display: none; +} + /* Header bar (SQL ASSISTANT + expand button) */ .assistant-tab-bar { align-items: center; @@ -185,7 +195,7 @@ margin-bottom: 16px; } .action-card { - background: var(--surface); + background: rgba(14, 24, 45, 0.82); border: 1px solid var(--vsc-border); border-radius: 6px; cursor: pointer; @@ -194,9 +204,12 @@ gap: 3px; padding: 9px 10px; text-align: left; - transition: border-color 0.15s, background 0.15s; + transition: border-color 0.15s, background 0.15s, box-shadow 0.15s; +} +.action-card:hover { + border-color: rgba(88, 166, 255, 0.4); + box-shadow: 0 0 0 1px rgba(88, 166, 255, 0.4), 0 8px 24px rgba(88, 166, 255, 0.18); } -.action-card:hover { border-color: var(--vsc-orange); background: var(--vsc-highlight); } .action-card-icon { color: var(--vsc-muted); font-size: 15px; @@ -256,14 +269,16 @@ padding: 7px 9px; } .chat-msg.user { - background: color-mix(in srgb, var(--vsc-orange) 10%, transparent); - border: 1px solid color-mix(in srgb, var(--vsc-orange) 24%, transparent); + background: rgba(255, 107, 22, 0.11); + border: 1px solid rgba(255, 107, 22, 0.28); + border-radius: 12px 12px 4px 12px; color: var(--vsc-text); margin-left: 14px; } .chat-msg.assistant { - background: var(--surface); - border: 1px solid var(--vsc-border); + background: rgba(15, 23, 42, 0.62); + border: 1px solid rgba(148, 163, 184, 0.14); + border-radius: 4px 12px 12px 12px; color: var(--vsc-text); } .chat-msg.assistant .chat-rich-response { @@ -479,16 +494,16 @@ body, width: 0; } -body[data-theme="dark"] { +html, body { scrollbar-color: rgba(37, 99, 235, 0.32) transparent; } -body[data-theme="dark"] *::-webkit-scrollbar-thumb { +*::-webkit-scrollbar-thumb { background: rgba(37, 99, 235, 0.32); background-clip: padding-box; } -body[data-theme="dark"] *::-webkit-scrollbar-thumb:hover { +*::-webkit-scrollbar-thumb:hover { background: rgba(37, 99, 235, 0.5); background-clip: padding-box; } @@ -529,12 +544,12 @@ body[data-theme="dark"] *::-webkit-scrollbar-thumb:hover { /* ── Startup toast notification ───────────────────────── */ .toast { align-items: center; - background: var(--surface); - border: 1px solid var(--vsc-border); - border-left: 3px solid var(--vsc-orange); + background: #0d1728; + border: 1px solid rgba(148, 163, 184, 0.22); + border-left: 4px solid var(--vsc-blue); border-radius: 6px; bottom: 36px; - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35); + box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5), -2px 0 10px rgba(88, 166, 255, 0.12); color: var(--vsc-text); display: flex; font-size: 11.5px; @@ -565,6 +580,8 @@ body[data-theme="dark"] *::-webkit-scrollbar-thumb:hover { /* ── Tour overlay & spotlight ─────────────────────────── */ .tour-overlay { + background: rgba(7, 11, 20, 0.72); + /* No backdrop-filter: blur avoids muddy full-page blur during the tour; dimming comes from this scrim + .tour-spotlight ring shadow. */ display: none; inset: 0; pointer-events: none; @@ -574,9 +591,9 @@ body[data-theme="dark"] *::-webkit-scrollbar-thumb:hover { .tour-overlay.active { display: block; } .tour-spotlight { - border: 2px solid color-mix(in srgb, var(--vsc-orange) 90%, transparent); + border: 2px solid rgba(255, 107, 22, 0.7); border-radius: 6px; - box-shadow: 0 0 0 4px color-mix(in srgb, var(--vsc-orange) 18%, transparent), 0 0 16px color-mix(in srgb, var(--vsc-orange) 25%, transparent), 0 0 0 9999px rgba(0, 0, 0, 0.38); + box-shadow: 0 0 0 9999px rgba(7, 11, 20, 0.72), 0 0 60px rgba(255, 107, 22, 0.45), 0 0 0 4px rgba(255, 107, 22, 0.22); pointer-events: none; position: fixed; transition: top 0.25s ease, left 0.25s ease, width 0.25s ease, height 0.25s ease; @@ -584,11 +601,11 @@ body[data-theme="dark"] *::-webkit-scrollbar-thumb:hover { } .tour-tooltip { - background: var(--surface); - border: 1px solid var(--vsc-border); + background: #0d1728; + border: 1px solid rgba(148, 163, 184, 0.18); border-left: 3px solid var(--vsc-orange); - border-radius: 8px; - box-shadow: 0 10px 36px rgba(0, 0, 0, 0.45); + border-radius: 12px; + box-shadow: 0 10px 36px rgba(0, 0, 0, 0.65), -2px 0 12px rgba(37, 99, 235, 0.18); max-width: 272px; min-width: 230px; opacity: 0; @@ -628,8 +645,8 @@ body[data-theme="dark"] *::-webkit-scrollbar-thumb:hover { gap: 5px; } .tour-nav-btn { - background: var(--vsc-highlight); - border: 1px solid var(--vsc-border); + background: rgba(148, 163, 184, 0.1); + border: 1px solid rgba(148, 163, 184, 0.18); border-radius: 4px; color: var(--vsc-text); cursor: pointer; @@ -638,10 +655,11 @@ body[data-theme="dark"] *::-webkit-scrollbar-thumb:hover { padding: 4px 10px; transition: background 0.12s; } -.tour-nav-btn:hover { background: var(--vsc-border); } +.tour-nav-btn:hover { background: rgba(148, 163, 184, 0.18); } .tour-nav-btn.primary { - background: var(--vsc-orange); + background: linear-gradient(135deg, #ff6b16 0%, #ea580c 100%); border-color: transparent; + box-shadow: 0 2px 12px rgba(255, 107, 22, 0.4); color: #fff; } .tour-nav-btn.primary:hover { filter: brightness(1.1); } @@ -677,7 +695,7 @@ body[data-theme="dark"] *::-webkit-scrollbar-thumb:hover { } .chat-typing-dots .typing-dot { animation: typingBounce 1.2s infinite; - background: var(--vsc-muted); + background: #58a6ff; border-radius: 50%; height: 5px; width: 5px; @@ -711,65 +729,32 @@ body[data-theme="dark"] *::-webkit-scrollbar-thumb:hover { PALETTE POLISH: Neon glow pass (dark mode, logo-aligned) ══════════════════════════════════════════════════════════ */ -/* h1 accent span — neon text glow matching logo */ -body[data-theme="dark"] .hero-shell h1 span { - text-shadow: 0 0 14px rgba(37, 99, 235, 0.45), 0 0 24px rgba(249, 115, 22, 0.18); -} - -/* Install / CTA buttons — cyan glow */ -body[data-theme="dark"] .hero-install-btn, -body[data-theme="dark"] .topbar-install { - box-shadow: 0 2px 14px rgba(249, 115, 22, 0.28); -} - -/* Active tab — soft cyan underline glow */ -body[data-theme="dark"] .tab.active { - box-shadow: inset 0 -1px 0 rgba(37, 99, 235, 0.24), 0 2px 8px rgba(37, 99, 235, 0.12); +/* h1 accent span — neon text glow (skip gradient-clipped accent line) */ +.hero-shell h1 span:not(.hero-line--accent) { + text-shadow: 0 0 14px rgba(37, 99, 235, 0.45), 0 0 24px rgba(255, 107, 22, 0.18); } -/* Dark mode tabs — teal accent matching scrollbar */ -body[data-theme="dark"] .tabs { - background: rgba(11, 15, 15, 0.08); +/* Install / CTA buttons — orange glow */ +.hero-install-btn, +.topbar-install { + box-shadow: 0 2px 14px rgba(255, 107, 22, 0.28); } -body[data-theme="dark"] .tab { - background: rgba(21, 29, 28, 0.08); +/* Shell border — faint blue rim */ +.shell { + box-shadow: 0 24px 72px rgba(2, 6, 23, 0.65), 0 0 0 1px rgba(37, 99, 235, 0.14), 0 0 40px rgba(255, 107, 22, 0.06); } -body[data-theme="dark"] .tab.active { - background: rgba(249, 115, 22, 0.12); -} - -/* Shell border — faint cyan rim in dark mode */ -body[data-theme="dark"] .shell { - border-color: rgba(20, 39, 36, 0.14); - box-shadow: 0 24px 72px rgba(2, 6, 23, 0.55), 0 0 0 1px rgba(37, 99, 235, 0.12), 0 0 40px rgba(249, 115, 22, 0.05); -} - -/* Statusbar — keep cobalt, add subtle glow */ -body[data-theme="dark"] .statusbar { - box-shadow: 0 -1px 0 rgba(37, 99, 235, 0.18); -} - -/* Tour tooltip — cyan left border glow */ -body[data-theme="dark"] .tour-tooltip { - box-shadow: 0 10px 36px rgba(0, 0, 0, 0.6), -2px 0 12px rgba(37, 99, 235, 0.18); -} - -/* Toast — cyan glow */ -body[data-theme="dark"] .toast { - box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5), -2px 0 10px rgba(249, 115, 22, 0.16); +/* Statusbar — cobalt glow */ +.statusbar { + box-shadow: 0 -1px 0 rgba(37, 99, 235, 0.24); } /* Send button in assistant */ -body[data-theme="dark"] .input-send-btn { - box-shadow: 0 1px 8px rgba(37, 99, 235, 0.3); +.input-send-btn { + box-shadow: 0 1px 8px rgba(88, 166, 255, 0.3); } -/* topbar hover box-shadow — was rgba(0,85,168) */ -body[data-theme="light"] .topbar-icon-btn:hover { - box-shadow: 0 2px 10px rgba(29, 78, 216, 0.2); -} /* ── Chart cell (revenue bar chart) ───────────────────── */ .chart-cell { @@ -817,16 +802,22 @@ body[data-theme="light"] .topbar-icon-btn:hover { /* ── Chat install CTA link ────────────────────────────── */ .chat-install-cta { - color: var(--vsc-orange); + background: linear-gradient(135deg, #ff6b16 0%, #ea580c 100%); + border-radius: 999px; + color: #fff; cursor: pointer; display: inline-block; font-size: 11px; font-weight: 600; margin-top: 6px; + padding: 4px 12px; text-decoration: none; - transition: filter 0.15s; + transition: filter 0.15s, box-shadow 0.15s; +} +.chat-install-cta:hover { + box-shadow: 0 2px 12px rgba(255, 107, 22, 0.4); + filter: brightness(1.08); } -.chat-install-cta:hover { filter: brightness(1.15); } /* --- Mobile Enhancements --- */ .mobile-menu-btn { @@ -1032,6 +1023,18 @@ body[data-theme="light"] .topbar-icon-btn:hover { flex-direction: column !important; } + /* Collapsed via editor toolbar overrides mobile overlay toggles */ + .workbench.panel-left-hidden.show-left .activity-bar, + .workbench.panel-left-hidden.show-left .sidebar { + display: none !important; + } + + .workbench.panel-right-hidden .right-panel, + .workbench.panel-right-hidden.show-right .right-panel, + .workbench.panel-right-hidden.show-right .right-panel.expanded { + display: none !important; + } + /* When sidebars are open, we can dim the editor */ .workbench.show-left .editor-region::after, .workbench.show-right .editor-region::after { @@ -1070,6 +1073,7 @@ body[data-theme="light"] .topbar-icon-btn:hover { body.editor-minimized .hero-shell { height: auto; overflow-y: auto; + scroll-snap-type: none; } } @@ -1082,10 +1086,16 @@ body[data-theme="light"] .topbar-icon-btn:hover { .schema-context-bar::-webkit-scrollbar { display: none; } .schema-ctx-label { color: var(--vsc-muted); flex-shrink: 0; font-size: 9px; font-weight: 600; letter-spacing: .06em; } .schema-chip { - background: var(--surface); border: 1px solid var(--vsc-border); border-radius: 3px; - color: var(--vsc-muted); flex-shrink: 0; font-family: monospace; font-size: 9.5px; padding: 1px 5px; + background: rgba(37, 99, 235, 0.13); + border: 1px solid rgba(37, 99, 235, 0.22); + border-radius: 3px; + color: var(--vsc-muted); + flex-shrink: 0; + font-family: monospace; + font-size: 9.5px; + padding: 1px 5px; } -.active-chip { color: #1d4ed8; border-color: rgba(29,78,216,.4); background: rgba(29,78,216,.08); } +.active-chip { color: #58a6ff; border-color: rgba(88, 166, 255, 0.4); background: rgba(88, 166, 255, 0.08); } /* ?????? Context Menu (Attachment) ???????????????????????????????????????????????????????????????????????????????????????????????? */ .chat-attach-menu { diff --git a/docs/styles/landing-sections.css b/docs/styles/landing-sections.css new file mode 100644 index 0000000..dd38667 --- /dev/null +++ b/docs/styles/landing-sections.css @@ -0,0 +1,858 @@ +/* ── Landing topbar (works with minimized + expanded viewport) ───── */ +.desktop-topbar.landing-topbar { + background: rgba(6, 13, 26, 0.78); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border-bottom-color: rgba(255, 255, 255, 0.06); +} + +.landing-topbar .desktop-topbar-links a, +.landing-topbar .desktop-topbar-links button { + color: rgba(255, 255, 255, 0.6); + font-size: 12px; +} + +.landing-topbar .desktop-topbar-links a:hover, +.landing-topbar .desktop-topbar-links button:hover { + color: #fff; +} + +.landing-topbar .play-tour-btn { + border-color: rgba(249, 115, 22, 0.45); +} + +.landing-topbar { + flex-wrap: wrap; + gap: 10px 12px; +} + +.landing-topbar .immersive-brand { + align-items: center; + display: flex; + flex-shrink: 0; + gap: 10px; + margin-right: auto; +} + +.immersive-brand-mark { + background: linear-gradient(135deg, #ff6b16, #ff9a3c); + border-radius: 8px; + box-shadow: 0 0 24px rgba(255, 107, 22, 0.28); + flex-shrink: 0; + height: 26px; + position: relative; + width: 26px; +} + +.immersive-brand-mark::after { + border: 2px solid #07101d; + border-left: 0; + border-radius: 0 8px 8px 0; + content: ""; + height: 14px; + left: 8px; + position: absolute; + top: 6px; + width: 9px; +} + +.immersive-brand-text { + display: flex; + flex-direction: column; + gap: 0; + line-height: 1.15; +} + +.immersive-brand-title { + color: #ff6b16; + font-size: 15px; + font-weight: 800; + letter-spacing: 0.02em; + text-transform: uppercase; +} + +.immersive-brand-sub { + color: rgba(255, 255, 255, 0.45); + font-size: 11px; + letter-spacing: 0.02em; +} + +.topbar-brand-icon { + align-items: center; + background: #f97316; + border-radius: 4px; + color: #fff; + display: inline-flex; + font-size: 14px; + font-weight: 800; + height: 26px; + justify-content: center; + line-height: 1; + width: 26px; +} + +.topbar-brand-name { + color: rgba(255, 255, 255, 0.85); + font-size: 13px; + font-weight: 600; + letter-spacing: -0.01em; +} + +.topbar-brand-name span { + color: #f97316; +} + +.btn-install-cta { + border-radius: 7px; + font-size: 12px; + font-weight: 600; +} + +/* Nav order: menu (mobile) → brand → links → actions */ +@media (min-width: 641px) { + .landing-topbar .topbar-menu-btn { + order: 0; + } + + .landing-topbar .immersive-brand { + order: 1; + margin-right: 0; + } + + .landing-topbar .landing-topbar-nav-collapsible { + order: 2; + } + + .landing-topbar .topbar-actions { + margin-left: auto; + order: 3; + } +} + +/* ═══ Section chrome (below hero) ═══ */ +.section-divider { + border: 0; + border-top: 1px solid rgba(255, 255, 255, 0.06); + margin: 0 auto; + max-width: var(--landing-content-max); + width: calc(100% - 32px); +} + +.landing-section { + margin: 0 auto; + max-width: var(--landing-content-max); + padding: 56px clamp(24px, 4vw, 72px) 48px; + width: 100%; +} + +body.editor-minimized .landing-section { + box-sizing: border-box; + flex-shrink: 0; + scroll-margin-top: 0; + scroll-snap-align: start; + scroll-snap-stop: normal; +} + +/* Full-viewport slices: capabilities, pricing — not Get started (footer follows as its own block) */ +body.editor-minimized .landing-section:not(.badges-section) { + display: flex; + flex-direction: column; + justify-content: center; + min-height: var(--landing-section-min-height); +} + +body.editor-minimized .landing-section.badges-section { + /* Content-sized; avoids one empty viewport that hid the real footer below */ + display: block; + padding-bottom: 40px; +} + +.section-label { + color: #f97316; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.1em; + margin-bottom: 12px; + text-transform: uppercase; +} + +.section-title { + color: #fff; + font-size: clamp(1.8rem, 3vw, 2.6rem); + font-weight: 700; + letter-spacing: -0.02em; + line-height: 1.15; + margin-bottom: 16px; +} + +.section-sub { + color: rgba(255, 255, 255, 0.48); + font-size: 15px; + line-height: 1.6; + margin-bottom: 40px; + max-width: min(720px, 100%); +} + +.features-grid { + display: grid; + gap: 16px; + grid-template-columns: repeat(3, 1fr); +} + +.feature-card { + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 12px; + padding: 28px 24px; + transition: border-color 0.2s ease, background 0.2s ease, transform 0.2s ease; + color: inherit; + cursor: pointer; + display: flex; + flex-direction: column; + font: inherit; + position: relative; + text-align: left; + width: 100%; +} + +.feature-card:hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.12); + transform: translateY(-2px); +} + +.feature-card:focus-visible { + border-color: rgba(249, 115, 22, 0.6); + outline: 2px solid rgba(249, 115, 22, 0.45); + outline-offset: 2px; +} + +.feature-card-cta { + color: rgba(249, 115, 22, 0.8); + font-size: 11px; + font-weight: 500; + letter-spacing: 0.02em; + margin-top: 16px; + opacity: 0; + transform: translateY(2px); + transition: opacity 0.18s ease, transform 0.18s ease; +} + +.feature-card:hover .feature-card-cta, +.feature-card:focus-visible .feature-card-cta { + opacity: 1; + transform: translateY(0); +} + +.feature-icon { + align-items: center; + background: rgba(249, 115, 22, 0.1); + border-radius: 10px; + color: #f97316; + display: inline-flex; + font-size: 20px; + height: 44px; + justify-content: center; + margin-bottom: 16px; + width: 44px; +} + +.feature-card h3 { + color: #fff; + font-size: 16px; + font-weight: 600; + margin-bottom: 8px; +} + +.feature-card p { + color: rgba(255, 255, 255, 0.5); + font-size: 13px; + line-height: 1.6; +} + +.feature-card .feature-tags { + display: flex; + flex-wrap: wrap; + gap: 5px; + margin-top: 14px; +} + +.feature-tag { + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 4px; + color: rgba(255, 255, 255, 0.4); + font-size: 10px; + padding: 2px 7px; +} + +/* Pricing */ +.pricing-grid { + display: grid; + gap: 20px; + grid-template-columns: 1fr 1fr; +} + +.pricing-card { + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 14px; + padding: 36px 32px; + position: relative; +} + +.pricing-card-roadmap { + border-color: rgba(255, 255, 255, 0.1); +} + +.pricing-name { + color: #fff; + font-size: 18px; + font-weight: 600; + margin-bottom: 4px; +} + +.pricing-desc { + color: rgba(255, 255, 255, 0.45); + font-size: 13px; + margin-bottom: 20px; +} + +.pricing-amount { + color: #fff; + font-size: 36px; + font-weight: 800; + letter-spacing: -0.03em; + margin-bottom: 4px; +} + +.pricing-amount .period { + color: rgba(255, 255, 255, 0.35); + font-size: 14px; + font-weight: 400; +} + +.pricing-items { + list-style: none; + margin: 20px 0; +} + +.pricing-items li { + color: rgba(255, 255, 255, 0.65); + font-size: 13px; + line-height: 1.6; + padding: 4px 0 4px 22px; + position: relative; +} + +.pricing-items li::before { + color: #22c55e; + content: "✓"; + left: 0; + position: absolute; +} + +.pricing-items-muted li { + color: rgba(255, 255, 255, 0.5); +} + +.pricing-cta { + background: transparent; + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 8px; + box-sizing: border-box; + color: rgba(255, 255, 255, 0.85); + cursor: pointer; + display: inline-block; + font-family: inherit; + font-size: 13px; + font-weight: 600; + padding: 10px 20px; + text-align: center; + text-decoration: none; + transition: border-color 0.15s ease, background 0.15s ease; + width: 100%; +} + +.pricing-cta.primary { + background: #f97316; + border-color: #f97316; + color: #fff; +} + +.pricing-cta.primary:hover { + filter: brightness(1.08); +} + +.pricing-cta:hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.4); +} + +.badges-row { + align-items: center; + display: flex; + flex-wrap: wrap; + gap: 12px; + justify-content: center; + margin-top: 12px; +} + +.badge-btn { + align-items: center; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 10px; + color: rgba(255, 255, 255, 0.7); + display: inline-flex; + font-size: 13px; + gap: 8px; + padding: 12px 20px; + text-decoration: none; + transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease; +} + +.badge-btn:hover { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.2); + color: #fff; +} + +.badge-btn-icon { + align-items: center; + background: rgba(255, 255, 255, 0.1); + border-radius: 6px; + display: inline-flex; + font-size: 18px; + height: 32px; + justify-content: center; + line-height: 32px; + text-align: center; + width: 32px; +} + +.badge-btn-text strong { + color: #fff; + display: block; + font-size: 12px; +} + +.badge-btn-text span { + color: rgba(255, 255, 255, 0.4); + font-size: 10px; +} + +.site-footer.landing-site-footer { + border-top: 1px solid rgba(255, 255, 255, 0.06); + margin: 0 auto; + max-width: var(--landing-content-max); + padding: 40px clamp(24px, 4vw, 72px) 36px; + width: 100%; +} + +body.editor-minimized .site-footer.landing-site-footer { + box-sizing: border-box; + flex-shrink: 0; + /* Compact site footer — not a full-viewport “section” */ + margin-top: 8px; + scroll-snap-align: start; +} + +.footer-grid { + display: grid; + gap: 32px; + grid-template-columns: 2fr 1fr 1fr 1fr; +} + +.footer-brand-title { + font-size: 15px; + margin-bottom: 12px; +} + +.footer-desc { + color: rgba(255, 255, 255, 0.42); + font-size: 12px; + line-height: 1.65; + margin-bottom: 16px; + max-width: 320px; +} + +.footer-social { + display: flex; + gap: 10px; +} + +.footer-social a { + align-items: center; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 8px; + color: rgba(255, 255, 255, 0.5); + display: inline-flex; + height: 34px; + justify-content: center; + text-decoration: none; + transition: border-color 0.15s ease, color 0.15s ease; + width: 34px; +} + +.footer-social a:hover { + border-color: rgba(255, 255, 255, 0.22); + color: #fff; +} + +.footer-social svg { + height: 16px; + width: 16px; +} + +.footer-col h4 { + color: rgba(255, 255, 255, 0.55); + font-size: 11px; + font-weight: 600; + letter-spacing: 0.08em; + margin-bottom: 16px; + text-transform: uppercase; +} + +.footer-col a { + color: rgba(255, 255, 255, 0.42); + display: block; + font-size: 12px; + margin-bottom: 10px; + text-decoration: none; + transition: color 0.15s ease; +} + +.footer-col a:hover { + color: #fff; +} + +.footer-link-btn { + background: none; + border: 0; + color: rgba(255, 255, 255, 0.42); + cursor: pointer; + display: block; + font-family: inherit; + font-size: 12px; + margin-bottom: 10px; + padding: 0; + text-align: left; + text-decoration: none; + transition: color 0.15s ease; +} + +.footer-link-btn:hover { + color: #fff; +} + +.footer-bottom { + align-items: center; + border-top: 1px solid rgba(255, 255, 255, 0.05); + display: flex; + flex-wrap: wrap; + gap: 12px; + justify-content: space-between; + margin-top: 32px; + padding-top: 20px; +} + +.footer-copy { + color: rgba(255, 255, 255, 0.32); + font-size: 11px; +} + +@media (max-width: 1180px) { + .footer-grid { + grid-template-columns: 1fr 1fr; + } + + .features-grid { + grid-template-columns: 1fr 1fr; + } +} + +@media (max-width: 960px) { + .pricing-grid { + grid-template-columns: 1fr; + } + + .landing-section { + padding: 48px 28px 40px; + } + + .site-footer.landing-site-footer { + padding: 32px 28px 28px; + } +} + +@media (max-width: 640px) { + .landing-section { + padding: 40px 20px 32px; + } + + .features-grid { + grid-template-columns: 1fr; + } + + .footer-grid { + grid-template-columns: 1fr; + } + + .site-footer.landing-site-footer { + padding: 28px 20px 24px; + } +} + +/* Capability modal — fixed centering; keyframes must include translate(-50%, -50%) or they override UA/dialog centering */ +.capability-modal { + background: transparent; + border: 0; + color: inherit; + left: 50%; + margin: 0; + max-height: 86vh; + overflow: visible; + padding: 0; + position: fixed; + top: 50%; + transform: translate(-50%, -50%); + width: min(720px, calc(100vw - 32px)); +} + +.capability-modal::backdrop { + backdrop-filter: blur(6px); + background: rgba(8, 10, 16, 0.66); +} + +.capability-modal[open] { + animation: capability-modal-pop 0.18s ease-out; +} + +@keyframes capability-modal-pop { + from { + opacity: 0; + transform: translate(-50%, calc(-50% + 8px)) scale(0.98); + } + + to { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + } +} + +@media (prefers-reduced-motion: reduce) { + .capability-modal[open] { + animation: none; + } +} + +.capability-modal-inner { + background: linear-gradient(180deg, rgba(22, 24, 32, 0.98) 0%, rgba(14, 16, 22, 0.98) 100%); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 16px; + box-shadow: 0 24px 64px rgba(0, 0, 0, 0.45), 0 1px 0 rgba(255, 255, 255, 0.04) inset; + display: flex; + flex-direction: column; + max-height: inherit; + overflow: hidden; +} + +.capability-modal-header { + align-items: flex-start; + border-bottom: 1px solid rgba(255, 255, 255, 0.06); + display: grid; + gap: 14px; + grid-template-columns: 44px 1fr auto; + padding: 22px 22px 18px; +} + +.capability-modal-icon { + align-items: center; + background: rgba(249, 115, 22, 0.12); + border-radius: 10px; + color: #f97316; + display: inline-flex; + font-size: 20px; + height: 44px; + justify-content: center; + width: 44px; +} + +.capability-modal-heading { + min-width: 0; +} + +.capability-modal-eyebrow { + color: rgba(249, 115, 22, 0.85); + font-size: 10px; + font-weight: 600; + letter-spacing: 0.16em; + margin-bottom: 6px; + text-transform: uppercase; +} + +.capability-modal-title { + color: #fff; + font-size: 20px; + font-weight: 600; + letter-spacing: -0.01em; + margin: 0 0 6px; +} + +.capability-modal-tagline { + color: rgba(255, 255, 255, 0.6); + font-size: 13px; + line-height: 1.55; + margin: 0; +} + +.capability-modal-close { + align-items: center; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 8px; + color: rgba(255, 255, 255, 0.7); + cursor: pointer; + display: inline-flex; + height: 32px; + justify-content: center; + transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease; + width: 32px; +} + +.capability-modal-close:hover, +.capability-modal-close:focus-visible { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.16); + color: #fff; + outline: none; +} + +.capability-modal-body { + display: grid; + gap: 18px; + grid-template-columns: 1fr 1fr; + overflow-y: auto; + padding: 22px; +} + +.capability-section { + background: rgba(255, 255, 255, 0.02); + border: 1px solid rgba(255, 255, 255, 0.05); + border-radius: 10px; + padding: 16px 16px 14px; +} + +.capability-section-heading { + align-items: center; + color: rgba(255, 255, 255, 0.92); + display: flex; + font-size: 12px; + font-weight: 600; + gap: 8px; + letter-spacing: 0.04em; + margin-bottom: 10px; + text-transform: uppercase; +} + +.capability-section-heading::before { + background: rgba(249, 115, 22, 0.7); + border-radius: 2px; + content: ""; + display: inline-block; + height: 10px; + width: 3px; +} + +.capability-section ul { + display: flex; + flex-direction: column; + gap: 8px; + list-style: none; + margin: 0; + padding: 0; +} + +.capability-section li { + color: rgba(255, 255, 255, 0.66); + font-size: 13px; + line-height: 1.55; + padding-left: 16px; + position: relative; +} + +.capability-section li::before { + color: rgba(249, 115, 22, 0.7); + content: "▸"; + font-size: 10px; + left: 0; + position: absolute; + top: 4px; +} + +.capability-section li strong { + color: rgba(255, 255, 255, 0.88); + font-weight: 600; +} + +.capability-modal-footer { + align-items: center; + border-top: 1px solid rgba(255, 255, 255, 0.06); + display: flex; + flex-wrap: wrap; + gap: 12px; + justify-content: space-between; + padding: 16px 22px; +} + +.capability-modal-tags { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.capability-modal-tags .feature-tag { + font-size: 11px; + padding: 3px 9px; +} + +.capability-modal-link { + background: rgba(249, 115, 22, 0.14); + border: 1px solid rgba(249, 115, 22, 0.4); + border-radius: 8px; + color: #fdba74; + font-size: 12px; + font-weight: 600; + padding: 8px 14px; + text-decoration: none; + transition: background 0.15s ease, border-color 0.15s ease; +} + +.capability-modal-link:hover, +.capability-modal-link:focus-visible { + background: rgba(249, 115, 22, 0.22); + border-color: rgba(249, 115, 22, 0.6); + outline: none; +} + +@media (max-width: 720px) { + .capability-modal { + width: calc(100vw - 24px); + } + + .capability-modal-body { + grid-template-columns: 1fr; + padding: 18px; + } + + .capability-modal-header { + grid-template-columns: 40px 1fr auto; + padding: 18px 18px 14px; + } + + .capability-modal-footer { + padding: 14px 18px; + } +} diff --git a/docs/styles/workbench-layout.css b/docs/styles/workbench-layout.css index 4e7dcf6..c7fbf15 100644 --- a/docs/styles/workbench-layout.css +++ b/docs/styles/workbench-layout.css @@ -1,6 +1,6 @@ .titlebar { align-items: center; - background: linear-gradient(180deg, var(--vsc-activitybar) 0%, var(--vsc-tab-inactive) 100%); + background: #070c13; border-bottom: 1px solid var(--vsc-border); display: flex; gap: 8px; @@ -8,10 +8,6 @@ padding: 0 12px; } -body[data-theme="dark"] .titlebar { - background: linear-gradient(180deg, #11181b 0%, #0d0f0f 100%); -} - .window-controls { display: flex; gap: 6px; @@ -36,14 +32,17 @@ body[data-theme="dark"] .titlebar { .dot.red { background: #ff5f57; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25); } .dot.yellow { background: #febc2e; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25); } .dot.green { background: #28c840; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25); } .title-text { @@ -99,17 +98,12 @@ body[data-theme="dark"] .titlebar { } .activity-icon.active { + box-shadow: inset 3px 0 0 var(--vsc-orange); color: var(--vsc-text); } .activity-icon.active::before { - background: var(--vsc-orange); - border-radius: 2px; - content: ""; - height: 20px; - left: -4px; - position: absolute; - width: 2px; + content: none; } .activity-icon.pgstudio img { @@ -118,7 +112,7 @@ body[data-theme="dark"] .titlebar { width: 20px; } -body[data-theme="dark"] .activity-icon.pgstudio img { +.activity-icon.pgstudio img { filter: brightness(0) invert(1) saturate(0.2); } @@ -139,9 +133,9 @@ body[data-theme="dark"] .activity-icon.pgstudio img { .sidebar-header, .sidebar-group-title { - color: var(--vsc-muted); + color: #8fa2c5; font-size: 11px; - font-weight: 600; + font-weight: 800; letter-spacing: 0.08em; padding: 9px 10px 5px; } @@ -168,12 +162,12 @@ body[data-theme="dark"] .activity-icon.pgstudio img { color: var(--vsc-text); } -body[data-theme="dark"] .sidebar-tool { - background: rgba(255, 255, 255, 0.06); +.sidebar-tool { + background: rgba(255, 255, 255, 0.04); } -body[data-theme="dark"] .sidebar-tool.active { - background: rgba(249, 115, 22, 0.14); +.sidebar-tool.active { + background: rgba(255, 107, 22, 0.14); } .sidebar-group-title { @@ -184,7 +178,7 @@ body[data-theme="dark"] .sidebar-tool.active { border-top: 1px solid rgba(0, 0, 0, 0.04); } -body[data-theme="dark"] .sidebar-group { +.sidebar-group { border-top-color: rgba(255, 255, 255, 0.03); } @@ -213,7 +207,7 @@ div.tree-row { } .tree-row.active { - background: var(--vsc-highlight); + background: rgba(37, 99, 235, 0.22); } .tree-row.active .tree-label { @@ -221,14 +215,6 @@ div.tree-row { font-weight: 600; } -body[data-theme="light"] .tree-row.active { - background: color-mix(in srgb, var(--vsc-highlight) 90%, var(--vsc-border)); -} - -body[data-theme="dark"] .tree-row.active { - background: rgba(37, 99, 235, 0.15); -} - /* tree-row uses CSS var — auto-switches */ .depth-1 { @@ -300,21 +286,6 @@ body[data-theme="dark"] .tree-row.active { color: var(--vsc-blue); } -body[data-theme="dark"] .tree-file-icon.readme { - color: color-mix(in srgb, var(--vsc-blue) 72%, #ffffff); -} - -body[data-theme="dark"] .tree-file-icon.notebook { - color: var(--vsc-orange); -} - -body[data-theme="dark"] .tree-file-icon.doc { - color: var(--vsc-blue); -} - -body[data-theme="dark"] .tree-file-icon.workflow { - color: color-mix(in srgb, var(--vsc-orange) 88%, #ffffff); -} .tree-badge { background: color-mix(in srgb, var(--vsc-orange) 14%, transparent); @@ -329,9 +300,6 @@ body[data-theme="dark"] .tree-file-icon.workflow { color: var(--vsc-green); } -body[data-theme="dark"] .badge-dev { - background: color-mix(in srgb, var(--vsc-green) 16%, transparent); -} .editor-region { display: flex; @@ -340,6 +308,56 @@ body[data-theme="dark"] .badge-dev { min-width: 0; } +.editor-tab-strip { + align-items: stretch; + background: var(--vsc-tab-inactive); + border-bottom: 1px solid var(--vsc-border); + display: flex; + flex-shrink: 0; + min-height: 34px; +} + +.editor-tab-strip .tabs { + border-bottom: none; + flex: 1; + min-width: 0; +} + +.editor-layout-actions { + align-items: center; + align-self: stretch; + border-left: 1px solid var(--vsc-border); + display: flex; + flex-shrink: 0; + gap: 2px; + padding: 0 6px; +} + +.layout-toggle-btn { + align-items: center; + background: transparent; + border: 0; + border-radius: 4px; + color: var(--vsc-muted); + cursor: pointer; + display: flex; + flex-shrink: 0; + height: 26px; + justify-content: center; + padding: 0; + width: 26px; +} + +.layout-toggle-btn:hover { + background: var(--vsc-highlight); + color: var(--vsc-text); +} + +.layout-toggle-btn[aria-pressed="true"] { + background: color-mix(in srgb, var(--vsc-orange) 18%, transparent); + color: var(--vsc-orange); +} + .tabs { align-items: flex-end; background: var(--vsc-tab-inactive); @@ -386,6 +404,7 @@ body[data-theme="dark"] .badge-dev { .tab.active { background: var(--vsc-tab-active); border-top-color: var(--vsc-orange); + box-shadow: inset 0 2px 0 var(--vsc-orange); color: var(--vsc-text); } @@ -483,10 +502,6 @@ body[data-theme="dark"] .badge-dev { color: var(--vsc-green); } -body[data-theme="dark"] .pill-ok { - background: color-mix(in srgb, var(--vsc-green) 12%, transparent); - border-color: color-mix(in srgb, var(--vsc-green) 30%, transparent); -} .metrics { display: flex; @@ -556,8 +571,9 @@ body[data-theme="dark"] .pill-ok { } .cell { + background: #0d1728; border: 1px solid var(--vsc-border); - border-radius: 8px; + border-radius: 10px; margin: 16px 18px; overflow: hidden; } @@ -607,7 +623,7 @@ body[data-theme="dark"] .pill-ok { } .cell-lens button:hover { - background: var(--vsc-highlight); + background: rgba(37, 99, 235, 0.12); color: var(--vsc-text); } @@ -627,8 +643,8 @@ body[data-theme="dark"] .pill-ok { padding: 10px 12px; } -body[data-theme="dark"] .sql { - background: rgba(26, 26, 27, 0.8); +.sql { + background: rgba(10, 16, 30, 0.72); } .kw { @@ -647,18 +663,14 @@ body[data-theme="dark"] .sql { color: var(--vsc-muted); } -body[data-theme="dark"] .kw { +.kw { color: color-mix(in srgb, var(--vsc-blue) 70%, #ffffff); } -body[data-theme="dark"] .fn { +.fn { color: var(--vsc-blue); } -body[data-theme="dark"] .comment { - color: var(--vsc-muted); -} - .query-result { border-top: 1px solid var(--vsc-border); } @@ -683,12 +695,16 @@ body[data-theme="dark"] .comment { } .query-result th { - background: var(--surface); + background: rgba(37, 99, 235, 0.12); color: var(--vsc-muted); font-weight: 500; text-align: left; } +.query-result td { + border-bottom-color: rgba(148, 163, 184, 0.1); +} + .query-result.running .result-meta::after { animation: pulse 1s infinite; content: " • Running"; @@ -713,9 +729,6 @@ body[data-theme="dark"] .comment { padding: 20px 24px; } -body[data-theme="dark"] .json { - color: var(--vsc-text); -} .jk { color: var(--vsc-blue); @@ -745,7 +758,7 @@ body[data-theme="dark"] .json { .feature-card.active { border-color: var(--vsc-orange); - box-shadow: 0 0 0 1px color-mix(in srgb, var(--vsc-orange) 22%, transparent) inset; + box-shadow: 0 0 0 1px var(--vsc-orange) inset, 0 0 0 4px rgba(255, 107, 22, 0.15); } .feature-detail { @@ -840,18 +853,13 @@ body[data-theme="dark"] .json { } .insight-panel { - background: color-mix(in srgb, var(--vsc-blue) 8%, transparent); - border: 1px solid color-mix(in srgb, var(--vsc-blue) 22%, transparent); + background: rgba(37, 99, 235, 0.07); + border: 1px solid rgba(37, 99, 235, 0.3); border-radius: 6px; margin: 0 18px 16px; padding: 10px 12px; } -body[data-theme="dark"] .insight-panel { - background: rgba(37, 99, 235, 0.12); - border-color: rgba(249, 115, 22, 0.22); -} - .insight-panel h3 { font-size: 13px; margin-bottom: 6px; @@ -862,9 +870,38 @@ body[data-theme="dark"] .insight-panel { font-size: 12px; } +/* ── Query cell: outputs hidden until Run (`query-output-stack--pending`) ── */ +.query-output-stack { + margin-top: 2px; +} + +.query-output-hint { + background: rgba(255, 255, 255, 0.03); + border: 1px dashed rgba(148, 163, 184, 0.28); + border-radius: 8px; + color: var(--vsc-muted); + font-size: 12px; + line-height: 1.5; + margin: 10px 18px 12px; + padding: 10px 14px; +} + +.query-output-hint strong { + color: var(--vsc-orange); + font-weight: 600; +} + +.query-output-stack--pending .query-output-inner { + display: none; +} + +.query-output-stack:not(.query-output-stack--pending) .query-output-hint { + display: none; +} + .statusbar { align-items: center; - background: var(--vsc-statusbar); + background: linear-gradient(90deg, #1f3a8a 0%, #1d4ed8 100%); display: flex; font-size: 10px; gap: 10px; @@ -955,8 +992,6 @@ body[data-theme="dark"] .insight-panel { .git-badge { flex-shrink: 0; font-size: 9px; font-weight: 700; margin-left: auto; padding-right: 4px; } .git-mod { color: #e2c08d; } .git-new { color: #73c991; } -body[data-theme="light"] .git-mod { color: #a07030; } -body[data-theme="light"] .git-new { color: #367f45; } /* ── Sortable result table headers ──────────────────────── */ .sortable-th { cursor: pointer; user-select: none; } @@ -988,3 +1023,295 @@ body[data-theme="light"] .git-new { color: #367f45; } .history-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .history-time { color: var(--vsc-muted); font-size: 9.5px; padding-right: 4px; } +/* ═══════════════════════════════════════════════════════════ + PHASE 2: Immersive Layer — Background Grid + Orbit Ring + ═══════════════════════════════════════════════════════════ */ + +/* ── Background grid (absolute, behind shell) ─────────── */ +.workbench-bg-grid { + background-image: + linear-gradient(rgba(148, 163, 184, 0.055) 1px, transparent 1px), + linear-gradient(90deg, rgba(148, 163, 184, 0.055) 1px, transparent 1px); + background-size: 48px 48px; + inset: 0; + mask-image: linear-gradient(to bottom, black, transparent 80%); + -webkit-mask-image: linear-gradient(to bottom, black, transparent 80%); + pointer-events: none; + position: absolute; + z-index: 0; +} + +/* Background grid visible on landing + demo (immersive canvas) */ + +/* ── Orbit ring behind the shell ──────────────────────── */ +.shell-orbit { + animation: orbit 18s linear infinite; + border: 1px solid rgba(34, 211, 238, 0.12); + border-radius: 50%; + height: 560px; + left: 50%; + pointer-events: none; + position: absolute; + top: 50%; + transform: translate(-50%, -50%) rotateX(66deg); + width: 560px; + z-index: 0; +} + +/* Global orbit ring: hidden when landing — hero column uses .landing-orbit-ring instead */ +body.editor-minimized .shell-orbit { + display: none; +} + +@keyframes orbit { + from { transform: translate(-50%, -50%) rotateX(66deg) rotateZ(0deg); } + to { transform: translate(-50%, -50%) rotateX(66deg) rotateZ(360deg); } +} + +@media (prefers-reduced-motion: reduce) { + .shell-orbit { animation: none; } +} + +@media (max-width: 980px) { + .shell-orbit { display: none; } + .workbench-bg-grid { display: none; } +} + +/* Positioning context + 3D perspective for the immersive layer */ +.hero-shell { + perspective: 1600px; + position: relative; +} + +/* ── Floating context node pills ──────────────────────── */ +.ctx-node { + -webkit-backdrop-filter: blur(12px); + animation: floatNode 3.5s ease-in-out infinite alternate; + backdrop-filter: blur(12px); + background: rgba(7, 14, 26, 0.75); + border: 1px solid rgba(88, 166, 255, 0.18); + border-radius: 999px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4); + display: flex; + flex-direction: column; + gap: 1px; + padding: 6px 14px; + pointer-events: none; + position: absolute; + transition: opacity 0.6s ease; + z-index: 1; +} + +.ctx-node-label { + color: #9fb0cc; + font-size: 8.5px; + font-weight: 600; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.ctx-node-value { + color: #f8fbff; + font-size: 10.5px; + font-weight: 500; +} + +.ctx-env-dev { color: #22c55e; font-weight: 700; } +.ctx-env-prod { color: #ff6b16; font-weight: 700; } + +/* Positions (viewport-relative, snapped outside shell bounds) */ +.ctx-one { left: 4%; top: 28%; animation-delay: 0s; } +.ctx-two { left: 3%; top: 58%; animation-delay: 0.8s; } +.ctx-three { right: 4%; top: 38%; animation-delay: 1.6s; } + +@keyframes floatNode { + 0% { transform: translateY(0px); } + 100% { transform: translateY(-10px); } +} + +/* Fade after first workbench interaction */ +body.nodes-faded .ctx-node { + opacity: 0; + pointer-events: none; +} + +/* Hidden on landing, below 1180px, and reduced-motion */ +body.editor-minimized .ctx-node { display: none; } + +@media (max-width: 1180px) { + .ctx-node { display: none; } +} + +@media (prefers-reduced-motion: reduce) { + .ctx-node { animation: none; } +} + +/* ═══════════════════════════════════════════════════════════ + PHASE 2: Shell opening 3D animation + ═══════════════════════════════════════════════════════════ */ + +@keyframes shellOpenIn { + 0% { + opacity: 0; + transform: rotateY(-7deg) rotateX(3deg) translateY(-12px) scale(0.96); + } + 60% { + opacity: 1; + transform: rotateY(-3deg) rotateX(1deg) translateY(0) scale(1); + } + 100% { + opacity: 1; + transform: rotateY(0deg) rotateX(0deg) translateY(0) scale(1); + } +} + +/* Applied via JS class while animating — blocks clicks during 0.85s */ +.shell.shell-opening { + animation: shellOpenIn 0.85s cubic-bezier(0.22, 0.61, 0.36, 1) both; + pointer-events: none; +} + +/* Reduced-motion: simple fade instead of 3D tilt */ +@media (prefers-reduced-motion: reduce) { + .shell.shell-opening { + animation: shellOpenFade 0.4s ease both; + } + + @keyframes shellOpenFade { + from { opacity: 0; } + to { opacity: 1; } + } +} + +/* Kill 3D rotation on narrow desktops (980px) */ +@media (max-width: 980px) { + .shell.shell-opening { + animation: shellOpenFade 0.3s ease both; + } +} + +/* ═══════════════════════════════════════════════════════════ + PHASE 2: Decorative command palette overlay + ═══════════════════════════════════════════════════════════ */ + +@keyframes paletteIn { + 0% { opacity: 0; transform: translateX(-50%) translateY(-8px) scale(0.96); } + 10% { opacity: 0; } + 38% { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); } + 74% { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); } + 84% { opacity: 0.6; } + 100% { opacity: 0; transform: translateX(-50%) translateY(-4px) scale(0.98); } +} + +.cmd-palette-demo { + animation: paletteIn 9s ease-in-out infinite; + -webkit-backdrop-filter: blur(20px); + backdrop-filter: blur(20px); + background: rgba(7, 12, 24, 0.88); + border: 1px solid rgba(88, 166, 255, 0.22); + border-radius: 10px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(88, 166, 255, 0.08); + cursor: default; + left: 50%; + max-width: 340px; + opacity: 0; + pointer-events: none; + position: absolute; + top: 48px; + transform: translateX(-50%); + width: 90%; + z-index: 50; +} + +.cmd-palette-header { + align-items: center; + border-bottom: 1px solid rgba(148, 163, 184, 0.1); + display: flex; + gap: 8px; + padding: 8px 12px; +} + +.cmd-palette-prompt { + background: rgba(88, 166, 255, 0.14); + border: 1px solid rgba(88, 166, 255, 0.24); + border-radius: 4px; + color: #58a6ff; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.04em; + padding: 2px 5px; +} + +.cmd-palette-title { + color: #9fb0cc; + flex: 1; + font-size: 10.5px; + font-weight: 500; +} + +.cmd-palette-badge { + background: rgba(255, 107, 22, 0.14); + border: 1px solid rgba(255, 107, 22, 0.28); + border-radius: 999px; + color: #ff6b16; + font-size: 8.5px; + font-weight: 700; + letter-spacing: 0.05em; + padding: 1px 6px; + text-transform: uppercase; +} + +.cmd-palette-rows { padding: 4px 0; } + +.cmd-palette-row { + align-items: center; + display: flex; + gap: 10px; + padding: 6px 12px; +} + +.cmd-palette-icon { + color: #9fb0cc; + flex-shrink: 0; + font-size: 11px; + width: 14px; +} + +.cmd-palette-text { + color: #c8d8f0; + font-size: 11.5px; + font-family: "Fira Mono", monospace; +} + +.cmd-palette-row.is-active { + background: rgba(88, 166, 255, 0.1); + border-radius: 5px; + margin: 0 4px; + padding: 6px 8px; +} + +.cmd-palette-row.is-active .cmd-palette-text { + color: #f8fbff; + font-weight: 600; +} + +.cmd-palette-row.is-active .cmd-palette-icon { + color: #58a6ff; +} + +/* Suppress palette once user has interacted with the shell */ +body.shell-engaged .cmd-palette-demo, +body.editor-minimized .cmd-palette-demo { + display: none; +} + +/* Hidden on mobile */ +@media (max-width: 760px) { + .cmd-palette-demo { display: none; } +} + +/* Respect reduced-motion preference */ +@media (prefers-reduced-motion: reduce) { + .cmd-palette-demo { animation: none; display: none; } +} + diff --git a/package.json b/package.json index 28f772c..ca6c259 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "postgres-explorer", "displayName": "PgStudio (PostgreSQL Explorer)", - "version": "1.3.8", + "version": "1.2.5", "description": "PostgreSQL database explorer for VS Code with notebook support [Nightly]", "publisher": "ric-v", "private": false, @@ -3387,4 +3387,4 @@ "webpack": "^5.76.0", "webpack-cli": "^5.0.0" } -} +} \ No newline at end of file