Portfolio/docs/superpowers/specs/2026-06-14-nychthemeron-library-refactor-design.md
Matthew L McPeak ccf5ebd6c9
Some checks failed
ci / build (push) Failing after 10s
ci / publish (push) Has been skipped
Inital Commit
2026-06-19 06:36:35 -04:00

6 KiB

Refactor portfolio to use @nychthemeron/library

Context

The portfolio currently ships a hand-rolled "Nychthemeron" design system: local components in src/components/ds/ (NychButton, NychCard, NychInputText, NychTextarea, NychMessage, NychTag, LaurelSpinner, LaurelDivider, ImageSlot) backed by ~1200 lines of token CSS in src/assets/styles/.

@nychthemeron/library (now installed from the private registry at git.mcpeakdev.com) is the extracted, PrimeVue-backed version of this same design system: unstyled PrimeVue components (Button, Card, InputText, Textarea, Message, Tag, LoadingIcon, plus others not yet used here) wired up with the same nych-* passthrough classes, and ships the same theme as CSS via @nychthemeron/library/style and @nychthemeron/library/theme.

Goal: replace the local duplicated implementation with the library, keeping only what the library doesn't provide (LaurelDivider, ImageSlot, and the 580px static hero spinner).

Styling / setup

  • src/main.ts:
    • Add import '@nychthemeron/library/style' and import '@nychthemeron/library/theme'.
    • Register PrimeVue: app.use(PrimeVue) (the library's components are PrimeVue components under the hood).
    • Keep the existing import './assets/styles/styles.css', but trim its @import manifest (see below) so it only covers portfolio-specific CSS; the library CSS imports are added separately in main.ts.
  • Delete src/assets/styles/tokens/fonts.css, tokens/colors.css, tokens/base.css — fully superseded by @nychthemeron/library/style (same theme CSS variables for both hades/apollo themes, font imports, base reset, focus-ring, and the nych-spin keyframes).
  • src/assets/styles/tokens/components.css: delete every section except LaurelDivider (currently the last section, ~line 738 onward). Rename the file to tokens/laurel-divider.css containing just that section. Everything else (Button, Input/Textarea, Checkbox/Radio, ToggleSwitch, Select, Card, Message, Tag, Dialog) is covered by @nychthemeron/library/theme.
  • Keep as-is: tokens/spacing.css, tokens/typography.css, portfolio.css, brand SVGs in src/assets/brand/.
  • Update src/assets/styles/styles.css's @import manifest to drop the removed files and add tokens/laurel-divider.css in place of tokens/components.css.

Component mapping

Local component Replacement Notes
NychTag Tag from @nychthemeron/library severity / rounded props pass straight through
NychMessage Message severity / closable pass straight through
NychInputText InputText v-model, placeholder, type, invalid pass through; drop the local size="normal" prop (PrimeVue size only accepts small/large/default — normal maps to "don't pass size")
NychTextarea Textarea v-model, rows, placeholder, invalid — direct match
NychButton Button severity, disabled, loading, default + icon slots — direct match. The library's Button has a built-in loading spinner (laurel wreath), replacing the local LaurelSpinner usage inside NychButton
NychCard Card slot rename: local image slot → PrimeVue header slot; local default slot → PrimeVue content slot; title/subtitle props match
LaurelSpinner (small, used inside NychButton) dropped — covered by Button's built-in loader
LaurelSpinner (Hero, 580px static, :spinning="false") kept as a local component, rewritten as a thin wrapper around NychLoadingIcon imported from @nychthemeron/library/components, with scoped CSS to set width/height and override/disable the nych-spin animation when spinning is false per approved "wrap with CSS overrides" approach
LaurelDivider, ImageSlot unchanged, no library equivalent

Files affected

Deleted:

  • src/components/ds/NychTag.vue
  • src/components/ds/NychMessage.vue
  • src/components/ds/NychInputText.vue
  • src/components/ds/NychTextarea.vue
  • src/components/ds/NychButton.vue
  • src/components/ds/NychCard.vue
  • src/assets/styles/tokens/fonts.css
  • src/assets/styles/tokens/colors.css
  • src/assets/styles/tokens/base.css

Rewritten:

  • src/components/ds/LaurelSpinner.vue — becomes a thin wrapper around the library's NychLoadingIcon, preserving its existing size / color / spinning prop API so HeroSection.vue doesn't need to change its usage.
  • src/assets/styles/tokens/components.csstokens/laurel-divider.css (LaurelDivider section only).
  • src/assets/styles/styles.css (updated @import manifest).
  • src/main.ts (add PrimeVue + library CSS imports, app.use(PrimeVue)).

Updated imports/usages:

  • src/components/portfolio/SkillsSection.vueNychTag from library.
  • src/components/portfolio/WorkSection.vueNychCard, NychTag from library; update NychCard slot usage (imageheader, default → content).
  • src/components/portfolio/ContactSection.vueNychInputText, NychTextarea, NychButton, NychMessage from library.
  • src/components/portfolio/HeroSection.vueNychButton from library; LaurelSpinner continues to be imported from ./ds/LaurelSpinner.vue (rewritten).

Verification

  • bun run build and bun run type-check must pass.
  • Visually verify via dev server (bun run dev):
    • Hero section renders the large static laurel wreath at the same size.
    • Skills/Work section tags render with correct severity colors.
    • Work section cards render header image, title, content, footer tags.
    • Contact form inputs/textarea/button/message render and behave (loading spinner shows in button while "sending").
    • Both hades and apollo themes (toggle data-theme on <html>) still render correctly.

Out of scope

  • No changes to LaurelDivider.vue or ImageSlot.vue internals.
  • No changes to other library components not currently used (Checkbox, Select, Dialog, ToggleSwitch, RadioButton, etc.).
  • No changes to the CI workflow or registry configuration.