Commit Graph
31 Commits
Author SHA1 Message Date
hoelee 419c962e2f feat(architecture): implement consultant review r4 (stream separation, nav upgrade, internal cta, schema & anchor fixes)
Deploy / build (push) Successful in 25s
2026-10-27 01:19:38 +08:00
hoelee 4a3c329fc6 feat(about): upgrade about page into dual-track work-with-me conversion hub 2026-10-27 00:44:44 +08:00
hoelee 355fecd348 feat(content): implement consultant review recommendations (executive summary, dynamic cta, homelab cleanup)
Deploy / build (push) Successful in 25s
2026-10-27 00:31:50 +08:00
hoelee f0b98843e9 feat(home): upgrade hero with lightbox banner, infra stats grid, tech pills, and category shortcuts
Deploy / build (push) Successful in 17s
2026-10-26 10:39:59 +08:00
hoelee d5a0fc089d feat(hero): refactor home hero to 2-column desktop grid and mobile visual flow
Deploy / build (push) Successful in 24s
2026-10-26 10:16:14 +08:00
hoelee 9fd02b8320 feat(hero): add AI-generated 'From Code to Production' architecture banner to homepage
Deploy / build (push) Successful in 23s
2026-10-26 09:46:24 +08:00
hoelee 18145b5db2 feat(header): logo mark + Lee Teong Hoe in brand, two-row mobile nav
Deploy / build (push) Successful in 29s
- brand: three-colour Hoelee mark (rasterised from the brand vector,
  transparent, public/images/hoelee-mark-96.png) followed by the name
- section links grouped in .nav-links so the mobile header puts them on
  their own row instead of wrapping past the search/lang/theme controls
- measured 320/360/390/414/600/768/1280: scrollWidth == innerWidth,
  header 91.6px two rows (<600px) / 60.3px one row, mark loads at 22/26px
2026-10-26 08:26:01 +08:00
hoelee 0a4fc47fce feat(categories): replace procedural SVG art with Gemini-generated WebP editorial banners
Deploy / build (push) Successful in 23s
2026-10-26 02:48:06 +08:00
hoelee 200dd46848 fix(css): add scroll-margin-top to headings for sticky header offset
Deploy / build (push) Successful in 15s
2026-10-21 06:54:13 +08:00
hoelee 84b412470b style(related): two-up on desktop, one-up on phones
Deploy / build (push) Successful in 33s
Six photo cards in 2 columns (3 rows) at desktop widths; phones collapse to a
single full-width column and still show only the first four. Drops the 900px
two-column step (now the base) and the cramped-card type overrides that only
existed for the 2-up phone grid.
2026-10-20 23:16:17 +08:00
hoelee 7f2680ea92 feat(related): photo cards — 6 on desktop, 4 on phones, each post's own share card
Deploy / build (push) Successful in 33s
Related posts were 4 text-only cards. They now carry the post's language-specific
ogImage (/og/<slug>.jpg for EN, /og/zh-<slug>.jpg for ZH), so an English page never
shows Chinese art. Grid is 3 across above 900px, 2 across below, and phones show the
first 4 only; read-time is dropped under 600px so the date fits.

Verified in the built HTML + headless Chrome at 1264/884/500px: 3/2/2 columns,
6/6/4 visible cards, no horizontal overflow, all six images decoded.
2026-10-20 22:50:37 +08:00
hoelee d3eb7ff9b0 post: cap embedded video/iframe to the column (1920px clip overflowed), swap demo to the 2 s 1080p take
Deploy / build (push) Successful in 15s
2026-10-20 07:28:07 +08:00
hoelee f391682fc3 Round 7: zero-text frames, escaped/curly titles, plan-driven banner crops
Deploy / build (push) Successful in 19s
The consultant's review of the shipped set found two defects, both ours, and both fixed
at the source rather than in the output:

1. The banner/thumb crop re-framing detected only the glowing core of the object. Column
   brightness measures 2-6 levels above the background on dark glass, so it boxed 8 % of
   the frame for an object group spanning 35 %+. The detector is now a background-plane
   deviation plus the largest connected components (`plan_banner_crops.py`, detector in
   `probe_band_crop.py`), 0 % false-positive on the frame's own negative space, stable
   across thresholds. The crop plan is frozen as `banner-plan.json` and consumed by the
   renderer; a thin subject is centred at 53.5 % of the banner width with the shortfall
   filled by the art's own edge pixels, one row at a time (a single averaged fill left a
   visible tonal step, tried and rejected). Measured on the delivered 72: 0 clipped,
   silhouette median 47.0 %, centre median 53.5 % (`verify_banner_crops.py`).

