Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
c538cb6
Add VE2 theme generator pipeline and bootstrap family audit fixes.
rhengles May 24, 2026
e39f888
[WIP] theme generator v1
rhengles Jun 1, 2026
006e786
feat: VE literal converter — component migration, theme contract expa…
rhengles Jun 10, 2026
50b1780
chore: ignore root-level debug artifacts
rhengles Jun 10, 2026
20e7ed6
feat: backport T8 emitter fixes for T9 theme fan-out
rhengles Jun 10, 2026
5291cc4
feat: VE literal converter — component migrations, bootstrap theme ex…
rhengles Jun 13, 2026
2ebfac0
feat: brite theme literal verification to zero + emitter/harness fixes
rhengles Jun 14, 2026
c54d3b2
feat: cerulean theme literal verification to zero (fixes fan out via …
rhengles Jun 14, 2026
a84141c
feat: quartz theme to zero (gradient body + flow-root); migrate remai…
rhengles Jun 14, 2026
63205a1
feat: sketchy theme literal verification to zero + Popper font-race h…
rhengles Jun 15, 2026
a845266
docs: capture font-load-race / Popper-reanchor lessons from sketchy t…
rhengles Jun 15, 2026
98a3625
feat: sandstone theme literal verification to zero (433/433)
rhengles Jun 15, 2026
09bb4d9
feat: materia theme literal verification to zero (433/433)
rhengles Jun 15, 2026
ae0a96c
feat: vapor theme literal verification to zero (433/433)
rhengles Jun 15, 2026
277b189
chore: bump bootstrap-fork submodule (multi-class modal open hook)
rhengles Jun 16, 2026
eebc939
feat: slate theme literal verification to zero (433/433)
rhengles Jun 16, 2026
ad00d1b
feat: morph theme literal verification to zero (433/433)
rhengles Jun 16, 2026
b74fee1
feat: lux theme literal verification to zero (433/433)
rhengles Jun 16, 2026
e0d0ab1
feat: solar theme literal verification to zero (433/433)
rhengles Jun 16, 2026
9d73855
feat: superhero theme literal verification to zero (433/433)
rhengles Jun 16, 2026
8e2b804
feat: lumen theme literal verification to zero (433/433)
rhengles Jun 17, 2026
66cdb27
feat: journal theme literal verification to zero (433/433)
rhengles Jun 17, 2026
3ac0a9a
feat: spacelab theme literal verification to zero (433/433)
rhengles Jun 17, 2026
70c7627
feat: darkly theme literal verification to zero (433/433)
rhengles Jun 17, 2026
0328643
feat: simplex theme literal verification to zero (433/433)
rhengles Jun 17, 2026
677eff2
feat: cyborg theme literal verification to zero (433/433)
rhengles Jun 18, 2026
c2eca10
@
rhengles Jun 18, 2026
5ef8eef
@
rhengles Jun 18, 2026
fe46ebd
feat: litera theme literal verification to zero (433/433)
rhengles Jun 18, 2026
4f45683
feat: zephyr theme literal verification to zero (433/433)
rhengles Jun 18, 2026
9cb85d1
feat: flatly theme literal verification to zero (433/433)
rhengles Jun 18, 2026
512fb05
feat: cosmo theme literal verification to zero (433/433)
rhengles Jun 19, 2026
c7aa452
feat: pulse theme literal verification to zero (433/433)
rhengles Jun 19, 2026
2f41970
feat: yeti theme literal verification to zero (433/433)
rhengles Jun 19, 2026
8148648
chore: add opened-dropdown/modal screenshot baselines for verified th…
rhengles Jun 19, 2026
2a8373b
refactor(T10): retire heuristic generators, keep granular runtime + s…
rhengles Jun 19, 2026
0f276e8
fix(scope-emitter): capture all standalone body{} blocks via AST walk
rhengles Jun 19, 2026
a57d490
feat(offcanvas): add /ui/offcanvas family, verified to zero across al…
rhengles Jun 21, 2026
f7b2638
feat(granular): G1 utilities/used family + G2 partition emitter
rhengles Jun 21, 2026
c17a1c7
feat(granular): G3 regenerate loader map + aggregators for all 27 themes
rhengles Jun 22, 2026
b9a68cc
docs(granular): mark G3 done in family-split plan
rhengles Jun 22, 2026
ba6ea2b
feat(granular): G4 closure check — family coverage clean across 433 s…
rhengles Jun 23, 2026
bdf8b31
fix(granular): G5 wip — granular verify support + offcanvas/state-cla…
rhengles Jun 23, 2026
eff93d8
fix(granular): G5 — bootstrap granular verifies to zero (all families)
rhengles Jun 24, 2026
8f2605a
chore(granular): require --skip-to-route; disable verify-ve-family
rhengles Jun 25, 2026
20f42e6
feat(capture): validate --skip-to-route against real routes (exact or…
rhengles Jun 25, 2026
ead534b
fix(granular): G5 — `:not()` negations no longer own the subject family
rhengles Jun 25, 2026
cfeefb3
fix(literal): G5 — keep trailing `a` at element specificity via :where()
rhengles Jun 27, 2026
54e2f40
fix(granular): G5 — bare [type=checkbox]/[type=radio] rules belong to…
rhengles Jun 27, 2026
bc5451d
fix(capture): brace-aware CSV split so --route globs survive parsing
rhengles Jun 28, 2026
924ba4f
docs(ve3): mark G5 + the granular split milestone complete
rhengles Jun 28, 2026
c66ed34
refactor(granular): drop route-driven preload; components are self-su…
rhengles Jul 1, 2026
6916c0a
perf(ve2): lazy-load all route components
rhengles Jul 1, 2026
95b508b
perf(ve2): defuse Vite entirelyImportRE regex bomb — full build 206mi…
claude Jul 2, 2026
f5d166c
Merge pull request #4 from arijs/claude/ve2-build-performance-kaarps
rhengles Jul 2, 2026
0f59517
perf(ve2): stub ALL non-selected theme modules in filtered builds — 6…
claude Jul 2, 2026
8cc4201
Merge branch 'claude/ve2-build-performance-kaarps' into ve-literal-co…
rhengles Jul 2, 2026
6050bf1
docs: plano de empacotamento/publicação de @arijs/bootswatch-ve
claude Jul 20, 2026
d4b540f
docs(packaging): fecha as decisões §9 (prefixo, fonte do preset, fork…
claude Jul 20, 2026
7653816
feat(pkg): Fase 1 — build-package.mjs (espinha do @arijs/bootswatch-ve)
claude Jul 20, 2026
94d92c6
feat(preset): Fase 3 (spine) — presetBootswatch UnoCSS + decisões do …
claude Jul 20, 2026
d760e5a
feat(preset): Fase 3 completa — utilities derivadas do Sass + autopre…
claude Jul 20, 2026
6fa3f88
docs(packaging): decisão §9.6 — vars 100% hasheadas + camada de vars …
claude Jul 20, 2026
d811890
docs(packaging): vars hasheadas pelo próprio VE (sem namespace --bsvev-)
claude Jul 20, 2026
9f8a55c
feat(preset): camada de vars públicas — utilities compõem com os tema…
claude Jul 20, 2026
f7c57ff
feat(solid+demo): Fase 4 — runtime /solid, extractor u(), demo integrada
claude Jul 20, 2026
c49f333
feat(pkg): build de TODAS as famílias do bootstrap (F1 completo p/ o …
claude Jul 20, 2026
b2f2b6f
feat(pkg): sweep de port — 0 literal --bs-* no artefato do bootstrap
claude Jul 20, 2026
04f0f16
feat(pkg): F1 completo — pacote publicável @arijs/bootswatch-ve@0.1.0
claude Jul 20, 2026
5f79360
fix(port): caret do split-dropdown desalinhado no loader granular
claude Jul 20, 2026
93f20bd
feat(pkg): F2 — build dos 27 temas (0 literal, contract compartilhado)
claude Jul 20, 2026
7cec432
feat(pkg): F5 — tooling de release do @arijs/bootswatch-ve
claude Jul 20, 2026
09f0b4a
docs(ci): workflows do F5 em docs/github-workflows (mover p/ .github/…
claude Jul 21, 2026
746d7b4
ci(pkg): publish via trusted publishing (OIDC) em vez de NPM_TOKEN
claude Jul 21, 2026
e7e709c
feat(verify): driver resumível por rota p/ verificação VE dos temas (…
rhengles Jul 21, 2026
0f80965
perf(ve2): lazy-load only the active theme scope.css in granular mode
rhengles Jul 21, 2026
233ab11
fix(ve2): move theme font <link>s inside <head> in index.html
rhengles Jul 21, 2026
df4920d
Merge branch 've-literal-converter' into claude/packaging-plan
rhengles Jul 21, 2026
a3f5e71
npm audit fix
rhengles Jul 21, 2026
a128bfb
ci: ativa workflows do pacote
rhengles Jul 21, 2026
546713e
fix(pkg): peerDep solid-js aceita prereleases do Solid 2.0
claude Jul 21, 2026
31eec13
fix(pkg): expõe no barrel /contract as classes genéricas de estado/co…
claude Jul 21, 2026
ed19c1d
fix(pkg): expõe no barrel /contract as public vars (--bs-*) de _publi…
claude Jul 21, 2026
f81dc06
refactor(build): usa prefixo de hash `b` em vez de `bsve_`
claude Jul 21, 2026
b7302b0
Merge remote-tracking branch 'refs/remotes/origin/claude/packaging-pl…
rhengles Jul 21, 2026
1c6cb3a
chore(release): script driver + guia de publicação
claude Jul 21, 2026
63b3c9e
Merge remote-tracking branch 'origin/claude/packaging-plan' into ve-l…
rhengles Jul 21, 2026
6d7118c
fix(deps): sincroniza package-lock.json (npm ci)
claude Jul 21, 2026
d45ee5b
style(biome): escopa o lint ao código autoral e formata
claude Jul 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
79 changes: 79 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# CI do pacote @arijs/bootswatch-ve — gates DETERMINÍSTICOS (independentes de
# ambiente). NÃO roda a verificação por screenshots: o pixel-diff absoluto
# depende das fontes do ambiente (font-AA), então a verificação de fidelidade
# roda na máquina do mantenedor / num runner com as fontes dos baselines.
# Ver docs/packaging-plan.md (nota metodológica do fix split-caret).

name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
package:
name: Build & gates do pacote
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
# Gate 1: compila os 27 temas só com o plugin VE; FALHA se sobrar qualquer
# literal --bs-* (build-package.mjs sai com código 1).
- name: Build do pacote (0 literal em 27 temas)
run: npm run pkg:build
# Gate 2: monta a raiz publicável (contract + themes + preset + solid).
- name: Assembla o pacote publicável
run: npm run pkg:pack
# Gate 3: fidelidade do preset UnoCSS vs bootstrap.css (46/46, determinístico).
- name: Probe do preset
run: npm run pkg:probe
- name: npm pack --dry-run (dimensiona o tarball)
run: cd package && npm pack --dry-run

generated-up-to-date:
name: Fontes geradas estão atualizadas
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
# Regenera as famílias dos 27 temas e falha se o resultado divergir do que
# está commitado (pega edição de fonte sem regenerar).
- name: Regenera famílias (todos os temas)
run: npm run pkg:generate
- name: Confirma que nada mudou
run: |
if ! git diff --quiet -- ve-project2/src/themes; then
echo "::error::Fontes geradas desatualizadas. Rode 'npm run pkg:generate' e commite."
git diff --stat -- ve-project2/src/themes
exit 1
fi
echo "OK — famílias geradas conferem com o commit."

lint:
name: Lint (informativo)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- name: Biome check
run: npx biome ci .
94 changes: 94 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Publish do @arijs/bootswatch-ve no npm — via TRUSTED PUBLISHING (OIDC).
#
# Não usa token de longa duração (NPM_TOKEN). O GitHub Actions se autentica no
# npm por OpenID Connect: o npm aceita o publish deste workflow com um token
# efêmero assinado, e gera provenance automaticamente. Funciona mesmo com 2FA
# ligado na conta. (Os tokens "bypass 2FA" estão sendo depreciados — ago/2026
# param de pular 2FA em ops sensíveis; ~jan/2027 perdem o publish direto.)
#
# PRÉ-REQUISITOS (uma vez, no npmjs.com):
# Settings do pacote → Trusted Publishers → Add → GitHub Actions:
# - Organization/user: arijs
# - Repository: bootswatch-solid
# - Workflow filename: publish.yml
# Obs.: o pacote precisa existir p/ configurar o trusted publisher. Na 1ª vez,
# faça UM publish manual (`npm publish` local, com OTP) p/ criar
# @arijs/bootswatch-ve; depois configure o trusted publisher e os próximos
# releases publicam sozinhos por aqui.
#
# Dispara ao publicar um Release (tag vX.Y.Z) ou manualmente.

name: Publish

on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: 'Versão a publicar (sem o "v", ex.: 0.1.0)'
required: true
type: string
dry_run:
description: 'npm publish --dry-run (não publica de verdade)'
required: false
default: false
type: boolean

jobs:
publish:
name: Build + npm publish (OIDC)
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # necessário p/ o OIDC do trusted publishing
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
registry-url: 'https://registry.npmjs.org'

# Trusted publishing exige npm >= 11.5.1 (o npm que vem com o Node 22 é
# mais antigo). Atualiza o CLI.
- name: Atualiza o npm (>= 11.5.1 p/ OIDC)
run: npm install -g npm@latest

- run: npm ci

# Deriva a versão: da tag do release (tira o "v") ou da entrada manual.
- name: Resolve a versão
id: ver
run: |
if [ "${{ github.event_name }}" = "release" ]; then
V="${{ github.event.release.tag_name }}"
V="${V#v}"
else
V="${{ github.event.inputs.version }}"
fi
echo "version=$V" >> "$GITHUB_OUTPUT"
echo "Versão resolvida: $V"

# Gate antes de publicar: 0 literal em todos os temas.
- name: Build do pacote (0 literal)
run: npm run pkg:build

- name: Assembla a raiz publicável
env:
BSVE_VERSION: ${{ steps.ver.outputs.version }}
run: npm run pkg:pack

- name: Confere a versão montada
run: node -e "const v=require('./package/package.json').version; if(v!=='${{ steps.ver.outputs.version }}'){console.error('versão divergente:',v);process.exit(1)} console.log('package/package.json →',v)"

# Sem NODE_AUTH_TOKEN: o OIDC (id-token: write) + trusted publisher
# configurado no npmjs.com autenticam o publish. Provenance é automática.
- name: npm publish (trusted publishing)
working-directory: package
run: |
if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then
npm publish --dry-run
else
npm publish
fi
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
node_modules
dist
/_ignore/
/debug*.log
/docs/ve-theme-generator-validation
/public/theme
/screenshots/**/*.verify.png
/screenshots/**/*.verify.diff.png
Expand All @@ -9,6 +12,7 @@ dist
/screenshots/**/markup.diff.json
/screenshots/**/markup.diff.md
/verify-*.txt
/verify-run/
/tmp-*.*
/ve-project/verify-*.txt
/debug-*.txt
Expand All @@ -17,3 +21,14 @@ dist
/scripts/debug-*.mjs
/scripts/tmp-*.mjs
*.elements.xml
/debug*.*

# pacote @arijs/bootswatch-ve (Fase 1)
dist-pkg/
package/
ve-project2/src/__pkg/

# demo (F4) — artefatos de build
examples/demo/dist/
examples/demo/demo.png
examples/**/node_modules/
20 changes: 17 additions & 3 deletions biome.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{
"files": {
"includes": [
"{src,ve-project,ve-project2}/**/*.{ts,tsx}",
"{src,ve-project2}/**/*.{ts,tsx}",
"scripts/**/*.{js,mjs}",
"biome.json"
"biome.json",
"!ve-project2/src/themes",
"!ve-project2/src/theme-contract/_public-vars.css.ts"
]
},
"formatter": {
Expand Down Expand Up @@ -38,5 +40,17 @@
"formatter": {
"trailingCommas": "none"
}
}
},
"overrides": [
{
"includes": ["scripts/**"],
"linter": {
"rules": {
"suspicious": {
"noTemplateCurlyInString": "off"
}
}
}
}
]
}
90 changes: 90 additions & 0 deletions docs/changelog/2026-07-20-granular-scope-lazy-load.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# 2026-07-20 — Granular mode: lazy per-theme scope loading

## Prompt original

> When I open this page from dev server:
> `http://localhost:5175/ui/offcanvas/default-offcanvas?style-loader=granular`
> I see many network requests that in theory should not be needed, like scope
> files for all themes beyond the current theme ("bootstrap" by default). They
> seem to be loaded by Ve2Shell.tsx, but the page should only execute
> Ve2GranularShell in theory from the url. Am I missing something?

Follow-up: proceed with **Option A** (runtime-only async scope resolution), then
document + commit + push.

## O que foi implementado

Em `--style-loader=granular` a página carregava os 27 `themes/*/scope.css` (um por
tema) mesmo usando um só. Havia **duas** fontes de import estático:

1. **`theme-runtime.ts`** (gerado) importava os 27 `scope.css` estaticamente para
montar o mapa `themeScopes`, consumido por `resolveVe2ThemeClass()` de forma
síncrona. Um lookup de uma chave arrastava os 27 módulos de efeito colateral.
2. **`Ve2ShellRuntime.tsx`** importava `Ve2Shell` estaticamente; como `Ve2Shell`
também importa os 27 `scope.css`, o módulo do fallback carregava tudo mesmo no
branch granular do `<Show>` (o `<Show>` controla renderização, não import).

Correções (Option A — só runtime, sem mexer no emitter/contract):

- **Gerador `generate-granular-loaders.mjs`**: substituído o mapa estático
`themeScopes` + `resolveVe2ThemeClass` por `ve2ThemeScopeLoaders`
(`() => import('../themes/<t>/scope.css').then(m => m.<t>Scope)`) + a função
`loadVe2ThemeScope()`. `theme-runtime.ts` regenerado.
- **`Ve2GranularShell.tsx`**: resolve a scope class de forma assíncrona via
`createEffect(themeKey, …)` (forma de 2 args do Solid 2.0) para um signal, com
guarda de resolução obsoleta, e só renderiza a subárvore atrás de `<Show>`
quando o único `scope.css` do tema ativo carrega. Espelha o padrão `themeReady`
já existente em `Ve2Shell`.
- **`Ve2ShellRuntime.tsx`**: `Ve2Shell` agora é `lazy()`, então os 27 imports de
scope só carregam quando o modo theme/literal é realmente usado.

Detalhe do Solid: a versão do projeto é **solid-js 2.0.0-beta.7**, onde `on` e
`createResource` não existem e escrever signal síncrono dentro de
`createRenderEffect` viola `SIGNAL_WRITE_IN_OWNED_SCOPE`. A forma de 2 args do
`createEffect(source, effectFn)` roda o callback fora do escopo "owned", que é o
que permite o write — como já fazia o `Ve2Shell`.

## Antes / depois

Requests de `scope.css` na rota `/ui/offcanvas/default-offcanvas`:

| Página | Antes | Depois |
|---|---:|---:|
| granular (bootstrap) | 27 | **1** (`bootstrap`) |
| granular (`&theme=darkly`) | 27 | **1** (`darkly`) |
| theme mode (inalterado) | 27 | 27 |

Theme/literal mode continua carregando 27 — é o caminho do monólito `Ve2Shell`,
fora do escopo desta correção.

## Como foi testado

Verificação funcional via Playwright contra um dev server limpo (porta alternativa,
pois o do usuário estava com deps otimizadas defasadas):

- Contou requests casando `/themes/<t>/scope.css` por rota.
- Asseverou que `.bd-example` renderiza (scope aplicado) e que não há `pageerror`.
- Resultado: granular default → 1 scope; granular `&theme=darkly` → 1 scope
(darkly, troca de tema funciona); theme mode → 27; todos renderizam, 0 erros.

`biome check` limpo nos arquivos alterados. `tsc` sem erros nos arquivos alterados
(os ~11k erros do `tsc` raiz são ruído pré-existente do monorepo: `node_modules`
do astro e `.css.ts` do vanilla-extract sob o tsconfig raiz frouxo).

## Testes criados/alterados

Nenhum teste automatizado permanente adicionado — a verificação foi um script
Playwright descartável (o projeto verifica o caminho granular pela suíte de
screenshots `capture-leaf-screenshots.mjs`, não por unit tests de runtime). O
invariante contínuo é a métrica de contagem de scope requests descrita acima.

## Arquivos

- `scripts/generate-ve-theme/generate-granular-loaders.mjs`
- `ve-project2/src/theme-runtime/theme-runtime.ts` (regenerado)
- `ve-project2/src/components/shell/Ve2GranularShell.tsx`
- `ve-project2/src/components/shell/Ve2ShellRuntime.tsx`

> Nota: `ve-project2/index.html` aparece como modificado no working tree, mas é uma
> mudança **pré-existente** a esta sessão (reordenação dos `<link>` de fontes para
> dentro do `<head>`), não incluída neste commit.
Loading
Loading