Skip to content

refactor(docs): rebuild the documentation template on the webkit design system - #2340

Merged
bruno-andrade-azion merged 34 commits into
release/new-azion-docsfrom
feature/new-docs-template
Sep 11, 2026
Merged

bruno-andrade-azion merged 34 commits into
release/new-azion-docsfrom
feature/new-docs-template

Conversation

@bruno-andrade-azion

Copy link
Copy Markdown
Contributor

What & why

Related issue: none
Pages affected: every documentation page — this is the shell, not the copy. The only content files touched are the two home pages (src/content/docs/{en,pt-br}/homes/), which moved out of the content collection into real Astro pages at the same URLs.

Rebuilds the documentation template on @aziontech/webkit 5 and @aziontech/theme 5, so the docs render from the design system instead of from hand-written CSS. The reference is the webkit docs demo; each piece below was matched against it.

Shell — docs top bar, left rail, "On this page" outline, prev/next pagination and footer rebuilt on webkit components; the masthead now spans the content column as a banner; the home gets its own layout without the page rail.

Prose — headings wrap their own anchor and reveal the link glyph only on hover or keyboard focus, with scroll-mt clearing the sticky header; markdown tables carry webkit's Table tokens (rounded surface, h-11 header row, row rules dropped on the last row) and scroll inside their own wrapper; the page closes on the prose contract's 48px step instead of running flush into the footer.

Toolkit — the design-system ESLint rules are wired and the code brought up to them: typed props, no style overrides on webkit components, tokens instead of raw colors, type-only imports where verbatimModuleSyntax needs them.

Type of change

  • 🆕 New content (feat)
  • 🩹 Fix (fix) — typo, broken link, wrong information
  • ♻️ Content update (docs) — rewrite, expansion, upkeep
  • 🌐 Translation sync (i18n)
  • 🏗️ Platform / structure (refactor / chore) — reviewed by UXE, no content mixed in

Author checklist

  • PR title follows type(scope): summary (see GOVERNANCE.md §4)
  • Frontmatter complete: title, description, meta_tags, namespace, permalink, last_reviewed — n/a, no page authored or re-slugged
  • No legacy "edge-" product names in the copy — the only edge- strings added are icon-font classes (ai ai-edge-firewall)
  • How-to/tutorial content includes at least one runnable, copy-paste-tested code block — n/a
  • Screenshots (if any) have alt text and follow image standards — n/a, none added
  • Internal links are relative and resolve locally
  • If any permalink changed or page moved: redirect added in this PR — no permalink changed: the home left the content collection but is served at /documentation/ and /documentacao/ as before
  • i18n: pt-br updated in this PR — the home move and the nav data cover both languages; no copy was rewritten
  • I ran pnpm build:local (build + frontmatter check) without errors — 1628 pages, exit 0

Review notes

Two things a reviewer should know:

  • patches/@aziontech__webkit@5.0.0.patch is a local fork that fixes hydration; it has to be rebuilt on every webkit upgrade rather than dropped.
  • The h1 renders 30px under 640px where the reference renders 24px. That is a version gap, not a bug here: webkit 5.0.0 (the latest published) ships text-heading-2xl sm:text-heading-xl as DocPageHeader's default h1, and the demo runs an unreleased build. Desktop is identical.

egermano and others added 30 commits September 10, 2026 10:45
Adds the webkit ESLint and stylelint rules, the husky pre-commit gate, the
webkit MCP server and the CLAUDE.md guidance, as produced by webkit init.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… into real Astro pages

The en and pt-br homes were MDX entries reached through [lang]/[...slug].astro.
They are now pages under src/pages, with their copy as structured data in
src/data/docs-home, which also supplies the synthetic collection entries the
docs endpoints still derive from, so the home stays in the search feed,
llms.txt, canonicals, the path map and the sitemap. Rendered output is
byte-identical in both languages.

Also drops two unused locals in files this change already touches.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…sign-system styles

A <script setup> using the runtime defineProps({...}) form exposes no typed
default export, so .astro importers failed to resolve these three. Switching to
withDefaults(defineProps<Props>()) fixes that and clears the ts2613 errors.

