Skip to content

refactor: Rebuild the docs on Astro 7, Tailwind 4 and @aziontech/webkit 4 - #2328

Draft
isaque-bock-azion wants to merge 21 commits into
mainfrom
release/new-azion-docs
Draft

refactor: Rebuild the docs on Astro 7, Tailwind 4 and @aziontech/webkit 4#2328
isaque-bock-azion wants to merge 21 commits into
mainfrom
release/new-azion-docs

Conversation

@isaque-bock-azion

@isaque-bock-azion isaque-bock-azion commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Rebuilds the documentation site on the current Azion stack: Astro 7, Tailwind CSS 4, and @aziontech/webkit@4 with @aziontech/theme@4. The previous design-system dependencies — azion-webkit@1, azion-theme@1, primevue, primeflex — are gone, and the components that used to be maintained by hand in this repo now come from the design system.

Supersedes #2315, which carries the same work on the old branch name.

What changes

Area Before After
Build Astro 5, Tailwind 3, Vite 6 Astro 7, Tailwind 4, Vite 8
Design system azion-webkit@1 + primevue + primeflex @aziontech/webkit@4.4.0 + @aziontech/theme@4.3.1
Prose contract local .prose CSS webkit DocProse via ReadableContent
Tabs Preact component + CSS modules webkit TabView
Cards, titles 6 hand-built components DocCard, DocCardGroup, SectionTitle, Overline
Footer controls hand-built dropdown, hex-painted status dot ThemeSwitcher, StatusIndicator, Dropdown
Lint eslint 8 + .eslintrc.js eslint 9 flat config, typescript-eslint 8, stylelint 16
Repo hygiene .claude/ and .codex/ checked in both removed and ignored

70 components deleted from src/components; 875 files changed overall (+12,322 / −17,240). The agent tooling directories .claude/ and .codex/ are gone from the tree and now ignored — a local permission allowlist, a browser launch config, a stale git worktree and a Codex environment file, none of it project configuration.

Notes for review

Buttons in the article body. DocProse styles every a in the prose with !important and steps aside only for [data-doc-chrome]. A webkit Button with href is such an a, so it rendered as a blue underlined link over its own fill. Button sets inheritAttrs: false and forwards only class, so the attribute cannot go on the component — hence DocButton, which carries it on a wrapping span. The 650 content files that use it were swept mechanically; the import line was identical in all of them and every file was re-checked through the MDX compiler.

Tab authoring is unchanged. All 328 tab blocks across 178 content files keep the <Fragment slot="tab.x"> API; no .mdx was edited for the tab migration. Inactive panels stay in the DOM behind hidden rather than using webkit's Panel, which mounts behind v-if — dropping them would take half the prose of every tabbed page out of the served HTML, out of Ctrl+F and out of the crawl.

One patched dependency. patches/@aziontech__webkit@4.4.0.patch gates DocProse's copy-tip teleport behind a mounted flag. Astro never re-emits Vue's teleport payload into the served markup, so on hydration Vue walked into <body>, found the page's own first element where it expected its anchor, and discarded the server DOM — on every documentation page. Drop the patch and the patchedDependencies entry once the fix ships upstream.

Known defects, not fixed here

  • Nothing nested in the Footer island hydrates. The theme switcher, language select and system status paint but do not respond to a click. This predates the webkit adoption — SystemStatus has the same symptom and was not touched. It belongs to the Footer island, so the fix goes there rather than in any one control.
  • Dropdown and ThemeSwitcher teleport to <body> with the same defect the DocProse patch works around. The fix is that patch extended upstream to tooltip and dropdown.
  • The hero is still hand-built. webkit's HeroTitle always renders the highlighted span at the start of the headline; both homes author it at the end ("Welcome to Azion Docs"). Adopting it means losing the accent, inverting the sentence, or rewriting both headlines — an editorial call.
  • SectionTitle's full-header branch is unexercised. It compiles, but none of the 70 call sites passes a title today.
  • ArticleNavigationButton.astro is orphaned, importing components this branch deletes. Nothing imports it and astro build does not compile unreachable .astro, so build:local passes, but pnpm check would fail on it.