2. `art-meta.json` pinned two slugs to the hand-accepted sample frames — the very frames
   that carried the HUD readouts — which also kept them out of the crop plan. Pins removed.

Prompt side: 9 frames still printed glyphs at the consultant's bar (>=12 px and >=2
characters). Every offending noun is measured and now asserted against: a literal `marked
at 28` printed "28"; `storefront kiosk` printed "PRINATA"; `voucher card` printed
"Voucher"; `market booths` printed "10MARKET"; `glass button` printed "OC"; `gateway pylon`
printed "GATELY". 50 forbidden words, 0 hits across 72 captions, and all 9 frames
re-rendered clean.

Also: YAML escapes are honoured in the frontmatter reader and straight quotes become
curly ones (the ZH cards shipped a literal backslash), the evidence line is capped at 65
characters, and the light theme gives dark artwork a hairline border plus a soft shadow
(consultant option A) so it reads as a dark display case instead of a black slab.

OCR gate at the consultant's bar: 72/72 frames clean (16 carry sub-threshold single
glyphs, exempt as geometry noise).
2026-10-19 11:02:28 +08:00
hoelee 6e9d58b8cc feat(design): bento featured grid, theme-aware cards, mono tag chips
Deploy / build (push) Successful in 44s
- Homepage (EN + ZH) featured section becomes a 2x2 Cyber-Bento grid: OG
  thumbnail at 65%/140px behind a scrim, category badge + metric pill,
  3-line-clamped description, arrow CTA; 1 column under 680px.
- Bento scrim/pill/dot now use theme tokens (--card-veil, --pill-bg,
  --bento-visual-opacity). The original hardcoded dark blend measured
  1.96:1 pill contrast on the light theme; now 6.56 dark / 6.10 light.
- Add the missing @keyframes bento-pulse (the doc claimed a pulsing dot,
  none existed), disabled under prefers-reduced-motion.
- Tag chips: mono face, hairline border, 4px radius; dashed border for
  non-link tags.
- ZH pages: brand links /zh/, in-post category tag links
  /zh/categories/<cat>/ instead of the EN route.
- project-state: B6 shipped note with measured readings; correct the
  prompts-catalog path claim (file is outside the repo).

Measured in headless Chrome at 1280px and 390px, EN + ZH: 4 cards,
2 cols / 1 col, scrollWidth-clientWidth 0, no card overflow, all four
-800.webp thumbs loaded at 800x420.
2026-10-18 15:56:40 +08:00
hoelee 3f63150d51 feat(design): deploy default OG card (JPG/PNG), complete banner hygiene (E8), modernize CJK typography (E9), align title & hero (A2)
Deploy / build (push) Successful in 21s
2026-10-18 02:27:45 +08:00
hoelee 6b7c5a983f feat(identity): real author photo across the site + About page rewrite
Deploy / build (push) Successful in 48s
The photo is the identity evidence the external review flagged as the biggest
gap. One source image (Pictures/Professional Portrait with Blue Gradient
Background.png, 1254x1254), two sizes, WebP first with a JPEG fallback —
continuous tone is the case where WebP/JPEG beat PNG:

  640x640  42 KB JPG / 26 KB WebP   About page (190 CSS px)
  128x128   3 KB JPG /  2 KB WebP   author card + home hero avatar

It now appears in the About hero, the author card at the end of every post, the
home hero (both languages), and JSON-LD Person.image — the node search engines
read to associate the name with a face.

About went from 1,024 characters to five sections: identity with photo, "By the
numbers" (162 containers / 3 hosts / 71 essays / 0 hosting companies between me
and the servers), the real tech stack in four columns, the Hoelee Enterprise
block (website design and development is the main business, email hosting
secondary), and a contact split between hiring and business.

Also: the headshot's dark-blue background sits close to the page background, so
the photo, hero avatar and card avatar get a faint brand ring plus shadow.

