Commit Graph
100 Commits
Author SHA1 Message Date
tiennm99 57057a73b5 feat: publish Newsletter #111 2026-06-11 21:23:03 +07:00
tiennm99 4c035836c4 feat: publish Newsletter #110 2026-06-07 15:39:25 +07:00
tiennm99 6e0cfbb25a feat(post): add newsletter #109 — IDE history, debugging, containers, AI coding, vector indexing 2026-06-06 06:21:13 +07:00
tiennm99 db6908101c refactor(referral): reorder AI coding platform providers
- Move Z.ai and MiniMax to the top of the section
- Place Xiaomi MiMo directly above ModelArk
2026-06-05 09:38:14 +07:00
tiennm99 ee42ef56de fix(referral): simplify MiniMax description, remove personal reward amount 2026-06-04 17:59:10 +07:00
tiennm99 ea9d4de17a feat(referral): update MiniMax description — 5 voucher, Jul 1 deadline, add minimax.png 2026-06-04 17:56:54 +07:00
tiennm99 b3168fc2f1 feat(post): add newsletter #108 — AI coding, mental models, developer productivity 2026-06-04 17:50:18 +07:00
tiennm99 73e34a61ad fix(referral): add missing mimo.png image 2026-06-04 17:39:13 +07:00
tiennm99 54e230f2cc feat(referral): add thank-you note 2026-06-04 17:27:25 +07:00
tiennm99 e961c449c4 feat(referral): add Xiaomi MiMo Open Platform referral 2026-06-04 17:20:59 +07:00
tiennm99 c5599d4e34 feat(referral): add Alibaba Cloud referral program 2026-06-04 17:19:58 +07:00
tiennm99 dd61a076b1 feat(post): add Gemini CLI / Antigravity as 4th AI coding tool
- Add Gemini CLI and Antigravity to the list of tools used
- Add dedicated section with deprecation timeline (June 18 cutoff)
- Update tags with Gemini CLI and Antigravity
2026-06-04 15:13:56 +07:00
tiennm99 ee88718b1c feat(post): add post on rotating AI coding tools to maximize subscription value 2026-06-04 09:43:32 +07:00
tiennm99 4f6afb224d feat(referral): mark friend's claude pass as out of stock 2026-06-03 09:52:05 +07:00
tiennm99 8f4e1928d8 feat(tooling): run blog from Claude Code, OpenCode & Codex on shared engine
Extract newsletter scripts to a neutral scripts/newsletter/ engine and add
side-by-side support for all three AI coding tools off one source of truth.

- Move 9 scripts + substack config from .claude/skills/**/scripts to
  scripts/newsletter/ (history preserved); fix PROJECT_ROOT depth and
  cross-require/config paths; repoint all SKILL.md invocations