Verification

  • pnpm build:prod: 1494 pages, test-frontmatter passing.
  • Deployed to the preview environment: https://nqx0zzdhgos.map.azionedge.net/en/documentation/
  • Spot-checked in the browser on the en and pt-br homes, a product home, a CLI guide and both pricing pages: buttons render with the design system's own fill, radius and ink; the 7 product cards render through DocCardGroup; no hydration mismatch from DocProse.
  • Still in the console on pages with a breadcrumb: a hydration mismatch from webkit's Breadcrumb, unrelated to this branch.

isaque-bock-azion and others added 18 commits August 28, 2026 18:25
Replaces the deprecated @astrojs/tailwind integration (capped at Astro 5)
with Tailwind 4 via @tailwindcss/postcss, unblocking the Astro 7 upgrade.

- Vendor azion-webkit@1's entry CSS (src/styles/webkit-v1-main.css) since
  it contained Tailwind v3 directives; the file is removed once webkit v4
  lands.
- New Tailwind entry in src/styles/main.css: cascade-layer order keeps
  PrimeVue between base and utilities (same cascade as v3), `important`
  import flag preserves v3's important:true, @source compiles the raw
  .vue components azion-webkit@1 ships, and v3 preflight compatibility
  styles keep border/placeholder/cursor defaults.
