Skip to content

feat(webkit): add frame-box, section-gap, section-title and hero-title - #880

Open
gabriel-lisboa-azion wants to merge 13 commits into
mainfrom
feat/site-layout-set
Open

feat(webkit): add frame-box, section-gap, section-title and hero-title#880
gabriel-lisboa-azion wants to merge 13 commits into
mainfrom
feat/site-layout-set

Conversation

@gabriel-lisboa-azion

@gabriel-lisboa-azion gabriel-lisboa-azion commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Promotes the framed layout set out of the sample app into the design system: frame-box, section-gap, section-title and hero-title, each with its spec, a browser-mode test suite, a story and a flat export.
  • frame-box addresses every side and every corner individually: borders and marks each take a keyword, a single name or an explicit list, and flush names the sides a neighbour already draws and subtracts them — so a shared edge is one rule at one colour, on either axis (flush for a stack, flush="left" for a row).
  • section-gap owns the hatch texture; it is the one band with no copy of its own, so the texture gives a break its identity without sitting behind a headline.

How to test

  1. pnpm storybook:devComponents/Layout/FrameBox → Flush: a vertical stack and a horizontal row. Each shared edge is a single hairline with one mark per corner — not two rules, and not one line at doubled opacity.
  2. FrameBox → Borders and → Marks: each keyword, a single side/corner, and an explicit list. On Default, every control in the panel changes the canvas.
  3. Components/Layout/SectionGap → Sizes: the three steps read 1 : 2 : 3 and grow with the window (32/64/96px at 390px wide, 96/192/288px at 1440px). The Controls tab is absent on this and every other composite — they hard-code their props.
  4. SectionGap → Hatch and Templates/PageExample: the texture appears only in the gaps; the hero and both section headers are clean. Every junction on the page is a single hairline.
  5. pnpm webkit:test → the four co-located suites pass in Chromium, including axe on each component.

Notes

  • No breaking change. Four new flat exports (./frame-box, ./section-gap, ./section-title, ./hero-title), each with a size-limit budget.
  • Depends on feat(theme): make the neutral border tokens opaque surface steps #889. The frame draws its rules, marks and hatch in --border-default / --border-muted. Those tokens are semi-transparent on main, so a rule paints a different colour on every backdrop and the hatch reads faint; feat(theme): make the neutral border tokens opaque surface steps #889 makes them opaque steps of the surface palette. This PR needs no change when that lands — merge feat(theme): make the neutral border tokens opaque surface steps #889 first, then rebase here and regenerate baselines.
  • The sample-app migration that consumes these components stays on demo/vue-sample: apps/webkit-sample does not exist on main, so it cannot ride in this PR.
  • The design's Spacer has a fourth step (160px) that no prop maps to, because the canonical size vocabulary is small | medium | large. Recorded in .specs/section-gap.md § Theme gaps — exposing it would mean amending the size scale in .claude/rules/prop-vocabulary.md + .claude/hooks/_lib/prop-vocabulary.mjs, which belongs in its own PR.

The framed layout set the marketing pages are built from, promoted out of the
sample app into the design system.

frame-box is the registration frame: a hairline box with a corner mark inside
each corner, an optional hatch texture, a borders prop (all|x|y|none) so a
neighbour or a divider grid can own an edge, and flush to collapse a junction
between two frames to a single hairline.

section-gap is that frame used empty, as the air between two sections. Its size
steps are one, two or three times --spacing-xxl, so the page rhythm comes from
the theme's own scale and inherits its responsiveness.

section-title and hero-title are the section and page headers: kind picks the
section layout (centered, left, or a two-column horizontal row) and the hero
paints an optional accent phrase into its h1.
One story file per component (Default plus the composite axis story and the
boolean states), and a Templates/PageExample story that composes the whole set
as a marketing page — hero band, a large gap, a horizontal section header, a
divider grid of borderless frames, a medium gap, and a centered closing header.
84 new snapshots: the 14 gated stories of frame-box, section-gap, section-title
and hero-title across the six theme x viewport modes. No existing baseline
changes — the set only adds components. The PageExample story gets none because
src/stories/templates/ is in the runner's testPathIgnorePatterns.
@isaque-bock-azion

Copy link
Copy Markdown
Contributor
image Acredito que a gente não consiga trabalhar com opacidade. Quando tivermos overlap vai ficar assim

@isaque-bock-azion

Copy link
Copy Markdown
Contributor
image image Tanto o hatch quanto o flush nao parecem terem efeitos.

@isaque-bock-azion

Copy link
Copy Markdown
Contributor
image Hatch nao parece ter efeito no SectionTitle

@isaque-bock-azion

Copy link
Copy Markdown
Contributor

Control Panel do sectiongap nao altera o componente
image

@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator Author

@isaque-bock-azion otimos pontos, ta faltando um pouco de contraste. E tambem o flush das bordas era para funcionar... não sei pq rolou isso. Mas vejo com calma e atualizo.

