Repository navigation
Apply the new Vortex design system - #120
lwwmanning wants to merge 98 commits into
Conversation
- Load vortex-skin.css after globals.css: the Blue accent, warm greys, 6px cards and 4px controls. It sets only visual properties, and app/vortex-skin.test.ts holds it to that. - Load Geist and Geist Mono with Funnel Display in one font request. - Replace the Lucide icons with Material Symbols Sharp, in one shared icons module. The GitHub mark stays. - Write the Compression Size headings as words, without emoji. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Bench preview for |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
- Bench paints its one --accent as words and as fills. Fills now take --accent-fill with white text: blue-bright (#6e5cff) in Dark, and the same Blue as words in Light, so Light does not change. - app/vortex-skin.test.ts reads globals.css and fails if an accent fill there has no override in the skin. - Dark muted text is grey-450 (#9c9c99), one step below body text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
- The group title's description hint was a Unicode text glyph beside Material Symbols Sharp icons. It now renders the Sharp `info` icon from the same pinned source as the others. - components/icons.test.tsx fails if a component uses a text glyph as an icon again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
…x.dev - src/styles holds copies of the system's tokens and the base, brand, site, docs, blog and focus components. Its type styles read var(--font-*), which point at next/font's faces and fallbacks. - next/font loads Funnel Display 500 and 600, Geist and Geist Mono. - The ground is the system's Dark ground (#0f0f0e), mirrored in src/lib/theme.ts for the verify parity check. - The blog follows the reader's stored theme (vx-theme); every other page is Dark. An inline script sets it before first paint, and RouteTheme sets it again on client-side navigation. - bun test runs tests/unit in CI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
🔦 Lighthouse audit
Run |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7a4c372aab
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Playwright's default pattern matched the node:test files in tests/unit and failed to load them. testMatch now takes *.spec.ts only; bun test runs tests/unit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
- Header follows the Header card's site variant: the Vortex wordmarks (Dark and Light), nav Docs, Bench, Explorer, Blog, Slack, and the GitHub button with the star count. Below 800px the nav takes a second row. - src/lib/github.ts reads the star count at build time with a one-day revalidate and a timeout. The count hides when the fetch fails. - Footer follows the Footer card: the LF mark, the LF Projects line, and Charter, Code of conduct, Security and Calendar. - The root layout puts header, main and footer in one --page-max frame. - Remove the old logos and the donor credit's logo, with their REUSE entries. Annotate the new wordmarks as CC-BY-4.0. - Replace the scramble smoke test with header and footer link checks. Signed-off-by: Will Manning <will@willmanning.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fixes - The GitHub button's count is the Material Symbols Sharp `star` beside the number, not a ★ glyph, and the link names the repository and its stars in full. - A post marks the Blog link as the current section (aria-current="true"); the index stays the current page. - The header's wrap at 800px, the right-hand end group on two rows and the wrapping footer nav are now in the design system; the site's stopgap overrides are removed after syncing its styles. - tests/unit/icons.test.ts fails if site code uses a text glyph as an icon. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8171a90d3c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The header now links /slack, a redirect to Slack's invite page, which answers CI's fetch with 403. The internal-link check no longer follows redirects off the site; a redirect means the route exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
- The page follows the Home card: the hero (Eyebrow, the vx-display headline, InstallTabs and the AsciiMark), then two empty bands for the BenchmarkCard and the LogoBanner. At 1440 x 900 the page fills one screen. Below 1100px the hero stacks, and on phones the headline is 48px. - InstallTabs: Rust, Python, DuckDB, Spark and CLI, one tab stop with the arrow keys, Home and End, and a copy button that leaves out the prompts. All panels share one cell, so the block keeps its height. - src/lib/maven.ts reads the Spark version from Maven Central's metadata at build time with a one-day revalidate. The command shows <latest> when the read fails. - AsciiMark runs the system's renderer, vendored unchanged in src/vendor/vortex-design, with three 0.170.0 from npm. Both load only after the page is idle. Without WebGL it shows the Vortex symbol. - Add the content_copy and check icons. - Remove the old OGL hero and its overlay. - Replace the hero smoke tests with headline, tab, copy and mark checks. Signed-off-by: Will Manning <will@willmanning.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The smoke test built a RegExp from a source host such as "iceberg.apache.org", so its dots matched any character. CodeQL flagged it. A plain string matches a substring of the link's name, which is what the test meant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
Random access sums several charts into one dataset's bucket. A window that missed one of them still counted the bucket, so the card could show a time summed from part of a dataset. Each bucket now takes the group's full chart list from /api/groups, a chart with no times joins its bucket empty, and a time panel uses its times only when every bucket is measured for Vortex and Parquet. Otherwise it shows bench's scores. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
main moves CI, the types, and both Vercel projects to Node 26 (#143). package.json and renovate.json take main's Node 26 lines. CLAUDE.md takes main's note on @types/node and keeps this branch's record that postcss-selector-parser went with @tailwindcss/typography, so main's override rule for it is not needed here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
It mentions Vortex in one sentence. The list keeps posts where Vortex is a significant part. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
bench drew Vortex in red, Parquet in cyan, and Arrow in orange. Now each format takes the design system's series palette: - Vortex is Blue: blue-bright (#6e5cff) on datafusion and for encode, a lighter Blue (#8b84f3) on duckdb and for decode. vortex-compact takes an azure Blue. - Parquet, DuckDB, Lance, and Arrow take muted hues (sand, sage, warm grey, and dusty rose), each at its own lightness. - A pair (two engines, or encode and decode) keeps its hue and changes its lightness. Before, encode and decode had one color. - Each color holds 3:1 on the Light and the Dark card, so the chart still does not recolor when the theme changes. Only the colors change. Widths, order, and the cold dash stay. Signed-off-by: Will Manning <will@willmanning.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing above the fold said that Vortex is a file format. A standfirst under "Fast, small, open: pick three." now says it: "Vortex is an open-source columnar file format for fast scans, random access, and compression." It is one vx-lede line in ink-body, 12px under the headline. It fits in the text column's free height, so the hero keeps its height, and the ASCII mark keeps its size: 472 × 383 at 1512 × 860, 472 × 423 at 1440 × 900, and 472 × 472 at 1512 × 982. New smoke tests check the standfirst and the mark's size. Signed-off-by: Will Manning <will@willmanning.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The landing page wrapped its groups in a Suspense boundary, so a browser got them in a hidden segment that only React's inline script reveals. With JavaScript off, a reader saw the loading card and nothing else. The page now awaits its data and sends the groups as visible HTML. On a Data Cache miss the browser shows nothing until the groups have been read; performance.md has the numbers. Visible groups can paint before the last one arrives on a slow connection, so the open-groups bootstrap now runs before the first group and opens each listed group from a MutationObserver as the parser inserts it. A finish step after the last group opens groups listed by slug and leaves the marker. The loading card is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
The root <html> renders with a no-js class, and the pre-paint bootstrap swaps it for js as its first statement. Controls that do nothing without JavaScript carry data-requires-js, which .no-js hides: the theme toggle, the mobile nav toggle, Expand and Collapse All, the filter dropdown, the group jump menu, and a chart card's toolbar, canvas and range strip. On a phone the nav shows in the header row instead, with its GitHub link. The group copy-link control is now a real link to /#<anchor>; with JavaScript a click, Enter or Space still copies it. A collapsed group's body now hides through CSS, since it sits after the <details>. A <noscript> list of each group's chart links was measured and left out: it adds 7.3 KB gzipped (151 KB raw) to the landing page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
The canvas is now role="img" with an aria-label that names the chart. Once the chart has data, the label adds one sentence with each visible series' value at the latest commit with data, dated, in the chart's display unit and formatted as the tooltip formats it. On the production data the newest commit in every chart's window has no results yet, so the literal latest commit would always read as empty. The controller restates the label after construction, a payload swap, a filter change and a legend click. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
Without JavaScript a group's summary still toggles its <details>, but opening it shows nothing more. Under the no-js class the row now reads as a plain heading: no chevron, pointer, hover or open state. The note for readers without JavaScript opens <main> and says the summaries are complete and the charts need JavaScript. The copy link lets a modified or middle click through, so open in a new tab works. It renders as "Link to <group>" and takes the copy wording once mounted, so hydration matches. Header swaps a no-js class back in a layout effect, before paint. The open-groups bootstrap defines its finish step before it makes the observer, and makes none when the fragment lists nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
Each request to / starts reading its data and waits up to 150 ms. A Data Cache hit answers in time, so the page renders the groups as plain HTML, as before. A miss streams the loading view at once inside a Suspense boundary, and the groups follow when the read finishes; a client navigation to / shows it the same way. Without JavaScript the loading view says to reload in a few minutes, since the CDN keeps / for five. HomeLoading and its styles are back. Measured on the local dump, a miss now gets its first byte at 180 ms and the loading view at 328 ms instead of a blank page until 720 ms; a hit is unchanged. performance.md has the table, and notes that a database failure inside the wait returns a real 500. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
The AsciiMark's host was empty until the page went idle, and empty for good without scripts. The server now renders the static symbol in it, sized as the design system's fallback; the live or reduced-motion mark replaces it when it draws, and it stays without WebGL or on an error. The root renders with a no-js class, which the first-paint script swaps for js as its first statement; RouteTheme swaps it back if React ever re-renders the root. Controls that do nothing without scripts carry data-requires-js and hide: the install tabs and copy button (every install panel then shows, stacked under its tab's name), the logo banner's pause (the logos then sit still, as under reduced motion), the blog's theme switch, code copy buttons and newsletter form. With scripts and WebGL on, the homepage, the 404 page and /blog are pixel identical to #120. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
The symbol the server renders for readers without scripts showed from first paint until the live mark drew, then jumped to the mark at a different size; #120 showed an empty box. With scripts the symbol now stays hidden, and shows only once the host's data-mark-mode says the mark cannot draw (static or error). Readers without scripts keep it. The mark's host is pixel identical to #120 at DOMContentLoaded, at load and once drawn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
Browsers send a middle click as auxclick, never click, so the button check in the click handler could not match. The modifier keys still pass through. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
performance.md's note on misses now says an ingest causes none, since it marks the Data Cache stale rather than dropping it. The 150 ms loading-view threshold was measured against a local Data Cache and needs checking against Vercel's function logs on a preview. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
The caption after the headline's dot read as a spec: "times in ms, the geomean over queries or datasets, the rest against Parquet = 1, best first". Now it is "times in ms, ratios to Parquet, best first". The method moves to the caption's title, for hover, and to screen-reader text after the caption: "A time is the geomean over the queries or datasets that bench's score covers. A ratio is against Parquet = 1." The design system's benchCaption and benchMethod build both from the panels' units, so the score fallback still gets its own words, and no unit that no panel shows is named. The vendored benchmark-card module is a byte-for-byte copy of the system's. Signed-off-by: Will Manning <will@willmanning.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Take origin/wm/bench-skin-2 at a1a27c2: the homepage and bench work without scripts. The fixes from the page review stay on top. Signed-off-by: Will Manning <will@willmanning.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without scripts the static symbol stands in for the ASCII mark, and the install commands stack. The hero still stretched to fill the window, so a tall window put a wide empty band around the small symbol. Now, from 1100px wide and only under html.no-js, the hero takes its content's height with the scripts-on page's room at 1512 × 860: 72px from the header to the eyebrow, and 64px from the install block to the benchmark card. The symbol is 56% of the host (264px), not 40%, so it balances the stacked commands. AsciiMark reads that width from --mark-still-width, with 40% as the default. With scripts the page does not change: the mark's box stays 472 × 383 at 1512 × 860, 472 × 423 at 1440 × 900, and 472 × 472 at 1512 × 982. A smoke test checks the hero without scripts at 1512 × 860 and 1512 × 1400. Signed-off-by: Will Manning <will@willmanning.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a1a27c28ad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
On /blog at 1512px, "datalakehousehub.com" ran out of the 150px meta column into the title, and iceberg.apache.org and parquetreader.com touched its edge. The BlogIndex card now: - sets the meta column to 180px, which holds the longest listed host on one line, - puts the host in its own span, which ends in an ellipsis if a longer host comes, and - gives the source the full host as its title. A smoke test checks every external host in links.ts at 1512, 1440, and 375px. The CSS is the design system's, copied with site-styles.mjs. Signed-off-by: Will Manning <will@willmanning.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The index was one list of 40 rows with no breaks. Now each year has a
quiet heading in Geist Mono ("2026", "2025") over that year's own list,
from the BlogIndex card:
- h2.vx-label.vx-posts-year, in ink-muted, on the column's edge, with an
id such as posts-2026.
- One ul.vx-posts per year, so the rows keep their list semantics and
stay in date order.
- Each row's title is now an h3 under its year's h2.
byYear in src/lib/posts.ts splits the rows by the UTC year of each date,
as the date line reads. Unit and smoke tests check the groups, their
order, and the headings.
Signed-off-by: Will Manning <will@willmanning.io>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The copy link's href was a bare /#anchor, so a modified or middle click opened the group without the page's filters, such as ?engine=duckdb. Once mounted, the href is now the same permalink a plain click copies, and it is refreshed on pointer down and focus so it carries the group's series too. Without scripts the link stays /#anchor, because filters do nothing there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
Signed-off-by: Will Manning <will@willmanning.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Will found the themed series palette hard to read. Bench's charts go back to their original colours, the same as on main. Legibility of the data comes before the brand palette there. This reverts commit b1cd3b8. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Will Manning <will@willmanning.io>
The Dark accent was #6e5cff, a periwinkle 6° of hue from Lance's mark (about #625eff). It is now cobalt: blue-bright #2f63ff for marks and fills, and blue-soft #8fa9ff for Blue text and thin lines, both near 225°. Contrast holds: #2f63ff is 4.0:1 on the page with white text at 4.8:1 on it, and #8fa9ff is about 8:1. Light keeps its Blue. The design system's tokens, the bench skin, the Open Graph images, and the ASCII mark's brush all take the new values. Signed-off-by: Will Manning <will@willmanning.io>
There was a problem hiding this comment.
💡 Codex Review
vortex.dev/bench/web/lib/chart-format.ts
Lines 117 to 121 in b9f222a
When bench uses its Light theme with the white card background, duckdb:vortex-file-compressed has only 2.28:1 contrast and datafusion:parquet only 2.14:1; on the Dark #171716 card, duckdb:vortex-compact reaches only 2.57:1. Because this mode-independent palette uses solid lines, these important graphical objects fall below the 3:1 non-text contrast threshold and become difficult for low-vision readers to distinguish; choose colors that clear 3:1 against both card backgrounds or theme the series colors.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Each format now has a colour that identifies it: Vortex is cobalt #2f63ff, vortex-compact is red, Parquet is teal, Lance is purple, DuckDB is yellow, and Arrow is orange. The duckdb run of a format is a shade of that colour. Widths, order, and dashes do not change. One set of colours cannot be legible on both cards. A colour with 3:1 contrast on the white card and on the #171716 card must have a very narrow range of lightness, and ten lines do not fit in it. Thus there is one set for each theme, and the chart controller recolours a drawn chart when the theme changes. lib/theme.ts holds the theme helper that the header and the charts use. New tests make these rules for each card: - Each colour has a minimum of 3:1 contrast against the card. - Each two formats have a minimum ΔE2000 of 25, and 12 with simulated protanopia and deuteranopia (Machado 2009). - All other pairs of lines in a query chart have a minimum ΔE2000 of 15, and 5 with the simulations. - Lance is a minimum of 25° of hue from Vortex, and Parquet 20°. No format other than Vortex is in its blue family. The old palette failed all of these rules. Signed-off-by: Will Manning <will@willmanning.io>
A format now has one colour on every engine. The engine shows as the line style: a duckdb run is dashed, and a datafusion run is solid. A cold random-access run stays dashed. The two never share a chart. DuckDB is green: a soft green on the Dark card and a deep forest green on the Light card. Parquet's Dark teal moves from #0fb0aa to #09aeae to stay apart from the green. The duckdb shades and their tests are removed. seriesStyle returns the dash, so datasets.ts no longer sets it. Signed-off-by: Will Manning <will@willmanning.io>
This change applies the Vortex design system to all pages in this repository: the homepage, the blog, the 404 and error pages, and bench.
src/vendor/vortex-design/. Tailwind is removed.🤖 Generated with Claude Code