# 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.css` → `tokens/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.vue` — `NychTag` from library. - `src/components/portfolio/WorkSection.vue` — `NychCard`, `NychTag` from library; update `NychCard` slot usage (`image` → `header`, default → `content`). - `src/components/portfolio/ContactSection.vue` — `NychInputText`, `NychTextarea`, `NychButton`, `NychMessage` from library. - `src/components/portfolio/HeroSection.vue` — `NychButton` 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 ``) 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.