Files
dzanan.net/Claude outputs/2026-09-06-dark-technical-redesign-design.md
amar.dzanan 4d754f33c1
All checks were successful
Deploy dzanan.net / deploy (push) Successful in 1m0s
redesign complete
2026-09-06 22:16:19 +02:00

174 lines
9.2 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.
# dzanan.net — "Dark & technical" redesign
Date: 2026-09-06 · Status: approved by Amar (direction C of three mockups)
## Goal
Replace the current warm/editorial design of dzanan.net with the "Dark & technical"
direction: near-black surfaces with a faint grid, monospace labels, a terminal-style
profile panel, and a single glowing green accent. The site serves both employers and
consulting clients equally. The CV becomes a PDF that Amar provides; the site links to it.
Non-goals: new content for the case studies (text stays), a light theme, a CMS, new routes.
## Scope
Kept: Angular 22 app structure, SSR + prerendering, `SeoService`, `PageShellComponent`
(restyled), landing page, four `/work/*` case-study pages, `SystemDiagramComponent`
(recoloured), not-found page, Tailwind v4 install, Docker deploy.
Removed: `CvPageComponent` + its spec, `ThemeService`, `ThemeToggleComponent`, the theme
bootstrap script in `src/index.html`, the `cv` client route, the `cv` prerender route.
Added: `public/cv.pdf` (placeholder until Amar supplies the file), a 301 from `/cv` to
`/cv.pdf` in `src/server.ts`, self-hosted fonts.
## Visual system
Defined as CSS custom properties on `:root` in `src/styles.scss`; no `.dark` variant.
| token | value | use |
|---|---|---|
| `--bg` | `#0D1015` | page background |
| `--panel` | `#12161D` | cards, list panel, code panel |
| `--panel-2` | `#0F1318` | panel headers / inset |
| `--line` | `#232A33` | borders, dividers |
| `--line-strong` | `#2A323D` | tag borders, button outline |
| `--text` | `#E6EAF0` | primary text |
| `--muted` | `#8B95A5` | secondary text |
| `--dim` | `#5C6672` | tertiary text, comments |
| `--accent` | `#8BE04A` | labels, links, primary button, status dot |
| `--accent-glow` | `rgba(139,224,74,.22)` | button and dot glow |
| `--code-key` / `--code-str` / `--code-num` | `#7AA2F7` / `#C3E88D` / `#F78C6C` | profile.json panel |
Grid: `linear-gradient` lines at 2.8% white, 64px cell, fixed to the page background.
Type: JetBrains Mono (labels, nav, meta, code, buttons) and IBM Plex Sans (headings and
body), self-hosted via `@fontsource-variable/jetbrains-mono` and `@fontsource/ibm-plex-sans`
(weights 400/500/600) imported in `styles.scss`. Fallbacks: Consolas/Menlo/monospace and
"Segoe UI"/system-ui/sans-serif. Base body 16px; headline scale `clamp(2.4rem, 5vw, 3.9rem)`
for h1, `clamp(1.75rem, 3vw, 2.1rem)` for h2, letter-spacing -0.03em/-0.025em, weight 600.
Labels (`.label`): mono, 12px, uppercase, 0.08em tracking, accent colour, prefixed with
`// ` in markup (e.g. `// selected work`). Tags (`.tag`): mono 12px, 24px tall, 1px
`--line-strong` border, 4px radius. Panels (`.panel`): `--panel` fill, 1px `--line`
border, 10px radius. Buttons: 46px tall, 6px radius, mono 14px; `.btn-accent` accent fill
with dark text and glow, `.btn-line` outlined.
Container: `.shell` = `min(1160px, 100% - 40px)` centred. Section spacing 96px desktop,
64px below 720px.
## Pages
### Shell (header, footer, mobile menu)
Header: sticky, `--bg` at 92% with blur, bottom border. Left: mono wordmark `~/` (accent)
+ `dzanan.net` (600). Right (desktop): mono nav `work · experience · contact · cv.pdf`,
then a divider and the status `● available` (accent dot with glow). `cv.pdf` is an `<a
href="/cv.pdf">` with a download icon, opens in a new tab. Below 720px the nav collapses to
the existing signal-driven menu button; the status stays visible.
Navigation config: `[{work,'/',#work},{experience,'/',#experience},{contact,'/',#contact}]`
plus the CV link rendered separately as a plain anchor (not a `SectionNavItem`).
Footer: mono 12px, `Amar Džanan · Sarajevo, Bosnia and Herzegovina` left; email and
LinkedIn right.
### Landing (`/`)
1. Hero — two columns (1.05fr / .95fr, 64px gap), stacks below 1024px.
Left: label `Senior full-stack engineer — .NET · Angular · MCP`; h1 "Complex systems,
<accent>understood before changed.</accent>"; lead paragraph "I modernize enterprise
software and connect it to AI through narrow, validated, verified interfaces — the kind
you can run in production and sleep at night."; buttons `amar@dzanan.net` (accent,
mailto) and `cv.pdf` (outline, download).
Right: `profile.json` terminal panel — title bar with three dots and file name, then a
`$ whoami --json` line and a JSON object: name, role, stack `[".NET","Angular",
"TypeScript"]`, focus `["modernization","safe AI integration"]`, since `2018`, location
`"Sarajevo · CET"`, open_to `["senior roles","consulting"]`, closing prompt with a
blinking cursor. Rendered from a small typed data structure in the component so it can
change without touching markup.
2. `// selected work` (`#work`) — heading "Production systems, anonymized." and a right-aligned
mono count `4 case studies`. One `.panel` containing four rows (`data-testid="project-row"`,
`routerLink` to `/work/<slug>`): index (accent on the featured first row), title + one-line
summary (a new short `tagline` field on `PortfolioProject`, ~60 chars), up to four stack
tags (first four of `stack`), arrow. Hover: row background `--panel-2`, arrow turns accent.
Below 720px: grid collapses to index+title, tagline, tags stacked.
3. `// experience` (`#experience`) — grid 340px / 1fr. Left: 96px square grayscale portrait
(`NgOptimizedImage`, 8px radius, 1px border), label, h2 "Eight years, one product at a
time.", about paragraph, LinkedIn link. Right: four role rows (period mono `2025 — now`,
title + company, focus sentence), 1px dividers.
4. `// capabilities` — three equal `.panel` cards: `01 System modernization`, `02 Full-stack
product delivery`, `03 Safe AI integration`, each with the existing detail text.
Single column below 720px.
5. Contact (`#contact`) — a `.panel` with a 1px accent-tinted border and inner glow:
label `// contact`, h2 "Need a senior engineer who can understand the system before
changing it?", `.btn-accent` mailto button, mono `Sarajevo · CET / CEST`.
Structured data (schema.org Person) unchanged.
### Case study (`/work/:slug`)
Breadcrumb as a path: `~/work/` (dim) + slug (text), mono. Header: label
`<category> · <period>`, h1 title, lead summary, then a meta strip in a `.panel`: `role`,
`period`, stack tags. Sections keep content; labels become `// 01 context`, `// 02 delivery`,
`// 03 architecture`, `// 04 result`; contributions as a numbered list with mono indices;
decisions as a 2×2 `.panel` grid (single column < 720px); technology as a tag row.
`SystemDiagramComponent` stays, recoloured: node fill `--panel`, stroke `--line-strong`,
accent node stroke/text `--accent`, lines `--line-strong`, notes `--dim`, mono text.
Prev/next as two `.panel` links. Contact block reused. The "View full CV" link points to
`/cv.pdf`.
### Not found
Terminal panel: `$ open <path>` then `command not found: <path>` in `--code-num`, a short
sentence, and a `.btn-line` back to `/`. Server still returns 404.
## Behaviour
- Motion: hero children fade-up (opacity 0→1, translateY 12px→0, 480ms, 80ms stagger) once
on load; cursor blink 1s step; row hover transitions 150ms. All wrapped in
`@media (prefers-reduced-motion: no-preference)`.
- Smooth anchor scrolling with `scroll-padding-top` for the sticky header (kept).
- Focus rings: 2px accent outline, 3px offset.
- `<meta name="theme-color">` → `#0D1015`; `color-scheme: dark`.
## Server
`src/server.ts`: before the Angular handler, `app.get('/cv', (_, res) => res.redirect(301,
'/cv.pdf'))`. `public/cv.pdf` is served by the existing static middleware. Until Amar
supplies the file, a one-page placeholder PDF saying "CV coming soon — amar@dzanan.net" is
committed so the link never 404s. `public/sitemap.xml` drops `/cv`.
## Files
Modified: `styles.scss`, `index.html`, `server.ts`, `app.ts`, `app.routes.ts`,
`app.routes.server.ts`, `app.routes.spec.ts`, `page-shell.component.ts`,
`navigation.config.ts`, `landing-page.component.ts` + spec, `portfolio-page.component.ts`
+ spec, `system-diagram.component.ts`, `not-found-page.component.ts`,
`portfolio-project.model.ts`, `portfolio-projects.data.ts`, `public/sitemap.xml`,
`package.json`/lock (fontsource packages).
Removed: `features/cv/cv-page.component.ts`, `features/cv/cv-page.component.spec.ts`,
`core/services/theme.service.ts`, `shared/ui/theme-toggle/theme-toggle.component.ts`.
Added: `public/cv.pdf` (placeholder), this spec, the implementation plan.
## Testing
- Unit: route spec lists routes without `cv`; landing spec asserts the new h1, four project
rows, `a[href="/cv.pdf"]`, mailto and LinkedIn links, the four role titles; portfolio spec
unchanged in intent; new not-found assertion optional. Run with headless Chromium.
- Build: `ng build` (production, SSR, prerender of `/` and the four work pages) with zero
errors and within budgets (component styles are inline SCSS; keep under 8kB each).
- Visual: serve `dist` and screenshot `/`, one case study and `/404` at 1440px and 390px;
fix wrapping, overflow and contrast issues found.
- Smoke: `curl -I /cv` → 301 to `/cv.pdf`; `/cv.pdf` → 200.
## Delivery
Work happens in the cloud copy of the repo; changed and new files are written back to the
`dzanan.net` folder on Amar's machine, removed files are moved into `_to_delete/`. Amar runs
`npm install` locally afterwards (new font packages) and drops the real PDF over
`public/cv.pdf`.