Files
Portfolio-2026/docs/superpowers/specs/2026-08-16-portfolio-2026-design.md
T

241 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: Portfolio 2026 Theme Design
description: Surface overhaul, conflict resolution, and template build-out for the ks-portfolio WordPress theme.
created: 2026-08-16
status: approved
---
# Portfolio 2026 Theme — Design Spec
## 1. Purpose
Rebuild the surface of `ks-portfolio` (WordPress theme at `wp-content/themes/ks-portfolio/`) to match the **Portfolio 2026** identity defined in `notes/DESIGN.md`, `notes/TOKENS.md`, and the three mockups (`home-screen.png`, `archive-screen.png`, `single-screen.png`). Resolve the documented conflicts in `notes/DESIGN.md` §12. Keep the SoloFrame Evo architecture and the installed `projects-portfolio` plugin as-is; build only the presentation layer.
## 2. Source hierarchy
When sources disagree, follow `notes/DESIGN.md` §1. In short:
1. `style.css` for current identity.
2. `notes/Projects Plugin Design.md` for content model.
3. `notes/Background Gradient.md` for atmospheric field.
4. `theme.json`, `styles/`, ACF JSON, templates for implemented tokens.
5. `README.md` and `docs/` for inherited architecture.
User decisions (locked at brainstorm time):
- **Projects source**: theme renders templates against the `projects` CPT provided by the installed `projects-portfolio` plugin. The theme does NOT re-register the CPT.
- **Mockup content**: live `projects` CPT with empty-state fallbacks ("Nothing here yet..."). The mockups are layout references, not content sources.
- **Test scope**: Chromium + axe only. Firefox / WebKit / mobile are out of scope.
- **Pen-test**: static security audit (PHPCS + grep + manual review). No OWASP ZAP.
## 3. Identity & naming
- `style.css` keeps `Theme Name: Portfolio 2026`, `Text Domain: ks-portfolio`.
- PHP namespace `SoloFrameEvo``KsPortfolio` across all PHP files (composer script + manual review).
- Drop `screenshot.png` (Basic WP) at the end; replace with a Carbon-Blue-themed capture.
## 4. Visual system
### 4.1 Body surface
```css
body {
background-color: #100e0b; /* Carbon Blue page base */
color: var(--color-on-surface); /* #e3e1e9 — ~14:1 on dark */
}
```
The existing rule `main#maincontent { background: var(--color-background); }` is removed. Sections paint directly on the dark body; there is no light block underneath content.
### 4.2 Carbon Blue atmospheric field
Implemented as a `views/partials/aura-bg.php` partial loaded on the home and project archive templates (per mockup: dark atmospheric field on hero surfaces, plain dark surface elsewhere).
- Layer 1: linear 138deg `#05070c → #0f172a → #172554 → #1e3a8a`. `mix-blend-mode: normal`. `transform: translateZ(0)`.
- Layer 2: radial ellipse `45% 50% at 72% 40%`, `rgba(96,165,250,0.20)` → transparent 68%. `mix-blend-mode: screen`. `filter: blur(105px)` mobile, `151px` desktop.
- Layer 3: inline SVG `feTurbulence baseFrequency="0.7" numOctaves="4" stitchTiles="stitch"`, `mix-blend-mode: overlay`, `opacity: 0.85`.
- All three: `position: absolute; inset: 0;`, `pointer-events: none;`, `aria-hidden="true"`.
- Parent container: `position: relative; overflow: hidden; min-height: 100vh;` with NO `background-color` (per the blend-mode architecture warning in `notes/Background Gradient.md`).
- Content wrapper: `position: relative; z-index: 1`.
### 4.3 Tokens
Resolve the unresolved tokens from `notes/DESIGN.md` §12:
- Define `--font-headings: var(--font-sans)` in `styles/base/typography.css`.
- Update `theme.json` `styles` block to reference the existing palette slugs (`theme-bg`, `theme-text`) — currently references `background` / `text` which don't exist.
- Add Carbon-Blue editor palette entries in `theme.json`: `theme-surface` (#121318), `theme-on-surface` (#e3e1e9), `theme-outline` (#8f909d), `theme-outline-variant` (#444651), `theme-primary` (#b6c4ff), `theme-on-primary` (#05297a).
- Add 100900 mix tokens for `theme-primary` if not already present.
- Remove legacy hex values (`#3857BC`, `#ddd`) from pagination CSS; replace with `var(--color-outline-variant)` / `var(--color-primary)`.
Keep the implemented light tokens in `styles/base/colors.css` for any block-editor surface that still wants light, but default new portfolio-facing CSS to the dark surface.
## 5. Template → mockup mapping
### 5.1 `front-page.php` — matches `notes/home-screen.png`
- Header: `WP_DEV_2026` logo, top nav (Plugins, Themes, Open Source, Documentation, Blog), `Download CV` button (right-aligned).
- Hero on Carbon Blue: heading + intro + two CTAs (`Download CV`, `View Repositories`) pulled from ACF Homepage Hero fields. No hardcoded sample text.
- "Recent Projects" section: queries `projects` CPT, max 3, rendered as 3-column grid on `lg`, single column on mobile.
- Each card: type badge (Plugin / Theme / Pattern), title, excerpt, `Download` + `View Repo` links when both URLs exist (provider-agnostic labels).
- Empty state when zero published projects: "Nothing here yet..." + "No published projects found." centered in the grid area.
- Footer: copyright + GitHub / Privacy / License / Site Status links.
### 5.2 `archive-projects.php` (new) — matches `notes/archive-screen.png`
- Hero: `Project Archive` heading + intro from ACF option (or page-derived intro).
- Grid: project cards 3-up on `lg`, 2-up on `md`, 1-up on mobile.
- Each card: type label (PLUGIN / THEME FRAMEWORK / INTEGRATION, uppercase tracking-wide), title, excerpt, language pill + star count, `View Repo →` link.
- Pagination via `the_posts_pagination` styled against dark surface.
### 5.3 `single-projects.php` (new) — matches `notes/single-screen.png`
- Hero: provider icon + type pill, project title + version suffix (from `projects_portfolio_get_latest_version()`), excerpt.
- Primary `Download vX.Y.Z` button + secondary `View Repo` link.
- Two-column body below: featured image / project content on the left; sidebar (Maintainer, Repository Details table, four stat cards) on the right.
- Owner avatar: 40px square using `background-image` with explicit `width: 40px; height: 40px; background-size: 40px 40px;` (per `notes/Projects Plugin Design.md` §9 — host CSS quirk workaround).
- Below columns: `Architecture & Implementation` (post body content), `Key Features` (list), `Installation` (code block) — all from WordPress content.
### 5.4 `taxonomy-project-type.php` (new)
- Same template as `archive-projects.php` with taxonomy-aware title: `<h1>{project-type label}</h1>` plus a back link to the full archive.
### 5.5 Other templates
- `index.php` (post archive), `search.php`, `single.php` (post), `page.php`, `404.php`: keep structure, recolor surfaces to dark, remove `picsum.photos` fallback URLs, ensure empty-state copy matches existing `Nothing here yet...` / `No published posts found.` / `Page Not Found` patterns.
- Keep `Resources` CPT and `resource_type` taxonomy styling independent from `projects`.
## 6. Components
### 6.1 Buttons
Keep the existing token-driven button block (Primary / Secondary / White / Black × Default / Outline × Small / Medium / Large × Auto / Small / Wide / Full Width). The Primary button in the mockup maps to the existing default-styled Primary button (3px border, semibold 16px, 200ms transitions, focus outline offset, 99% active press).
### 6.2 Project card
New `views/components/project-card.php`:
- Border `1px solid var(--color-outline-variant)`.
- Background `var(--color-surface-container)` (#1e1f25).
- Radius `lg` (1rem).
- Padding `1.5rem`.
- Type badge top-left (small, uppercase, tracking-wide).
- Provider icon top-right (decorative if visible text label is present).
- Title (h3 if in archive, h2 on home), excerpt (line-clamp), action row at bottom with `Download` and `View Repo`.
- Hover: subtle border tint to `var(--color-primary)`.
- Focus-visible: 2px primary outline, 3px offset.
### 6.3 Stat card
New `views/components/project-stat-card.php`:
- Square surface with `var(--color-surface-container)`, radius `lg`, padding `1rem`.
- Icon (decorative), large value, uppercase label below.
### 6.4 Navigation
Keep `views/components/nav-main.php`, `nav-aux.php`, `nav-main__toggle.php`. Recolor links to `var(--color-on-surface)`. Preserve skip link, dropdown behavior, focus visibility, mobile variants.
### 6.5 Header layout
Switch from `grid-cols-[83px_auto]` to a three-region responsive layout (logo | main nav | aux action button). The `Download CV` button is in the right region on `lg`, collapses into the mobile menu below.
## 7. Accessibility (WCAG 2.1 AA)
- Skip-to-main link: preserved (`#f6ff00` on black, yellow focus outline).
- Body text contrast: `#e3e1e9` on `#100e0b` ≈ 14:1 — passes AA.
- Primary buttons: `#b6c4ff` background with `#05297a` text ≈ 9:1 — passes AA.
- All decorative layers `aria-hidden="true"` + `pointer-events: none`.
- Heading order: each template has exactly one `<h1>`. Mockup headings map to page `<h1>`; lower-level headings step down in order.
- Provider icons supplement text (GitHub, Gitea, Download, View Repo) — never replace them.
- Keyboard: tab order header → hero → projects → footer; focus-visible on every interactive element.
- `prefers-reduced-motion`: media-query guard around hover scale on cards / media.
## 8. Security
- All forms use `wp_nonce_field`; state-changing requests use `wp_verify_nonce`.
- Dynamic output escaped with the right `esc_*` function for its context (`esc_html`, `esc_attr`, `esc_url`, `wp_kses_post`).
- Post meta access via `get_post_meta( $id, $key, true )` with explicit defaults.
- No `$_GET` / `$_POST` / `$_REQUEST` without `sanitize_*` + `wp_unslash`.
- External URLs (Download / View Repo) use `esc_url` and add `rel="noopener noreferrer"` when `target="_blank"`.
## 9. Testing plan
### 9.1 Unit / static (composer)
- `composer run lint` (PHPCS with WordPress + WPCS ruleset) must pass clean across all theme PHP.
- Fix any violations inline.
### 9.2 Static security audit
- PHPCS `WordPress.Security` ruleset (`NonceVerification`, `ValidatedSanitizedInput`, `EscapeOutput`).
- Grep audit for `$_GET` / `$_POST` / `$_REQUEST` without `sanitize_*` / `wp_unslash` / `esc_*`.
- Manual review of every new template for nonce, sanitize, escape coverage.
- Severity-ranked written report (Critical / High / Medium / Low / Info) with `file:line` citations and remediation per finding.
### 9.3 Browser / functional (Playwright)
- `playwright.config.js`: chromium project only, base URL `http://portfolio.test` (matches `.env`).
- New `tests/home.spec.js`: home renders Carbon Blue hero, project grid or empty state, no axe violations.
- New `tests/archive.spec.js`: project archive grid renders, no axe violations.
- New `tests/single.spec.js`: project detail hero + sidebar + Download button visible, no axe violations.
- Keep existing `tests/site-a11y.spec.js` (homepage, blog index, 404).
- axe tags: `wcag2a, wcag2aa, wcag21a, wcag21aa, wcag22a, wcag22aa`.
- Full-page screenshots saved to `test-results/` per test.
## 10. File-level changes
### Modified
- `style.css` (already correct — verify)
- `functions.php` (namespace swap, project helper include)
- `header.php`, `footer.php` (namespace swap, dark surface)
- `index.php`, `single.php`, `page.php`, `search.php`, `404.php`, `front-page.php` (namespace swap, dark surface, remove `picsum.photos`)
- `lib/*.php` (11 files: `activation.php`, `class-acf.php`, `class-breadcrumbs.php`, `class-enqueue.php`, `class-menuitems.php`, `class-resources.php`, `extras.php`, `helpers.php`, `hooks.php`, `search-features.php`, `show-template.php` — namespace swap + dark surface tweaks)
- `views/blocks/*/block.json` and any block PHP that uses a namespace (light touch — only what axe or the new templates require)
- `views/forms/search.php` (light touch — escape review only, no behavior change)
- `theme.json` (fix preset references, add dark palette)
- `styles/base/colors.css` (add Carbon Blue tokens)
- `styles/base/typography.css` (define `--font-headings`)
- `styles/base/global.css` (dark body, remove light main rule)
- `views/components/nav-*.php`, `views/partials/*.php` (namespace swap, dark overrides)
### New
- `archive-projects.php`
- `single-projects.php`
- `taxonomy-project-type.php`
- `views/partials/aura-bg.php` (Carbon Blue layers + grain)
- `views/components/project-card.php`
- `views/components/project-stat-card.php`
- `lib/class-projects.php` (thin wrapper around plugin helpers: `get_provider_label()`, `get_release_url()`, `get_repo_browse_url()`, `get_repo_data()`, `get_owner_data()`, `get_download_url()` with provider-agnostic fallbacks)
- `tests/home.spec.js`
- `tests/archive.spec.js`
- `tests/single.spec.js`
- `docs/superpowers/specs/2026-08-16-portfolio-2026-design.md` (this file)
- `docs/superpowers/specs/2026-08-16-portfolio-2026-testing-report.md` (final report)
### Removed
- `screenshot.png` (Basic WP) — replaced at the end
- `picsum.photos` fallback URLs in `index.php`, `search.php`
- Legacy hex values in pagination CSS
## 11. Out of scope
- Migrating existing content (site has minimal published content — no destructive cleanup).
- Changing `projects-portfolio` plugin behavior (we only consume its helpers).
- Removing the `Resources` CPT (per notes: keep both, don't conflate).
- Block-editor UI polish (follow-up).
- Firefox / WebKit / mobile browser testing (out of scope per user choice).
- OWASP ZAP scan (out of scope per user choice).
## 12. Definition of done
- `composer run lint` exits 0.
- Playwright suite passes locally (Chromium, axe-core zero violations across all four specs).
- Static security audit produced with no Critical or High findings (Medium+ requires remediation before sign-off).
- All three mockups (home, archive, single project) reachable on `http://portfolio.test` and visually consistent with their reference screenshot.
- `screenshot.png` replaced with a Carbon-Blue capture.
- Final testing report committed to `docs/superpowers/specs/2026-08-16-portfolio-2026-testing-report.md`.