Also satisfies the new webkit lint rules: the hero's margin moves to a wrapper
we own, the sidebar header's padding moves inside its slot, and raw Tailwind
text sizes become the generated typography classes of the same size. The four
remaining overrides are load-bearing layout, not restyling, so they carry a
scoped disable explaining why.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
remove()'s callback indexed child.children[0] without checking the array had
anything in it, so an aside written with an empty label threw a TypeError
mid-transform. Narrowing the node properly also settles the `unknown` type the
`in` check left behind. Verified equivalent on a real labelled aside.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
<Community /> was rendered with no lang, so it fell back to its 'en' default and
the pt-br pricing page showed English community links.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…equires them

LinkCheckerOptions, CheckHtmlPageContext and AllPagesByPathname are interfaces,
so they have to be imported with `import type`. Also attaches the caught error
as `cause` when build-index rethrows, which the lint rules now require.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
getTranslatedPagesByNamespace now always returns an array rather than
`[] | undefined`, and loses a duplicate groupPagesByLang that nothing imported
(every call site uses the typed one in ~/util/groupPagesByLang). CodeBlock
defaults showLineNumbers to false, matching the Vue component's own default;
i18n/util types its Object.keys; generate-integration-pages narrows the mdast
list node before reaching into it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… into the content column

The footer now sits inside #main-content rather than spanning the viewport
below <main>, so its top hairline reads as the end of the content column. The
brand leads the social row from lg up and drops to the signature band below it,
which replaces the old tagline. The two controls in its slots follow: the
language switcher is rebuilt on the DS dropdown and the status indicator loses
its pill, so both read as part of the status row instead of buttons.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The desktop-only primary "Sign in" button becomes a secondary "Console" button
that shows at every width and points at the console root rather than its login
route. The signInLabel prop is left in place for the moment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…banner