Pictures/ keeps the converted JPG master next to the untouched PNG.
2026-10-16 22:07:25 +08:00
hoelee 215051ef08 polish(home): drop the redundant badge from featured cards, widen the search pill
Deploy / build (push) Successful in 48s
All four featured posts are case studies, so the badge repeated the same word
four times; the card grid already sits under a 'Featured' heading. Search pill
gets a little horizontal room so 'Search /' does not read as cramped.
2026-10-16 21:41:16 +08:00
hoelee f4008d9e8b feat(structure): compact archive + tag pages + hero/featured, and fix site search
Deploy / build (push) Failing after 13m52s
Found a real bug while verifying the nav search: /pagefind/pagefind.js is an ES
module that defines no window.Pagefind, but Search.astro loaded it with a classic
<script src> and read window.Pagefind — so every query answered "Search is
unavailable." (confirmed live before the fix). Now a dynamic import; the specifier
must be a variable or Rollup resolves it at build time and the build fails.

Measured before/after in a real browser:

- archive /posts/ + /zh/posts/: 18,220px -> 3,788px (71 rows at 44px, grouped by
  year) with a client-side filter (title/tags/description text, category chips,
  14 tag chips, zero requests). Tested: "nginx" -> 6 rows, chip devops -> 28.
- tag pages for tags with >= 3 posts. Measured 235 distinct tags (an earlier brief
  claimed 74), 156 used exactly once — pages only where a topic exists: 40 tags ->
  80 pages, build 165 -> 245 pages. Pills link only when a page exists.
- homepage + ZH homepage: hero (288px) with the real scale claim, three CTAs, a
  fixed Featured 4 (scale -> automation -> observability -> a delivered result),
  Latest 10 -> 6. ZH hero had linked "关于我" to the English /about/.
- long code blocks collapse above 420px with an Expand button + gradient, copy
  button still copies the whole block (verified on the 1010px block).
- search is visible ("⌕ Search /" pill, "/" plus the existing Ctrl/Cmd+K) and the
  zero-result screen offers topic chips instead of a dead end.

Docs: project-state B3 entry, ops-runbook Pagefind gotcha.
2026-10-16 21:18:25 +08:00
hoelee 874c434576 fix(i18n,404,nginx): broken-windows batch B2 from the external review
Deploy / build (push) Successful in 3m59s
All items measured before/after with curl, on the origin and through Cloudflare:

- /posts/zh/ answered 403 (directory with no index) -> nginx 301 to the new archive
- /zh/posts/ 404'd -> new src/pages/zh/posts/index.astro (build 163 -> 165 pages)
- ZH nav pointed "关于" at /zh/ and "文章" at /zh/ -> /zh/about/ and /zh/posts/
- og:locale was "en" on every Chinese page -> zh_CN, plus og:locale:alternate on
  both languages (EN pages now advertise zh_CN as well)
- hreflang "zh" -> "zh-Hans"; <html lang> on ZH pages -> zh-Hans
- no 404 page existed -> src/pages/404.astro, served by nginx with a 404 status so
  crawlers skip it, offering search + archive + the 3 newest posts
- JSON-LD Person gained worksFor (Hoelee Enterprise); image still omitted until the
  author photo exists rather than pointing at a placeholder

