redesign complete
All checks were successful
Deploy dzanan.net / deploy (push) Successful in 1m0s

This commit is contained in:
amar.dzanan
2026-09-06 22:16:19 +02:00
parent 886292aca9
commit 4d754f33c1
43 changed files with 2123 additions and 691 deletions

View File

@@ -0,0 +1,173 @@
# 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`.