DocPageHeader moves out of px-container so the rule it closes on reads as the
page's horizon instead of a line under the title. Its words still land on the
container's measure, because doc-page-banner pads it by exactly what
px-container would have.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Quote style, semicolons, trailing commas and script indentation only; verified
to be logically identical to the previous revision.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* release/new-azion-docs:
  Potential fix for pull request finding 'CodeQL / Incomplete string escaping or encoding'
  chore(webkit): adopt the design-system toolkit and report adoption on every PR (#2335)
…surfaced

Drops symbols nothing referenced (an unused import, two dead JSON helpers, a
translations placeholder, a slug normaliser, a leftover isTranslatable and an
unused useTranslations), narrows a catch that ignored its binding, and attaches
the caught error as a cause where csv.js rethrows.

azion.config.mjs is the exception worth reading: those `argument` values are
strings, not regex literals, so JS was already dropping the backslashes before
the edge saw them. They are rewritten to exactly what they evaluate to, so
routing is byte-identical, and each carries a note that the real fix is to
double the escapes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ount

The summary log read `contentMatch.length`, but no such variable exists — the
two in scope are contentMatchSingleQuote and contentMatchDoubleQuote — so the
script raised a ReferenceError on every iteration that actually found a link.
It now sums both, null-safe.

Also drops the redundant `\:` escapes in the two regex literals below it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ules

Three kinds of change, all driven by the rules the webkit toolkit adopted:

Typed authoring. Runtime defineProps({...}) and defineEmits([...]) become the
type-based macros with a named Props interface and withDefaults, and every
rendered slot is declared with defineSlots. Twelve components move to
<script setup lang="ts"> as a result.

Tokens. Raw Tailwind text sizes become the generated typography classes of the
same computed size, so nothing shifts visually. The hex values in AgentMark are
third-party brand marks — Claude's orange, the Gemini and Copilot gradient stops
from their official SVGs — which have no Azion token, so they carry a scoped
exemption instead.

Style overrides. Where a class was text treatment it moves inside the
component's slot; where it is box geometry or placement the shell owns — the
sticky header, the rail's height chain, responsive visibility, a panel's inset —
it keeps a scoped disable that says why. One class, readable-content on
DocProse, turned out to be a hook nothing targeted and is simply gone.

Also swaps the compound menu import for menu-root and replaces the unpublished
use-mounted composable with the plain onMounted equivalent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…out the page rail

The home is a set of card grids, not prose, so the "On this page" rail had
nothing useful to index — but it was on MainLayout, the generic doc-page layout,
which fills the secondary-sidebar slot unconditionally. It now has
DocsHomeLayout, which fills no such slot.

Dropping the slot alone was not enough: at the xl breakpoint the grid is
`auto 1fr 20rem`, so the rail's column stayed reserved and left a dead gutter.
BaseLayout now derives both the aside and that third track from whether the slot
was filled, which leaves every other page untouched.

Removes the headings helper the home no longer needs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bring both language homes onto the shape the design system's own DocsHome
reference draws — same components, same spacing rungs, same tokens.

The masthead was a HeroTitle island wrapped in page spacing; it is now the
reference's hero header as static markup, so only the copy pill hydrates. Its
h1 caps at --container-2xl (the narrowest rung holding the headline on one line
at 56px) and the lead one rung under it, and both controls keep their natural
size at every width — HeroTitle stretched them full-bleed below sm, which made
the rounded-full pill read as a second primary.

The guided-route cell was missing its ground: PixelateField ports the system's
PixelateBanner as pure CSS, masked to one ellipse in the outer corner so it
fades out before reaching the copy.

Sections open at 64 / 96 instead of DocProse's flat 56 — the page is heading,
sentence and bordered grid throughout, where 56 reads as one continuous stack —
and the column's own inset takes the same pair. The step lands in @layer
components: Tailwind runs in important mode here, and the cascade reverses layer
order for important declarations, so nothing else outranks DocProse's pt-14.

The home also stops routing through PageContent, the reading shell: no trailing
hr, and DocPagination closes the page with only its next half filled. Templates
take the colored framework marks where the icon set ships one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`patchedDependencies` pins the patch to an exact version, so the bump alone
failed with ERR_PNPM_UNUSED_PATCH. Both keys that name the version — the patch
entry and `minimumReleaseAgeExclude` — are retargeted, and the patch file is
renamed with them.

The patch is rebuilt against 5.0.0 rather than dropped: none of its ten changes
landed upstream, so removing it would regress the Astro hydration fixes (the
`:disabled="!isMounted"` teleports), the `use-mounted` export, the doc-step
counter fallback and the doc-page-header i18n props. Seven files re-applied on
offsets; doc-prose, doc-step and menu-sub-trigger had drifted in 5.0.0 and their
hunks were re-derived by hand.

Verified: install applies the patch, `astro build` completes 1628 pages, and a
docs page hydrates with no Vue mismatch in the console.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
webkit 5's eslint plugin adds two comment checks — no run over 5 comment lines,
and no file that is 20% or more prose comment — which reported 39 errors across
27 files. One-line JSDoc and directives are exempt, so most blocks collapse into
a single summary line.

Comments that restated the line below them are gone; rationale is compressed to
the constraint it carries. Design notes keep their facts: the flex-row-reverse
overflow that clipped the theme switcher off the left edge at 375px, the
`shrink-0` that stops the status band squeezing the language select to ~83px.
Also drops a commented-out footer entry.

Comments only — every file's code is byte-identical, checked by stripping
comments and blank lines and comparing against the index. eslint reports 0
errors (the 11 remaining warnings pre-date the upgrade), `astro build` completes
1628 pages, and tsc reports the same three pre-existing errors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…stem reference

FOOTER — four columns, one clean social row.

The link grid had three columns in a four-track grid, leaving a 181px track empty.
Both languages now carry the live site's own four (Company / Resources / Getting
Started / Developer), with every new URL checked rather than invented; the
Documentation link moved out of Getting Started, where it would have duplicated
the new column, and became How to start.

The mark was leading the social row from `lg` up, copying a reference whose row
spans the viewport. This one is half a column between two rails — 322px of
content at 1440 against the 344px a mark plus six 40px buttons need — so the row
wrapped and orphaned Discord on a line of its own. The mark keeps the signature
band at every width instead, which is where the DS puts it and where the
reference puts it at any width the row cannot hold both. That also retired the
stylesheet rule reaching into the DS's internal data-testid to hide that band,
and the second brand element that existed only to be hidden by CSS.

Also: `ai ai-x` for the X mark (pi-twitter is the old bird), social aria-labels
that name the profile, and `kind="content"` stated rather than inherited.

SHELL — no gap, no stylesheet.

The grid carried `gap: 1rem` between the rail and the reading column. The
reference uses none: the columns abut on hairlines the components already draw —
webkit's Sidebar ships `border-r`, and the outline column takes `border-l`. A gap
set the columns off from a rule that was already separating them.

So the row is flex with no gap, and BaseLayout's <style> block is gone: the
geometry is utilities reading webkit tokens (--container-3xs for the outline,
--spacing-14 for the bar offset, --border-default for the rule). Dropped with it
were declarations that were inert on a static grid item (z-index, inset-*,
max-height), `layout--no-rail` and its media query (an unrendered aside takes no
flex space), a `main-column` class no stylesheet defined, and the shell's own
`pt-4 pb-6` — a page opens its own column now, which is what puts the docs home's
h1 at the 152 the reference names. The one rule no utility can carry
(`astro-island { display: contents }`) moved next to the markup it is for.