- Add canonical AGENTS.md; reduce CLAUDE.md to an @AGENTS.md import
- Add opencode.json (permissions, no MCP); skills auto-discovered in place
- Add codex/prompts/*.md (6 prompts) + copy installers (install.sh/.ps1)
- Add docs/multi-tool-usage.md (setup, per-tool invocation, teardown) + README pointer
2026-06-02 14:07:22 +07:00
tiennm99 1dea951355 feat(referral): prioritize opencode go referral 2026-06-01 16:44:47 +07:00
tiennm99 a542128395 feat(referral): add opencode go referral 2026-06-01 16:36:47 +07:00
tiennm99 fe06f547de feat(newsletter): add Newsletter #107 with articles and bonus images 2026-05-30 21:22:06 +07:00
tiennm99 d262159742 refactor(skills): fix dedup edge cases and modularize mt-* scripts
- fix checkDuplicate false-negative on Substack cover images (uuid with no size suffix)
- stop cleanUrl from corrupting the query string on unparseable input
- extract shared fetchWithTimeout into url-utils (consistent timer cleanup)
- split find-substack-post html/rss helpers into html-text-utils
- scan content/post for duplicates, matching the other scripts
- correct doc drift in mt-add-image/mt-add-url and drop plan-phase code comment
2026-05-30 20:31:50 +07:00
tiennm99 eada44d407 refactor(skills): share Substack image helpers and harden URL dedup/routing
- extract isSubstackImage/substackImageUuid into shared url-utils
- route Substack images by host (handles f_auto/.avif/extensionless CDN URLs)
- replace grep-based duplicate check with boundary-aware pure-JS scan
- share one fetch budget across publications in deep sitemap crawl
- expand file-extension classification (avif/heic/mkv/pptx/etc.)
2026-05-30 20:13:27 +07:00
tiennm99 5f78b3e2be feat(mt-add-image): confirm image label from source post candidates
ByteByteGo images carry no caption/alt and image order cannot be mapped to
titles automatically (sponsor and video items interleave). Extract the source
post's TOC topic titles as candidates and let the user pick the matching label
(caption is used directly when a publication provides one; typing is always
available). Validated against newsletters 101-106: the correct title appears
in the candidate set for all 8 images.
2026-05-30 17:23:10 +07:00
tiennm99 f40103fe82 feat(skills): add mt-add-image handler with Substack source lookup
Add the image handler in the meta-dispatch architecture. Given an image
URL it resolves a label and inserts it into the newsletter Bonus -> Images.

For Substack-hosted images, decode the S3 image UUID and find the source
post across configured publications (ByteByteGo by default): RSS feed first,
then a sitemap crawl up to ~3 months back. Label priority is figure caption,
then post title, then a user-typed name. Non-Substack images are best-effort
then ask. Publications are configurable and the skill offers to add a new one
when the user identifies it.

Wire mt-add-url to dispatch the image route to mt-add-image (previously a
fallback). Update the project skills list.
2026-05-30 16:55:47 +07:00
tiennm99 f5fa315ea1 feat(skills): split newsletter URL workflow into meta dispatcher + handlers
Add mt-add-url meta skill that classifies a URL and auto-dispatches to a
handler skill: articles to mt-add-post, YouTube links to the new
mt-add-video (Bonus -> Videos with a Vietnamese title + short summary).
Unsupported types (image, etc.) prompt the user to add or extend a skill;
image support is deferred to a future mt-add-image handler.

Shared logic (add-url.js router, url-utils.js, find-newsletter-number.js)
and a shared post-mechanics reference live under mt-add-url/. mt-add-post
is reduced to an article-only handler. add-url.js detects watch/youtu.be/
shorts, normalizes to the canonical watch URL, dedups by video id, and
fetches the title via oEmbed. checkDuplicate uses execFileSync (no shell).
2026-05-30 16:23:27 +07:00
tiennm99 6ebf27714a fix(mt-add-post): preserve YouTube video id in duplicate check
bareUrl() dropped the query string, collapsing every youtube.com/watch
URL to the same bare key and flagging all YouTube links as duplicates.
Keep host identity params (v for youtube) so distinct videos are not
treated as duplicates.
2026-05-30 15:48:52 +07:00
tiennm99 225be80c96 docs(newsletter): add Newsletter #106 2026-05-29 00:24:59 +07:00
tiennm99 0694d37f9c docs(newsletter): add Newsletter #105 2026-05-27 22:10:44 +07:00
tiennm99 b8d28a8ef3 docs(newsletter): add Newsletter #104 2026-05-24 23:58:59 +07:00
tiennm99 63082b89d1 docs(newsletter): add Newsletter #103
11 articles covering AI coding, career lessons, email internals,
Git performance, binary search optimization, Swiss tables, and more.
2026-05-23 22:22:33 +07:00
tiennm99 659a48b021 docs(newsletter): validate URLs, fix redirects, strikethrough dead links
- Update ~38 URLs to current canonical (domain moves, restructures, tracking-param strip)
- Strikethrough ~15 sections with confirmed dead URLs (404/410/DNS-fail)
- Fix malformed markdown ((double parens, stray bracket)
- Correct evanhahn.com URL typo

Two-pass review with verification pass to catch HEAD-only false-positives.
2026-05-15 21:21:58 +07:00
tiennm99 4d64da13dc fix(ci): correct subpath URL emit + build into public/tsuki for htmltest
Run 25919953710 still failed htmltest on both Hugo legs. Two distinct
issues, both pre-existing latent bugs that v0.3.0 made impossible to
ignore:

1. Several theme templates piped paths with a leading slash through
   `relURL`, which in Hugo means "this is already absolute — leave it
   alone." The intended subpath prefix (`/tsuki/`) was therefore never
   added, producing hrefs like `href="/search/"` and `href="/"`. In
   production the GitHub Pages mount masked this (broken links from
   the page's perspective still happened to resolve under the repo
   path most of the time), but htmltest correctly reported them as
   broken. Fix by either:
   - using `site.Home.RelPermalink` for the home link, or
   - piping a string without a leading slash through `relLangURL`
     (so Hugo prepends the baseURL path), or
   - stripping the leading slash from data-driven URLs first via
     `strings.TrimPrefix "/"` and then `relLangURL`.

   Affected: header.html, search-button.html, recent-posts.html,
   home/hero.html, nav.html, 404.html, search/list.html (Pagefind UI
   asset URLs).

2. htmltest has no URL-rewriting feature (the `URLSwap` config in the
   prior `d30f50f` "fix" was never read by htmltest — confirmed by
   reading htmltest 0.17.0 source). The only clean way to make
   internal-link checking work with a `/repo/`-style baseURL is to
   mirror the URL structure on disk. CI now builds with
   `hugo --destination public/tsuki`, runs Pagefind/smoke/htmltest
   against that path, and uploads `exampleSite/public/tsuki/` as the
   Pages artifact. The artifact contents become the served site
   under `/tsuki/`, identical to the prior behaviour from the
   browser's point of view. `.htmltest.yml` drops the dead URLSwap
   block.

Also: `tmp/` (htmltest's runtime cache) added to .gitignore so local
runs don't dirty the working tree.

Local verification: 32 smoke checks green; htmltest reports
`✔✔✔ passed, tested 29 documents` against the subpath build.
2026-05-15 20:31:00 +07:00
tiennm99 f885af9e83 fix(ci): unbreak smoke + htmltest steps post v0.3.0
Three independent CI failures from run 25916500415:

1. Smoke test [linkToSection aria-label] fail on Hugo 0.146 leg.
   The assertion pinned to $post selected via `find ... | head -1`,
   which on 0.146 picked `doc-sach-quan-sat/index.html` — a post with
   zero h2/h3/h4 headings, so zero heading-anchor markup. Rewrite the
   check to scan all built post HTML (same pattern already in use for
   render-link rel). Now reports 13 matches on the demo build.

2. htmltest URLSwap silently never matched. The prior
   `^/tsuki/: /` config (added in d30f50f) used a regex anchor that
   doesn't match htmltest's substring evaluation against minified
   `href=/tsuki/...` attributes. Switch to the unanchored
   `"/tsuki/": /` form. CI has been failing on this since v0.2.0
   despite the "fix" commit; this is the real fix.

3. head.html referenced `/favicon.ico` and `/favicon.svg` but neither
   asset existed in exampleSite/static/. Add a minimal SVG favicon,
   drop the legacy .ico reference (modern browsers fall back to a
   site-rooted /favicon.ico by convention; sites needing one can
   override head.html). Switch the SVG link to `relURL` so the
   `/tsuki/` baseURL prefix is honoured under GitHub Pages subpath
   deploy.

Local validation: all 32 smoke checks green; favicon resolves to
`/tsuki/favicon.svg` and ships in the build artifact.
2026-05-15 20:18:26 +07:00
tiennm99 a3e1da0fe7 docs(newsletter): review and clean all newsletter posts (excluding #100)
- Append review footer to 101 newsletter posts
- Remove 13 duplicate sections across 11 posts (link kept in earlier post)
- Strikethrough user's personal commentary about AI tools/models in intros
2026-05-15 19:55:16 +07:00
tiennm99 12da47e9b2 docs: v0.3.0 sync — CHANGELOG, accessibility statement, plan close-out
- README: add a11y badge linking to docs/accessibility.md.
- CHANGELOG: full v0.3.0 entry under Unreleased (Added/Changed/Fixed/
  Deferred-to-v0.3.1). Documents per-kind CSS bundles, Tier A
  features, Lighthouse-relevant polish, contrast-token visual diff,
  tap-target sizing decisions, and Hugo CI matrix.
- docs/accessibility.md: new — WCAG 2.2 AA conformance summary,
  Lighthouse measurement instructions, projected baseline (TBD entries
  to fill after first production deploy), known limitations.
- docs/customization.md: cover-image override snippet (v0.4.0 native
  pipeline promise); document breadcrumbs/prev-next/lang-switcher opt-ins.
- plans/260510-0144-tsuki-v0.3.0/: mark all phases completed; note
  narrow-TOC <details> deferral to v0.3.1; record audit-pass scope
  additions integrated into Phases 2–6.
- plans/reports/: add researcher-260515-tsuki-vs-stack-papermod-feature
  -gap.md (verdict: feature parity on must-haves; Tier A gaps shipped
  this round) + code-reviewer-260515-lighthouse-80-baseline-audit.md
  (projected ≥80 on all 4 categories; ≥95 a11y achievable with
  shipped fixes).
2026-05-15 18:56:12 +07:00
tiennm99 6a3ca88fa4 test: expand smoke suite to 32 checks + Hugo CI matrix
scripts/smoke-tests.sh:
- Per-kind CSS budget (home/post/list/archives/search), each ≤ 4200 B gz
- theme-color light/dark meta tags
- aria-pressed SSR on theme-toggle
- breadcrumbs nav + BreadcrumbList JSON-LD presence on post,
  absence on home
- prev/next nav + rel=prev attribute
- linkToSection aria-label on heading anchors
- Speculation Rules absent by default
- llm.txt artifact present
- Pagefind UI preload-swap pattern on /search/
- Giscus preconnect gating (absent when comments disabled)
- Per-kind CSS bundle routing (home loads home.css but not single.css;
  post loads single.css but not home.css)
- code-copy.js gating (post loads it, home does not)

.github/workflows/pages.yml:
- Build matrix on Hugo 0.146.0 (theme.toml floor) + 0.154.0 (current).
  Smoke + htmltest run on both. Artifact upload + deploy gated on
  the current version only.
- Drop the redundant standalone CSS-budget step; smoke-tests.sh now
  enforces per-kind budgets.
2026-05-15 18:55:59 +07:00
tiennm99 b2834749c9 feat: v0.3.0 — Tier A parity, per-kind CSS, llm.txt, a11y baseline
Headline outcomes:
- Feature parity with Stack/PaperMod on Tier A polish: breadcrumbs
  (+BreadcrumbList JSON-LD), prev/next post navigation (rel=prev/next),
  language switcher UI (gated on hugo.IsMultilingual), code-copy button
  polish, <details> styling.
- Per-page-kind CSS bundles: core loads everywhere; home/single/archive/
  search bundles load only where needed. Frees ~1 KB gz from non-post
  pages. code-copy.js gated to post pages.
- Lighthouse-relevant network polish: Pagefind UI CSS preload-swap,
  conditional preconnect to giscus.app on comment-enabled posts,
  hreflang alternates on multilingual sites, <meta name=theme-color>
  light/dark variants, aria-pressed SSR-rendered on theme-toggle.
- WCAG AA contrast: --tsuki-fg-subtle darkened to #6b6b6b (light); was
  3.54:1 on bg, now 5:1. Pagination disabled uses --tsuki-fg-muted
  without opacity compound. Header tap targets bumped to 40×40; pagination
  to 44×44.
- i18n: full i18n/en.yml mirror (~50 keys); render-heading aria-label
  i18n-driven via linkToSection key; new keys for breadcrumb*, prevPost,
  nextPost, copyCode, copiedCode.
- Discovery: /llm.txt output format (llmstxt.org) on home; Speculation
  Rules opt-in via params.prefetch.enable.
- <html lang> fallback: site.Language.LanguageCode → Lang → "en"
  (was hard-coded "vi").

Per-kind bundle gz sizes on demo: home 3673 / post 4167 / list 2897 /
archives 3363 / search 3179 B (all under 4200 B cap).

Plan: plans/260510-0144-tsuki-v0.3.0/
2026-05-15 18:55:47 +07:00
tiennm99 2a6cbed44a docs(referral): add BigModel GLM Coding Plan link and split entries
Separate the general BigModel platform invite (20M free tokens) from
the new GLM Coding Plan referral (5% friend discount, tiered cashback
at 3 and 30 invitees).
2026-05-14 14:03:21 +07:00
tiennm99 69ac7d18ff docs(readme): add content structure and theme customization sections 2026-05-11 21:47:22 +07:00
tiennm99 36dcea28bc docs: flesh out README 2026-05-11 20:15:13 +07:00
tiennm99 c29982ac1d docs: update old repo name learn-netty → try-netty 2026-05-11 17:21:44 +07:00
tiennm99 b6b6a1438d docs: update old repo name MaiBD2021 → mai-birthday-2021 2026-05-11 17:21:41 +07:00
tiennm99 1ff9756881 ci: fix htmltest URLSwap for /tsuki/ baseURL
htmltest was resolving links like `/tsuki/css/foo.css` against
`exampleSite/public/tsuki/...` (which doesn't exist); actual path
is `exampleSite/public/...`. URLSwap strips the baseURL prefix.

Failing on every CI run since v0.2.0 — deploys not propagating.
2026-05-10 03:07:40 +07:00
tiennm99 b43257ccc6 docs: post-v0.2.0 planning + v0.3.0 roadmap
Reports from parallel review agents (code-reviewer, researcher, project-manager)
plus brainstorm synthesis recommending the three-release sequence
(v0.2.0 ships, v0.2.1 patches review P1s, v0.3.0 features).

Plans created:
- plans/260510-0232-tsuki-v0.2.1-patch/  (status: code-complete)
- plans/260510-0144-tsuki-v0.3.0/        (6 phases, ~5d, Phase 1 complete)

Reports:
- code-reviewer-260510-0144: 30 post-v0.2.0 findings (6 P1, 13 P2, 11 P3)
- researcher-260510-0144:    Hugo theme 2026 evolution (WCAG 2.2, llm.txt, Speculation Rules)
- project-manager-260510-0144: v0.2.0 status audit
- brainstorm-260510-0144:    three-release recommendation
- code-reviewer-260510-0244: v0.2.1 patch review (9.7/10, auto-approve)
- tester-260510-0244:        v0.2.1 patch validation (11/11 smoke, CSS 3962/4200)

Cross-linked plan dependencies:
- v0.2.0 prereq → blocks v0.2.1, v0.3.0
- v0.2.1 patch → blocks v0.3.0

Journal: docs/journals/260510-0232-post-v0.2.0-planning-session.md
2026-05-10 03:05:13 +07:00
tiennm99 3295d61ec3 fix: post-v0.2.0 review P1s + CI hygiene (v0.2.1)
Security:
- render-link: drop `| safeHTML` on .Text (self-XSS surface w/ Goldmark unsafe:true)
- projects.html: safeURL + noreferrer + target=_blank on repo/demo
- comments: require repo+repoId+categoryId in gate (prevent broken Giscus iframe)
- htmltest-action: pin to commit SHA 31be84a (supply-chain)

Fixed:
- seo.html: nil-safe \$authorURL chain (no nil.url template error)
- nav.html: relURL on Menu.URL (sub-path deploy correctness)
- pages.yml: drop dead if-find Pagefind guard
2026-05-10 03:04:58 +07:00
tiennm99 0087f33048 chore: archive v0.2.0 roadmap, add prerelease checklist
The 7-phase v0.2.0 implementation roadmap is shipped (commits
6e17ee6..5d73a13). Move it under plans/archive/ so plans/ root only
shows active work.

Add plans/260509-0947-v0.2.0-prerelease-checklist/ capturing what's
left before the v0.2.0 tag and gallery submission: action SHA pin,
phase-07 plan-todo accuracy fix, CI watch, journal, tag, plus
maintainer decisions (Q1 unsafe Goldmark, Q3 audience) and external
tasks (hugoBasicExample smoke, hugoThemes registry PR).
2026-05-09 09:52:00 +07:00
tiennm99 878854ecba refactor: consolidate TOC gate, inline single-call SEO partial, prune unused i18n
- Extract duplicated TOC predicate to _partials/toc-enabled.html
  (single.html + footer.html were both computing the same 6-line gate).
- Inline _partials/head/og-image.html into head/seo.html — single caller,
  the fallback chain is the contract; the partial wasn't earning its
  override surface.
- Drop 6 unused i18n keys: postedOn, tags, categories, archive, noResults,
  copyright. None referenced by any template (verified via grep). Also
  removed an accidental duplicate of the callout title block; vi.yml
  reorganized into thematic groups.

Behavior unchanged. Smoke (11 checks) + Hugo build clean. CSS bundle
unchanged at 3962 B gz.
2026-05-09 09:45:57 +07:00
tiennm99 3cdd8e188b docs: v0.2.0 changelog and implementation roadmap
Document all v0.2.0 phases (audit, a11y, SEO, UX, discovery, release, CI)
with detailed changes. Archive implementation plan and research reports.
2026-05-09 09:32:44 +07:00
tiennm99 9b36ae4928 ci: htmltest smoke tests and build validation
Add htmltest configuration, smoke test script, CSS budget assertion in CI
pipeline for quality gates.
2026-05-09 09:32:40 +07:00
tiennm99 92b90328e5 chore(release): theme metadata, module mounts, installation guide
Update theme.toml with v0.2.0, configure module mounts for clean theme
structure, add comprehensive installation documentation.
2026-05-09 09:32:36 +07:00
tiennm99 a665c3aad8 feat: related posts discovery with configurable algorithm
Add related posts sidebar component, configure related: block in Hugo config,
enable readers to discover similar content.
2026-05-09 09:32:33 +07:00
tiennm99 dab430c133 feat: native Markdown callouts, reading time, archetype scaffold
Add blockquote-to-callout rendering, reading time estimate, improved default
archetype with demo callout content and Vietnamese translations.
2026-05-09 09:32:29 +07:00
tiennm99 a45f750783 feat(seo): JSON-LD Article schema and OG/Twitter cards
Add semantic structured data and social sharing metadata for better
discoverability and previews across platforms.
2026-05-09 09:32:25 +07:00
tiennm99 b9c07dbc98 feat(a11y): skip-link, focus rings, render hooks, giscus paint fix
Add skip-to-content link, enhance focus indicators, implement custom render
hooks for links and images, fix giscus dark mode paint issue.
2026-05-09 09:32:21 +07:00
tiennm99 2d67d3c77f fix: address v0.1.0 audit findings and security notes
Fixes issues flagged in audit: improve footer spacing, meta tag refinement,
code-copy utility robustness, and add security notes to data schemas.
2026-05-09 09:32:17 +07:00
tiennm99 875c76c433 chore: add 1500x1000 screenshot and 900x600 thumbnail for theme gallery
Captured via puppeteer headless Chrome from local exampleSite build.
2026-05-07 22:26:50 +07:00
tiennm99 b0a3760caf feat: docs, changelog, expanded examples for v0.1.0 (Phase 8)
- docs/config.md: full params reference (required + optional + per-post
  frontmatter); explains why theme defaults don't deep-merge into
  consumer sites
- docs/data-schemas.md: profile.yaml + projects.yaml field tables
- docs/customization.md: layout overrides, design token override via
  custom CSS, font self-hosting, per-page color overrides, kill switches
- docs/migrating-from-stack.md: submodule swap, drop list, Stack-to-tsuki
  param mapping, frontmatter compat, gotchas (heading id changes break
  inbound anchor links)
- CHANGELOG.md: complete 0.1.0 entry covering all phases
- README.md: drop "under construction"; add full params snippet, search
  + comments + browser support sections, links to all docs
- exampleSite/data/projects.yaml: +tsuki, +penny-pincher (6 total)

Screenshots, miti99 migration, and v0.1.0 tag are user-driven actions
recorded in phase-08 plan.
2026-05-07 22:20:44 +07:00
tiennm99 8c82df90c9 feat: Pagefind search and Giscus comments (Phase 7)
- search/list.html: Pagefind UI container + module init with full vi
  i18n strings; loads /pagefind/pagefind-ui.{css,js} from generated dir
- search-button.html in header, gated by params.search.enable
- comments.html for Giscus, opt-in via params.comments.giscus.enable;
  reads repo/repoId/category/categoryId/mapping/theme/lang from params
- giscus-theme.js: MutationObserver on data-theme, postMessage iframe
  on toggle so Giscus theme stays in sync with site
- search.css: header-actions row, search button, Pagefind UI tokens
  mapped to tsuki design tokens
- comments.css: min-block-size on iframe to prevent layout shift
- exampleSite/hugo.yaml: commented giscus params block as docs
- i18n/vi.yml: Pagefind UI strings (clear, loadMore, zeroResults...)

Both features no-op when disabled. CSS bundle 3.5 KB gz (budget 15).
2026-05-07 22:03:32 +07:00
tiennm99 52d9eab2b1 feat: visual layer with vi typography, dark mode, view transitions (Phase 6)
- 9 CSS files (tokens, reset, typography, layout, components, home,
  archive, toc, view-transitions) bundled via resources.Concat
- 3 ES module JS files (theme-toggle, code-copy, toc-active); toc-active
  loaded only on long posts
- @view-transition: navigation auto for cross-page morph (CSS-only)
- TOC partial gated by WordCount>400 and Params.toc!=false; sticky on
  wide viewports, framed block on narrow
- render-heading.html adds cosmetic anchor links
- Hugo asset pipeline: resources.Concat | minify | fingerprint (no
  SCSS, no PostCSS, no Node)
- i18n/vi.yml extended with prev/next/posts/archiveEmpty/toggleTheme
- Bundle sizes: CSS 3.3 KB gz (budget 15), JS 0.8 KB gz (budget 8)

Config: github-ascii heading IDs, :contentbasename permalink token for
clean ASCII URLs, pagination.pagerSize migration (Hugo 0.128+).
2026-05-07 21:27:46 +07:00
tiennm99 b665e6dd3f feat: posts, taxonomies, archive (Phase 5)
- post/list.html paginated section list with post-card
- pagination.html partial (renders only when >1 page)
- _default/taxonomy.html for term lists (/tags/, /categories/) with counts
- taxonomy/term.html for single term pages (paginated posts)
- archives/list.html + archive-group.html: year/month grouped flat list
- exampleSite: 4 new posts across 2025-2026, 2 categories, 4 tags, archive index

Modern Hugo 0.146+ template naming: term.html resolved via taxonomy/
path (Hugo 0.154 lookup ignores _default/term.html).
2026-05-07 21:10:28 +07:00
tiennm99 7366d05e24 feat: homepage personal portfolio (Phase 4)
- data/profile.yaml schema: name, handle, tagline, avatar, bio, links
- data/projects.yaml schema: featured projects with title, tagline, repo, demo, image, tags
- _partials/home/hero.html: avatar + name + tagline + bio + social links
- _partials/home/projects.html: data-driven project grid
- _partials/home/recent-posts.html: configurable count, view-all link
- home.html composes hero → projects → recent-posts
- assets/icons: github, mail, rss (Lucide-style)
- exampleSite fixtures: profile, 4 projects, 5 SVG placeholder images
2026-05-07 20:53:06 +07:00
tiennm99 da7a834b8f feat: core layouts and partials (Phase 3)
- baseof.html with named blocks (head_extra, body_class, main, scripts)
- single.html with data-pagefind-body wrapper
- list.html using post-card partial
- home.html placeholder (Phase 4 fills hero/projects/recent-posts)
- 404.html with vi i18n
- _partials: head (full meta + OG + Twitter Card + RSS autodiscovery + theme-flash script), header, nav, footer, meta, post-card, icon
- Sample post fixture in exampleSite to validate render

ci: bump GitHub Actions to Node 24-compatible versions

- actions/checkout v4 → v6
- actions/setup-node v4 → v6, node 20 → 22
- actions/upload-pages-artifact v3 → v5
- actions/deploy-pages v4 → v5
2026-05-07 20:45:31 +07:00
tiennm99 1112fdf039 ci: skip Pagefind step when no HTML pages exist yet 2026-05-07 20:29:33 +07:00
tiennm99 fb0c9e1248 build: add package-lock.json for npm cache in CI 2026-05-07 20:28:23 +07:00
tiennm99 a7f7566094 feat: initial theme scaffold
- Repo metadata: theme.toml, README, Apache-2.0 license
- Hugo defaults: vi language, post permalinks, taxonomies, paginate, TOC config
- exampleSite skeleton with themesDir wiring
- CI: Hugo build + Pagefind index + Pages deploy
- Pagefind devDependency in package.json (Dependabot weekly)
- vi i18n strings, default archetype
- Empty layouts/_partials/_markup/_shortcodes directories ready for Phase 3
2026-05-07 20:27:07 +07:00
tiennm99 807abe02bd Initial commit 2026-05-07 20:25:16 +07:00
tiennm99 e7c0669745 feat(content): add Newsletter #102 with 4 articles on agentic workflows, engineering laws, defensive databases, and productivity 2026-05-05 22:54:37 +07:00
tiennm99 ac6e53946a refactor(content): move Newsletter #100 to correct date-based path 2026-05-05 20:46:32 +07:00
tiennm99 ce72d073fc feat(content): add Newsletter #101 with 8 articles on AI engineering, agents, algorithms, and git 2026-05-04 21:32:08 +07:00
tiennm99 ab107095ac feat(content): add newsletter no.100 2026-05-03 22:46:58 +07:00
tiennm99 42ba06145d refactor(referral): show friend passes inline instead of spoiler 2026-04-29 11:06:15 +07:00
tiennm99 92de741f7d refactor(referral): show claimed Claude Code pass with out-of-stock label
Replace blockquote update with an inline strikethrough list entry so
the pass URL stays visible alongside its status.
2026-04-28 12:31:25 +07:00
tiennm99 08c8c8b456 feat(referral): note Claude Code passes claimed, add friend's pass
- Mark all own Claude Code Guest Passes as claimed (2026-04-28)
- Add friend's pass behind a collapsible spoiler
2026-04-28 12:27:29 +07:00
tiennm99 abbc5dba8c feat(content): add Newsletter #99 with 8 articles on AI quality, API design, IAM, and networking 2026-04-26 20:09:58 +07:00
tiennm99 07201e7ab3 feat(referral): add MiniMax Token Plan referral 2026-04-25 22:46:58 +07:00
tiennm99 f4a533db31 fix(ci): handle clean index after git add in projects workflow 2026-04-22 20:19:00 +07:00
tiennm99 8531e1f962 docs(projects): clarify supported URL types in description 2026-04-22 20:15:28 +07:00
tiennm99 5876b79689 refactor(projects): rename pages section to projects with contributions
- rename content/page/pages → content/page/projects, keep /pages alias
- list owned + contributed repos (GraphQL repositoriesContributedTo)
- filter by URL (homepage or has_pages), not just GitHub Pages enabled
- rename script/workflow to update-projects-list.mjs / update-projects.yml
2026-04-22 20:09:33 +07:00
tiennm99 f9927e6098 feat(ci): replace github-pages shortcode with daily workflow
Fetch repos server-side via GitHub API using PAGES_FETCH_TOKEN and
inject the pages list into content/page/pages/index.md between HTML
markers. Runs daily at 00:00 Asia/Saigon and on manual dispatch.
2026-04-22 19:57:36 +07:00
tiennm99 1763bc2acb refactor(referral): group services into categories 2026-04-22 19:43:36 +07:00
tiennm99 56426d69e8 feat(referral): make ModelArk image clickable to referral link 2026-04-22 19:29:11 +07:00
tiennm99 04f34f01c5 feat(referral): add PikPak cloud storage referral link 2026-04-22 19:17:59 +07:00
tiennm99 1d4f0b7cd6 feat(content): add Newsletter #98 with 11 articles on AI design tools, Go patterns, and engineering careers 2026-04-18 10:00:45 +07:00
tiennm99 3a5183f6e3 feat(content): add Newsletter #97 with 7 articles on AI agents, GC, and engineering practices 2026-04-17 19:38:26 +07:00
tiennm99 8b9f264a3b feat(content): add Newsletter #96 with 6 articles on Go internals, AI agents, and engineering culture 2026-04-16 22:12:00 +07:00
tiennm99 428e7c24a1 feat(content): add article on AI-assisted engineering workflows to Newsletter #95 2026-04-14 21:52:17 +07:00
tiennm99 a9cbf48f48 refactor(skills): convert mt-webfetch script to Node.js for project consistency 2026-04-14 21:46:33 +07:00
tiennm99 4df75a25fb feat(skills): add mt-webfetch fallback + improve mt-add-post URL cleaning and duplicate detection 2026-04-14 21:41:15 +07:00
tiennm99 7f69b0a64f feat(content): add Newsletter #95 with 11 articles on AI, system design, and performance 2026-04-14 21:26:23 +07:00
tiennm99 2e08632407 feat(content): add post about getting entity ID after Hibernate merge 2026-04-11 10:52:16 +07:00
tiennm99 9d638d5464 feat(content): add post about fixing Gradle test OOM with maxHeapSize 2026-04-11 10:51:01 +07:00
tiennm99 4b1aa8aaa9 feat(content): add post about mocking Java time for testing 2026-04-11 10:43:09 +07:00
tiennm99 34b0cd9c78 feat(content): add post about fixing OpenClaw Docker pairing issue 2026-04-05 13:08:46 +07:00
tiennm99 f93e506ef4 feat(content): add Claude Code guest pass referral and reorder referral page 2026-04-04 21:01:51 +07:00
tiennm99 6925d731bf refactor(skills): convert shell scripts to Node.js
Replace bash scripts with cross-platform Node.js equivalents for
mt-add-post and mt-add-tags skills. Update SKILL.md references.
2026-04-02 16:44:48 +07:00
tiennm99 2295bd08a7 feat(content): add Newsletter #94 with 10 articles
Topics: Claude Code internals, AI & tech debt, Slack notifications,
developer workflow, Java performance, Go naming, AI agent skills,
leadership beliefs, programming tricks, shell tricks.
2026-04-02 11:44:11 +07:00
tiennm99 60677a5d09 feat(content): add post about Claude Max, Claude Kit and MiniMax investments 2026-04-01 23:22:41 +07:00
tiennm99 3335b2a249 feat(settings): add claude session-state to gitignore 2026-04-01 17:03:30 +07:00
tiennm99 8eabaab2e0 feat(content): add ClaudeKit referral link 2026-04-01 17:00:47 +07:00
tiennm99 e383275041 refactor(settings): disable project plugins and scope file permissions
Disable commit-commands, skill-creator, and superpowers plugins.
Narrow Edit/Read/Write permissions from wildcard to content directory.
2026-04-01 09:54:01 +00:00
tiennm99 4de3c11229 feat(content): add Newsletter #93 with 7 articles 2026-03-28 14:47:34 +07:00
tiennm99 f8f18eea55 feat(content): add ModelArk referral link 2026-03-25 20:41:09 +07:00