nginx: config moved from the stock image file to a host bind mount
(/mnt/user/docker/nginx-hoelee-blog/conf.d/default.conf, Portainer stack 247 on
endpoint 3), validated with nginx -t in a throwaway container before the redeploy.
It also sets /_astro/* to immutable 1-year (hashed names) and HTML to
must-revalidate; unhashed /og/*.png and /banners/*.png keep the default TTL on
purpose. Note: the public HSTS and 16-day asset TTL come from Cloudflare zone
settings, not from this nginx.

Docs: ops-runbook.md (the nginx layer + why each rule), project-state.md (B2 entry
and the two open Cloudflare items my token cannot write).
2026-10-16 20:50:26 +08:00
hoelee f364084284 perf(images): WebP banners, text-only related cards, resized list thumbnails
Deploy / build (push) Successful in 56s
Measured before/after with headless Chrome + CDP (not by eye):

- article banner: <picture> WebP q78 with the PNG as fallback, because the PNG
  must stay for og:image (social scrapers do not reliably render WebP cards).
  70 banners: 6.02 MB -> 2.52 MB (42%). JPEG measured *larger* than PNG here
  (q85 = 129%) — the art is flat terminal-style with sharp text edges.
- post page related cards: dropped four 1200x630 PNGs (183 KB) to display
  526x276 where the embedded code is illegible; now text-only cards with a
  category badge, date and reading time.
- list thumbnails (home + archive): new /og/thumb/<name>-{400,800}.webp served
  via srcset/sizes. Rows display at ~398px but were pulling full 1200x630 PNGs.
  Homepage thumbnails ~450 KB -> 62 KB; archive (71 rows) ~3.2 MB -> 436 KB.
- desktop banner capped at 720px centred: 67% -> 45% of a 900px viewport,
  keeping the art intact instead of cropping it.

Post page totals: images 277 KB -> 38 KB; page height 5758 -> 5065 (desktop)
and 9423 -> 8807 (mobile). Build: 163 pages.

Script: scripts/optimize-images.py; policy: docs/design-guide.md §3; runbook
step added to docs/ops-runbook.md.
2026-10-16 17:11:27 +08:00
hoelee 4cf52e04c1 Categories page: descriptions, per-category terminal illustrations, full ZH version
Deploy / build (push) Successful in 17s
- 7 categories now listed with name, blurb, post count and a
  per-category terminal-style SVG illustration (CategoryArt)
- empty categories show '0 posts · coming soon' (non-link, no soft-404)
- new zh pages: /zh/categories/ index + /zh/categories/[category]/ detail
- PostList is locale-aware (zh-CN dates, zh category links)
- zh nav '分类' now points to /zh/categories/
- category detail pages get art + description header
- language switch wired both ways (EN <-> ZH)
2026-09-13 23:50:08 +08:00
hoelee 7ecf1b878a Move banner below title/meta; related posts: og-image cover cards, 2-col desktop / 1-col mobile; doc: one-tap CTA rule
Deploy / build (push) Successful in 36s
2026-09-09 06:38:59 +08:00
hoelee 3a00a2d517 Add per-post banners (16:9 hero images) + banner-gen script; add banner to all posts
Deploy / build (push) Successful in 37s
2026-09-09 06:33:13 +08:00
hoelee ca650f69c0 Enlarge post list thumbnails to 400px on desktop
Deploy / build (push) Successful in 28s
2026-09-09 06:21:14 +08:00
hoelee 493dab88ba Widen container to 70rem; show post thumbnails full-width on tablet, side image only on desktop 1024px+
Deploy / build (push) Successful in 33s
2026-09-09 06:15:07 +08:00
hoelee ef6b54b2f1 Show post OG thumbnails in post list (left image + right text on desktop)
Deploy / build (push) Successful in 34s
2026-09-09 06:08:57 +08:00
hoelee 184395695f Add Chinese translation of DigiKedai bot post; center search icon
Deploy / build (push) Successful in 21s
2026-09-06 07:45:18 +08:00
hoelee 1314587ba1 Fix post ordering (distinct pubDates) and align nav control heights
Deploy / build (push) Successful in 15s
2026-09-06 07:35:28 +08:00
hoelee 93c716f876 Add Pagefind search, sort posts by update time, link DigiKedai bot repo
Deploy / build (push) Successful in 20s
2026-09-06 07:31:02 +08:00
hoelee e0d4b0fbb7 feat: locale routing (en flat, zh subfolder), language switcher, dark default
Deploy / build (push) Successful in 11s
- Derive lang from folder (posts/zh/* -> zh, else en); remove lang: frontmatter
- Change post route to [...slug] to capture nested zh paths
- Add nav language switcher (EN <-> 中文) + /zh/ landing page
- Default theme to dark (light opt-in via toggle)
- Translate hello-world-zh placeholder into English intro post
- Update case study: docker-compose sample + real install gotchas (commit history)
- Add docs/project-state.md (Tier 1/2/3 backlog)
2026-09-06 06:37:34 +08:00
hoelee a0b238bc98 feat: design-system upgrade + brand to 'Mr Hoelee'
Deploy / build (push) Successful in 16s
- Extract CSS into src/styles/global.css with design tokens (hoelee.com brand palette)
- Self-hosted Inter + JetBrains Mono via @fontsource
- Sticky nav + manual light/dark toggle + copy-button code blocks
- Author card + Person JSON-LD (E-E-A-T), article meta, related posts, reading time
- Full SEO: canonical, OG (with dims), twitter:card, favicon (all sizes), RSS + sitemap
- New /categories/ and /categories/[category]/ pages
- Add docs/ knowledge guides (content, design, seo, ops) + README index
- Brand name: hoelee.dev -> Mr Hoelee
2026-09-06 06:21:28 +08:00