Verified on a production build at 1440 / 1100 / 375: gap 0 both sides, hairlines
present, rails still scroll through their own primitives, reading pages unmoved
at h1 125.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ure band

The reference fills the footer's `brand` slot only BELOW `lg`, so its docs footer
has no signature band on a desktop and the mark leads the social row. Filling
that slot at every width gave the opposite: a centred logo inside a bordered,
corner-marked row at the foot of the page that the reference never draws.

The mark had been moved there because the row could not hold it — measured before
the shell was cleaned up. Removing the column gap and narrowing the outline grew
the reading column 725 -> 821, and with it this band, so the mark fits again.

It still cannot fit at every width, and the gate is the FOOTER's own width rather
than the viewport's: from `md` the band is half the footer, so the reference's
`lg` viewport test says nothing about the room a column between two rails has.
The band gives its content half the footer less `--spacing-lg` either side, and a
mark plus six 40px buttons and their gaps need 352 — so the mark steps out under
a footer width of 800 and the row is the six glyphs alone.

Measured on a production build: one line at 375, 1280, 1440, 1920, with the mark
leading it from a 1440 viewport up, and no signature band at any width.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The pair rendered inside an `aside` that carried its column and its top space,
and on a reading page it sat under an `hr` with only 8 above it. The reference
puts both on the component: `layout-column-content layout-boundary-inline pt-12`
on a reading page, `pt-16` on the home, and no rule above either.

