# Portfolio Site
`06 · portfolio-site · Open source`
الموقع الذي تقرأه. React · Vite · TypeScript مع CSS قائم على tokens، محتوى EN/RU/AR typed، مرايا Markdown، telemetry تراعي الخصوصية، وnavigation واعية بالroute.
**النطاق:** Solo · مستمر
**الدور:** Engineering portfolio · 2025–2026
---
## السياق
> ست حالات لا يستطيع recruiter فتحها. وموقع واحد يستطيع.
من أصل ستة مشاريع معروضة، خمسة خلف نطاق مغلق أو NDA — client work، internal tooling، وR&D. لا يستطيع recruiter فتحها أو diff history. الموقع نفسه هو artifact العام الوحيد الذي يستطيع reviewer تدقيقه فورا: DevTools، network، CSS، view-source. كل تفصيل يراه المستخدم هو أيضا قرار يراه المهندس.
القيد مزدوج: يجب أن يقرأه recruiter خلال خمس ثوان — cards ثابتة الشكل، spec-sheets mono، ASCII diagrams. ويجب أن يصمد أمام senior eye بطيئة — token-first design، i18n مخصص، view transitions، وHero ember field لا يسخن iPhones.
## حقائق
| | |
|---|---|
| **النطاق** | Solo · مستمر |
| **الأسطح** | Home + 6 cases · EN/RU/AR · dark/light · 3 palettes |
| **المصدر** | مستودع GitHub عام · CV PDF · أزرار copy-as-Markdown |
| **التقنيات** | React 18 · Vite · TypeScript · CSS variables |
| **المحتوى** | Typed dictionaries · public/private content trees · مرايا Markdown مولدة |
| **القياس** | أحداث دون ملفات تعريف ارتباط إلى same-origin · dashboard للمدير فقط |
| **الحركة** | View transitions · يحترم prefers-reduced-motion |
| **الحالة** | Open source · live |
## المعمارية
### شجرة providers + routing
```text
// src/theme/ThemeContext.tsx
// src/i18n/LangContext.tsx
→
```
**ترتيب providers مهم.** ThemeProvider في الخارج حتى تكتب palette على `` قبل أن يقرأ أي child متغيرات اللون. LangProvider بعده حتى يكون `useT()` متاحا في كل مكان. Loader وscroll restoration وanalytics داخل router لأنها تحتاج routed content أو `useLocation()`.
**مساران وظيفيان + fallback.** `/` يعرض home، و`/cases/:slug` يعرض case study، و`*` يعود إلى home للروابط غير المعروفة. slug whitelist يعيش في `src/config/cases.ts` وتستهلكه Nav وProjectDetailPage؛ server analytics لديه allowlists خاصة به.
**لا code-splitting بعد.** المساران يشحنان في bundle واحد. Lighthouse ما زال أخضر؛ يعاد النظر عندما يظهر route ثالث.
### سلسلة حلّ tokens
```text
1 ThemeContext theme = 'dark' → palette = 'ochre'
│
▼ writes data-attrs on
2
│
▼ tokens.css matches via attribute selectors
3 [data-theme="dark"] → --bg --fg --line
[data-palette="ochre"][data-theme="dark"] → --accent --accent-soft
│
▼ CSS modules imported by styles.css consume via var()
4 .hero h1 { color: var(--fg) }
.chip { background: color-mix(in oklab, var(--bg) 10%, …) }
```
**Theme يحدد palette.** الاشتقاق deterministic: dark → ochre وlight → electric. كلا `data-theme` و`data-palette` يكتبان على ``. CSS يبدل عبر attribute selectors؛ صفر branching في JS لكل عنصر.
**Token file + CSS modules، بلا Tailwind.** `tokens.css` هو مصدر الحقيقة للألوان والمسافات والخطوط والزوايا. `styles.css` مجرد entry يستورد base وhome وmedia وcase-study وruntime. نظام tokens يقوم بدور Tailwind config، والselectors تقوم بدور utility classes.
**oklch + color-mix للخلفيات.** استخدام كثيف لـ `color-mix(in oklab, var(--bg) X%, transparent)` للطبقات الملوّنة — hero chips، case-study glows، diagram backdrops. يتجنب opacity hacks على اللون الخطأ.
### Loader + مراحل دخول الواجهة
```text
T=0 T=400 ms T=900 ms
│ │ │
▼ ▼ ▼
pulse → rush → gone
hairline two whiteish blurred loader unmounted
opacity pulses run from 15% / 85% hero/about reveal
0.22-0.7 toward center (600 ms) (staggered)
at T+400 ms of rush:
html.is-loading removed (was set synchronously by inline