Review found a stacked junction reading as two rules. `flush` was a `-mt-px`
that pulled the frame up so its own top rule landed ON the neighbour's bottom
rule; because the border tokens are semi-transparent, the two composited into a
line measurably brighter than every other hairline instead of merging. It now
names the sides a neighbour already draws and SUBTRACTS them from this frame's
own set, so a shared edge is one rule at one colour and nothing overlaps. That
also makes it work on both axes: `flush` (shorthand for `top`) for a vertical
stack, `flush="left"` for a horizontal row, a list for a grid cell.

Sides and corners are now addressable individually. `borders` and `marks` each
take a keyword, a single name, or an explicit list, so a frame can draw one
rule or one corner tick. Pairing `flush` with the opposite `marks` keyword is
what stops a shared edge carrying two ticks per corner a few pixels apart.

The hatch is the section gap's design asset, so `section-gap` gains `hatch` and
`section-title` loses it. Its texture was `--border-muted` behind an
`opacity-40` wrapper, compounding to roughly 2% — measured rgb(4) on the dark
canvas against rgb(26) for the frame's own rules, which is why it read as
absent. It now draws at the token's full strength and the radial mask alone
does the fading.
… the hatch

Review found the SectionGap `size` control changing nothing. The composite
stories hard-code their props, and `controls: { disable: true }` was nested
under `parameters.docs` — which only governs the Docs page, so the story-view
Controls panel stayed populated and live while the canvas ignored it. Hoisted
to the story-level `parameters`, where it actually hides the tab.

The hatch belongs to the gap, the one band with no copy of its own, so it moves
off both section headers and the hero band onto the two `SectionGap` frames.
Adds a Marks composite and a Hatch story for the gap, and the Flush story now
shows a vertical stack and a horizontal row so the shared edge reads on both
axes.
…rks work

Marks are now per corner, so every stacked frame drops its top pair; the hatch
draws at the token's full strength; and FrameBox Marks and SectionGap Hatch are
new stories. Also prunes the six SectionTitle Hatch snapshots — that story is
gone, and the CI update pass leaves obsolete files behind rather than deleting
them.
@gabriel-lisboa-azion

gabriel-lisboa-azion commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author

@isaque-bock-azion updated — obrigado pelos apontamentos, os três eram reais. Split em dois PRs porque a causa raiz é de token, não de componente.

#889 (theme) — a causa raiz do overlap que você apontou. --border-default / --border-muted eram alpha, então a mesma régua pintava uma cor diferente em cada fundo (rgb(26) no --bg-canvas, 35 no --bg-surface, 44 no raised, 95 no overlay) e duas se encontrando compunham um quinto valor mais claro. Agora são degraus opacos da paleta de surface. Você tinha razão: com opacidade não dá para trabalhar.

#880 (componentes)

  1. Bordas dobradas no flush — medido: a junção estava em rgb(49,49,49) contra rgb(26,26,26) de qualquer outra régua. O flush era um -mt-px que empilhava as duas bordas. Agora ele subtrai os lados que o vizinho já desenha, então não existe sobreposição — e por isso funciona nos dois eixos (flush para pilha, flush="left" para linha).
  2. Hatch sem contraste — era --border-muted atrás de um opacity-40, compondo ~2%: rgb(4) no fundo escuro. Agora desenha na com border strong. Ele também saiu do SectionTitle e do hero: passou a ser asset do SectionGap, que é a única faixa sem conteúdo próprio.
  3. Controls do SectionGap — você estava na story Sizes, que fixa os três valores. O controls: { disable: true } estava aninhado em parameters.docs, que só afeta a página de Docs; o painel continuava vivo. Subiu para o nível da story.

Também deixei cada lado e cada canto endereçáveis individualmente (borders / marks aceitam keyword, um nome só, ou uma lista) — dá para pedir só marks="top-right".

Ordem: #889 primeiro, depois rebase do #880 e regenero as baselines. Sem ele o hatch fica com low contrast dos tokens alpha.

isaque-bock-azion and others added 4 commits August 12, 2026 11:35
…dgets

The three budgets were written earlier in this PR, against a frame-box
whose borders/marks were single keywords. The component since gained
per-side and per-corner addressing (and flush as a side subtraction),
which is what section-gap and section-title inherit by composing it.
Measured gzip: frame-box 1.93, section-gap 2.53, section-title 3.59 KB.
Collapsing the four corner spans into a v-for was measured and is
larger (1.96 KB), so there is no shrink to take here.
@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator Author

Bundle budget raise — justification per .claude/rules/bundle-budget.md.

The size gate started running on this PR once the build paths were flagged, and three entries were over:

entry measured (gzip) old budget new budget
frame-box 1.93 KB 1.5 KB 2.5 KB
section-gap 2.53 KB 2 KB 3 KB
section-title 3.59 KB 3 KB 4 KB

These are not raises of a released ceiling: all three budgets were introduced earlier in this same PR (6a53c21), sized against a frame-box whose borders/marks were single keywords. The component has since gained per-side and per-corner addressing, and flush as a side subtraction — section-gap and section-title inherit that cost by composing it.

No shrink was available: the three import only vue and each other (no cn), and collapsing the four corner <span>s into a v-for + data-corner variants measures larger (1.96 KB), because the extra variant classes outweigh the markup saved. The new numbers keep ~25-30% headroom, in line with the other small entries (button 1.84/2.5, hero-title 1.70/2.5).

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.

3 participants