- Slim tailwind.config.cjs: theme-only copy of what azion-webkit@1's
  config provided; its v3-only addUtilities plugins now live in CSS as
  @Utility px-shell/px-container. The unused `container.padding` config
  is dropped (crashes Tailwind 4's compat layer with custom screens).
- Rename removed v3 utilities: flex-shrink-0 -> shrink-0, rounded ->
  rounded-sm.
- Drop autoprefixer (built into Tailwind 4).
Astro 7.2.3, Vite 8, Vue 3.5, and the Content Layer API. Also patches the
9 published vulnerabilities in astro <7.0.4.

Content Layer (mandatory since Astro 6 removed legacy collections):
- Move src/content/config.ts to src/content.config.ts with a glob() loader
  and `astro/zod` imports.
- entry.slug -> entry.id and entry.render() -> render(entry) across pages,
  layouts, components, and utils. The [lang]/[...slug] route rebuilds the
  legacy id (path with extension) from entry.filePath for getGithubEditUrl,
  and docs-path-by-url.json now uses entry.filePath directly.

Markdown: keep the unified() processor from @astrojs/markdown-remark so the
custom remark/rehype plugins keep running; porting them to Sätteri is a
follow-up.

Integrations: @astrojs/mdx 7, @astrojs/vue 7, @astrojs/preact 6,
@astrojs/sitemap 1.0.1 -> 3.7.3, astro-expressive-code 0.44,
astro-auto-import 0.5, astro-og-canvas 0.13.

Vite 8 adjustments:
- Tailwind 4 moves from @tailwindcss/postcss to @tailwindcss/vite (Vite 8's
  postcss-import no longer resolves the bare `tailwindcss` import).
- A small config plugin bundles primevue/azion-webkit/azion-theme into the
  new prerender environment: Astro marks primevue as external there, and
  primevue 3's ESM files use directory imports Node cannot resolve.
- Drop the obsolete vite.ssrBuild flag.

TablePricing now caches pricing API responses per product_slug for the whole
build; the prerender pass fetching once per page caused transient DNS
failures.

Build verified: 1494 pages, frontmatter test passing, asides/heading
anchors/expressive-code/JSON+md+llms.txt endpoints/sitemaps all present in
the output.
…th Tailwind (#2316)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Ports the header, search trigger and palette from the webkit design
system sample (feat/doc-masthead-action-belt) to the docs site.

- Header: rebuilt on GlobalHeader (.Left/.Brand/.Nav/.Right) with
  @container so the search trigger can switch shapes via container
  query instead of viewport breakpoints
- HeaderSearch: two-root trigger (IconButton narrow / field-shaped
  wide) with @min-[47rem] container query, verbatim from the sample
- HeaderSearchDialog: CommandMenu shell (⌘K shortcut, Dialog/Overlay
  owned by webkit) feeding Algolia via direct client.search() across
  the four i18n indices; replaces vue-instantsearch + AlgoliaDialog
- HeaderRightSidebar: mobile nav migrated from manual Teleport to
  webkit Drawer (side="left", size="small"); closes on palette-open
  cross-island event
- DocsTopNav: NavigationMenu extracted into its own client:idle island
  so the hover-pill highlight (pointerenter + provide/inject) hydrates
  correctly; was dead inside the SSR-only Header.vue
- main.css: added text-overline-md / text-overline-sm Tailwind shims
  so Kbd keycaps (⌘K, ESC) render at the token's 12px, not 16px
- Removed: AlgoliaDialog, AlgoliaInstantSearch, AlgoliaIndexHit,
  KeyboardKey, DocsSearchTrigger, vue.config.js; dep vue-instantsearch
Deletes public/assets/docs/css/ (theme.css, index.css), and the
orphaned SCSS layers under src/styles/ (breakpoints, functions, icons,
tokens) — none of these were imported anywhere after the webkit/theme
migration; all design tokens now come from @aziontech/theme.
Replaces the hand-rolled footer flex layout with webkit's Footer
component, aligned with the design system's own sample (SiteFooter.vue).
Updates the i18n model: drops the legacy `cta` (phone numbers) and
`copyright` exports, adds `tagline` in their place, as the DS Footer
now renders the signature band with the brand mark and tagline from
the component itself.
- LeftSidebar: drops SidebarContent (Astro/SCSS/TSX trio) and the
  sidebarpanelmenu/ pair; now delegates to DocsSidebarMenu (webkit DS)
  via the menuToWebkit adapter
- ReadableContent: rewired to webkit's DocProse for article typography
  (heading ladder, prose body, callout, code chip); removes the local
  .prose/.article SCSS that duplicated those rules
- RightSidebar: swaps the local TableOfContents/TableOfContentsItem
  pair for webkit's OnThisPage component
- PageContent/MainLayout: layout adjustments for the webkit rail's
  sizing contract (auto column instead of fixed 20rem)
…egrations

- Aside: replaced hand-rolled admonition (inline SVGs + SCSS) with
  webkit's doc-callout; maps caution→warning, unwraps <p> to inline
  prose, preserves authored titles as lead-in text
- Code: switched from astro-expressive-code to local CodeBlock wrapper
  (webkit's syntax highlighting); removes expressive-code integration files
- LinkButton: wraps button roots in `data-doc-chrome` span (display:contents)
  so DocProse prose-link paint does not repaint buttons inside article content
- AzionLogo.vue: deleted (unused after Header.vue moved to GlobalHeader.Brand)
- plugins/rehype-autolink-config: adds data-doc-anchor on heading anchors
  so DocProse's link rules skip them
- .gitignore: add Azion CLI build artifacts (.edge/, .vulcan, .open-next)
- pnpm-workspace.yaml: pin @aziontech/theme and webkit to current versions
New components used by the sidebar/toc/code refactor:
- CodeBlock: webkit syntax highlighting shell (replaces expressive-code)
- DocPageHeader: page title + metadata band above article content
- DocsSidebar: webkit Sidebar rail wrapper for the left nav
- DocsSidebarMenu: webkit Menu tree rendering the navigation tree
- OnThisPage: webkit table-of-contents for the right sidebar
- menuToWebkit: adapter converting the docs navigation data model
  (getNavigationMenu) to webkit's Menu/tree props contract
- integrations/astro-code-blocks: Astro integration wiring CodeBlock
  into the remark/rehype pipeline
Adds the auto-generated azion.config.mjs (build preset: astro,
storage bucket for docs-preview-webkit) and the GitHub Actions workflow
for Azion deploy, alongside the azion/ config directory generated by
the CLI.
Replaces the LinkButton compatibility wrapper with @aziontech/webkit/button
imported directly. Props mapped: link→href, severity="secondary"→kind="secondary";
added size="medium" and class="not-prose no-underline" on every call site.
Removes the unused Container import.
DocProse styles every `a` in the article body as a prose link -- link ink,
underline, flat radius -- with `!important`, and steps aside only for
`[data-doc-chrome]`. A webkit Button rendered with `href` is such an `a`, so
every button in the docs body came out blue, underlined and square on top of
its own fill. `class="not-prose no-underline"` never had a chance: the
contract's selector is more specific and important.

The attribute cannot go on the Button itself -- it sets `inheritAttrs: false`
and forwards only `class`, so `data-doc-chrome` is dropped before it reaches
the DOM. DocButton puts it on a wrapping span instead, whose subtree the
contract also excludes, and adds `data-doc-block` for the standard block
spacing.

Same treatment for HeroHome's actions row: the hero CTAs live inside
ReadableContent too and were painted as prose links for the same reason.
…utton

The 650 pages that import the button rendered it as a prose link -- blue,
underlined, square corners over the button's own fill -- because DocProse
styles every `a` in the article body and only stops at `[data-doc-chrome]`.
DocButton carries that boundary; swapping the import is the whole fix.

Two leftovers from the LinkButton era go with it. `class="not-prose
no-underline"` was reaching for this same escape and never worked, and
`iconPos="left"` names a prop the webkit Button does not have -- it has one
icon slot, always leading -- so it was dropped on the floor either way.

Mechanical: the import line was identical in all 650 files, `<Button` has no
closing-tag form here, and occurrences inside code fences were left alone.
All 650 files re-checked through the MDX compiler.
… mounted

Every documentation page logged "Hydration completed but contains mismatches".
DocProse's copy tip lives in a `<Teleport to="body">`, and Astro does not
re-emit Vue's teleport payload into the served markup -- so on hydration Vue
walks into `<body>` looking for the teleport anchor and finds the page's own
first element instead. Vue then discards the server DOM for that subtree and
re-renders it on the client, on every page.

Gating the teleport on a mounted flag keeps the server render and the client's
first render identical -- the tip is a `v-if` comment inline in the root either
way -- and it costs nothing, since the tip only ever opens on pointerover.

Carried as a pnpm patch because the fix belongs upstream in @aziontech/webkit;
drop `patches/` and the `patchedDependencies` entry once a release ships it.
The authoring API is unchanged: 328 tab blocks across 178 content files keep
writing `<Tabs>` with `<Fragment slot="tab.x">` / `slot="panel.x">`, so not one
.mdx was touched. `Tabs.ts` re-exports the SFC because the content imports
`~/components/tabs/Tabs` without an extension and Vite's resolve.extensions
does not include .vue.

Panels stay in the DOM behind `hidden` instead of using TabView's Panel, which
mounts its slot behind `v-if`. Dropping inactive panels would take half the
prose of every tabbed page out of the served HTML -- out of Ctrl+F, out of the
crawl, and out of reach of the heading-anchor wiring ReadableContent installs
once on mount. The cost is TabView's sliding indicator and edge fades; this
component owns the active value, the ids and the arrow keys instead, and the
chips fall back to Item's standalone `selected` styling, which paints the same.

Two things the port had to fix rather than carry over. Astro hands slots to the
island in resolution order, not authoring order, so a panel holding an island
(`<Code>`) overtakes the panel written above it -- the tabs are now the source
of order and panels are paired by key, which also moves the default from "first
panel" to "first tab" (they diverge in 23 of the 328 blocks, some of them real
content typos). And the shared store subscribes only on mount: `tabStore` is a
module singleton, so subscribing during SSR would leak a listener per render
and let one request's choice bleed into the next.

PricingTableOfContents comes along as Vue over webkit's DocOnThisPage, keeping
the two pricing-specific behaviors: the `-1` anchor remap for the `real` tab,
and the scroll-spy that skips headings under `[hidden]`.
… originals

Overline, TitleSection and the four-part card family (CardBase,
CardBaseClickable, CardTitle, CardDescription) all had an equivalent already
shipping in @aziontech/webkit, so they are gone: 502 lines of local markup
replaced by Overline, SectionTitle, DocCard and DocCardGroup.

The card grid is the change worth reading. DocCardGroup is both the frame and
the rules -- cards abut inside it and the hairlines between them are the
group's own gaps -- so Cardlist no longer draws a grid, a gap or a border of
its own. Two deliberate omissions: no icon, because the content data carries
SVG paths while DocCard's `icon` expects a PrimeIcons class, and no CTA link,
because the data has no call-to-action copy and inventing i18n strings is not a
refactor. The old card's arrow goes with them; the whole card is still the
link.

Overline is a `w-fit` inline element rather than a block, so centering moved
from `text-center` to `self-center` on the parent. And in the branch where
SectionTitle takes over the whole header, `titleTag` stops having an effect --
the design system fixes h2 there. That branch compiles but no page exercises it
today: none of the 70 call sites passes a `title`.

The hero stays hand-built on purpose. webkit's HeroTitle always renders the
highlighted span at the *start* of the headline, and both homes author it at
the end ("Welcome to <span>Azion Docs</span>"). With no title slot, adopting it
would mean losing the accent, inverting the sentence, or rewriting both
headlines -- an editorial call, not a refactor.
ThemeSwitcher becomes an adapter over webkit's ThemeSwitcher (196 -> 112
lines): the dropdown, its trigger, the viewport measuring and the document
click/Escape listeners all go, and what stays is the part the design system
does not own -- reading and writing the preference. The stored value keeps its
exact old shape, the `prefers-color-scheme` key holding 'System' | 'Dark' |
'Light', because BaseLayout reads that same key in a blocking inline script and
every returning visitor already has one of those strings saved; the lowercase
mode names webkit speaks are paired to them here rather than migrating anyone's
storage. Visually this turns a dropdown into a segmented icon group.

SystemStatus takes its dot and label from StatusIndicator, so severity comes
from theme tokens instead of the inline hex the component used to paint with.
The pill around it stays a plain anchor: webkit's Button takes its content
through a `label` string and exposes no default slot, so wrapping the indicator
in one would render the text and drop the dot. Also removes STATUS_PAGE and its
`status` ref, which nothing read.

SelectLang moves to webkit's Dropdown -- not Select, which is still draft in
the catalog. `placement="auto"` replaces the hand-rolled "is there room below?"
measurement. The options stay real anchors so the translated route is still
crawlable and middle-clickable.

Two known defects are documented in BaseLayout rather than worked around.
Nothing nested in this Footer island hydrates today, SystemStatus included, and
that predates the webkit adoption -- the controls paint but do not respond to a
click. And webkit's Dropdown and ThemeSwitcher teleport an overlay to <body>,
which Astro never re-emits into the served markup; the fix is the doc-prose
patch in patches/ extended upstream to tooltip and dropdown. `client:only`
looks like the answer to both and is a trap: an island nested inside a Vue
island never mounts under it, so the controls vanish entirely instead of merely
being inert.

BaseLayout also carries an unrelated change that was already pending in the
working tree: the ScrollArea rules for the "On this page" rail.
This is not one change; it is everything that was sitting uncommitted in the
tree, swept in at the author's request so nothing is left dangling. Two
distinct bodies of work:

The webkit/Tailwind 4 adoption in progress: 68 legacy components removed
(BackendGuidesNav, Badge, Breadcrumb, Button, the NavGrid and tabs .astro
families, the Preact leftovers TableOfContents, SidebarToggleTabGroup,
ExternalLinkIcon and Spoiler, and the rest), Footer rebuilt on the design
system's own Footer, and the supporting changes across content.config.ts,
content.ts, the i18n helpers, src/util and the layouts.

The lint toolchain migration (MM-15912), authored in a parallel session:
flat config in eslint.config.mjs replacing .eslintrc.js and .eslintignore,
eslint 9 with typescript-eslint 8, stylelint 16 with postcss-html and
postcss-scss, and the call sites those rules touched.

Also included: azion.config.mjs and azion/azion.json from the preview deploy,
and .claude/launch.json.

Neither body of work is mine and neither was reviewed here. They are committed
as they stood, so the history has a point to return to before the deploy.
@isaque-bock-azion
isaque-bock-azion requested a review from a team September 1, 2026 21:52
@isaque-bock-azion isaque-bock-azion changed the title Rebuild the docs on Astro 7, Tailwind 4 and @aziontech/webkit 4 refactior: Rebuild the docs on Astro 7, Tailwind 4 and @aziontech/webkit 4 Sep 1, 2026
@isaque-bock-azion isaque-bock-azion changed the title refactior: Rebuild the docs on Astro 7, Tailwind 4 and @aziontech/webkit 4 refactor: Rebuild the docs on Astro 7, Tailwind 4 and @aziontech/webkit 4 Sep 1, 2026
@isaque-bock-azion
isaque-bock-azion marked this pull request as draft September 1, 2026 21:54
`.claude/` and `.codex/` are per-machine scratch, not project configuration:
the first held a local permission allowlist (whose three entries referenced
`azion-webkit`, a dependency this branch removes), a browser launch config, and
a stale git worktree; the second, a Codex environment file. None of it belongs
to anyone checking the repo out.

Both are now ignored, so a tool that recreates them does not put them back in
the history. The worktree was detached with `git worktree remove` rather than
deleted, so no metadata is left behind in .git.
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