So the wrapper goes and the pagination carries `px-container` (this repo's
equivalent measure, so it lands on the prose's own column) plus the close its
placement asks for — 48 on a reading page, 64 on the home, which is the same rung
the home opens its sections one step above. The trailing `hr` goes with it: 48 of
rule plus 48 of padding said the same thing twice, and the reference draws none.
Rules authored in a page's own MDX are untouched.

Dropping the `aside` also drops a `complementary` landmark that wrapped a `nav`
already carrying one.

The labels take sentence case, and `Back` becomes `Previous page` so the two
halves name one concept: the DS's own wording, and § 2 of the microcopy rule.

Rendered markup now matches the reference class for class on the link and the
nav, verified against a production build. Three differences remain and are all
deliberate: the testids stay `documentation-doc-pagination` / `__next`, which are
webkit 5's derived defaults and follow the `<category>-<name>` testid rule, where
the reference's are a sample app's override; the icon keeps webkit's
`transition-[translate]`, which animates the same property as the reference's
`transition-transform` in Tailwind v4; and the label carries no section suffix
because this repo's first nav group has no label to name.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
webkit went to 5.0.0 in 1552a70 but the theme stayed pinned at 4.3.1, and 5.0.0
is what declares the tokens webkit 5 expects: --layout-measure-site (1388),
--layout-measure-site-header, --layout-measure-content, and the layout-column-site
/ layout-column-content / text-amount-* utilities. Nothing caught the skew because
webkit's own manifest asks for ^4.0.0, a range 4.3.1 satisfies — so pnpm resolved
it cleanly and the missing custom properties simply emitted nothing.

Latent rather than visible until now: `kind="site"` is used nowhere here and
neither Currency nor CardPricing is rendered, so the undeclared vars had nothing
to break yet. GlobalHeader was the sharpest edge — an undefined var inside its
`calc()` drops the whole padding declaration.

5.0.0 removes --layout-measure-docs, --container-site and layout-column-docs
(renamed layout-column-content); this repo references none of the three, and no
webkit 5 file uses the old names either. Every token the app does use kept its
value across the bump (--container-3xs/2xl/xl/4xl, --spacing-14/16/24), verified
by rebuilding and re-measuring the shell, the footer and the pagination.

The `minimumReleaseAgeExclude` entry keeps 4.3.1 alongside 5.0.0 because webkit
still resolves 4.3.1 for itself. That copy is inert for the build — webkit imports
the theme nowhere in its components, and the app's own `@reference` resolves to
5.0.0 — so it costs store space, not correctness.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`ai ai-twitter` is not in azionicons — the pseudo-element resolved to
`content: none` at width 0, so that row sat iconless beside five that
were not. Same glyph the footer moved to.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The reference's `#toc` slot is the outline, the complementary groups,
then the offer pushed to the foot of the column (DocsAgentSetup's
sibling, AzionDocsPage.vue). `DocCta` lives in @aziontech/webkit-docs,
which this project does not install, so it is ported from the upstream
source out of the same parts — FrameBox, Brand, Button — as an Astro
template, which ships no JS for two links and a wordmark.

The rail itself becomes the reference's single column: the webkit
ScrollArea carries the geometry and the scroll, `tabindex="-1"` because
a column that is nothing but links is scrolled by tabbing through them,
and the scroller moves out of the OnThisPage island so the composition
reads in the template. Dropped on the way: the `nav` wrapper, which put
a landmark named "Secondary" around DocOnThisPage's own better-named
one, and `wrap-nav` / `wrap-nav--island`, which resolve to no CSS
anywhere — the pricing rail held the last reference.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The GitHub button sat inside a `hidden sm:contents` wrapper, so the link
disappeared on phones — the one place the header has room for it in the
overflow. Drop the wrapper and keep the flex-sizing lint pragma around the
action cluster, which the wrapper used to carry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both roots of this component land directly in the header's action row.
Declaring the trigger last puts the visible control next to the GitHub
and Console buttons instead of behind the command menu's node.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
egermano and others added 4 commits September 11, 2026 09:54
Whitespace only: tabs, semicolons, the 100-column wrap, and the
unindented script block the rest of the components already use.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every MDX title rendered a permanent link glyph beside it, because the
autolink pass appended the icon after the heading text. The reference
wraps the whole title in the anchor and only shows the glyph on hover or
keyboard focus, so switch to `behavior: 'wrap'` and build that markup.

The heading also carries `data-doc-heading` and a `scroll-mt` that clears
the 56px sticky header, so the jump is the browser's again: the click
handler no longer hijacks the anchor, and only the glyph still copies the
URL. Its listener is now removed on scope dispose.

SectionHeading imports the classes from the autolink module rather than
restating them, and the dead `.readable-content` CSS goes with it - no
element in the repo sets that class.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Table styling lived in a `<style>` block scoped to `.readable-content`, a
class nothing in the repo sets, so markdown tables rendered with browser
defaults inside a bare scroll wrapper.

A markdown table IS a webkit Table: webkit's own is a flex tree and this
is real `<table>` markup, so carry the tokens over rather than the markup,
with the classes kept identical to `doc-markdown.vue` in webkit-docs. The
wrapper gains `data-doc-block`, which is the hook DocProse already spaces
a block with - the dead CSS had been trying to do that with a margin.

The pass it replaces walked only `tree.children`, so any table below the
document root was left unwrapped; this one visits at any depth.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The article had no bottom padding, so the prev/next pagination ended
flush against the site footer - webkit's Footer ships no top border and
no top padding of its own, so nothing else was providing the separation.

`pb-12` is what the reference article takes, and 48 is the same step the
pagination already opens with above it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@bruno-andrade-azion
bruno-andrade-azion merged commit f048e07 into release/new-azion-docs Sep 11, 2026
2 checks passed
@bruno-andrade-azion
bruno-andrade-azion deleted the feature/new-docs-template branch September 11, 2026 14:40
lucas-langeloh-azion added a commit that referenced this pull request Oct 2, 2026
…atch forward

5.3.0 ships the Menu and Sidebar SSR fixes the sidebar needs (aziontech/webkit,
ENG-48323). Dropping the patch outright broke the release: every MDX page with
<DocSteps>/<DocStep> (238 files) threw "useDocStepsContext must be used within
DocSteps" in SSR and its HTML truncated. So the hunks that existed for 5.0.0
move to a 5.3.0 patch unchanged. None of the ENG-48323 changes are in it;
removing the patch is left for its own piece of work.

Carried hunks, by origin:
- #2340: DocPageHeader lastUpdatedLabel/locale; DocProse, Dropdown and Tooltip
  Teleport disabled until mounted (with the use-mounted export); DocStep and
  DocSteps without a provider; MenuSubTrigger icon on inline rows; TabViewPanel
  requestAnimationFrame guard
- #2345: Sidebar footer as a bar
- #2390: NavigationMenu viewport measured at scale 1 under important mode

Two hunks were re-applied by hand on 5.3.0: the package.json export (its
neighbour moved from .js to .ts) and the viewport scale (a max-size cap now
sits around it).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants