|
| 1 | +# Journal Entry 002 - 2026-02-18 - iOS Health-inspired UI polish |
| 2 | + |
| 3 | +## Goal |
| 4 | + |
| 5 | +Polish the Hugo website with microanimations and a professional, iOS Health-inspired design system. Criteria: no flashy effects, professional/detail-oriented feel, looks good on mobile, preserves existing UX. |
| 6 | + |
| 7 | +## What Changed |
| 8 | + |
| 9 | +### `website/assets/css/main.css` (complete rewrite) |
| 10 | + |
| 11 | +**Color system — Apple semantic palette:** |
| 12 | +- `--text: #1d1d1f` (Apple near-black, up from `#1a1a1a`) |
| 13 | +- `--text-secondary: #6e6e73` (Apple secondary, up from `#666`) |
| 14 | +- `--bg-secondary: #f5f5f7` (Apple light surface, was `#f6f6f6`) |
| 15 | +- `--accent: #007AFF` (Apple blue, was GitHub blue `#0969da`) |
| 16 | +- `--accent-hover: #0055D4` (was `#0550ae`) |
| 17 | +- Added `--accent-subtle: rgba(0, 122, 255, 0.08)` for hover backgrounds |
| 18 | +- Added `--border-subtle: rgba(0, 0, 0, 0.06)` for hairline separators |
| 19 | +- Added `--radius-sm: 6px`, `--radius-md: 10px`, `--radius-lg: 14px` |
| 20 | +- Added `--shadow-sm`, `--shadow-md`, `--ease: 0.15s ease` |
| 21 | +- Dark mode: `--bg: #1c1c1e`, `--accent: #0A84FF` (Apple exact dark-mode variants) |
| 22 | + |
| 23 | +**Nav — iOS frosted glass:** |
| 24 | +```css |
| 25 | +.nav { |
| 26 | + background: rgba(255, 255, 255, 0.82); |
| 27 | + backdrop-filter: saturate(180%) blur(16px); |
| 28 | + -webkit-backdrop-filter: saturate(180%) blur(16px); |
| 29 | + border-bottom: 1px solid var(--border-subtle); |
| 30 | +} |
| 31 | +[data-theme="dark"] .nav { background: rgba(28, 28, 30, 0.88); } |
| 32 | +``` |
| 33 | + |
| 34 | +**Hero — staggered entrance animation:** |
| 35 | +```css |
| 36 | +@keyframes fadeSlideUp { |
| 37 | + from { opacity: 0; transform: translateY(10px); } |
| 38 | + to { opacity: 1; transform: translateY(0); } |
| 39 | +} |
| 40 | +.home-hero h1 { animation: fadeSlideUp 0.45s ease both; } |
| 41 | +.home-desc { animation: fadeSlideUp 0.45s 0.07s ease both; } |
| 42 | +.home-links { animation: fadeSlideUp 0.45s 0.14s ease both; } |
| 43 | +.home-metrics { animation: fadeSlideUp 0.45s 0.21s ease both; } |
| 44 | +``` |
| 45 | + |
| 46 | +**CTA buttons — Apple HIG-style:** |
| 47 | +- Primary: `background: var(--accent)` filled with `box-shadow: 0 1px 4px rgba(0,122,255,0.28)`; hover lifts with `translateY(-1px)` and stronger shadow |
| 48 | +- Secondary: outlined with `border: 1px solid var(--border)`, hover fills `--bg-secondary` |
| 49 | + |
| 50 | +**Sidebar active state — iOS selected cell:** |
| 51 | +```css |
| 52 | +.sidebar-link.active::before { |
| 53 | + content: ''; |
| 54 | + position: absolute; |
| 55 | + left: 0; top: 20%; height: 60%; |
| 56 | + width: 2.5px; |
| 57 | + background: var(--accent); |
| 58 | + border-radius: 0 2px 2px 0; |
| 59 | +} |
| 60 | +``` |
| 61 | + |
| 62 | +**Other interactions (all `0.15s ease`):** |
| 63 | +- All `a` tags: `transition: color` |
| 64 | +- Nav brand: `opacity` fade on hover |
| 65 | +- Dark toggle: `color + border-color + background` |
| 66 | +- Table rows: `background` on `tbody tr:hover` |
| 67 | +- Docs list items: `translateY(-1px) + shadow-md + border-color` on hover |
| 68 | +- Mobile sidebar: `slideDown` keyframe entrance + close-on-outside-click |
| 69 | +- TOC links: `color` transition + `.toc-active` class set by JS |
| 70 | + |
| 71 | +**Mobile sidebar** adds `animation: slideDown 0.2s ease` on `.sidebar.open`. |
| 72 | + |
| 73 | +**Quick Start steps** — card-style via: |
| 74 | +```css |
| 75 | +.home-section ol { |
| 76 | + list-style: none; padding-left: 0; |
| 77 | + display: flex; flex-direction: column; gap: 0.6rem; |
| 78 | +} |
| 79 | +.home-section ol > li { |
| 80 | + padding: 0.85rem 1rem; |
| 81 | + background: var(--bg-secondary); |
| 82 | + border: 1px solid var(--border-subtle); |
| 83 | + border-radius: var(--radius-md); |
| 84 | +} |
| 85 | +``` |
| 86 | + |
| 87 | +**`prefers-reduced-motion`** — disables all animations/transitions for accessibility. |
| 88 | + |
| 89 | +### `website/layouts/index.html` |
| 90 | + |
| 91 | +Added `.home-metrics` section between CTA links and terminal code block: |
| 92 | +```html |
| 93 | +<div class="home-metrics"> |
| 94 | + <span class="metric-badge"><span class="badge-dot badge-dot-heart"></span>Heart Rate</span> |
| 95 | + <span class="metric-badge"><span class="badge-dot badge-dot-steps"></span>Steps</span> |
| 96 | + <span class="metric-badge"><span class="badge-dot badge-dot-sleep"></span>Sleep</span> |
| 97 | + <span class="metric-badge"><span class="badge-dot badge-dot-spo2"></span>Blood Oxygen</span> |
| 98 | + <span class="metric-badge"><span class="badge-dot badge-dot-vo2"></span>VO2 Max</span> |
| 99 | + <span class="metric-badge"><span class="badge-dot badge-dot-workout"></span>Workouts</span> |
| 100 | +</div> |
| 101 | +``` |
| 102 | + |
| 103 | +Badges use iOS Health metric colors: `#FF375F` heart, `#30D158` steps, `#636EFF` sleep, `#5AC8FA` SpO2, `#FF9F0A` VO2, `#FF6B35` workouts. |
| 104 | + |
| 105 | +### `website/static/js/main.js` |
| 106 | + |
| 107 | +- **Mobile sidebar**: Added `document.addEventListener("click", ...)` to close sidebar when tapping outside it or the hamburger button. |
| 108 | +- **TOC IntersectionObserver**: Highlights the active TOC link as user scrolls: |
| 109 | +```js |
| 110 | +var observer = new IntersectionObserver(fn, { |
| 111 | + rootMargin: "-8% 0px -75% 0px", threshold: 0 |
| 112 | +}); |
| 113 | +``` |
| 114 | +Uses `rootMargin` trick: heading must be in the top ~17% of the viewport to be "active". Sets `.toc-active` class on the corresponding `<a>` tag. |
| 115 | + |
| 116 | +## Key Insights |
| 117 | + |
| 118 | +### `backdrop-filter` needs explicit dark-mode override |
| 119 | +The nav `background: rgba(255,255,255,0.82)` is hardcoded (not `var(--bg)`) because CSS variables can't decompose to `rgba` components. Dark mode requires a separate `[data-theme="dark"] .nav { background: rgba(28,28,30,0.88) }` rule. This is the same pattern iOS itself uses — bg color + blur, not transparency alone. |
| 120 | + |
| 121 | +### Quick Start `ol` card styling doesn't affect docs `ol` |
| 122 | +The `.home-section ol` selector is scoped to the homepage only (docs pages don't have `.home-section` ancestors), so stripping `list-style` and adding `display: flex` doesn't leak into docs content. |
| 123 | + |
| 124 | +### Hugo not available in the deployment environment |
| 125 | +`hugo` binary was not installed in the session environment (not on PATH, not findable). Validated: |
| 126 | +- CSS brace balance via Python (`128 opens == 128 closes`) |
| 127 | +- HTML div balance via Python |
| 128 | +- JS syntax via `node --check` |
| 129 | +Build validation depends on CI (GitHub Actions → Cloudflare Pages). |
| 130 | + |
| 131 | +### IntersectionObserver `rootMargin` for TOC is tricky |
| 132 | +`rootMargin: "-8% 0px -75% 0px"` means the "active zone" is from 8% from top to 25% from top of viewport. When a heading scrolls into that narrow band, it becomes active. This gives a natural feel where the TOC highlights slightly ahead of the heading reaching the very top. |
| 133 | + |
| 134 | +## Decisions Made |
| 135 | + |
| 136 | +- **Apple blue (`#007AFF`) over GitHub blue (`#0969da`)** — the project is health-data tooling inspired by iOS Health; Apple blue is more on-brand and warmer. The exact dark-mode variant `#0A84FF` is from Apple's HIG. |
| 137 | +- **`fadeSlideUp` not `fadeIn`** — the 10px vertical movement makes the entrance feel physical and intentional, not a flat opacity pop. 0.45s is the sweet spot: fast enough to not feel slow, long enough to read as intentional. |
| 138 | +- **Metric badge color dots, not icons** — icons would require SVG assets or an icon font. Tiny colored dots (7px circles) convey the same category identity as iOS Health's chart colors with zero added complexity. |
| 139 | +- **No scroll-triggered animations beyond hero** — section headings and content boxes do NOT animate in on scroll. Only the hero (above the fold) gets the entrance animation. Scroll animations on content risk looking like a SaaS landing page. |
| 140 | +- **`prefers-reduced-motion`** — zero-cost accessibility improvement, collapses all `animation-duration` and `transition-duration` to `0.01ms`. Important for users with vestibular disorders. |
| 141 | + |
| 142 | +--- |
0 commit comments