chore(primevue): F3 — PrimeVue foundation with parallel-mode operation #24
Reference in New Issue
Block a user
Delete Branch "chore/f3-primevue-foundation"
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?
Implements F3 of RFC-WS-FRONTEND-PRIMEVUE (with three RFC amendments landing in this branch). 10 commits, ~2 days work.
Quality gates
What this delivers
Infrastructure
Components & composables
FormField.vue— wrapper around @primevue/forms with label + required asterisk + error Message + hintuseFormError.ts— provide/inject-based API 422 bridge withapplyApiErrors+clearApiErrorsIcon.vue— thin wrapper over @iconify/vue rendering<Icon name="tabler-X" />as real SVG<Toast />+<ConfirmDialog />mounted at App.vue top levelLayout shell (R-10 isolated commit
43915501)AppShell.vue— PrimeVue-only (~210 lines). Hard constraint honored: no Vuetify imports.Sample
login.vuemigrated to FormField + Zod + PrimeVue inputs as F3 sample. Validates FormField API end-to-end with 422 routing via useFormError.RFC drift corrections (commit
d5c9cf19)Three RFC v1.0 inaccuracies discovered during F3 implementation:
@primevue/themes@^4.5→@primeuix/themes@^2(PrimeVue 4's official install docs prescribe this path; @primevue/themes was deprecated by maintainers)<i class="i-tabler-X">→<Icon name="tabler-X" />wrapping @iconify/vue (UnoCSS not in stack; existing Crewli pattern retained)Known F3 functional regressions — all returning in F3.5 or F4
Per B7 commit body: NavSearchBar, ContextSwitcher, NavbarThemeSwitcher, NavbarShortcuts, NavBarNotifications, rich UserProfile menu, ImpersonationBanner, Portal event-mode topbar. F3.5 (immediately after this PR) addresses notifications/user-info/search visually; F4 sub-packages restore full functionality.
What this does NOT change
Post-merge action required
Re-upload
.claude-sync/to Project Knowledge (manifest SHA changed; RFC and PRIMEVUE_COMPONENTS.md amended in commitd5c9cf19).🤖 Generated with Claude Code
Two new artifacts that together provide the F4 form-migration target: apps/app/src/components/forms/FormField.vue — project-owned wrapper around @primevue/forms' built-in FormField. The default slot accepts the actual input (e.g. <InputText name="email" />); the wrapper renders label (with optional required asterisk), error Message, and hint chrome around it. Reads field state from the parent <Form> via the built-in FormField's scoped slot, so call-sites do not need to thread $form manually. apps/app/src/composables/useFormError.ts — the API 422 bridge. Parent component calls useFormError() once; the composable provides an apiErrors ref through Vue inject. Each FormField in the component reads its own field name from that map. applyApiErrors() reads the Crewli backend's { errors: { field: string[] } } shape and surfaces the first message per field; clearApiErrors() resets between submits. Error precedence per RFC Appendix A: explicit apiError prop > inject apiErrors map > Zod resolver error from $field. Signature note: RFC's useFormError(formRef) is implemented as useFormError() — the formRef parameter is unused in the provide/inject implementation, and Crewli convention avoids unused parameters. RFC will be aligned in B9 if it remains a meaningful spec gap during F4. Verification: - pnpm typecheck — clean. - pnpm test — 402 tests pass unchanged. - B8 will exercise the components end-to-end on the login page; F4d validates against the public-registration multi-step form. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Layout-shell rewrite per RFC AD-3, B7-option-B. R-10 isolation invariant honored — this single commit is revertible to roll back the layout change without losing B1–B6 progress. New component (PrimeVue-only, no Vuetify imports per F3 hard constraint): - apps/app/src/layouts/components/AppShell.vue (~210 lines) - Desktop sidebar (Tailwind grid, lg+ breakpoint) renders nav items as PrimeVue Buttons + Icons. Mobile (<lg) hides sidebar; PrimeVue Drawer slides in on hamburger toggle. - Top bar (Tailwind) has hamburger + title (mobile) and an Avatar + Menu (PrimeVue) for the user dropdown with "Mijn Profiel" and "Uitloggen" actions. - Nav items accept the existing { title, to: { name }, icon: { icon } } shape from src/navigation/vertical so call-sites stay terse. Five top-level layouts delegate to AppShell (filename preserved per AD-3 so vite-plugin-vue-meta-layouts continues to resolve routes unchanged): - default.vue — org + (super-admin) platform nav - OrganizerLayout — same nav as default; matches authenticated org UX - PortalLayout — portal-specific 2-item nav ("Mijn evenementen", "Mijn Profiel") - blank.vue — minimal chrome-less wrapper for login etc. - PublicLayout — minimal wrapper for public form-fill routes; uses <main> for semantic structure F3 functional regressions (intentional — F4 sub-packages reintroduce each item through PrimeVue): - NavSearchBar (Vuetify-heavy combobox/overlay) — absent from top bar - ContextSwitcher (Vuetify VBtn + VMenu) — absent - NavbarThemeSwitcher (Vuetify IconBtn) — absent; dark mode driven by PrimeVue's darkModeSelector: '.dark' continues to work via the existing @core skin classes until F6 cleanup - NavbarShortcuts (Vuetify-heavy) — absent - NavBarNotifications (Vuetify-heavy) — absent - UserProfile from @/layouts/components/ (Vuetify-heavy menu) — replaced with the minimal Avatar + Menu dropdown described above; rich profile panel returns in F4 - ImpersonationBanner — absent; super-admin impersonation UX is F4 work - PortalLayout event-mode vs platform-mode topbar (route.meta.navMode driven) — absent; F4 reintroduces via AppShell prop or slot - Suspense + AppLoadingIndicator wrapping pages — dropped; pages handle their own loading via PrimeVue ProgressSpinner VApp at App.vue level still wraps everything, so Vuetify components inside still-Vuetify pages continue to render correctly during the parallel-mode window. Test updates (no Vuetify in layout structure to assert against anymore): - OrganizerLayout.spec.ts — mocks AppShell instead of the deleted DefaultLayoutWithVerticalNav reference; provides Pinia. - PortalLayout.spec.ts — same mock pattern; new structural assertions go through AppShell stub; the new third test verifies PortalLayout forwards portal nav items + title to AppShell. - PublicLayout.vue — uses <main> for semantics; PublicLayout.spec.ts still passes unchanged. Auto-generated component/auto-import dts files refreshed for the new AppShell component (committed for stable dev workflow). Verification: - pnpm typecheck — clean. - pnpm test — 402 tests pass (test count unchanged after spec rewrites). - pnpm build — succeeds in 14.05s; AppShell chunk is ~57 KB raw. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>