Skip to content

feat(website/home): hero redesign with solid headline, formatted-SQL demo and proof line - #717

Open
ajitpratap0 wants to merge 2 commits into
mainfrom
feat/hero-redesign
Open

ajitpratap0 wants to merge 2 commits into
mainfrom
feat/hero-redesign

Conversation

@ajitpratap0

Copy link
Copy Markdown
Owner

Summary

Implements the Phase 2 hero redesign (#662):

  • Headline: solid text-fg h1; the brand gradient (from-brand to-accent, both semantic tokens so light mode switches to the darker AA values) applies only to "speed of Go". Removed hyphens-auto/break-words, added text-balance. Mascot logo unchanged.
  • Above the fold: the section is min-h-[calc(100svh-4rem)] (4rem = fixed navbar) and top-aligned instead of vertically centred, with tighter spacing. At 1440x900 the whole demo, input and output, fits in the first viewport; on a ~400px-wide phone viewport the demo starts at ~595px. The mobile input is capped at 180px so the output tabs come into view sooner.
  • Demo: defaults to the Formatted tab. A chip row shows the measured parse time (only the WASM parse call is timed, and only after WASM loads), the dialect and the statement type. The "AST" tab is now Tree and drops null/false/empty-string/empty-array/empty-object fields. website/scripts/gen-sample-ast now also writes the formatted sample (formatter.FormatString, the same call wasm/main.go uses), so the precomputed pre-WASM view is real formatted SQL and not raw JSON. The deferred WASM load from perf(website/home): defer WASM load until user intent; SW only on /playground #701 is unchanged.
  • Proof line under the CTAs, built only from src/data/metrics.ts: headline parse-stage ops/sec with its caption (stage, hardware, Go version), which links to /benchmarks, plus dialect count, lint-rule count and test count. No competitor numbers.

CHANGELOG.md was not edited, per maintainer instruction. Release note for the next version: "Homepage hero redesign: brand-highlighted headline, formatted-SQL demo with parse/dialect/statement chips, pruned Tree view, metrics-sourced proof line."

Test Plan

  • cd website && npm ci && npm run typecheck && npm run lint && npm run build: typecheck clean; lint has 0 errors and 7 warnings, all react-hooks/set-state-in-effect and none new (the 2 in MiniPlayground are on the existing parse effects); build succeeds
  • npm run check:metrics: passes
  • task check (fmt, vet, lint, race tests): passes; gen-sample-ast regenerated, and the AST is the same apart from the new formatted field
  • Headless Chrome screenshot at 1440x900: the headline, CTAs, proof line and whole demo are visible without scrolling
  • Real Chrome at ~400x770: demo input starts above the fold; light theme renders the h1 as #111827 with a #15803D to #4F46E5 gradient
  • Live WASM in Chrome: after clicking the input, the chips show "parsed in ...", "Generic" and "SELECT". The Tree tab output contains no null or false
  • Lighthouse CI (.github/workflows/lighthouse.yml) on this PR

Breaking Changes

None.

Closes #662
Part of #634

🤖 Generated with Claude Code

https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

@vercel

vercel Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
gosqlx-website Ready Ready Preview Oct 14, 2026 7:59pm UTC

@vercel

vercel Bot commented Oct 14, 2026

Copy link
Copy Markdown

Deployment failed for project gosqlx-website with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/coolajitpratapsingh0-9932s-projects?upgradeToPro=build-rate-limit

@ajitpratap0

Copy link
Copy Markdown
Owner Author

Fixed in 124de60: removed aria-live="polite" from the MiniPlayground chip row, so the parsed in … timing chip is no longer announced on every debounced keystroke or tab/dialect switch (matches the old non-live status span). Typecheck passes and lint shows 0 errors (7 existing warnings).

🤖 Generated with Claude Code

https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 20s —— View job


PR #717 review: hero redesign

Overall this is a clean, well-scoped change. I read the diff only and did not build or run it. Below are a few issues worth considering, most important first.

1. Stale output after a tab or dialect switch (medium)
MiniPlayground.tsx: shown = output || (!ready && sql === SAMPLE_SQL ? precomputed : '').

  • Before WASM is ready, the Lint tab has precomputed = '', so it renders an empty panel. A short placeholder such as "Interact with the input to run lint" would be clearer.
  • The dialect chip updates immediately when the dialect changes, but the precomputed output stays the same until WASM loads. That is fine, though the chip could look like it applies to output that was not produced with it.

2. Formatted view when format fails (low)
In runDemo, if api.format returns an object without .result, the output becomes ''. Both output and error are then empty, so the panel is blank with no message. The old code fell back to JSON.stringify. Consider setting an explicit error such as "Formatter returned no output".

3. statementLabel is heuristic (low)

  • It reads the first keyword from the SQL text, not from the AST. It can disagree with the parse, for example (SELECT ...) UNION ..., which gives "statement".
  • It also mishandles dialect-specific starts and EXPLAIN ANALYZE. If the AST has a type discriminator, such as the Go struct type name, using it would be more robust. Otherwise the fallback is acceptable.
  • STATEMENT_KEYWORDS.includes is fine at this size.

4. Parse timing (low)
parseUs times api.parse only. But runDemo then calls format or lint as well. Timing is correct, though it runs parse on every tab switch (the useEffect re-runs). That is acceptable for a demo. performance.now() is coarse in some browsers, so very small values may read as 0.0µs or be rounded.

5. pruneTree (nit)

  • It drops false, '', null and empty containers. It keeps 0, which is correct.
  • A recursive prune on large ASTs runs on every keystroke after debounce. That is fine for demo-size input.
  • SAMPLE_TREE is computed at module load, which is a small constant cost.

6. Accessibility

  • The chip row has no aria-live, which is consistent with your last commit.
  • The proof line <ul> separators use &middot; hidden from assistive tech, which is good.
  • On mobile the separators are hidden (hidden sm:inline). Wrapped items then have only gap spacing, which is still readable.
  • Tabs have role="tab" but no aria-controls or arrow-key navigation. This is pre-existing and not a blocker.

7. Go generator
gen-sample-ast/main.go looks correct. It uses the same formatter.FormatString call as wasm/main.go, and the new formatted field is committed in sample-ast.json. The generated file could drift from the generator. A CI check that regenerates the file and diffs it would prevent that, if one is not already in place.

8. Styling

  • The GradientText change to from-brand to-accent is good.
  • Headline: bg-clip-text inside an h1 with text-fg is fine.
  • min-h-[calc(100svh-4rem)] depends on the navbar staying 4rem. A shared CSS variable would avoid a magic number.

Security: no concerns. There is no dangerouslySetInnerHTML, and the output is rendered as text.

Tests: there are no automated tests for pruneTree or statementLabel. They are pure functions, so unit tests are cheap if the website has a test runner. The unchecked Lighthouse CI box is still pending.

No blocking issues. Item 2 is the one I would fix before merging.

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 28s —— View job


PR review: hero redesign (#717)

I reviewed the diff only. I didn't build or run anything. Overall this is a clean, well-scoped change, and I found no blocking issues.

What looks good

  • GradientText is only used in Hero.tsx, so switching it to from-brand to-accent has no side effects elsewhere.
  • Timing only the api.parse call, and only after WASM is ready, makes the "parsed in" chip honest.
  • The proof line takes all its figures from metrics.ts, so there are no hardcoded numbers.
  • gen-sample-ast uses formatter.FormatString, which matches what wasm/main.go calls. The precomputed Formatted view is therefore real output.
  • The pruneTree recursion is safe for JSON-shaped input, and the cost per keystroke is negligible.

Suggestions (non-blocking)

  1. Lint and Format now depend on a successful parse. runDemo (MiniPlayground.tsx) calls api.parse first and returns early on error. Previously the Format and Lint tabs ran independently. If the lint or format engines accept input the parse step rejects (dialect edge cases), those tabs now show an error instead. It would be safer to run the tab's own call even when parse fails, and only suppress the parse-time and statement chips.
  2. The Lint tab also runs a second parse. On every keystroke the Format and Lint tabs run api.parse and then format or lint. This is fine at demo sizes, but the work doubles. You could skip the parse unless the chips need it.
  3. Statement chip heuristic. statementLabel guesses the type from the first keyword, so it falls back to a generic "statement" label for anything not in the list. That includes EXPLAIN ANALYZE, (SELECT …) UNION … and BEGIN. Reading the type from ast.Statements[0] (the node's type name) would be more robust, if the WASM JSON exposes it.
  4. Proof-line separators. The · separator is rendered before each of the dialect, lint-rule and test items. When the list wraps on sm+ widths, a dot can end up at the start of a line. Putting the dot on li + li or using gap only would avoid this.
  5. Pruning drops false. This is intentional, but it also hides meaningful flags, such as Distinct: false or All: false on set operations, from a view labelled "Tree". A one-line tooltip or note on the tab would make the pruning explicit.
  6. Pre-WASM edits. If a user edits the SQL before WASM is ready, shown is empty, so the panel is blank with no hint beyond the status text. Consider an empty-state message such as "Loading parser…".
  7. Test coverage. There are no unit tests for pruneTree or statementLabel. These are pure functions and cheap to cover, for example null, false, '', empty arrays and objects, 0 (must be kept), and CTE and multi-statement labels. The Lighthouse item in the test plan is still unchecked.

Security and performance

  • No security concerns. The output is rendered as text inside <code>, with no dangerouslySetInnerHTML.
  • Moving the sample.formatted import to module scope is fine. SAMPLE_TREE is computed once at load.

Ajit Pratap Singh and others added 2 commits October 15, 2026 01:40
…demo and proof line

- Solid h1 with the brand gradient (brand -> accent tokens, light/dark aware)
  only on "speed of Go"; drop hyphens-auto, add text-balance.
- Hero fills 100svh minus the 4rem navbar and is top-aligned so the live
  demo starts above the fold at 1440x900 and phone widths.
- Demo defaults to formatted SQL with chips (measured parse time, dialect,
  statement type); the AST tab becomes "Tree" and drops null/false/empty
  fields. gen-sample-ast now also emits the formatted sample so no raw JSON
  is shown before WASM loads.
- Proof line under the CTAs built only from src/data/metrics.ts.

Closes #662

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
The parsed-in timing chip changes on every debounced keystroke, causing
screen readers to announce it repeatedly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 15s —— View job


Review of PR #717: hero redesign

I read the diff against origin/main and did not build or run anything. The change is well scoped and I found no blocking issues. Two points are worth fixing before merge.

Should fix

  1. Format and Lint now depend on a successful parse (MiniPlayground.tsx, runDemo). It calls api.parse first and returns early on error. Previously each tab ran its own call. If the formatter or linter accepts input the parser rejects, those tabs now show an error instead. Run the tab's own call regardless, and only suppress the parse-time and statement chips when the parse fails.
  2. A missing formatter result gives a blank panel. If api.format returns an object without .result, the output is '' and error is null, so the panel is empty with no message. The old code fell back to JSON.stringify. Set an explicit error such as "Formatter returned no output".

Nice to have

  • Extra parse per keystroke. Format and Lint both call api.parse before their own call, so the work doubles. If you do item 1, the parse is only needed for the chips.
  • Empty states. The Lint tab is blank before WASM loads, and so is any edited input. A short placeholder such as "Loading parser…" would help.
  • statementLabel is a heuristic. It reads the first keyword of the SQL text. (SELECT …) UNION …, EXPLAIN ANALYZE and BEGIN all fall back to "statement". If the WASM JSON exposes a node type, use Statements[0] instead.
  • Pruning drops false. This hides flags like Distinct: false from a view labelled "Tree". A short note on the tab would make that explicit.
  • Proof-line separators. The · is the first child of each li, so when the list wraps on sm+ widths a dot can start a line. Use gap only, or put the dot on li + li.
  • Magic number. calc(100svh-4rem) depends on the navbar height. A shared CSS variable would keep them in sync.
  • Sample drift. Nothing stops sample-ast.json drifting from gen-sample-ast. A CI step that regenerates it and diffs would catch this, if one doesn't already exist.
  • Tests. pruneTree and statementLabel are pure and cheap to unit test. Cases worth covering: 0 is kept, empty containers are dropped, and single, multi and CTE statements. The Lighthouse item in the test plan is still unchecked.

What looks good

  • GradientText is only used in Hero.tsx, so the from-brand to-accent change has no side effects elsewhere.
  • Timing only api.parse, and only after WASM is ready, keeps the "parsed in" chip honest.
  • Every figure in the proof line comes from metrics.ts.
  • gen-sample-ast uses the same formatter.FormatString call as wasm/main.go.
  • The chip row has no aria-live, and the separators are aria-hidden.
  • There are no security concerns. Output is rendered as text, with no dangerouslySetInnerHTML.

This branch was successfully deployed

1 active (outdated) deployment
Preview — 0fe2e130 Deployed Oct 14, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(website/home): hero redesign with solid headline, formatted-SQL demo and proof line [2.4]

1 participant