Epic: shadcn/ui redesign — 2/3 drop zone + 1/3 actions panel (desktop) #27
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
EduarD3V/AutoFirme#27
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Restyle the sign flow with shadcn/ui (Svelte port — shadcn-svelte). Reference screenshots provided by operator (shadcn default style, neutral palette).
Desktop layout (two-column divs, NO full-width stacking)
Firmarpinned at card bottom (h-12+, full width)Ownership boundaries (parallel work in flight)
src/lib/components/{FileDrop,FileCard,SignButton,ResultCard,CertPicker}.svelte,app.css, tailwind config, newsrc/lib/components/ui/(shadcn primitives)src/lib/{sign,pkcs12,keystore,certs}.tslogic files,src/lib/stores.tssignatures store (issue #29 owns it),src/lib/mcp/(issue #13 owns it), anytest/filesAcceptance
bullet: coder launched on branch
issue/27-epic-shadcn-ui-redesign-2-3-dr(modelnan/deepseek-v4-flash).Claimed — branch
issue/27-epic-shadcn-ui-redesign-2-3-dr. Doing: shadcn-svelte init + 2/3 dropzone / 1/3 sticky actions grid inweb/, visual-only, existing tests green.Plan — Issue #27: shadcn/ui redesign, 2/3 drop zone + 1/3 actions panel (desktop)
Restated goal
Restyle the sign flow of AutoFirma Web with shadcn-svelte so the desktop view is a real
two-column layout: a 2/3 column holding the drop zone (shadcn Card + dashed dropzone, drag&drop +
click-to-browse) and the selected-file list (shadcn Table rows: filename, size, format, status
badge, per-row remove), and a 1/3 sticky column holding the actions card (certificate/PKCS#12
upload + certificate selection, format options, and a big primary
Firmarbutton, full width,h-12+). Dark mode moves to the shadcn CSS-variable convention (
.darkclass +:rootvars),mobile (< 1024px) falls back to the current stacked flow. The refactor is visual-only: every
component keeps its existing props, and every existing test stays green.
"Done" = shadcn-svelte initialized in
web/(components.json +src/lib/components/ui/withbutton, card, table, badge, dropdown-menu, dialog, input, tooltip),
web/src/app.csscarries theshadcn CSS vars for light + dark,
App.svelterenderslg:grid-cols-3with the left columnspanning 2 and the right column sticky,
pnpm test+pnpm check+pnpm buildall green, andsrc/lib/components/ui/primitives.test.tssnapshots each primitive.Scope
Will change (matches the issue's ownership list):
web/src/app.css— shadcn CSS variables +@custom-variant dark, keeping the existingink-*/brand-*@themetokens alive (components and tests still reference them).web/src/app.html— tiny inline script settinghtml.darkfromprefers-color-scheme(shadcn convention: class-based dark mode).
web/package.json,web/pnpm-lock.yaml,web/components.json— shadcn-svelte init output.web/src/lib/utils.ts— shadcncn()helper.web/src/lib/components/ui/**— new shadcn primitives (button, card, table, badge, input,dropdown-menu, dialog, tooltip + their sub-parts).
web/src/lib/components/FileDrop.svelte— Card + dashed dropzone styling (same props).web/src/lib/components/FileCard.svelte— one shadcn Table row: filename, size, format,status badge, remove button (same props).
web/src/lib/components/CertPicker.svelte— restyle only;#pkcs12-file,#pkcs12-pinand thenative
<select id="cert-picker">stay, because App.test.ts assertsrole=combobox,select.valueand#cert-pickerby id.web/src/lib/components/BatchQueue.svelte— the actions card: big primaryFirmar(
h-12 w-full) pinned at the card bottom (same props).web/src/lib/App.svelte—lg:grid-cols-3(leftlg:col-span-2, rightlg:col-span-1lg:sticky lg:top-6), shadcn Card/Table/Badge/Button/DropdownMenu/Tooltip/Dialog in the shell.web/src/lib/components/ui/primitives.test.ts— new snapshot test per primitive usage.Will NOT touch (explicit):
web/src/lib/{sign,pkcs12,keystore,certs}.ts,web/src/lib/verify/**,web/src/lib/batch.ts,web/src/lib/i18n.ts(copy keys are already sufficient — no new copy needed).web/src/lib/stores.ts— does not exist in this tree; issue #29 owns it. No stored-signaturepicker is built here (its data source is missing).
web/src/lib/mcp/**— not present, untouched.web/test/**and every existing*.test.ts(App.test.ts,batch.test.ts,crypto tests). No test is edited, skipped or weakened.
decompiled/**,original/**,extracted/**,docs/**.Ordered tasks
shadcn-svelte initinweb/(neutral base,$libaliases, existingsrc/app.css)test -f web/components.json && grep -c bits-ui web/package.jsonls web/src/lib/components/uiink-*+brand-*@themetokens; add.darkbootstrap inapp.htmlgrep -n 'color-ink-900|\.dark' web/src/app.css web/src/app.htmlFileDrop.svelte→ Card + dashed dropzonecd web && pnpm vitest run src/lib/App.test.tsFileCard.svelte→ shadcn Table row + status badgecd web && pnpm vitest runCertPicker.svelterestyle (ids + native select intact)cd web && pnpm vitest run src/lib/App.test.tsBatchQueue.svelte→ actions card,Firmarh-12 w-fullpinnedcd web && pnpm vitest run src/lib/batch.test.tsApp.svelte→ 2/3+1/3 sticky gridcd web && pnpm vitest run && pnpm checkprimitives.test.tssnapshotscd web && pnpm vitest run src/lib/components/uipnpm check && pnpm test && pnpm buildgit log --oneline bullet-develop..HEADOpen questions → assumptions taken
SignButton.svelte/ResultCard.sveltedo not exist in this tree; theFirmarbutton andthe result list live in
BatchQueue.svelte, andsrc/lib/batch.test.tsmountsBatchQueuestandalone and clicks
Firmar+Descargar ZIPinside it. → Assumption: no split. The wholeBatchQueuebecomes the right-hand actions card with the primary button pinned at its bottom.Splitting it would have required editing an existing test, which is forbidden.
src/lib/stores.ts(#29) and the stored-signature picker are not available. → Assumption: nostored-signature control is rendered (a disabled placeholder would be a stub). The
select from stored signaturesslot is the existing<select id="cert-picker">inCertPicker.svelte, which#29 can extend. The
dropdown-menuprimitive is used for the real language switcher instead.dropdown-menu→ language switcher;dialog+tooltip→ the privacy note (short tooltip text, full text in the dialog);table→the selected-file list;
badge→ per-file status + the "pending #N" format chip..darkclass, but the app currently followsprefers-color-scheme. Assumption: keep both —@custom-variant dark+ a 3-line inline scriptin
app.htmlthat setshtml.darkfrom the media query, so behaviour is unchanged.shadcn-svelteCLI (network is up,git.eduard3v.comandregistry.npmjs.orgboth reachable). Fallback if it fights the repo:hand-copy the shadcn source into
src/lib/components/ui/and add onlybits-ui,clsx,tailwind-merge,tailwind-variants,tw-animate-css(the shadcn-svelte runtime set).Risk
app.csstheme tokens (ink-50,brand-500,font-sans) → those classes areused across components; re-add the
@themeblock after init and re-runpnpm test.bits-ui) → if install fails, pin the versions theregistry resolves for Svelte 5 and re-run; worst case hand-write the primitives (fallback above).
input[type="file"]first-match helper inApp.test.ts→ keep theleft column (with
FileDrop) before the right column in the DOM.role=comboboxelements would breakscreen.getByRole('combobox')→dropdown-menurenders
role=button, andCertPickerkeeps the single native<select>.aria-*,for/idpairs and native elements(
<select>,<input>,<fieldset>) for anything the tests or screen readers query.bullet: coder launched on branch
issue/27-epic-shadcn-ui-redesign-2-3-dr(modelnan/deepseek-v4-flash).bullet: coder session died — relaunched from committed state (branch
issue/27-epic-shadcn-ui-redesign-2-3-dr).Claimed (relaunch after a dead session) — branch
issue/27-epic-shadcn-ui-redesign-2-3-dr. The prior session's work is committed (6c37356,b3072ec,d8ced39,5332ea3). Doing: close the remaining acceptance gap (ui/inputhas no test), re-verify the gates and a real-browser layout proof, then report.DONE —
issue/27-epic-shadcn-ui-redesign-2-3-dr, 5 commits, tree clean, not pushed.Commits:
6c37356shadcn-svelte init + dark-mode CSS vars ·b3072ec2/3 drop zone + 1/3 sticky actions panel ·d8ced39primitive snapshot tests (operator-labelled WIP, content is a real deliverable) ·5332ea3README layer docs ·c0312f4certificate-picker input coverage (this session).Gates (all exit 0):
test -d decompiled→ PASSfind decompiled -name '*.java' | grep -q .→ PASSgit diff --check→ clean;git status --short→ cleancd web && pnpm test→ 11 files, 100 tests passedcd web && pnpm check→ 1059 files, 0 errors, 0 warningscd web && pnpm build→Wrote site to "build"(adapter-static)Browser proof (Chromium vs
pnpm previewof the build): 1280×900 →#panel-signgrid354.656px ×3, children 733 px / 355 px (ratio 2.06), asideposition: sticky,Firmar48 px high × full column width; 390×844 → single 350 px column, aside stacked andstatic;colorScheme: dark→html.dark, bodyoklch(0.145 0 0); verify-tab regression + ES/EN toggle clean,tab.errors()empty.Not done, needs a human call (report §"What a human must decide"): stored-signature combobox (needs #29's
src/lib/stores.ts, absent), visible/invisible PAdES options (needs #11's engine — PAdES radio still sayspendiente #11), and the actions column only mounts when ≥1 document is selected (pre-existing #5 design).Flake, unrelated to this branch:
pades.test.tsECDSA P-256 failed once in a full-suite run, passes standalone and on re-run; no commit here touchespades.ts.bullet: coder session died — relaunched from committed state (branch
issue/27-epic-shadcn-ui-redesign-2-3-dr).bullet: implementation finished (DONE: —
issue/27-epic-shadcn-ui-redesign-2-3-dr, 5 commits, tree clean, not pushed.) — moving to review.bullet: reviewer launched (model
9router/reviewer, independent of coder).Claimed — branch
issue/27-epic-shadcn-ui-redesign-2-3-dr. Doing: verify the shadcn redesign already committed on the branch (2/3 drop + 1/3 sticky actions), close the remaining primitive-snapshot gap, run tests/build + browser smoke.Plan — issue #27 (shadcn/ui redesign: 2/3 drop zone + 1/3 actions panel)
Claimed — branch
issue/27-epic-shadcn-ui-redesign-2-3-dr.State on arrival (read this first)
The branch already carries five commits of this work (
6c37356,b3072ec,d8ced39"wip: paused by operator",
5332ea3,c0312f4), so the flow is largely built and the tree isclean. My job is therefore verify → close the remaining acceptance gaps → gates → report,
not a rewrite. Current evidence:
web/src/lib/components/ui/{button,card,table,badge,dropdown-menu,dialog,input,tooltip}exist,ported shadcn-svelte style with
data-slotattributes;web/components.json+web/src/lib/utils.ts(cn()) in place.web/src/app.csscarries the shadcn token pair in oklch (:root/.dark) with@custom-variant dark (&:is(.dark *));web/src/app.htmlhas the inlineprefers-color-scheme→.darkbootstrap.web/src/lib/App.svelterenders#panel-signasgrid lg:grid-cols-3, leftCardatlg:col-span-2(drop zone + fileTableviaFileCard), right<aside>atlg:col-span-1with
lg:sticky lg:top-6(CertPicker, format fieldset, BatchQueue). Belowlgboth stack.web/src/lib/components/BatchQueue.svelteends with the primaryFirmarbutton(
h-12 w-full), disabled while no signer/hint, with a tooltip carrying the blocking reason.web/src/lib/components/ui/primitives.test.tssnapshots the primitives through their realconsumers (table row, desktop grid, help dropdown + privacy dialog, tooltip, cert-picker input).
pnpm test→ 11 files / 100 tests pass;pnpm build→ static build OK.Restated goal
Restyle the signing flow with shadcn-svelte primitives and the neutral default palette, laid out on
desktop (≥1024px) as a 2/3 documents column (dashed drop zone + file table with status badges and
per-row remove) next to a 1/3 sticky actions column (certificate loading, format choice, the queue
and the big
Firmarbutton pinned at the card bottom). Dark mode via shadcn CSS vars. Mobilestacks. Visual-only: no prop interface of an existing component changes, no crypto/store logic is
touched. Done = that layout observable in a browser at ≥1024px and stacked below it, primitives
initialized, dark vars live, existing + new tests green,
pnpm buildgreen.Scope
Change (this session):
web/src/lib/components/ui/primitives.test.ts— one missing primitive-usage snapshot (the dropzone's
Card, i.e. the card primitive through its real consumerFileDrop).web/src/lib/components/**orweb/src/app.css.Already-changed files I keep as-is (owned by this issue, reviewed by the fleet):
web/src/lib/App.svelte,web/src/lib/components/{FileDrop,FileCard,CertPicker,BatchQueue}.svelte,web/src/lib/components/ui/**,web/src/lib/utils.ts,web/src/app.{css,html},web/components.json,web/package.json+web/pnpm-lock.yaml,web/README.md.Do not touch:
web/src/lib/{sign,pkcs12,keystore,certs,x509,cms,xades,pades,batch,verify,der,asn1,c14n,zip,ooxml}.ts,web/src/lib/stores.ts(does not exist yet — issue #29 owns it),web/src/lib/mcp/(issue #13),web/test/**,web/src/lib/App.test.ts, and any pre-existing test outside the primitive suite.Never
main/main, never push, never close the issue.Ordered tasks
curlper comment-policy).Verify: HTTP 201 in the
curlresponse.cd web && pnpm test && pnpm build.Verify: 100+ tests pass,
built in+Wrote site to "build".pnpm dev, open at 1280×800, assert#panel-signcomputes tothree columns with the left card spanning 2 and the actions
<aside>sticky; screenshot lightand dark (system preference emulation).
Verify: two columns side by side (2/3 + 1/3),
Firmarfull widthh-12at the aside bottom.Cardusage snapshot (drop zone) toprimitives.test.ts.Verify:
pnpm test src/lib/components/ui/primitives.test.ts→ green.pnpm test,pnpm build,pnpm check,git diff --check, plus thebullet.yamlgates (test -d decompiled,find decompiled -name '*.java' | grep -q .).Verify: all exit 0.
web: snapshot the drop-zone card primitive (Refs #27); write.bullet/meta/issue-27.report.md; post the Done comment.Open questions (assumptions I proceed on)
in the actions card. Neither has any backing state in the app (no co-sign flow, PDF visible
signature options belong to #11) and the acceptance list does not require them, so I am not
inventing placeholder UI — no fake/no-op controls. Recorded in the report as a human decision.
(
web/src/lib/stores.tsabsent). Out of scope; the certificate list inCertPickerstays anative
<select>.SignButton.svelte/ResultCard.sveltefrom the ownership list do not exist; the button livesin
BatchQueue.svelteand results inBatchQueue/VerifyReport. Treated as illustrative names.Risk
primitives.test.tsuses an inline snapshot; adding one more is local anddeterministic (jsdom, no clock/random in
FileDrop). Fallback: assertdata-slot="card"+dashed classes instead of a full snapshot.
pnpm previewon the builtoutput, and if no browser control is available, the jsdom layout assertions stand with a stated
visual-proof limit.
REVIEW: FIXED 2 — findings: card primitive had no snapshot assertion → fixed
0cd1c71; dashed drop-zone card had no test → fixed6a12ae2; UNFIXED: noneDONE — Refs #27 (branch
issue/27-epic-shadcn-ui-redesign-2-3-dr, tree clean).Commits:
6c37356(shadcn primitives + cn + dark vars) ·b3072ec(2/3 + 1/3 sticky layout) ·d8ced39(wip paused by operator) ·5332ea3(README) ·c0312f4(input snapshot) ·0cd1c71+6a12ae2(card/FileDrop snapshot — a second fleet process committed these into theworktree mid-session; content verified, nothing mangled).
Gates:
test -d decompiled→ 0find decompiled -name '*.java' | grep -q .→ 0 (11487 files)cd web && pnpm test→ 0 — 11 files / 101 tests passedcd web && pnpm check→ 0 — 0 errors, 0 warningscd web && pnpm build→ 0 — static build writtengit diff --check→ cleanLive Chromium evidence (1280x900, one PDF in the drop zone):
#panel-sign= grid withgrid-template-columns: 354.656px x3; left Card 733px (2/3), right<aside>355px sticky at thesame top;
Firmar=h-1248x323px full-width at the card bottom; at 820px the grid collapses toone column (780px) and the aside goes static. Dark mode:
prefers-color-scheme: darkflips<html>to.darkwith no reload, body bgoklch(0.145 0 0), cardoklch(0.205 0 0).Screenshots:
/tmp/br-27-desktop-light.png,/tmp/br-27-desktop-dark.png.Not implemented (human decision, not a fake control): "upload existing signature file" and
"visible/invisible PDF sig" options in the actions card have no backing state in the app (PAdES
options are #11) and are absent from the acceptance list; the stored-signatures combobox waits on
#29's store.
CertPickerkeeps the native<select>for container certificates. Full detail inissue-27.report.md.References
bullet: fixer launched (round 1/2).
FIXED: applied 0 — no unfixed finding at HEAD
6a12ae2(identical to the reviewed head, verdict not stale); the two review findings already carry fix commits + regression tests and were re-proved here, so re-applying them would require rewriting the reviewer's commits (forbidden) or duplicating assertions. Proof — finding 70cd1c71+ finding 86a12ae2(primitives.test.ts:79data-slot === 'card';:52-65dashed drop-zone card): mutating the Card primitive'sdata-slotmakes BOTH tests fail (expected 'cardMUTANT' to be 'card';cardnull at theborder-dashedassert) → assertions are discriminating. Tree restored, clean. UNFIXED: none — caveat only: intermediate commit0cd1c71is red standalone (FileDrop rendered without its import; repaired in6a12ae2), unfixable without amend/rebase per hard-law §4; HEAD is green so only bisect granularity is affected. Checkers at HEAD:pnpm test101/101 ·pnpm check1059 files 0 errors 0 warnings ·pnpm buildOK · gatestest -d decompiled+find decompiled -name '*.java' | grep -q .exit 0 ·git diff --checkclean ·git status --shortempty. No new commits, not pushed. Report:.bullet/meta/issue-27.report.md.bullet: reviewer launched (model
9router/reviewer, independent of coder).REVIEW: CLEAN — commit
6a12ae2: findings nonebullet: review CLEAN — ready to publish.
bullet: branch
issue/27-epic-shadcn-ui-redesign-2-3-drnot on origin — cannot integrate.bullet: PR #34 open →
bullet-develop(auto-merge follows).bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into
bullet-develop; PR auto-merges next tick.bullet: merge conflicts with
bullet-develop— conflict-solver agent owns the worktree until it pushes.bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into
bullet-develop; PR auto-merges next tick.Claimed (conflict-solver) — replaying
issue/27-epic-shadcn-ui-redesign-2-3-drontobullet-develop. Doing: resolve the web/→root layout rename + content conflicts, run gates, merge, publish to bullet-develop.Claimed — branch
bullet-develop. Doing: mergeorigin/mainintobullet-developfor the rolling PR; verification only —origin/mainis already an ancestor ofbullet-develop, and the live conflict-solver session (i-27) owns this worktree mid-merge, so nothing is written.RECONCILED: no trunk work to merge —
origin/mainf7dbab8is already an ancestor ofbullet-developa5c609a(git rev-list --count origin/main ^origin/bullet-develop= 0;git merge-tree HEAD origin/main= HEAD tree7161703a;git merge origin/main= "Already up to date."), so no commit/ref write/push; rolling PR #30 ismergeable: true; the 405 was PR #34 (issue/27 branch) conflicting withbullet-develop, owned by live conflict-solveri-27; gates green (test -d decompiled0,find decompiled -name "*.java" | grep -q .0,git diff --check origin/main origin/bullet-develop0).bullet: merge conflicts with
bullet-develop— conflict-solver agent owns the worktree until it pushes.bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into
bullet-develop; PR auto-merges next tick.RECONCILED: no trunk work to merge — origin/main
f7dbab8is already an ancestor of origin/bullet-developa5c609a(rev-list count 0, merge-tree = HEAD tree7161703a); rolling PR #30 is mergeable=true; the HTTP 405 is PR #34 (issue/27 → bullet-develop, mergeable=false), whose conflict is owned by live conflict-solver session bullet-EduarD3V/AutoFirme-i-27 mid-merge of6a12ae2in this worktree, so no reset/commit/push; gates green (test -d decompiled 0, find decompiled -name *.java | grep -q . 0, git diff --check origin/main origin/bullet-develop 0).bullet: merge conflicts with
bullet-develop— conflict-solver agent owns the worktree until it pushes.bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into
bullet-develop; PR auto-merges next tick.Claimed — branch
issue/27-epic-shadcn-ui-redesign-2-3-dr. Doing: replay onto bullet-develop, resolve shadcn/web conflicts, run gates, push.bullet: merge conflicts with
bullet-develop— conflict-solver agent owns the worktree until it pushes.bullet: merge blocked (HTTP 405) — conciliation agent merges trunk work into
bullet-develop; PR auto-merges next tick.bullet: merged into
bullet-develop— integration gates green.bullet: PR #34 closed — work already merged into
bullet-develop.