Skip to main content
❯ _
❯ main
  • Home
  • About
  • Hello
  • Feed
  • Email
  • Guestbook
❯ explore
  • Blog
  • Notebook
  • Now
  • Verify
  • Resume
  • Interests
  • Tags
  • Why
  • Changelog
  • Humans
  • Palette
  • Style
  • Privacy
  • Licensing
  • Projects
  • Colophon
  • Meta
  • Search
  • 8biticon
❯ meta
  • PGP Key
  • GitHub
  • LinkedIn
  • Resume.pdf
  • Discord
❯ options

Stops the site's blinking cursor flourishes.

Follows your OS/browser preferred color scheme. Manually switching the theme turns this off.

Shows an animated star field behind the site.

Hiragana rain falls behind the site. Enabling this turns off Stars.

❯ theme

 

 
All systems nominal Email copied!
$HOME / asce1062 / changelog _

Alex.


This is a changelog page1.

$ git log --oneline _

My Tinkering Log

261 total commits

I know I should stop "playing" with my site all the time and focus on writing; but I am having so much fun learning and experimenting with Astro. Want to see what I've been messing with on the webbed site, instead of actually writing content? Here's a list of changes I've made to my Astro site:

View all commits on GitHub

2026

Merge branch 'chore/updates'

May 6, 2026 asce1062 View on GitHub 0d1b039
Commit details
  • chore/updates:

refactor(ui): align interface utility usage

refactor(ui): align interface utility usage

May 6, 2026 asce1062 View on GitHub 1f404f2
Commit details
Apply the shared button utility stack to the guestbook entry actions trigger
and remove duplicated local trigger chrome from the guestbook stylesheet.

- add ordered-list coverage to the style guide prose specimen
- update style guide button personality specimens to the primary variant
- adjust the home Hello action color and add a bug icon on the Hello page

Merge branch 'fix/miscellaneous-issues'

May 4, 2026 asce1062 View on GitHub 5867d4c
Commit details
  • fix/miscellaneous-issues:

fix(layout): align offline assets and content footnotes

fix(layout): align offline assets and content footnotes

May 4, 2026 asce1062 View on GitHub 7215c48
Commit details
Fix two miscellaneous production issues affecting content pages and
offline-capable asset handling.

- allow Workbox asset rules to match image/font/script URLs with query strings
- ignore Netlify dpl deploy query params during precache lookup
- prevent queried static assets from falling through to the offline page
- align MDX footnotes with the active sidebar width when the rail collapses
- animate footnote width and padding with the same sidebar timing

Merge branch 'fix/theme-url-flavor-param'

May 4, 2026 asce1062 View on GitHub dfded12
Commit details
  • fix/theme-url-flavor-param:

fix(theme): support URL theme and flavor overrides

fix(theme): support URL theme and flavor overrides

May 4, 2026 asce1062 View on GitHub 9729ffc
Commit details
Add URL-driven appearance handling for theme and flavor while preserving
manual theme switching after a URL theme has been applied.

- apply ?theme=light|dark before paint without persisting it
- apply ?flavor=<id> before paint and persist explicit flavor selections
- retain stored/current flavor when a later URL only provides ?theme=
- keep shareable URLs intact when users toggle theme manually
- preserve match-device behavior when no URL theme override exists
- add regression tests for URL theme toggles and flavor retention

Verification:
- npx vitest run src/scripts/tests/themeManager.test.ts

Merge branch 'feature/style-guide-page'

May 4, 2026 asce1062 View on GitHub d73f488
Commit details
  • feature/style-guide-page:

feat(style): add personal style guide page

feat(style): add personal style guide page

May 4, 2026 asce1062 View on GitHub f671bb2
Commit details
Add /style as a writing-first field manual for alexmbugua.me, with
editorial voice rules, title conventions, formatting guidance, technical
writing standards, rule-breaking notes, and before/after examples.

- document supporting interface specimens for tokens, type, prose, links,
badges, buttons, forms, controls, cards, and terminal accents
- add the Style route to Explore navigation
- update the IcoMoon font build with the style-page icon set
- update the IcoMoon preload cache key in the shared layout

Merge branch 'chore/palette-theme-flavors'

May 4, 2026 asce1062 View on GitHub 31a6f16
Commit details
  • chore/palette-theme-flavors:

feat(palette): document theme flavor tokens

feat(palette): document theme flavor tokens

May 4, 2026 asce1062 View on GitHub fb26d83
Commit details
Expand the design token registry so the palette page reflects the current
light, dark, and flavor-aware color system.

- add semantic color roles, base theme OKLCH values, and all theme flavor token sets
- add a palette Flavors tab with dark/light token grids and copyable OKLCH values
- update email and console consumers to use current semantic token mappings
- resolve console colors from live CSS variables so active flavors affect the console egg
- add the flask-florence icon to IcoMoon and update the font preload cache key

Merge branch 'update/blog-content'

May 4, 2026 asce1062 View on GitHub d20e945
Commit details
  • update/blog-content:

update(content[blog]): add one about being brave enough to begin

update(content[blog]): add one about being brave enough to begin

May 4, 2026 asce1062 View on GitHub e3892e6

Merge branch 'fix/avatar-exploratory-state'

May 1, 2026 asce1062 View on GitHub ad7f9f0
Commit details
  • fix/avatar-exploratory-state:

fix(avatar): discard unsaved exploratory state

fix(avatar): discard unsaved exploratory state

May 1, 2026 asce1062 View on GitHub 19f775f
Commit details
Keep avatar edits exploratory until the user explicitly saves or opts in
through guestbook avatar submission.

- initialize the full avatar generator from saved localStorage state or defaults
- prevent randomize, layer edits, and gender changes from rewriting the page URL
- build share URLs on demand from the current exploratory avatar
- reset mini avatar widgets to saved/default state when they initialize
- preserve guestbook opt-in as an explicit save path
- add focused coverage for saved/default initialization and exploratory edits

Merge branch 'fix/avatar-generator-responsive-layout'

May 1, 2026 asce1062 View on GitHub 82a975d
Commit details
  • fix/avatar-generator-responsive-layout:

fix(avatar): make generator layout fully responsive

fix(avatar): make generator layout fully responsive

May 1, 2026 asce1062 View on GitHub 274b7a3
Commit details
Center the 8-bit avatar generator once the preview and selection areas
collapse into a single column, so the picker no longer sits left-aligned
during intermediate viewport widths.

- constrain preview and selection sections to the same stacked width
- center the selection section and layer picker in single-column layout
- keep desktop side-by-side layout and mobile picker height behavior intact
- preserve the updated avatar save/share action treatments

Merge branch 'fix/avatar-generator-responsive-selection'

May 1, 2026 asce1062 View on GitHub 04c62c8
Commit details
  • fix/avatar-generator-responsive-selection:

fix(avatar): improve generator controls responsiveness

fix(avatar): improve generator controls responsiveness

May 1, 2026 asce1062 View on GitHub 23ba6ec
Commit details
Refine the 8-bit avatar generator layout so the layer picker and preview
controls stay balanced across desktop and mobile views.

- make the layer tabs compact and shrink-wrapped when all tabs fit
- keep horizontal tab scrolling available only for narrow views
- preserve mobile picker height while increasing desktop selection height
- move save and share into icon actions below the avatar preview
- use primary-to-accent icon states for save/share hover and focus
- keep Randomize and Download as the main lower action buttons

Merge branch 'fix/mobile-terminal-neofetch-size'

May 1, 2026 asce1062 View on GitHub 7a22d83
Commit details
  • fix/mobile-terminal-neofetch-size:

fix(terminal): tune mobile neofetch text scale

fix(terminal): tune mobile neofetch text scale

May 1, 2026 asce1062 View on GitHub 68dd798
Commit details
Reduce the floating terminal's mobile neofetch/system output text so it no
longer appears larger than the init messages.

- size mobile system art and metadata rows to match the smaller status text
- reduce the system font label one step further for visual hierarchy
- keep regular terminal log, command, and init message sizing unchanged

feat(notification): redesign share feedback toast

May 1, 2026 asce1062 View on GitHub 36780c6
Commit details
Replace the flat share notification with a launch-stamp treatment that better
matches the site's retro-cosmic visual language.

- add a rocket sigil rail and compact stamped notification layout
- move notification-specific CSS out of global.css
- keep the existing framed error close button treatment
- show the dynamic copy message as muted supporting text
- rotate through common and rare static notification titles on display
- replace the plain slide animation with a clipped launch/depart motion

Verification:
- npm run test -- src/scripts/tests/feedbackManager.test.ts

fix(notification): use shared button styling for close control

April 30, 2026 asce1062 View on GitHub 9d5b6e1
Commit details
Replace the custom share notification close-button styles with the existing
button classes so the control matches the site's framed error button treatment.

- apply shared btn, btn-frame, btn-error, and btn-xs classes to the close button
- switch the close icon to the larger x-lg glyph
- remove the old notification-only close-btn CSS

fix(navbrand): stabilize sidebar text-effect state

April 30, 2026 asce1062 View on GitHub d87b34b
Commit details
Keep nav-brand copy ownership inside the coordinator so hover, resume,
return, and terminal-context messages do not race through DOM mutations.

- drive greeting, teaser, and visit-count updates through the shared text
effect API
- respect each element's declared random-effect configuration when the
coordinator starts an effect
- keep hover/focus terminal affordances scoped to the teaser line
- delay return-to-active settling until the return greeting finishes
- gate terminal-specific sidebar greetings until the terminal is open or docked
- remove obsolete cursor and hint-state exports after the prompt cursor moved
into the typing effect

Verification:
- npm run test -- src/lib/tests/navBrandMessages.test.ts

feat(sidebar): add nav-brand email copy and visit count

April 30, 2026 asce1062 View on GitHub c1eef7e
Commit details
Add lightweight utility interactions to the expanded sidebar nav-brand.

- copy the site email from the nav-brand identity line using the shared
clipboard/notification flow
- render the visit count after the shell prompt path with the shared typing
effect
- remove the redundant trailing underscore cursor and its cursor-mode styling

feat(share): prefer native device share

April 30, 2026 asce1062 View on GitHub 54a726a
Commit details
Add shared native-share-first behavior for site share surfaces while keeping
clipboard copy as the fallback.

- add shareOrCopyToClipboard to centralize Web Share API handling
- use native share for blog post, avatar, and guestbook entry share actions
- keep copy-only guestbook actions on the existing clipboard path
- center the blog share label and icon row without breaking mobile wrapping
- treat native share cancellation as a no-op instead of copying unexpectedly
- cover native share success, cancellation, unavailable API, and fallback copy

Verification:
- npx vitest run src/scripts/tests/feedbackManager.test.ts

fix(toc): offset anchors below sticky contents

April 30, 2026 asce1062 View on GitHub d2bbe6d
Commit details
Keep headings visible when selecting entries from the sticky table of
contents.

- define the default anchor scroll offset as a layout token
- measure the rendered TOC height at runtime and publish it to the token
- use the token for heading scroll margins instead of a fixed value
- update the offset after details toggle and viewport resize events

feat(social-share): add fediverse and forum targets

April 30, 2026 asce1062 View on GitHub 6d0360c
Commit details
Add Bluesky, Reddit, Mastodon, and LinkedIn targets to the content share
controls.

- use updated IcoMoon classes for the new platform icons
- refresh generated IcoMoon font assets and demo metadata
- update the Layout font preload hash to match the regenerated woff asset

fix: improve low-brightness atmosphere tokens

April 29, 2026 asce1062 View on GitHub 3044a05
Commit details
Separate decorative atmosphere colors from structural surface tokens so
background texture, matrix rain, and guestbook card patterns remain legible
without brightening borders, cards, or base surfaces.

- adds per-theme and per-flavor ink roles for:
- atmosphere texture
- guestbook card patterns
- matrix rain glyphs
- updates topography masks in global and sidebar styles to use atmosphere ink
- updates matrix rendering to read the matrix rain token
- gives sidebar flavor swatches fixed representative colors
- moves guestbook browser card, preview, and swatch masks to guestbook pattern ink
- updates guestbook notification and entry-copy emails to recolor notecard SVGs with email-safe pattern ink
- isolates missing-pepper hash tests from local GUESTBOOK_HASH_PEPPER values

chore(misc): update terminal scanlines and footnotes styling

April 22, 2026 asce1062 View on GitHub 81c8a67
Commit details
Updated terminal-windowbody scanlines to be more visible and theme-aware

- Moved scanlines into terminal-window
body::before so they overlay the terminal body without affecting layout.
- Increased line visibility from the old very subtle 2% content mix to 9%.
- Used a 2px transparent / 2px line rhythm similar to your reference.
- Added a subtle secondary-color sweep so it feels integrated with the terminal theme.
- Raised log and prompt content above the overlay with z-index: 1.

Updated footnotes styling for better readability and aesthetics
- Add numbering styles to the <ol> inside .footnotes:

feat(text-effects): add lifecycle motion language

April 22, 2026 asce1062 View on GitHub 0bb2362
Commit details
Redesign the terminal text effect engine from reveal-only playback into lifecycle-aware motion with effect metadata, paired enter/exit
families, standalone flourishes, cancellation, reduced-motion fallbacks, and declarative trigger coordination.

Add type, cipher, and rare signal families: typing/backspace, decrypt/entropy, and glitch-lock-on/signal-loss. Tune short/long text
pacing, terminal block cursor behavior, backspace realism, signal dropout holds, and rare signal visuals so they read differently from cipher
effects.

Add content-change, delayed route-enter settling, bind-time load delay support, hover replay guards, random-effect eligibility, and
registry-backed sidebar/header/terminal flourish wiring through data-text-effect attributes.

Move sidebar navbrand flourishes out of navBrand state policy and into declarative Sidebar.astro markup. Remove the navbrand-specific
effects adapter and transition-effect chooser so navBrand remains responsible for state, copy, cursor, and terminal nudges only.

Update tests for metadata, parser support, reduced motion, paired transitions, interruption restoration, rare signal behavior, content-
change, route-enter settling, sidebar declarative behavior, and navbrand state cleanup.

feat(text-effects): wire paired motion transitions

April 22, 2026 asce1062 View on GitHub 1915839
Commit details
Promote changed stable text from enter-only reveal into full paired transitions so typing uses backspace first, decrypt uses entropy first, and rare lock-on effects can use signal-loss.

Wire navbrand through runTerminalTextTransition instead of reset-then-reveal so the previous greeting remains available for the exit phase.

Add rare-family motion metadata and renderers for glitch-lock-on and signal-loss while keeping rare effects opt-in through explicit data-text-effect declarations.

Expand header greeting and terminal atmosphere declarations with reversible type/cipher exit effects and preserve terminal atmosphere stable text with data-text-effect-stable-text.

Document the motion model: public effect names, internal families, lifecycle roles, standalone safety, stable text caching, and paired-transition inference.

Expand focused tests for rare metadata/parser support, paired full-transition promotion, rare transition playback, and navbrand paired-transition behavior.

feat(text-effects): build terminal motion foundation

April 22, 2026 asce1062 View on GitHub 4b37a31
Commit details
Introduce effect metadata for terminal text effects, including family, lifecycle role, standalone eligibility, and reduced-motion strategy.

Add runTerminalTextTransition as the lifecycle-aware coordinator for enter-only, exit-only, standalone, and full text transitions.

Split playback into renderer functions for typing, backspace, decrypt, and entropy instead of continuing to expand the old branch-heavy playback path.

Centralize reduced-motion fallback behavior in the generic engine and add a neutral data-text-effect-stable-text cache while preserving data-greeting-target compatibility.

Decouple navbrand effect typing from hardcoded typing/decrypt values so the shared engine owns the generic effect vocabulary.

Expand terminal text effect tests for metadata, parser support, reduced motion, standalone backspace, backspace-to-typing transitions, cancellation restoration, entropy, and standalone-safe randomization.

feat(navbrand): polish terminal command surface

April 22, 2026 asce1062 View on GitHub 25d7cd8

feat(navbrand): polish terminal command output

April 22, 2026 asce1062 View on GitHub 4f8db89

feat(navbrand): strengthen terminal command base

April 21, 2026 asce1062 View on GitHub 2a97d35

feat(navbrand): refine terminal command output

April 21, 2026 asce1062 View on GitHub 4000c60

feat(navbrand): add staged terminal system profile

April 18, 2026 asce1062 View on GitHub d2ad500

feat(navbrand): update sidebar teaser assets and styles

April 18, 2026 asce1062 View on GitHub 61551b7

feat(navbrand): polish terminal interactions and button styles

April 18, 2026 asce1062 View on GitHub 93b28e3

feat(navbrand): add terminal teaser entry points

April 17, 2026 asce1062 View on GitHub 122277a

feat(navbrand): move commands into terminal modal

April 17, 2026 asce1062 View on GitHub 25dc177

feat(navbrand): add shared terminal modal shell

April 17, 2026 asce1062 View on GitHub 02b7166

refactor(navbrand): share terminal open event contract

April 17, 2026 asce1062 View on GitHub 19f57b5

refactor(navbrand): restore sidebar terminal teaser

April 17, 2026 asce1062 View on GitHub 5461592

test(navbrand): harden terminal helper contracts

April 17, 2026 asce1062 View on GitHub c115b51

test(navbrand): add terminal window and prelude helpers

April 17, 2026 asce1062 View on GitHub ebb598c

feat(navbrand): add action command intents

April 17, 2026 asce1062 View on GitHub a96a6ae

feat(navbrand): add search handoff support

April 17, 2026 asce1062 View on GitHub 0251036

feat(navbrand): add typed command launcher

April 17, 2026 asce1062 View on GitHub 526b6d9

feat(navbrand): align phase 3 launcher foundation

April 17, 2026 asce1062 View on GitHub 84a65ab

docs(effects): clarify flourish contracts and extension points

April 17, 2026 asce1062 View on GitHub 2faa281

refactor(effects): add declarative text effect registry

April 17, 2026 asce1062 View on GitHub 955cf70

feat(effects): expand shared text effect triggers

April 17, 2026 asce1062 View on GitHub 09900b0

refactor(effects): share terminal text transitions

April 17, 2026 asce1062 View on GitHub 5547554

feat(navbrand): add phase 2 transition effects

April 17, 2026 asce1062 View on GitHub 9ed0c10

feat(navbrand): add phase 1 presence engine coordinator

April 17, 2026 asce1062 View on GitHub 961937b

test(navbrand): add phase 1 message and state helpers

April 17, 2026 asce1062 View on GitHub fda0a63

fix(icomoon): font preload warning

April 16, 2026 asce1062 View on GitHub 9cb9368
Commit details
Reordered the IcoMoon @font-face sources to prefer woff before ttf.

Diagnosis:
- Layout.astro preloads /fonts/icomoon/fonts/icomoon.woff?4weq0r.
- But icomoon/style.css declares ttf before woff in @font-face.
- So the browser could preload woff and then still choose ttf,
which triggers the "preloaded but not used" warning.

refactor(sidebar): refine sidebar behavior and unify ascii widget handling

April 16, 2026 asce1062 View on GitHub b396680

refactor(security): rename guestbook hash salt to pepper and harden prod config

April 16, 2026 asce1062 View on GitHub 865ab36

Merge branch 'feat/navbrand-redesign'

April 16, 2026 asce1062 View on GitHub 5fb4aed
Commit details
  • feat/navbrand-redesign:

fix(navbrand): guard NaN corruption, negative elapsed, and sessionStorage exceptions
chore(privacy): document nav-brand-visits and nav-brand-last-visit keys
fix(navbrand): collapse hidden sub-row and increase max-height for expanded content
feat(navbrand): replace nav-brand-prompt CSS with shell prompt styles
feat(navbrand): update Sidebar.astro HTML structure
feat(navbrand): add DOM rendering and event listeners
feat(navbrand): add pure functions with unit tests
chore(prefs): add navBrandVisits and navBrandLastVisit keys

fix(navbrand): guard NaN corruption, negative elapsed, and sessionStorage exceptions

April 16, 2026 asce1062 View on GitHub af10b86

chore(privacy): document nav-brand-visits and nav-brand-last-visit keys

April 16, 2026 asce1062 View on GitHub e1b6b12

fix(navbrand): collapse hidden sub-row and increase max-height for expanded content

April 16, 2026 asce1062 View on GitHub 7374f78

feat(navbrand): replace nav-brand-prompt CSS with shell prompt styles

April 16, 2026 asce1062 View on GitHub aeb4d60

feat(navbrand): update Sidebar.astro HTML structure

April 16, 2026 asce1062 View on GitHub 120cffe
Commit details
Replace badge-stack nav-brand with multi-line visitor-aware shell prompt
layout and wire up the navBrand script import.

feat(navbrand): add DOM rendering and event listeners

April 16, 2026 asce1062 View on GitHub 0456016

feat(navbrand): add pure functions with unit tests

April 16, 2026 asce1062 View on GitHub 9b38293

chore(prefs): add navBrandVisits and navBrandLastVisit keys

April 16, 2026 asce1062 View on GitHub 88b0c5f

feat(tab): tiered idle title rotation with 12-message set

April 15, 2026 asce1062 View on GitHub 28479cf
Commit details
Three tiers keyed to idle duration
— playful (0-10s), system (10-30s), cosmic (30s+)
— cycling every 8s via setInterval. Index resets on tier
transition. Timer clears on tab focus restore.

chore(privacy): document three new localStorage keys

April 15, 2026 asce1062 View on GitHub 16fffcc
Commit details
Added theme-flavor, theme-transition, and sidebar-collapsed to all
privacy disclosures. All three disclosure files now
consistently declare nine localStorage keys.

- src/pages/privacy.astro
- six to nine
- added three <li> entries
- src/components/PrivacyPolicy.astro
- five to nine
- updated prose
- public/.well-known/dnt-policy.txt
- six to nine
- three new bullets
- "contact us" to "contact me"
- reassertion date 2026-04-15

fix(pwa): resolve service worker 404 on Netlify SSR builds

April 14, 2026 asce1062 View on GitHub f5c531c
Commit details
Update @vite-pwa/astro to pkg.pr.new/astro@73 (Astro 6 / Vite 6
compatibility pre-release) and add a custom pwa-sw-copy-to-dist
integration to bridge the build output mismatch.

Root cause: @astrojs/netlify v7 sets config.build.client to
.netlify/build/ (the SSR function directory). @vite-pwa/astro reads
this at config-setup time and writes sw.js + workbox-*.js there
instead of dist/ where Netlify serves static files.

The custom integration hooks into astro:build:done (runs after the
PWA integration) and copies sw.js and workbox-*.js from .netlify/build/
to dist/, falling back silently on local static builds where
.netlify/build/ is absent.

fix(pwa): set explicit globDirectory to suppress Workbox precache warnings

@astrojs/netlify v7 sets config.build.client to .netlify/build/ (the
SSR function bundle directory). @vite-pwa/astro picks this up as
globDirectory, finds no CSS/HTML/font assets there, and emits
"glob pattern doesn't match any files" warnings (leaving the precache
manifest empty).

Explicitly setting globDirectory to dist/ in the workbox config takes
precedence over the integration's auto-detected value, pointing Workbox
at the correct static output directory where all built assets live.

feat(sidebar): add collapsible desktop sidebar rail with bookmark tab

April 14, 2026 asce1062 View on GitHub 52ec810
Commit details
Implements a two-state collapsible sidebar for desktop (lg+).

Key design decisions:
- Sidebar width animation is the primary motion driver.
- All other elements follow its lead via CSS transitions and timing.
- Overflow switches to visible after the width animation completes
(transition: overflow 0s delay trick) so tooltip ::after pseudo-elements
can escape the panel once settled
- Nav-text uses opacity-only fade with a delayed max-width snap (no squish)
- Section labels, hidden sections, and footer are hidden via visibility:hidden
with no transition (the sidebar clip handles their visual disappearance)
- Header brand (prompt <> avatar) crossfades via opacity only
- Active item box-shadow removed in collapsed rail (too wide for 3.5rem)
- State persisted to localStorage and re-stamped on astro:after-swap to
survive Astro ClientRouter soft navigations
- Easter egg hidden instantly (display:none) to prevent flicker animation
playing during collapse
- Bookmark tab sits at z-39 (behind sidebar z-40) and slides out 14px on
hover via transform — no clip-path needed
- CSS-only tooltips (::after/::before) on nav-link[data-tooltip] in
collapsed mode, keyboard accessible
- Preference key: PREF_KEYS.sidebarCollapsed in lib/prefs.ts
- --sidebar-current-width CSS var drives both sidebar width and content
margin-left offset
- Desktop only, behavior unchanged on mobile

Files: Sidebar.astro, Layout.astro, sidebarCollapse.ts, sidebar.css,
prefs.ts, global.css, theme.css, icomoon (collapse/expand icons)

Squashed commit of the following:

April 13, 2026 asce1062 View on GitHub 3b6f5ee
Commit details
commit 361941368c9fa99c553cefde47c5284550c0ef6c
Author: asce1062 <tnkratos@gmail.com>
Date: Thu Apr 9 14:46:55 2026 +0300

chore(ctv2): misc adjustments

commit 320a1092796cb7283215f2c4bfad14ed6fa7a986
Author: asce1062 <tnkratos@gmail.com>
Date: Wed Apr 8 19:51:44 2026 +0300

feat(transitions): add switchFlavor - resolves effective style and calls atomicSwitch

commit 6ad6f423efa7ffc435fae9e565adb9d10de20b09
Author: asce1062 <tnkratos@gmail.com>
Date: Thu Apr 9 00:22:10 2026 +0300

feat(transitions): add transition pill styles to sidebar CSS

commit b4b20f466fe726378d2a9895b0c33bc9cf90ead2
Author: asce1062 <tnkratos@gmail.com>
Date: Thu Apr 9 00:05:12 2026 +0300

feat(transitions): implement scanline handler with CRT raster bands and halo beam

commit 31cf6cf9c0d6fd806d62f3acbe57e405167e0993
Author: asce1062 <tnkratos@gmail.com>
Date: Wed Apr 8 19:33:42 2026 +0300

feat(transitions): add transition manager - pref read/write and pill sync

commit c968445f7082624e68a60d032d1eba6575e70b79
Author: asce1062 <tnkratos@gmail.com>
Date: Wed Apr 8 19:58:55 2026 +0300

feat(transitions): pass context to atomicSwitch in handleThemeToggle

commit 3ad7b1a646113161eb0fbded9deeeb4e17b05235
Author: asce1062 <tnkratos@gmail.com>
Date: Wed Apr 8 19:45:54 2026 +0300

refactor(transitions): atomicSwitch dispatches to registry with cancel-and-replace guard

- Replace themeTransition.ts: atomicSwitch now accepts TransitionContext,
resolves style from stored pref, guards against terminal on init/soft-nav,
cancel-and-replaces any in-flight transition, dispatches to registry handler
- Add transitionState.ts: isolated cleanup-closure state to break circular dep
- Re-export registerTransitionCleanup from themeTransition for backward compat
- Deprecate initTransitionOverlay as a no-op stub (handlers own the overlay)
- Add "programmatic" to TransitionContext.source union in transitionRegistry

commit 5465dbf6f863817ebe280b6cc5e9c2d2cc3f179c
Author: asce1062 <tnkratos@gmail.com>
Date: Wed Apr 8 14:04:59 2026 +0300

feat(transitions): add transition registry - types, mapping, pure helpers, none handler

Introduces transitionRegistry.ts with:
- TransitionStyle union type and TRANSITION_STYLES constant
- FLAVOR_TRANSITION_MAP covering all 8 flavors
- getMappedTransitionForFlavor() and resolveEffectiveTransitionStyle() pure helpers
- TransitionContext interface and TransitionFn type
- Exported getOverlay/wait/clamp helpers for use by overlay-based transition handlers (scanline, phosphor, retune, etc.)
- Full transitionRegistry record with none handler + stubs for all 8 styles
- 13 tests covering map coverage, per-flavor lookups, and resolve priority

commit 8ace8afc5b3d523fc39825bb708e2c5d8381cbcd
Author: asce1062 <tnkratos@gmail.com>
Date: Wed Apr 8 13:57:03 2026 +0300

feat(transitions): add PREF_KEYS.transition preference key

commit b0fe9f572076beb80bafdf88bcd6b42ac80da525
Author: asce1062 <tnkratos@gmail.com>
Date: Mon Apr 6 23:15:43 2026 +0300

feat: 7-flavor optional theme system and dark/light overhaul

Add a flavor picker to the sidebar with 8 opt-in color overlays (default +
crt-green, amber, synthwave, dos, void, ice, redline). Each flavor overrides
OKLCH color tokens on html[data-theme="dark"][data-flavor="X"] for dark-mode-
native theming without touching light mode.

- theme.css: 7 flavor blocks (full OKLCH palette per flavor), boosted dark
base surface chroma (base-200/300 from 0.004→0.010/0.012 at hue 270),
semantic tokens (--color-heading, --color-link, --color-muted, --color-code-bg)
- global.css: split coupled h2+a rule into separate heading/link semantic tokens
- flavorManager.ts: flavor type, FLAVORS/LABELS/SWATCHES exports, setFlavor,
applyStoredFlavor, syncSwatches, initFlavorPicker with AbortController
- flavorPicker.ts: entry script wired to astro:after-swap + astro:page-load
- prefs.ts: add flavor key ("theme-flavor")
- Layout.astro: early-init is:inline script stamps data-flavor before paint
- Sidebar.astro: flavor section with 8 swatch buttons (data-flavor-btn)
- sidebar.css: .nav-flavor-picker/.nav-flavor-swatch styles with active glow

commit 5b9491ba74c5ce0a123d092593133ab5455b7945
Author: asce1062 <tnkratos@gmail.com>
Date: Mon Apr 6 22:50:10 2026 +0300

feat: semantic color tokens and warm void depth

- Add --color-heading/--color-link/--color-muted/--color-code-bg semantic tokens
to decouple h2 and link colors (previously both --color-warning = no hierarchy)
- Split h2, a { color: warning } into separate rules using semantic tokens:
h2 → --color-heading (amber, phosphor warmth)
a → --color-link (orange in light, coral in dark)
- Boost dark base surface chroma: base-200/300 from 0.004 to 0.010–0.012
at hue 270 to match base-100's purple ghost - surfaces now feel chromatic
- Strengthen dark mode glow tokens: active +4px, accent +4px, identity +8px
- Deploy --glow-accent to three surfaces: link-action hover, input focus,
layer tab active state

commit e3832a7de8215ce09b4e1ba5c5e54b04cf887ade
Author: asce1062 <tnkratos@gmail.com>
Date: Mon Apr 6 22:00:18 2026 +0300

fix: a11y, hardening, and greeting polish

- fix(404): add sr-only h1 to restore heading hierarchy (WCAG)
- fix(preview): replace shadow-xl with elevation token
- fix(avatar): layer tab icons visible (color: transparent → token)
- fix(avatar): add role=tablist/tab + aria-selected to LayerTabs
- fix(avatar): sync aria-selected on switchLayer + gender/ext changes
- fix(guestbook): AbortController cleanup for document-level listeners
- fix(guestbook): ArrowUp/Down keyboard nav for role=menu entry actions
- fix(guestbook): auto-focus first menuitem on open; borderRadius → 0rem
- fix(guestbook): expand entry-actions-trigger tap area to 44px (WCAG 2.5.5)
- fix(sidebar): expand nav-avatar-btn to 44px tap target
- fix(sidebar): most-specific active link match (no false /blog highlight)
- fix(search): center floating modal within content area on lg+ (sidebar offset)
- fix(greeting): inline-block constrains hover zone to text width only
- fix(greeting): period now scrambles in decrypt animation

commit 083be1a0b36aaa401d2d02eeb8d12bc96537af45
Author: asce1062 <tnkratos@gmail.com>
Date: Mon Apr 6 21:22:14 2026 +0300

chore: polish scope transitions and fix listener leaks

Scope transition-all → specific GPU-safe properties across components:
- Header, ThemeSwitcher, guestbook random btn: transition-[color,transform]
- ProjectCard link: transition-colors (color changes only)
- PreviewImage: transition-transform (scale only)
- BackToTop: transition-[opacity,transform,visibility] (fade + scale)
- scrollProgress: transition-[width] (only width changes)

Zero-radius: BackToTop rounded-full → rounded-none (UI control, not avatar)

scrollProgress: add AbortController so scroll listeners don't accumulate
across Astro soft navigations (same pattern as sidebarNav, FloatingSearch)

commit f8d1ab857d017927575e7a1a2743acc759645b77
Author: asce1062 <tnkratos@gmail.com>
Date: Mon Apr 6 21:14:16 2026 +0300

fix: harden FloatingSearch against listener accumulation

Memory leak: window/document event listeners (resize, scroll, orientationchange,
keydown x2) and ResizeObserver were never cleaned up between Astro soft
navigations, causing them to pile up on each astro:page-load reinit.

Fix: Add AbortController (_ac) and ResizeObserver ref (_ro) at module scope.
Each init tears down the previous set before registering new listeners -
identical pattern to sidebarNav.ts.

Also:
- Restore focus to the triggering element on modal close (accessibility)
- Replace setTimeout(fn, 100) focus call with requestAnimationFrame
- Scope transition-all → transition-opacity on modal div (GPU path only)

commit 88b7ce7be00be724f47f77b6e47081744e162cc3
Author: asce1062 <tnkratos@gmail.com>
Date: Mon Apr 6 21:08:59 2026 +0300

perf: optimize font loading and containment

Font loading:
- Add <link rel="preload"> for 0xProto-Regular, 0xProto-Bold, 0xProto-Italic,
and icomoon.woff before CSS is parsed - reduces FOUT window for body text
and nav icons

CSS containment:
- Add contain: layout style to .nav-menu (sidebar is a self-contained panel;
internal changes no longer trigger external layout recalculations)

Transition scope:
- AvatarGenerator layer items: transition:all 0.2s → specific border-color/box-shadow
- ContentCard link: transition-all duration-300 → transition-colors duration-200

commit abec107b6cfd0f374a2ff04bbea96ac87427f528
Author: asce1062 <tnkratos@gmail.com>
Date: Mon Apr 6 20:52:11 2026 +0300

chore: centralize and tokenize all transition/animation literals

Replace every hardcoded timing literal (0.1s–0.3s) and bare ease keyword
across the CSS system with motion design tokens. Scope broad transition: all
to specific properties for GPU-accelerated paths only.

Files updated:
- global.css, sidebar.css, collapsible-nav.css - dark-mode, nav, and chevron transitions
- btn.css, toggle.css - interaction feedback timings
- link-action.css - already committed in previous session
- input.css, checkbox.css - utility component transitions
- guestbook.css - entry bubble, swatch, actions trigger, action item
- search.css - pagefind clear button, result row, result link
- avatar.css - gender-option, layer-tabs, layer-tab (narrowed from transition:all)

Intentional exceptions kept as literals:
- asciiWidget.css: diceSpin 0.5s (one-shot effect)
- guestbook.css: entry-highlight 1.5s (narrative anchor animation)
- asciiReveal.css: art-scan, flicker sequences (effect timings)

commit 66b054482e3a1e8a4ba6d59813fb73a01bfc1c22
Author: asce1062 <tnkratos@gmail.com>
Date: Mon Apr 6 20:29:11 2026 +0300

chore: align with standards

- guestbook.css entry-bubble + textarea-wrapper border-radius
0.25rem → 0rem; defends zero-radius identity in guestbook UI
- global.css share-notification box-shadow → var(--elevation-3);
sidebar.css 800ms literal → var(--duration-crawl) var(--ease-out);
link-action.css 0.2s literals → var(--duration-base)
- meta.astro + guestbook.astro rounded-md/rounded-none;
all public pages now comply with zero-radius identity
- heading transition-all → transition: font-size var(--duration-instant)
on h1/h2/h3/.site-greeting; scoped to font-size only, not all properties

commit 4480359046d5e9bf1cfcab604255f4e633958ebe
Author: asce1062 <tnkratos@gmail.com>
Date: Sat Apr 4 22:32:40 2026 +0300

chore: update layout and language

- remove b{color:warning} from components layer.
- bold text in prose no longer inherits warning color
- remove h4 from warning color selector (h2,h4,a → h2,a);
- h4 is rarely used and warning color should be intentional, not default
- humanize sidebar option descriptions
- Avoid mechanical phrasing and jargon; now conversational
- aria labels updated from generic "Visit the X page"
- pattern to action-oriented descriptions (read, browse, sign, search)
- about.astro resume copy - "digital version of my resume
available here" → "My resume is available here"

commit f45d1d7688d0686b1738f3f9a7b47115f5cf758e
Author: asce1062 <tnkratos@gmail.com>
Date: Sat Apr 4 17:01:26 2026 +0300

feat: visual identity push

- faded-text gradient reduced from 5-stop rainbow to 2-stop
primary→accent (warm void palette only); references motion tokens
- add glow token vocabulary to theme.css - glow-active,
glow-accent, glow-identity
- apply glow-active to active nav link (inset coral wash);
apply glow-identity text-shadow to site greeting
- homepage exit section - Hello link-action upgraded to
link-action--primary; one clear primary CTA vs three equal-weight items
- greetingReveal.ts - site greeting decrypts through CRT block
drawing characters on page load, mouseenter, and
touchstart; cancel-and-restart on rapid re-trigger; reduced motion
respected; content always visible before JS runs
- sidebar brand prompt - blinking cursor added after :~$ badge
- greeting scramble chars using terminal block/box-drawing glyphs
- nav section labels - remove success badge from section names;
replace with .nav-section-name plain text at neutral-content color;
6 fewer competing badges across main/explore/meta/options sections
- contact prominence on homepage - Hello and Verify link-actions
in exit section; bio copy revised

commit c04b69965f45a972ed0dcd8f236fd5a4a6eeaecd
Author: asce1062 <tnkratos@gmail.com>
Date: Sat Apr 4 16:45:54 2026 +0300

chore: layout composition and spacing rhythm

- homepage section spacing mb-3/mb-6 → mb-8/mb-12; terminal
commands now breathe like a real shell session
- main page wrapper pb-4/pb-8 → pb-8/pb-12; grounded bottom
- about.astro exit section mb-6 → mb-10; consistent section rhythm
- header #navigation mb-3 → mb-4; tighter breadcrumb clearance
- ContentLayout metadata - display:block with mt/mb, replace
<br><br> hack with proper spacer; date/tags visually grouped
- heading margins in markdown.css - article h2/h3/h4 get
margin-top/bottom for reading rhythm; first-child exceptions suppress
double-spacing at section tops
- skip-link border-radius 0 0 4px 0 → 0; defends zero-radius
identity
- share-notification box-shadow rgba → oklch for color consistency

commit 5cbbda715fb3145a4f854b1eac8720c7d867d93c
Author: asce1062 <tnkratos@gmail.com>
Date: Sat Apr 4 16:36:42 2026 +0300

chore: foundation, correctness and token alignment

- remove rounded-md from ThemeSwitcher (breaks zero-radius identity)
- remove rounded-md from Header search button (same pattern)
- aria-hidden decorative blink cursors across 13 pages
- remove color override from b{} in global.css
- shadow tokens → oklch; add motion token vocabulary to theme.css
- sidebar overlay → oklch color space
- code highlight color → color-mix warm void tokens
- char-id syntax highlight → primary/accent/secondary tokens
- collapsible-nav references motion tokens; grid refactor deferred to phase 5
- fluid heading scale with clamp() scoped to article (content pages only)

fix(index): tighten mobile spacing to fit one viewport without scroll

April 4, 2026 asce1062 View on GitHub b8ad5a2
Commit details
Reduce paragraph margins from 1em to 0.4em on mobile (<768px) via scoped
style. Shrink inter-section gap from mb-6 to mb-3 on mobile (md:mb-6 on
desktop). Saves ~70px vertical space on 375px-wide devices; desktop layout
is unaffected.

Squashed commit of the following:

April 4, 2026 asce1062 View on GitHub e92baea
Commit details
commit 3b792f0a8a40cfeaecbd139a3da1b0e3057710cd
Author: asce1062 <tnkratos@gmail.com>
Date: Sat Apr 4 04:40:54 2026 +0300

feat: add Matrix rain canvas background with theme-awareness and mutual exclusion

- New sidebar toggle "Matrix" (icon-columns) wired to matrixBackground.ts
- Canvas injects into body, renders hiragana rain at ~30fps via rAF
- Colors read from CSS custom properties at runtime: --color-base-100 (trail)
and --color-base-300 (characters) so the effect adapts to light/dark theme
- MutationObserver on data-theme clears canvas and refreshes colors instantly
when the user switches themes — no stale trail bleeding through
- Mutual exclusion via custom DOM event "background:activate": enabling Matrix
fully disables Stars (stops rAF loop, removes canvas, unchecks toggle) and
vice versa; cross-tab sync handled symmetrically via storage event
- Reduced-motion guard: canvas is built but animation does not start when
prefers-reduced-motion is set
- Early-apply inline script in Layout.astro stamps data-matrix-bg before paint
to prevent FOUC on page load
- Added matrixBackground pref key to PREF_KEYS, sidebar option to navigation.ts
- Updated privacy.astro and dnt-policy.txt: five → six localStorage values,
added matrix-bg entry, updated REASSERTION date to 2026-04-04

Squashed commit of the following:

April 4, 2026 asce1062 View on GitHub d17090b
Commit details
commit 496026e37c5aef23e7cd56a27f0a49fa62eab269
Author: asce1062 <tnkratos@gmail.com>
Date: Sat Apr 4 03:01:20 2026 +0300

feat: inactive tab title with rotating messages

commit ce14fc8806858673856f98dc3ac2104c69f4d580
Author: asce1062 <tnkratos@gmail.com>
Date: Sat Apr 4 02:48:26 2026 +0300

feat: inactive tab title with rotating messages

Swaps document.title to a custom message when the user
switches away from the tab, restoring the real title on return.

- visibilitychange listener registered once at module scope (no duplicates across soft navs)
- astro:page-load re-captures activeTitle so soft navigations restore the right page title
- OG/SEO unaffected: og:title and <title> are server-rendered; this is client-only

Squashed commit of the following:

April 3, 2026 asce1062 View on GitHub 9b427be
Commit details
commit 43770944a7e3178f5a5790103eb0d65d14526615
Merge: 447ed35 fc16c6a
Author: asce1062 <tnkratos@gmail.com>
Date: Sat Apr 4 01:06:32 2026 +0300

merge: fix/visual-fixes → feat/warm-void-redesign

* fix/visual-fixes:
fix: visual fixes. Icon sizing, changelog layout, avatar save policy, token cleanup

commit fc16c6a8ce5682c0ef4f35969c0d394494c7d984
Author: asce1062 <tnkratos@gmail.com>
Date: Sat Apr 4 01:05:58 2026 +0300

fix: visual fixes. Icon sizing, changelog layout, avatar save policy, token cleanup

- Unify theme/search icon buttons to h-11 w-11 with flex centering
- Changelog: commit title on its own line; short SHA badge pushed right
- Avatar: persist to localStorage only on explicit Save
— remove all auto-persist from randomize, layer change, and gender switch

commit fa73bd408bc000c2802e50abf1d70576f6fc53af
Merge: f064325 f0d01fc
Author: asce1062 <tnkratos@gmail.com>
Date: Tue Mar 31 23:23:42 2026 +0300

merge: chore/phase4-polish → feat/warm-void-redesign (Phase 4 polish)

* chore/phase4-polish:
chore: UI/UX polish. Elevation tokens and UX fixes

commit f0d01fcf8c674a68f9ac6bec5662453312fa340c
Author: asce1062 <tnkratos@gmail.com>
Date: Tue Mar 31 23:23:08 2026 +0300

chore: UI/UX polish. Elevation tokens and UX fixes

Elevation tokens:
- theme.css: add --elevation-0/1/2/3/focus glow-based system

Polish:
- scrollProgress.ts: replace status-color gradient with brand tokens; add glow box-shadow
- guestbook.css: .entry-bubble hover border-color transitions to accent
- .nav-link--active gains 2px accent left border for clear active page indicator
— Mobile body font-size 14px → 15px
— Nav link min-height 2rem (32px) → 2.75rem (44px)

Minor fixes:
- sidebar.css: nav-section-label inline-flex → flex for full-width sticky coverage
— Sidebar <aside>: add role="navigation" (overrides implicit
complementary role) and update aria-label to "Main navigation"
— aria-hidden="true" on all decorative icon fonts in Header.astro
and ShareNotification.astro (hamburger, search, palette, close).
— role="status" aria-live="polite" aria-atomic="true" on
ShareNotification. Screen readers now announce copy success.
— @media prefers-reduced-motion suppresses stars GIF background.
Existing .blink rule updated to add visibility:visible so cursor
doesn't vanish when animation is disabled.
— Search and theme buttons enlarged from h-7 w-7 (28px) to h-11 w-11 (44px).
Meets WCAG 2.5.5 touch target minimum.
— Guestbook honeypot: aria-hidden="true" on wrapper <p>,
tabindex="-1" and autocomplete="off" on input.
— Header greeting changed from <h1> to <p class="site-greeting">.
.site-greeting in global.css preserves text-2xl/md:text-3xl
appearance. Fixes double H1 document outline on every page.

feat: add animated stars GIF background with toggle support

March 30, 2026 asce1062 View on GitHub c61852a
Commit details
Adds a stars.anim.gif background to the site with a user preference
toggle. Integrates the starsBackground script into Layout, wires up
navigation and sidebar toggle UI, and adds CSS for the background layer.

fix(hooks): enforce npm test in the active pre-commit hook

March 28, 2026 asce1062 View on GitHub 32c8943
Commit details
The pre-commit hook at the project subdirectory (asce1062/.husky/)
was never picked up. Git reads hooks from the repo root (.husky/).
Remove the dead inner hook and add npm test to the root-level hook
so tests are enforced on every commit.

refactor: update packages and migrate content config to Astro v6 format

March 28, 2026 asce1062 View on GitHub 1515391
Commit details
  • Update to rehype-slug and rehype-extract-toc.

- Update packages.
- Move src/content/config.ts → src/content.config.ts (required by Astro v6).
- Import z from "zod" directly; astro:content no longer re-exports it.

refactor: migrate remark-slug to rehype-slug and rehype-extract-toc

March 28, 2026 asce1062 View on GitHub 9c713b9
Commit details
Replace deprecated remark-slug with rehype-slug and migrate the TOC
extraction pipeline from the remark phase to the rehype phase.

Changes:
  • Remove: remark-slug (deprecated, no TS types)

  • Remove: @stefanprobst/remark-extract-toc

  • Add: rehype-slug (typed, maintained)

  • Add: @stefanprobst/rehype-extract-toc (has /mdx subpath, same API)


New rehypePlugins order:
rehypeSlug → extractToc → withTocExport → accessibleEmojis → externalLinks → prettyCode

The slug algorithm (github-slugger) is identical in both packages so all
existing heading anchor URLs remain valid. The maxDepth:3 option is not
available in the rehype version but TableOfContents.astro already limits
rendering to 3 levels so behaviour is unchanged.

Eliminates the remarkSlug as any cast. 0 errors on astro check, 263 tests
passing, lint and knip clean.

merge: test/security-critical-paths → main

March 28, 2026 asce1062 View on GitHub c886d00
Commit details
  • test/security-critical-paths:

feat(test): add security test suite and vitest infrastructure

feat(test): add security test suite and vitest infrastructure

March 28, 2026 asce1062 View on GitHub a5e381a
Commit details
Test infrastructure:
- vitest.config.ts - node environment, @/ path alias, globals
- package.json - test/test:watch scripts, vitest devDep
- eslint.config.mjs - vitest globals for *.test.ts files
- knip.json - vitest.config.* and test globs in entry, vitest ignored
- .husky/pre-commit - runs npm test after lint-staged

New test files:
- src/tests/middleware.test.ts - CSRF 403, token upgrade 303+cookie,
auth enforcement redirect, non-admin passthrough, security headers on all paths
- src/config/tests/email-config.test.ts - sanitizeUrl, sanitizeHeaderValue,
parseEmailAddress, sanitizeUserText, truncate, wrapText
- src/lib/api/tests/admin-auth.test.ts - isValidToken timing-safe comparison,
checkPostOrigin CSRF, checkAdminAuth token upgrade, cookie option consistency
- src/lib/api/tests/github.test.ts - renderMarkdownToHtml XSS regression
(HTML-escape ordering, javascript:/data:/vbscript: blocking), URL parsing, pagination
- src/lib/api/tests/guestbook.classify.test.ts - classifyEntry spam classifier
- src/lib/api/tests/guestbook.utils.test.ts - hashValue, safeParseReasons, assertStatus
- src/lib/api/tests/guestbook-notify.test.ts - sendEntryCopy 4 spam guards,
sendEmail retry logic (429/5xx retry, 4xx no-retry, transient errors, retry cap)

Production fixes bundled with this commit:
- src/lib/api/github.ts - renderMarkdownToHtml validates https:/http: before
injecting commit message URLs into hrefs (javascript: injection regression fix)
- src/lib/api/guestbook.ts - export assertStatus for testability; fix
OBFUSCATED_LINK_RE false-positive that auto-hid all entries containing valid URLs
- src/pages/guestbook.astro - maxlength=2000 + server-side length cap
- src/components/seo/OpenGraphTags.astro, src/pages/changelog.astro -
eslint-disable-next-line for intentional set:html usages (JSON.stringify output)

fix: update stale asset paths from public/ restructure

March 23, 2026 asce1062 View on GitHub 37d5fb6
Commit details
  • Replace ogImage="social-preview.png" with "images/social-preview.png"

- Fix rss.xml.ts: fs.existsSync check and both channel image URLs now point
to public/images/social-preview.png
- Update privacy.astro CLI snippet: gpg --import path updated to canonical
/downloads/public.pgp

refactor: migrate to Shiki built-in Rose Pine themes and reorganize email templates

March 23, 2026 asce1062 View on GitHub 0a69985
Commit details
  • Replace custom VS Code JSON theme exports with Shiki string

identifiers: dark "rose-pine", light "rose-pine-dawn". Removes JSON imports,
ThemeRegistration cast, and deletes public/theme/ directory entirely.
- Move email .astro templates from src/lib/email/templates/ to
src/components/email/ (standard Astro convention; lib/ is for logic only).
Update import paths in both builder files.
- Document remaining as-any casts in markdown.config.ts: remark-slug (deprecated,
no types) and rehype-accessible-emojis (upstream type gap).

refactor(public): reorganize static assets into icons/, images/, downloads/

March 23, 2026 asce1062 View on GitHub 505c096
Commit details
Move scattered root-level assets into purposeful subdirectories:
- icons/ - all favicon + PWA + apple-touch variants
- images/ - social previews + topography SVGs
- downloads/ - resume PDF + PGP key

Remove public/css/ (icomoon CSS served from /fonts/icomoon/style.css)
and root-level icomoon font duplicates.

All legacy paths (public.pgp, resume PDF, old spaced PDF URL) redirect
301 to their new canonical locations in downloads/. Cache headers updated
from shallow globs (/*.png) to deep globs (/**/*.png) to cover subdirs,
and /**/*.svg added for topography assets.

misc(chore): visual improvements

March 23, 2026 asce1062 View on GitHub 8d9e488

refactor(avatar): make randomize preview-only when a saved avatar exists

March 19, 2026 asce1062 View on GitHub e1c8a62
Commit details
Randomize previously used persist: avatarStore.isRemembered(),
logically inverted from the intended behavior. Changed to
persist: !avatarStore.isRemembered() across the mini widget and
AvatarStateManager so randomize only writes to localStorage on first
use (no saved avatar yet). For returning users it is preview-only;
Save remains the explicit commit action.

Three related behavioral fixes:

- avatarMiniWidget: gender switch was also using persist: isRemembered()
and loading getDefaultState unconditionally, which could overwrite a
saved avatar of the other gender with defaults. Now mirrors
AvatarStateManager.changeGender: restores the saved avatar for the
target gender if one exists, and only persists when a saved state for
that gender is already present.

- avatarStateManager: syncStore() now accepts an optional persist override
so randomize() can bypass the auto-persist logic without affecting the
behavior of updateLayerValue() and changeGender().

- guestbookAvatarWidget: opt-in checkbox called saveToStorage()
unconditionally. A returning user who randomized then checked opt-in
would silently overwrite their saved avatar. saveToStorage() is now
guarded by !avatarStore.isRemembered().

fix: guard e.key before toLowerCase in keydown handlers

March 18, 2026 asce1062 View on GitHub f773526
Commit details
Autofill and autocomplete fire synthetic keydown events where e.key is
undefined, causing "Cannot read properties of undefined (reading
'toLowerCase')" in these handlers.

- keyboardShortcuts.ts: guard in registerShortcut handler
- FloatingSearch.astro: guard in Escape and Ctrl+K listeners
- themeManager.ts: guard in Ctrl+Shift+L theme toggle listener

fix(api): replace single encoded state param with separate gender+avatar params

March 18, 2026 asce1062 View on GitHub 133defc
Commit details
Netlify's function infrastructure incorrectly re-parses percent-encoded
ampersands (%26) in query values after decoding, splitting the state
string gender=female&avatar=... into separate params and leaving state
empty causing "Missing state parameter" errors.

Fix by passing gender and avatar as direct top-level query params:
/api/avatar.png?gender=female&avatar=4-26-32-22-3-3

Neither value contains characters that need encoding, so no
double-encoding occurs and Netlify has nothing to misparse.

- avatar.png.ts: read gender + avatar directly; reconstruct state
string internally for compositeAvatarPng
- notify-template.ts, entry-copy-template.ts: parse avatarState with
URLSearchParams and build the new flat URL format

fix(avatar): mark /api/avatar.png as prerender = false

Astro was prerendering the API route at build time with no query params,
storing the 400 error body ("Missing gender or avatar parameter") as a
34-byte static file at dist/api/avatar.png. Netlify serves static files
before routing to functions, so every request hit that file and never
reached the SSR function.

fix(pwa): exclude API routes from SW navigation fallback and CDN caching

March 18, 2026 asce1062 View on GitHub cf1f930
Commit details
astro.config.mjs:
- Add /^\/api\// to navigateFallbackDenylist so API navigation
requests always reach the network
- Add NetworkOnly runtimeCaching rule for /^\/api\// so API responses
are never stored in the SW cache

netlify.toml:
- Add Cache-Control: no-store for /api/* to prevent Netlify's CDN
from treating /api/avatar.png as a static PNG asset (the /*.png
glob rule was matching it)

fix(avatar): respect saved avatar when switching gender

March 18, 2026 asce1062 View on GitHub fc52d05
Commit details
changeGender() always called getDefaultState(), discarding any saved
avatar regardless of localStorage. Now checks for a persisted avatar
matching the target gender first, falling back to defaults only when
none exists.

Adds avatarStore.getSavedStateForGender(gender) which reads directly
from localStorage so the check is always against the persisted value,
not the current in-memory store state.

fix(contributions): clip iframe white body bleed via overflow-y-hidden

March 18, 2026 asce1062 View on GitHub 7a3bcf3
Commit details
The jandee iframe renders its graph content at ~162px with the
remaining body background bleeding white at the bottom. Since the
iframe is cross-origin, CSS cannot be injected to fix it directly.

Replace the mask div approach (which scrolled away on horizontal
overflow) with a clip: container is h-[162px] with overflow-y-hidden,
iframe is h-48 (192px). The bleed sits in the clipped region
and never renders. Horizontal scrolling is unaffected.

feat: avatar system, match-device theme, feedback manager hardening, and privacy updates

March 18, 2026 asce1062 View on GitHub dd33402
Commit details
Avatar system
- Add AvatarMiniWidget component and avatarMiniWidget.ts with render race
guard renderSeq, duplicate binding guard data-widget-bound, and
AbortController-based lifecycle cleanup
- Add avatarStore.ts: singleton state bus with CustomEvent dispatch,
localStorage persistence via getPref/setPref, and cross-tab clear support
- Add avatarRenderCore.ts: shared canvas compositing (Promise.all concurrent
layer loading, zIndex ordering), state serialization/deserialization with
strict /^\d+$/ + Number.isFinite + Number.isInteger validation
- Add entryAvatarRenderer.ts: renders pixel art stamps on guestbook entry
canvases from data-avatar-state attributes
- Add guestbookAvatarWidget.ts: guestbook avatar opt-in flow with
AbortController lifecycle, hasDeliberateChoice guard, submitFallbackApplied
double-submit guard, and avatar state injection into form submission
- Add src/pages/api/avatar.png.ts: server-side PNG avatar compositing
endpoint with MAX_STATE_LENGTH=256 guard, duplicate param rejection,
and HTTP 400/500 semantics
- Add src/lib/email/helpers/avatarImage.ts: sharp-based PNG compositor
returning CompositeResult discriminated union; layer asset errors include
{ cause: err } for full stack chain
- Update email templates (EntryCopyEmail, NotifyEmail, builders) to embed
avatar image via /api/avatar.png endpoint instead of data URI
- Add avatar-frame.css utility and AvatarActions component
- Update GuestbookEntry, GuestBookEntryActions, AvatarGenerator, Sidebar
to wire avatar mini widget and opt-in flow

Theme system
- Add matchDeviceTheme.ts: sidebar "Match device" toggle wired to OS
prefers-color-scheme with AbortController cleanup, URL ?theme= override
precedence, and astro:after-swap re-stamp
- Harden themeManager.ts: move isMac detection into setupThemeShortcut,
fix updateThemeIcon to remove both classes before adding, add editable
field guard (INPUT/TEXTAREA/SELECT/contenteditable) to keyboard shortcut,
tighten getCurrentTheme/resolveActiveTheme JSDoc

Feedback manager
- Rename shareManager.ts → feedbackManager.ts
- Add notificationHideTimers map to track and cancel in-flight fade-out
completion timers independently from auto-hide timers
- Add iconRestoreTimers WeakMap for per-element flashCheckIcon restore timer
cancellation; add primaryIcon === checkIcon same-element guard
- Guard navigator.clipboard?.writeText availability in copyToClipboard
- Extract FADE_OUT_DURATION = 300 constant
- Replace clone-and-replace listener pattern with data-feedback-bound
dataset guard in initShareNotification
- Add notification.isConnected check before deferred DOM mutations

Preferences and privacy
- Add match-device-theme and avatar-state keys to PREF_KEYS
- Update PrivacyPolicy.astro, privacy.astro, and
public/.well-known/dnt-policy.txt: declare all four localStorage keys
(theme, match-device-theme, cursor-blink, avatar-state) with descriptions;
dnt-policy.txt reassertion date bumped to 2026-03-18

Miscellaneous
- Rename "Alex Mbugua Ngugi - Resume.pdf" → "Alex-Mbugua-Ngugi-Resume.pdf"
(remove spaces from public asset path)
- Add new icomoon icons to font set
- Split CSS utilities; add avatar-frame, guestbook, sidebar style updates
- Update db/config.ts and db/seed.ts
- Update guestbook.astro, ProjectCard, Skills, ThemeSwitcher, AsciiWidget,
SocialShareButtons, navigation, and Layout for new features
- Update blog/notes content

refactor(toc): rewrite scroll behavior, sticky detection, dead zone, and rAF batching

March 13, 2026 asce1062 View on GitHub d934510
Commit details
Replace brittle TOP_ZONE_PX constant with live getBoundingClientRect().top
check so sticky state is detected accurately regardless of post layout,
preview image presence, or lazy-loaded content.

- SCROLL_THRESHOLD raised 10px → 50px: prevents direction reversal within
the 300ms transition window, eliminating the visible bump on touchpad momentum
- setHidden() state guard: only writes DOM transform on actual state change,
eliminating redundant writes that re-evaluate the CSS transition
- rAF batching: burst scroll events collapse into one DOM write per frame
- isDetailsOpen tracked via native toggle event, not re-queried per scroll tick
- AbortController lifecycle: all listeners tied to one signal, cleanly torn
down on Astro soft navigation re-init
- lastScrollY only advances when a direction decision is made. Sub-threshold
oscillations accumulate toward threshold rather than endlessly resetting it
- TableOfContents.astro: single astro:page-load listener replaces double-init

chore: remove unused navigation exports and prune stale knip ignores

- Remove SocialLink interface, socialLinks, and contactLinks. Dead code
since footer links were consolidated into the sidebar
- Drop netlify-plugin-checklinks and netlify-plugin-submit-sitemap from
knip.json ignoreDependencies (plugins no longer in use)

feat: preferences system, CSS utilities split, privacy page redesign

March 13, 2026 asce1062 View on GitHub c654acb
Commit details
Preferences & storage
- add src/lib/prefs.ts
- centralized localStorage helpers (getPref/setPref/removePref) and PREF_KEYS constants
- update Layout.astro
- inline script to inject cursor-blink key via define:vars (single source of truth)
- update sessionStorage → localStorage across PrivacyPolicy.astro, dnt-policy.txt

Cursor blink preference
- new cursorBlink.ts
- localStorage persistence
- astro:after-swap flash prevention
- cross-tab sync via storage event
- add data-driven sidebar Options sidebarOptions[] section to navigation.ts
- add SidebarOption interface with icon + label + description fields

Theme manager
- fix getCurrentTheme priority: URL > localStorage > data-theme > default
- isMac computed once at module level (not per keydown)
- setupThemeShortcut now takes AbortSignal instead of returning cleanup fn
- ThemeSwitcher.astro simplified to single astro:page-load + AbortController

CSS utilities
- split global.css into src/styles/utilities/ (btn, badge, input, checkbox, toggle, link-action, content)
- add color variants (8 semantic colors) and size variants to all utilities
- fix toggle + checkbox base color to use base-content, not primary
- scope markdown.css checkbox rules to li to prevent bleed into sidebar toggle

Privacy page
- full redesign. Updated content and structure

feat: sidebar navigation, ASCII widget system, new pages, and site-wide polish

March 12, 2026 asce1062 View on GitHub 3568fa1
Commit details
Sidebar
- New Sidebar.astro component with CSS checkbox open/close state machine
- Collapsible nav drawer: hamburger, overlay click-trap, scroll lock on mobile
- Always-visible on desktop lg:translate-x-0, slide-in on mobile
- Nav links with active state highlighting and icon tilt on hover
- Avatar footer with controls sidebarAvatar.ts
- ASCII easter egg section: random art on load, dice randomize, brand name
badge updates to match the art's text value on dice click sidebarEgg.ts
- sidebarNav.ts: keyboard nav, AbortController cleanup across soft-navs

ASCII widget system
- AsciiWidget.astro: shared component with dice button, clipboard copy button,
font label, and art <pre>, all namespaced under a widgetId prop
- asciiReveal.ts: phosphor "wake-up" animation via IntersectionObserver.
Plays on viewport enter, resets on exit for re-animation on scroll-back;
replayOnDice option for 404 page; reduced-motion stable state; full teardown
(AbortController, observer disconnect, timer clear) for Astro soft-nav safety
- asciiWidget.ts: centralized init, variant parsing, no-repeat random pick,
render (art + font label + data-ascii-current), dice wiring, reveal setup;
onRender callback for side effects; used by sidebar, about, and 404
- Copy button: outputs [Font] header + ``figlet visual art block +
`json fenced valid JSON with properly escaped \n. one human-readable
and one programmatically parseable
-
ascii-art.json: pre-generated variant data
-
scripts/generate-ascii.mjs: generation script for ascii-art.json
-
asciiReveal.css, asciiWidget.css`: component stylesheets

New pages
- /about: whoami write-up + neofetch-style system profile with ASCII art
- /hello: contact / say hello page
- /interests: interests and media diet
- /verify: PGP / identity verification

Page and layout updates
- 404: AsciiWidget with phosphor reveal and replayOnDice
- Header, Layout: sidebar integration and structural adjustments
- changelog, colophon, now, palette: copy and layout refinements
- navigation.ts, site-config.ts, site-utils.ts: new routes and config

Scripts
- consoleEgg.ts: console easter egg
- neofetch.ts: sidebar neofetch display

Styles
- sidebar.css: nav drawer, overlay, easter egg flicker animation
- markdown.css: prose content component styles
- global.css, theme.css: updated imports and token updates

Content
- New notes: guiding-principles, licensing
- Updated personal site checklist to reflect current build state

Icons and tooling
- Updated icomoon icon set
- Updated pubvendors.json and added it to .well-known
- eslint and prettier config updates

feat: email notifications, admin moderation hub, security hardening, dead code cleanup

March 5, 2026 asce1062 View on GitHub 2a15279
Commit details
A broad feature + housekeeping pass spanning the guestbook subsystem,
admin infrastructure, email delivery, and project tooling.

EMAIL NOTIFICATIONS
src/lib/email/
src/lib/api/guestbook-notify.ts
src/config/email-config.ts

Integrate Resend for transactional email on new guestbook submissions:

Owner notification NotifyEmail.astro
- Fires on every new entry that passes spam checks.
- Includes submitter name, message, website/email if
provided, submission timestamp, and a direct link to the admin moderation
queue for one-click review.

Sender copy EntryCopyEmail.astro
- Opt-in confirmation sent to the submitter when they provide an email address.
- Acknowledges receipt and sets expectations about moderation.

Both templates are full HTML with light/dark theme variants keyed to the
submitter's active theme at time of submission. Plain-text fallbacks
included for clients that strip HTML.

Delivery orchestration in guestbook-notify.ts
- Handles both sends in parallel.
- Swallows per-send errors to keep them non-blocking.
- Logs outcomes without leaking PII to the console.

email-config.ts
- centralizes From/Reply-To addresses, subject-line
templates, and the Resend API key reference in one place.

ADMIN SECTION
src/pages/admin/index.astro
src/pages/admin/guestbook.astro

/admin
- token-based login screen.
- On success sets a 7-day httpOnly cookie and redirects
to the hub.
- Wrong token triggers a 500 ms server-side delay to slow
sequential brute-force attempts, then shows an inline error.
- Authenticated view lists all protected pages.

/admin/guestbook
- full moderation interface with four filter tabs:
- All
- Pending
- Hidden
- Audit Trail

Entry cards display:
- numeric #ID
- submitter name + URL + email
- current status badge warning/error/success
- moderation score
- flag reasons as inline pills
- message body in a scrollable pre block
- submission timestamp
- moderator/moderated-at metadata when available

Actions per entry:
Approve - set status → visible keep existing flags
Approve & Clear - set status → visible AND wipe flag reasons/score
for false positives
Hide - set status → hidden

Audit Trail tab renders the full GuestbookModerationLog as a compact
monospace table:
- entry deep-link
- action badge
- status transition from → to
- flag reasons at time of action
- score
- actor
- timestamp
Entry ID cells link back to the entry card in the All view via anchor.

CENTRALIZED ADMIN AUTH
src/lib/api/admin-auth.ts

sanitizeToken()
- strips CR/LF copy-paste artifact guard
- trims whitespace
- caps at 256 chars (arbitrary sanity limit to prevent DoS attempts with huge input)

safeEqual()
- wraps node:crypto timingSafeEqual.
- Performs a dummy same-length comparison when lengths differ
so the function always runs in proportional time regardless of input,
preventing length-based timing leaks.

isValidToken()
- reads ADMIN_TOKEN from env, guards against unset env var,
delegates to safeEqual via sanitizeToken on both sides.

setAdminCookie() / deleteAdminCookie()
- consistent cookie options on both set and delete
(path:/admin, httpOnly, secure:prod-only, sameSite:strict, maxAge:7d)
to prevent orphaned cookies.

checkPostOrigin()
- validates Origin header.
- Falls back to Referer for older browsers
- Explicitly rejects the string "null" sent by sandboxed iframes.

checkAdminAuth()
- unified auth check for cookie or ?token= query param
- returns cleanUrl token stripped so callers can redirect immediately,
keeping the token out of browser history and server logs.

MIDDLEWARE
src/middleware.ts

Centralize cross-cutting admin concerns so individual pages stay lean:

Route matching
- pathname === "/admin" || pathname.startsWith("/admin/")
- the trailing-slash prefix prevents false matches on /administer etc.

CSRF guard
- every admin POST is checked via checkPostOrigin before any
page logic runs.
- returns 403 Forbidden on failure.

?token= upgrade
- on any admin route, a valid token in the query string
causes the middleware to set the cookie and 303-redirect to the clean URL
before the page ever renders, keeping tokens out of browser history,
access logs, and Referer headers.

Auth enforcement
- /admin/* sub-pages redirect to /admin if auth fails.
- The /admin hub itself handles its own login form.

applyAdminHeaders()
- applied to every return path, including the early
CSRF 403 and auth redirects so no response ever escapes without the
full security header set:
      Content-Security-Policy: frame-ancestors 'none'; base-uri 'none'; form-action 'self'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Cache-Control: no-store, max-age=0 + Pragma: no-cache + Expires: 0
Referrer-Policy: no-referrer
X-Robots-Tag: noindex, nofollow, noarchive
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()
Strict-Transport-Security: max-age=31536000 (production only)


DATABASE & GUESTBOOK API
db/config.ts
src/lib/api/guestbook.ts

Add GuestbookModerationLog table to persist a full audit trail of every moderation action.
- entryId
- action
- fromStatus
- toStatus
- reasonsBefore
- scoreBefore
- actor
- at

getModerationLog(entryId?: number)
- no arg returns the full log for the audit tab.
- with entryId returns per-entry history for future detail views.

updateEntryStatus()
- gains a clearFlags option that zeroes out
moderationReason and moderationScore when approving false positives.

safeParseReasons()
- helper for safely deserializing the JSON reasons array
stored in the DB, with a graceful fallback to [].

Seed data expanded with styled sample entries covering the full range of
status/theme/pattern combinations for visual QA.

DATE FORMATTING
src/lib/content/utils.ts

Extend formatDate(date, format) with a "medium" variant (month: "short"
→ "Jan 1, 2024") to sit between "long" (January 1, 2024) and "short"
(2024-01-01).

Remove formatEntryDate() from guestbook.ts and formatChangelogDate()
from github.ts. Both were private wrappers around the same locale
options. All consumers updated to call formatDate(..., "medium") or
formatDate(...) directly.

DEAD CODE CLEANUP
src/config/
src/lib/api/github.ts

Delete src/config/index.ts
- re-export barrel with zero consumers.

Remove getAbsoluteUrl() from site-utils.ts
- no call sites in the codebase.
- URL construction handled inline or via Astro.url.

Remove groupEntriesByYear() from github.ts
- changelog.astro never imported it.
- entries are grouped directly in the template.

Remove export from hexColorValues in design-tokens.ts
- used only internally to derive hexLight/hexDark, never consumed outside the module.

PGP / SECURITY FILES
public/
public/.well-known/

Rotate public PGP key
- public/public.pgp
- public/.well-known/security.txt
- public/security.txt
- public/.well-known/security.txt.sig

Add WKD (Web Key Directory) support
- openpgpkey/hu/ hash files + policy
- so mail clients can auto-discover the key from the domain
when users click the email address in the guestbook entry.

Update privacy.txt and dnt-policy.txt content.

TOOLING
knip.json
eslint.config.mjs
package.json

knip.json
- add ignoreExportsUsedInFile for interface/type/function
- expand entry patterns to cover scripts/ and db/ directories
- add ignoreIssues for email template Astro files (false-positive type exports).

eslint.config.mjs
- sync rule updates.

package.json`
- add resend and validator.js
- update dependencies.

feat: add guestbook entry action menu and improve cross-browser background pattern support

February 20, 2026 asce1062 View on GitHub 47beb5e
Commit details
Add interactive kebab menu to each guestbook entry card
Start with 5 actions:
- Copy Style: copies entry's theme JSON to clipboard
- Request Edit/Remove: pre-filled GitHub issue (new tab)
- Request via Email: pre-filled mailto link for non-GitHub users
- Copy Message: copies raw message text to clipboard
- Share Entry: Web Share API with permalink clipboard fallback

Entry anchor navigation: #entry-{id} URLs scroll to and highlight the
target entry with an accent outline pulse animation.

Cross-browser pattern backgrounds
- Replace -webkit-mask-image with progressive enhancement
- Fallback uses background-image with:
- Reduced opacity for unsupported browsers
- @supports (mask-image: none) upgrades to the full themed mask effect

Other changes:
- EntryActions.astro: new component with menu trigger and action items
- GuestbookEntry.astro: integrate EntryActions, add id="entry-{id}"
- guestbook.astro: wire up initEntryActions + ShareNotification
- guestbook.css: action menu styles, z-index stacking, highlight keyframes
- eslint.config.mjs: add DOMException to browser globals
- knip.json: ignore guestbookEntryActions.ts
- db/seed.ts: update seed data
- IcoMoon: update icons

feat: refine guestbook customizer UI and entry card layout

February 20, 2026 asce1062 View on GitHub 3058e53
Commit details
Customizer:
- Add base-100, base-200 to color swatch selection
- Change color swatches from circles to squares (border-radius: 0rem)
- Extract swatchColors config, shared across border color pickers
- Set pattern-swatch border-radius to 0rem for visual consistency

Entry cards:
- Move author name + date to bottom of card, right-aligned
- Stack name and date vertically
- flex-direction: column
- Rename .entry-header → .entry-meta
- Add neutral background pill to entry-meta for legibility over some patterns
- Change date format from en-gb (day month year) → en-us (month day, year)
- Add topography.svg to public/notecards/
- Default bg to "topography" pattern for all entries

feat: add guestbook entry theme customizer with Hero Pattern backgrounds

February 19, 2026 asce1062 View on GitHub 92b3a02
Commit details
Allow users to personalize their guestbook entry card appearance.
Selections are stored as a JSON style column in the DB.
These are then rendered as inline styles on each entry card.

Schema:
style column stores a JSON string with the following shape:
    {
"bg": "topography", // Hero Pattern filename or "none"
"borderColor": "primary", // Semantic color: base-300 | primary | secondary | accent | info | success | warning | error
"borderWidth": "1.5px", // 0.5px – 4px in 0.5px steps
"borderStyle": "dashed", // solid | dashed | dotted | double | none
"borderRadius": "0.5rem" // 0rem | 0.25rem | 0.5rem | 1rem | 2rem
}

Entries with style: null render with defaults (bg-neutral, no pattern, base-300 border, 1px solid, 0.25rem radius).

Changes:
- Add style column (optional text) to Guestbook DB schema
- Add Hero Pattern SVGs to public/notecards/
- Source/Credits: Steve Schoger
- Theme-aware rendering via CSS mask-image (light/dark fill colors)
- Add customizer UI:
- Add pattern dropdown, border radius/width/color/style
- Add pickers with top-right corner previews
- Add live textarea preview
- Add randomize button
- Add client-side customizer script with hover preview on textarea,
click-outside-to-close, and astro:page-load support for View Transitions
- Refactor Expand component from CSS checkbox hack to JS toggle
- Extract customizer constants to src/config/guestbook.ts
- Rename Card.astro to ProjectCard.astro

feat: migrate guestbook from Netlify Forms to Astro DB + Turso

February 18, 2026 asce1062 View on GitHub 32e011c
Commit details
Replace Netlify Forms with Astro DB backed by
Turso (libSQL) for full data ownership and host-agnostic deployment.

- Add SSR guestbook route with inline POST handling and redirect flow
- Implement honeypot + content pattern spam detection
- HTML tags, BBCode, URL shorteners, obfuscated links, link-only posts
- Preserve ASCII art in messages with <pre> rendering and whitespace-
safe input handling
- Add Netlify adapter (conditional, production-only) with imageCDN off
- Add @astrojs/ts-plugin for virtual module type resolution
- Create CSV migration script (papaparse) for Netlify Forms export
- Update privacy policy, colophon, DNT policy, and pubvendors
- Reflect Turso-backed storage with no third-party data processing
- Clean up knip config and tsconfig for db/ directory

refactor: replace remark-reading-time with Astro recipe, add external link icons

February 18, 2026 asce1062 View on GitHub 2b412de
Commit details
  • Replace remark-reading-time + bridge plugin with a custom remark plugin

- Use reading-time and mdast-util-to-string directly

- Add rehype-external-links
- Automatically append icon-box-arrow-up-right to external links in content collections
- With target="_blank" and rel="noopener noreferrer" for security

- Update knip.json schema to @latest and clean up stale ignore entries.

feat: add notes collection, unified content architecture, privacy/well-known infrastructure

February 17, 2026 asce1062 View on GitHub d489a1c
Commit details
Notes & Content Architecture
- Add Notes collection with schema, utilities, and listing page (/notes)
- Merge BlogLayout + NoteLayout into unified ContentLayout with collection prop driving blog vs notes behavior
- Merge Post + NoteCard into unified ContentCard
— image prop controls layout
- flex-row with image for blog, column for notes
- Merge blog/notes utilities into shared src/lib/content/utils.ts
- formatDate, getContentUrl, sortByDate, getAllTags
- Extract common Zod contentSchema with shared fields
- title, description, pubDate, updatedDate, tags, permalink, draft
- blogSchema extends with image/featured, notesSchema currently uses base as-is
- Rename src/components/blog/ → src/components/content/ for cross-collection reusability
- Generalize PostNavigation → ContentNavigation with basePath prop and generic "Previous"/"Next" labels
- Update all blog content MDX files from BlogLayout → ContentLayout
- Add notes: hello-notebook and personal-site-checklist
- Add Notebook and Privacy to header navigation
- Add new blog post: from-necessary-to-impossible

Reading Time & Word Count
- Integrate remark-reading-time npm package for AST-based reading time calculation
- Add bridge plugin (remarkReadingTimeToFrontmatter) to map file.data.readingTime → file.data.astro.frontmatter
- remark-reading-time writes to file.data but Astro exposes file.data.astro.frontmatter
- Remove custom stripMarkup/estimateReadingTime/countWords
— remark plugin walks text+code AST nodes, inherently ignoring JSX props, imports, frontmatter, and HTML attributes
- Listing pages pre-render entries via render() from astro:content to access remarkPluginFrontmatter

Privacy & Well-Known Infrastructure
- Add /privacy page with PrivacyPolicy component, DNT, Security (with WKD note), Vendors, and Well-Known Resources sections
- Add .well-known/dnt
— JSON tracking status ("N" Not Tracking) per W3C DNT spec
- Add .well-known/dnt-policy.txt
— comprehensive DNT compliance policy with operator info, scope, data collection, forms, server logs
- Add .well-known/security.txt + /security.txt
— RFC 9116 security contact with no-consent-for-testing notice
- Add .well-known/security.txt.sig
— detached PGP signature
- Add .well-known/pubvendors.json
— Netlify, GitHub, jandee (Vercel), Google, IcoMoon, Pagefind
- Add .well-known/change-password
- Generate PGP key (RSA 4096, expires 2028-02-16) and publish at /public.pgp
- Add WKD notes to security.txt, dnt-policy.txt, and privacy page indicating future ping@alexmbugua.me migration
- Update netlify.toml
- Add /.well-known to skipPatterns in netlify.toml
- since there's no index page at that path (it's just a directory of machine-readable files)

Styling & Fixes
- Add site-wide checkbox styling in global.css using icomoon font glyphs (\e9aa unchecked, \f0ed checked)
- Fix circular dependency between site-config.ts and site-utils.ts — helpers now imported directly from site-utils
- Add updatedDate with future-date validation to content schema
- Harden offline fallback and PWA resource interception
- Add retry button and periodic server polling (2.5s) to the offline page
- The browser online event is unreliable on captive portals, so we verify with a real HEAD request.
- Extend navigateFallbackDenylist to exclude
- .json, .pgp, .sig, and /.well-known/ paths
- Ensures the service worker no longer redirects machine-readable resources to the offline page.
- PGP keys, dnt policy, etc.

fix: default ogImage to social-preview.png in Layout

February 5, 2026 asce1062 View on GitHub 50307e1
Commit details
Use SEO.ogImage as fallback when ogImage prop is not provided,
preventing blank social preview images on pages without explicit ogImage.

feat: add changelog page with GitHub commit history

February 4, 2026 asce1062 View on GitHub b1cb699
Commit details
  • Add /changelog page displaying all commits fetched at build time

- Extend src/lib/api/github.ts with changelog functions:
- fetchAllGitHubCommits() with pagination support
- getChangelogEntries(), formatChangelogDate(), renderMarkdownToHtml()
- getRepoSlugFromUrl(), getBaseRepoUrl() helpers
- Features:
- Shows 25 commits initially with "Load more" button
- Year grouping with sticky headers
- Expandable commit details for multi-line messages
- Graceful error handling for API failures
- Uses GITHUB_PAT for higher rate limits (5000/hr vs 60/hr)
- Add changelog link to navigation and colophon page

feat: add palette page with design tokens and click-to-copy

February 4, 2026 asce1062 View on GitHub ca5d9e1
Commit details
  • Add /palette page with tabbed Swatches/Ingredients views

- Create design-tokens.ts registry with colorRoles and colorValues
- Implement CSS-only tab switching with accessibility (ARIA roles)
- Add click-to-copy for computed colors and OKLCH values
- Add palette to header navigation between Colophon and Meta
- Update icon font with palette icons
- Link palette from colophon Typography & Design section

feat: add colophon/meta pages, refactor config to grouped exports

February 3, 2026 asce1062 View on GitHub 2ec25be
Commit details
Add colophon/meta pages:
- /meta: diagnostic, minimal, noindex (build info, package versions, SEO defaults)
- /colophon: narrative credits, philosophy, tech stack with icons

Config architecture improvements:
- Create deps-info.ts (centralized package.json access)
- Create build-info.ts (build timestamp, Node version)
- Create site-utils.ts (helper functions)
- Create index.ts barrel export
- Remove all legacy individual exports from site-config.ts
- Migrate all consumers to grouped exports (SITE, BLOG, SOCIAL, SEO, PWA, etc.)

SEO/meta tag fixes:
- OpenGraphTags: WebPage schema for non-articles, stable WebSite name,
Twitter meta uses name attr, title-case breadcrumbs, add isPartOf
- MetaTags: remove fake Atom feed, inaccurate geo metadata, obsolete tags
- Layout: safe Astro.site fallback, fix duplicate id on main element

Misc:
- Add /humans.txt following humanstxt.org standard
- Add .txt to service worker navigateFallbackDenylist
- Add Colophon and Meta to site navigation

Housekeeping:
- Icon font updates
- Remove trailing design-tokens.mjs and tailwind.config.mjs since tailwindCSS v4 update

feat: enhance project cards, theming, and navigation UX

January 29, 2026 asce1062 View on GitHub 7cc0187
Commit details
Project Cards:
- Add contributors, issues, and forks counts with icons
- Fetch contributor count via GitHub API
- Conditional color styling (warning for 0, info for >= 1)
- Separate stats row from project name link

Theme System:
- Add URL parameter support (?theme=dark or ?theme=light)
- Add keyboard shortcut (Ctrl/Cmd + Shift + L) for theme toggle
- Export setTheme() for programmatic theme control

Navigation & Footer:
- Replace inline SVG with icon-git-commit in footer
- Add hover pause for blink animation on nav links

feat: update 0xProto font, sticky TOC, and code block styling

January 23, 2026 asce1062 View on GitHub 7052393
Commit details
  • Update 0xProto font to complete set (Regular, Bold, Italic) with

woff2, otf, ttf formats; remove old NerdFont version
- Remove unused Josefin Sans and Poppins fonts
- Add sticky table of contents that shows on scroll-up only,
with auto-close on link click
- Add scroll-margin-top to headings for proper anchor positioning
- Set heading font weights (h1-h3 bold, h4-h6 semibold)
- Style .btn and .link-action with 0xProto italic
- Italicize footer build info text
- Update rehype-pretty-code config with grid option for full-width
line highlighting
- Fix code block theme switching to use data-theme attribute
- Add border and improved styling to code blocks
- Fix resume page fallback to fit content instead of fixed height

feat: upgrade to Tailwind CSS v4 with CSS-first configuration

January 14, 2026 asce1062 View on GitHub e301759
Commit details
BREAKING CHANGE: Tailwind CSS v3 → v4 migration

Core Changes
- Replace @tailwind directives with @import "tailwindcss"
- Migrate to @tailwindcss/postcss plugin
- Convert theme config to CSS-first approach with @theme directive
- Replace custom utilities with @utility directive syntax

Component Refactoring
- Extract CollapsibleNav as reusable component with:
- Height-based animation
- Full keyboard accessibility (Tab, Enter, Space)
- ARIA attributes for screen readers
- Smooth transitions with reduced-motion support

Bug Fixes
- Remove FOUC prevention that caused blank pages in tailwind v4
- Fix Card component flex layout with flex! override
- Fix breadcrumb inline wrapping with inline! override
- Fix nav text color inheritance from parent link
- Remove unused collapsibleNav.ts script

## Config Updates
- Update postcss.config.mjs for @tailwindcss/postcss
- Add autoprefixer and postcss-nesting to knip ignore list

refactor: more theming updates and migrations pre tailwindcss v4 upgrade

January 14, 2026 asce1062 View on GitHub 2a498a4
Commit details
Finalize the migration to a semantic CSS variable system that eliminates
light/dark theme duplication across the codebase.

Key changes:
- Fix CSS variable references in global.css to use correct theme paths
- Update tailwind.config.mjs to expose design tokens for theme() function
- Refactor entire codebase to use theme aware semantic variables
- Implement transparency support via color-mix() in project and blog cards
- Unify behavior for buttons and action links

chore: migrate from @astrojs/tailwind to PostCSS + Tailwind v3

January 9, 2026 asce1062 View on GitHub 18bbbc9

feat: establish retro design token system and theme infrastructure

January 6, 2026 asce1062 View on GitHub 114188a
Commit details
Major overhaul of the color system:
- Support semantic theme colors (brand, neutral, secondary, accent)
- Support backward compatibility with palette/light numbered scales

Design Token Updates:
- Expand design-tokens.mjs with full light/dark theme color scales
- Add documentation with usage patterns and examples
- Include semantic colors (brand-primary, default-font, subtext-color, etc.)
- Maintain backward compatibility with palette/light numbered scales

Theme Configuration:
- Update tailwind.config.mjs to expose new semantic color utilities
- Add theme.css for Tailwind CSS v4 compatibility

Component & Config Updates:
- Fix guestbook textarea placeholder visibility issue
- Update Prettier config htmlWhitespaceSensitivity setting to respect whitespace properly
- "ignore" to "strict" to preserve whitespaces as written
- Refactor components to use new design token references
- Update topography SVG variants for light/dark themes

This commit establishes the foundation for migrating away from legacy palette/light
numbered scales to a more maintainable semantic color system. These changes maintain
backward compatibility while preparing for future migration.

2025

update: footer resume icon

December 31, 2025 asce1062 View on GitHub efce735

fix: prevent service worker from intercepting PDF navigation on mobile

December 31, 2025 asce1062 View on GitHub 6e67114
Commit details
  • Fix issue where clicking "Open Resume" fallback on mobile showed offline page

- Add /\.pdf$/ to navigateFallbackDenylist in astro.config.mjs

fix: global search focus when not in view

December 31, 2025 asce1062 View on GitHub 74ac388

feat: improve PDF resume viewer with browser detection

December 31, 2025 asce1062 View on GitHub 53b52e2
Commit details
  • Add fallback overlay for browsers without inline PDF support

- Implement navigator.pdfViewerEnabled API for PDF detection
- Add iOS and in-app browser detection
- Show download button and text version link when PDF can't render inline
- Hide text version link when fallback overlay is displayed
- Update CSP headers in netlify.toml to allow PDF iframe loading
- Add 'self' to frame-src directive
- Change frame-ancestors from 'none' to 'self'
- Update X-Frame-Options from DENY to SAMEORIGIN

Fixes issues where:
- Some browsers showed blank iframes
- Some browsers displayed "contact site owner" errors

Browser support:
- Desktop: Shows inline PDF viewer (all modern browsers)
- iOS/Mobile: Shows fallback with download button immediately
- In-app browsers: Shows fallback automatically
- Legacy browsers: Falls back based on mobile detection

fix: update CSP frame-src directive to allow self

December 30, 2025 asce1062 View on GitHub 91d704d

feat: add floating search modal with responsive positioning

December 30, 2025 asce1062 View on GitHub ed1da27
Commit details
Add a global floating search modal that can be triggered from anywhere on
the site via the search icon or Ctrl+K/Cmd+K keyboard shortcut.

- Create FloatingSearch.astro component with dynamic positioning
- Positions at first HR divider in header
- Width matches body container responsively across all viewports
- Uses separate pagefind instance to avoid conflicts with search page
- Hidden on /search page to prevent duplication

- Extract reusable SearchBox.astro component
- Shared by both search page and floating modal
- Accepts searchId prop for unique pagefind instances

- Add search trigger button to Header
- Positioned below theme switcher toggle
- Only visible when not on search page

- Update search page to use SearchBox component
- Maintains existing functionality with new architecture
- Uses dedicated page-searchbox instance

- Update search.css to support both search contexts
- Styles apply to #pagefind-search and #pagefind-search-floating
- Consistent appearance across page and modal

Technical improvements:
- TypeScript null safety fixes in FloatingSearch
- ResizeObserver for responsive width updates
- Debounced resize handlers for performance

feat: Add resume viewer page and UI enhancements

December 30, 2025 asce1062 View on GitHub cdfe807
Commit details
  • Create dedicated Resume page with PDF iframe viewer (/resume)

- Implement reusable iframe theme management system (src/scripts/iframeTheme.ts)
- Enhance header breadcrumb navigation
- Add "/alex/" to path structure (~/ home / alex /)
- Implement grouped hover effect for home/alex links
- Improve UI
- Make BackToTop button position responsive (bottom-4 md:bottom-8)
- Replace footer commit text with Git commit SVG icon
- Remove rounded corners site-wide for sharper design

updates: bold header, fix footer contact information first row alignment

December 29, 2025 asce1062 View on GitHub 47cb447

updates: add terraform icon

November 4, 2025 asce1062 View on GitHub 5a5767a

updates

October 28, 2025 asce1062 View on GitHub 42f60d0

updates:

October 27, 2025 asce1062 View on GitHub 45c14ee
Commit details
  • fix header nav items rotation

- add space before posts

fix: resolve unparsable JSON-LD structured data in search console

October 27, 2025 asce1062 View on GitHub 350cc59
Commit details
  • Fix JSON-LD schema parsing errors reported by Google Search Console

- Change from set:text to set:html for JSON-LD script tags to prevent HTML escaping
- Add is:inline directive to all JSON-LD scripts to silence Astro warnings
- Add security documentation explaining safe use of set:html with JSON.stringify()
- JSON.stringify() automatically escapes dangerous characters (< > & " ')
- All data comes from controlled sources (MDX frontmatter, config files)
- No user input from forms or URL parameters
- Disable astro/no-set-html-directive ESLint rule at file level with justification
- Added a helper function formatBreadcrumbName() that:
- Returns "Blog" if the segment is "blog"
- Removes the date prefix matching the pattern YYYY-MM-DD- (e.g., 2025-08-13-)
- Converts remaining hyphens to spaces
The issue was that set:text was HTML-escaping quotes to &quot;, making the
JSON unparsable. Using set:html with JSON.stringify() is safe because:
1. JSON.stringify() escapes all dangerous characters
2. We control all data sources (no user input)
3. Characters like < and > are converted to \u003c and \u003e

Fixes Google Search Console error:
"Parsing error: Missing '}' or object member name"

feat: implement collapsible navigation with dynamic row detection

October 24, 2025 asce1062 View on GitHub cbff541
Commit details
  • Add chevron-bar-down icon to icomoon font set

- Create collapsibleNav.ts utility for responsive navigation management
- Dynamically detects first row items based on viewport width
- Automatically shows/hides toggle button when items wrap
- Smooth 180° rotation animation on expand/collapse
- Update Header component with collapsible navigation
- Add nav-toggle button with chevron icon
- Use Tailwind transition-transform for smooth animations
- Center toggle button on all screen sizes
- Maintain min-height to prevent layout shift
- Update navigation layout for better responsive behavior
- Change from center to left alignment on desktop (sm:justify-start)
- Tighten spacing from gap-1 to gap-0.5
- Reduce padding: px-1.5 (mobile), sm:px-1 (desktop)
- Improve horizontal rule visibility
- Change from bg-palette-700 to bg-palette-900
- Add border-0 to prevent border conflicts

feat: add multi-path icon support and improve navigation layout

October 24, 2025 asce1062 View on GitHub 43024d0
Commit details
  • Switch around header and footer content

- Add support for multi-path icons in navigation (icon-female with 10 paths)
- Update Header layout to wrap from left edge in desktop mode
- Tighten navigation spacing to prevent RSS feed wrapping
- Add 8biticon link to main navigation with proper icon rendering

update: packages

October 24, 2025 asce1062 View on GitHub e87e538
Commit details
@astrojs/check ^0.9.4 → ^0.9.5
@astrojs/mdx ^4.37 → ^4.3.8
@astrojs/rss ^4.0.12 → ^4.0.13
astro ^5.14.5 → ^5.15.1
astro-og-canvas ^0.7.0 → ^0.7.2
astro-themes ^0.2.6 → ^0.2.7
@eslint/js ^9.37.0 → ^9.38.0
@types/node ^24.6.2 → ^24.9.1
@typescript-eslint/eslint-plugin ^8.46.1 → ^8.46.2
@typescript-eslint/parser ^8.46.1 → ^8.46.2
astro-og-canvas ^0.7.0 → ^0.7.2
astro-themes ^0.2.6 → ^0.2.7
eslint ^9.37.0 → ^9.38.0
knip ^5.64.1 → ^5.66.2
lint-staged ^16.2.4 → ^16.2.6
netlify-cli ^23.9.1 → ^23.9.5

refactor: centralize share functionality with reusable notification component

October 24, 2025 asce1062 View on GitHub c49de9c
Commit details
  • Create ShareNotification.astro component for consistent notifications

- Add shareManager.ts utility for centralized clipboard operations
- Refactor avatar generator and blog share buttons to use shared utilities
- Move notification styles from avatar.css to global.css for site-wide availability
- Fix clipboard API user gesture chain by removing preventDefault
- Update service worker navigateFallbackDenylist regex patterns
- Ensure dark text color in notifications for better contrast
- Update icomoon fonts
- Update back to top icon

refactor: improve scroll UX and global navigation features

October 24, 2025 asce1062 View on GitHub 5c5b259
Commit details
  • Add global scroll progress bar across all pages

- Implement floating back-to-top button with auto-hide behavior
- Appears after 250px scroll, auto-hides after 3s of inactivity
- Centered horizontally for mobile compatibility (48px) and desktop (56px)
- Smooth scroll animation with hover pause functionality
- Fix theme switcher initialization on first page load
- Add document.readyState check for proper event listener setup
- Manually update localStorage and data-theme attributes
- Remove duplicate event listeners to prevent conflicts
- Extract scroll progress from blog-specific to global utility
- Move from blogInteractions.ts to scrollProgress.ts
- Remove blog-only back-to-top button in favor of floating button
- Add conditional initialization for AvatarGenerator
- Prevent errors on pages without avatar canvas element
- Separate back-to-top logic into dedicated script module
- Create src/scripts/backToTop.ts
- Update knip.json for new file

feat: implement comprehensive site enhancements and optimizations

October 23, 2025 asce1062 View on GitHub 7aeeb35
Commit details
## Blog Infrastructure
- Migrate blog posts to content collections with glob loader
- Create dynamic route /blog/[...slug].astro for blog post rendering
- Implement accurate reading time estimator based on word count (200 WPM)
- Add reading time display to blog cards and post layouts
- Update blog post paths from src/pages/blog to src/content/blog
- Update all MDX imports to use path aliases (@/)

Files: src/content/config.ts, src/pages/blog/[...slug].astro,
src/pages/blog/index.astro, src/pages/tags/[tag].astro,
src/layouts/BlogLayout.astro, src/lib/blog/utils.ts,
src/components/Post.astro

## SEO Enhancements
- Generate unique Open Graph images per blog post using astro-og-canvas
- Integrate content collections with OG image generation
- Add RSS feed auto-discovery meta tags for better feed detection

Files: src/pages/open-graph/[...route].ts,
src/components/seo/MetaTags.astro

## View Transitions & UX
- Implement Astro ClientRouter for SPA-like page navigation
- Add fade transitions between pages for smooth navigation
- Update all interactive components to support view transitions:
- Blog interactions (BlogLayout)
- Theme switcher (ThemeSwitcher)
- Search functionality (SearchField)
- GitHub contributions (GitHubContributions)
- Avatar generator (AvatarGenerator)
- Add astro:page-load event listeners for proper reinitialization
- Prevent duplicate search box initialization with state tracking

Files: src/layouts/Layout.astro, src/layouts/BlogLayout.astro,
src/components/ThemeSwitcher.astro, src/components/SearchField.astro,
src/components/GitHubContributions.astro,
src/components/AvatarGenerator.astro

## Dark Mode Improvements
- Add smooth CSS transitions for theme switching (0.3s bg, 0.2s colors)
- Implement smart exclusions to prevent animation conflicts
- Add prefers-reduced-motion support for accessibility
- Eliminate jarring theme switch flashes

Files: src/styles/global.css

## Footer Enhancements
- Add build timestamp to footer
- Display formatted build date alongside commit hash
- Capture build time at build-time via new Date().toISOString()

Files: src/data/navigation.ts, src/components/Footer.astro

## Implement Content Security Policy (CSP) headers:
- Add strict CSP directives to prevent XSS attacks
- Configure script-src with necessary inline permissions for Astro
- Restrict image sources to self, data URIs, HTTPS, and blobs
- Allow iframe embedding only from trusted GitHub contributions source
- Allow our service worker to fetch GitHub OpenGraph images from opengraph.githubassets.com
- Add Strict-Transport-Security with 2-year max-age and preload
- Enhance Permissions-Policy to restrict payment API access
- Add worker-src directive for service worker support
- Include connect-src for fetch/XHR restrictions

Files: netlify.toml

## Service Worker Enhancements
Add runtime caching strategy for GitHub OpenGraph images used in project cards:
- Cache GitHub OG images from opengraph.githubassets.com
- Use CacheFirst strategy for optimal performance
- Configure 30-day expiration with 50 image limit
- Enable offline support for project card images
- Reduce bandwidth usage by caching external images
- Eliminate network latency on repeat visits

Files: astro.config.mjs

## Technical Details
### CSP Directives
- default-src 'self' - Restrict all resources to same-origin by default
- script-src 'self' 'unsafe-inline' 'unsafe-eval' - Allow Astro hydration
- style-src 'self' 'unsafe-inline' - Allow inline styles for Astro
- img-src 'self' data: https: blob: - Support various image sources
- font-src 'self' data: - Allow local and data URI fonts
- connect-src 'self' https://jandee.vercel.app - Restrict API calls
- frame-src https://jandee.vercel.app - Only GitHub contributions iframe
- worker-src 'self' blob: - Support service workers and blob workers
- object-src 'none' - Block plugins like Flash
- base-uri 'self' - Prevent base tag hijacking
- form-action 'self' - Restrict form submissions
- frame-ancestors 'none' - Prevent clickjacking
- upgrade-insecure-requests - Force HTTPS for all resources

### Additional Security Headers
- X-Frame-Options: DENY (legacy clickjacking protection)
- X-XSS-Protection: 1; mode=block (legacy XSS protection)
- X-Content-Type-Options: nosniff (prevent MIME sniffing)
- Referrer-Policy: strict-origin-when-cross-origin (privacy)
- Permissions-Policy: Restrict camera, microphone, geolocation, payment
- Strict-Transport-Security: 2-year HSTS with preload eligibility

### Reading Time Algorithm
- Strip MDX frontmatter, imports, JSX, code blocks, and markdown syntax
- Count actual readable words
- Calculate based on 200 words per minute industry standard
- Provide fallback for empty content

### View Transitions Lifecycle
- Initialize on DOMContentLoaded for first page load
- Reinitialize on astro:page-load for client-side navigation
- Prevent duplicate initializations with state tracking
- Maintain functionality across page transitions

## Technical Notes

### Static Site CSP Limitations
While unsafe-inline weakens XSS protection, it's required for static Astro sites due to:
- Astro's component hydration using inline scripts
- astro-themes FOUC prevention scripts
- Service worker registration inline script
- View transitions client router inline code

## Performance Impact
- No hydration cost from view transitions (uses native API)
- Lazy search initialization with requestIdleCallback
- Optimized font loading with font-display: swap
- Build timestamp captured at build-time (zero runtime cost)

## Accessibility
- Automatic route announcements for screen readers
- prefers-reduced-motion support for theme transitions
- Proper ARIA labels maintained across transitions
- Skip-to-content links preserved
- GitHub OG Images: Instant loading after first visit (0ms latency)
- Offline Support: Project cards remain functional offline

feat: add commit hash display to footer and update environment configuration

October 23, 2025 asce1062 View on GitHub 65e1037
Commit details
Footer Enhancements:
- Display current commit hash in footer with link to GitHub commit
- Format: "open source on commit [hash]. made with astro"
- Conditional rendering - only shows when COMMIT_REF is available
- Add Astro link to footer text

Site Metadata Updates:
- Add commit hash logic to siteMetadata in navigation.ts
- Add computed properties: commitHash, commitHashFull, commitUrl
- Add astroUrl to siteMetadata for centralized link management
- Create helper functions getFullCommitHash() and getShortCommitHash()
- All footer data now centralized in single source of truth

PWA Screenshot Updates:
- Add 5 mobile screenshots (narrow form factor, 1242x2688)
- Add 8 desktop screenshots (wide form factor, 1280x720)
- Add proper sizes attribute to all screenshots for validation
- Comply with PWA manifest screenshot limits

Add automatic GitHub OG image fallback for project cards
- Add getGitHubOgImage() helper function to src/lib/api/github.ts
- Parses GitHub repo URLs to extract owner and repo name
- Generates OpenGraph preview URL: opengraph.githubassets.com/1/{owner}/{repo}
- Returns null for invalid URLs with proper error handling

- Update Card component to use GitHub OG fallback images
- Import and utilize getGitHubOgImage() helper
- Maintain image priority: local image prop → imagePath lookup → GitHub OG
- Render GitHub OG images when no local images exist

Build & Deploy Configuration:
- Set COMMIT_REF=$(git rev-parse HEAD) in package.json predeploy
- Ensures commit hash available for GitHub Pages deployments
- Add COMMIT_REF to .env.example with setup instructions

feat: integrate GitHub API for dynamic project fetching and display

October 22, 2025 asce1062 View on GitHub d57d932
Commit details
  • Implement GitHub API integration to fetch repositories dynamically

- Create getFeaturedProjects() with pagination support (up to 1000 repos)
- Add support for sorting by stars, name, or recent activity
- Include language enrichment via parallel API calls
- Add optional fork filtering and project blacklist

- Add language icon mapping utility
- Map programming languages to icon classes
- Support case-insensitive matching with fallback logic

- Refactor projects page to use GitHub API
- Replace static JSON with live API data
- Display all languages per project (not just primary)
- Add fork indicators with icon-git
- Sort by most recently pushed repositories
- Support optional project preview images (jpg/jpeg/png/gif)

- Update reusable Card component
- Consolidate project card layout into single component
- Add optional image loading with automatic format detection
- Include star counter, fork badge, and language tags with icons
- Support responsive grid layout via Columns component

- Update homepage projects list to also use GitHub API
- Fetch top 4 starred projects dynamically

- Improve blog post layout and accessibility
- Redesign post layout

- Add environment configuration
- Create .env.example with placeholders for GitHub PAT and Netlify tokens

Technical Details:
- Use Promise.all for parallel API calls (language fetching)
- Implement pagination to fetch all repos (100 per page, max 10 pages)
- Support word-breaking for underscore-separated names (break-all)
- Prevent star counter squeezing with flex-shrink-0

updates: offline support and enhance SEO with Person schema

October 21, 2025 asce1062 View on GitHub cfdb1c5
Commit details
  • Update PWA offline functionality:

- Create /offline page with connection status detection
- Implement OfflineManager utility for last page tracking
- Add auto-redirect when connection is restored
- Configure service worker offline fallback in astro.config.mjs

* Enhance structured data and SEO:
- Add Person JSON-LD schema to OpenGraphTags component
- Include expertise areas, education, and social profiles
- Improve search engine understanding of personal identity
- Add google website verification file

* Update homepage and TypeScript configuration

feat: add copy link button

October 18, 2025 asce1062 View on GitHub 6ec2966
Commit details
  • Add copy link button to blog social share buttons

- Create reusable CopyToClipboard utility in src/scripts/
- Add share button with icon-share icon and hover:-rotate-6 animation
- Copy format: "Title\nURL" for easy sharing
- Show notification on successful copy

fix: service worker intercepting URLs with query parameters and sending them to the 404 page

updates

October 17, 2025 asce1062 View on GitHub c61de47

fix(pwa): resolve service worker issues with XML files and development mode

October 17, 2025 asce1062 View on GitHub 78644a4
Commit details
  • Added navigateFallbackDenylist to prevent XML files (RSS, sitemap) from

being redirected to 404 page
- Added 'xml' to globPatterns to ensure RSS and sitemap files are precached
- Excluded /fonts/icomoon/ directory from precaching to fix 404 errors
- Updated service worker registration to only run in production mode,
preventing 404 errors during development

fix(pwa): exclude icomoon font directory from service worker precaching

October 17, 2025 asce1062 View on GitHub d47513c
Commit details
Resolved service worker precaching error by adding globIgnores configuration
to exclude the /public/fonts/icomoon/ directory, which is used for version
control of font definitions and not actively served in the application.

- Added globIgnores to workbox configuration in astro.config.mjs
- Excluded patterns: /fonts/icomoon/ and **/fonts/icomoon

This fixes the browser console error:
"bad-precaching-response: {"url":"https://alexmbugua.me/fonts/icomoon","status":404}"

feat: SEO enhancements

October 17, 2025 asce1062 View on GitHub c4f330e
Commit details
Add extensive SEO optimizations across the site to improve search engine
visibility, social media previews, and accessibility:

Open Graph & Twitter Card Enhancements:
- Add og:image dimensions (1200x630 for articles, 400x400 for website)
- Add og:image:type for proper image display
- Add article:author and article:section metadata
- Add twitter:label1/data1 for reading time display
- Add twitter:label2/data2 for published date
- Implement reading time estimation utility (200 words/min)

JSON-LD Structured Data:
- Add BreadcrumbList schema for navigation hierarchy
- Add Organization schema alongside Person schema
- Add wordCount and timeRequired to BlogPosting schema
- Enhance schema with comprehensive social profiles

Security & Privacy:
- Add referrer policy (strict-origin-when-cross-origin)
- Add color-scheme meta tag for dark mode support

Accessibility Improvements:
- Add skip-to-content link for keyboard navigation
- Ensure proper focus management and ARIA support
- Verify lang="en" attribute on html element

Favicon Optimization:
- Generate favicon-16x16.png and favicon-32x32.png
- Add multiple favicon sizes for better browser support
- Maintain .ico fallback for older browsers

[feat] Implement Progressive Web App (PWA) and accessibility fixes

October 17, 2025 asce1062 View on GitHub 8614467
Commit details
  • Add full PWA support with offline functionality and installability

- Fix accessibility tap target sizing (WCAG 2.1 compliance)
- Add adaptive theme colors for mobile browsers
- Generate optimized PWA icons with maskable variants
- Configure service worker with intelligent caching strategies

[chore] update README with Netlify deployment integration

October 17, 2025 asce1062 View on GitHub e41e314
Commit details
### README.md
Added Table of Contents:
Added Netlify Deployment Documentation:
1. Setup: Link Repository to Netlify (One-time)
- Netlify UI method (step-by-step):
* Log in and import existing project
* Connect GitHub and authorize
* Configure build settings (base directory, build command, publish directory)
* Add environment variables (GUESTBOOK_ID, NETLIFY_ACCESS, NODE_VERSION)
* Configure custom domain (alexmbugua.me)
* Update site name (optional)
- Netlify CLI method:
* Install options (npx vs global)
* Authentication with netlify login
* Link repository (--name flag or interactive)
* Verify connection with netlify status
* Set up local .env file
* Why use npx vs global install (detailed comparison)
2. Automatic Git Deployment (Recommended)
- Push to main triggers automatic deployment
- Netlify runs build with Node 22
- Deploys dist directory
- Runs plugins for optimization
- Deploy notifications setup
3. Local Development with Netlify Features
- Test environment variables injection
- Test redirects and headers
- Test form submissions locally
- Runs on localhost:8888 (proxies Astro dev on 4321)
4. Manual CLI Deployment
- Production deployment: npm run deploy:netlify
- Preview/draft deployment: npm run deploy:netlify:preview
- Both npx and global CLI examples provided
5. Netlify Configuration
- Build settings (Node 22, dist output)
- Deploy contexts (production, preview, branch)
- Security headers (all 5 explained)
- Cache control (1 year immutable, 1 week images)
- Redirects (404 fallback)
- Netlify plugins (4 plugins with descriptions)
- Environment variables (required and auto-configured)
- Custom domain setup
6. Netlify Dev Notes
- When to use npm run dev vs npm run preview:netlify
- Testing Netlify features locally
7. Troubleshooting Netlify Builds
- Husky devDependency issue (expected behavior)
- Import resolution errors (dependencies vs devDependencies)
- Plugin failures (cache clearing)
- Environment variable issues (scope and injection)

feat: Add Netlify deployment integration

October 17, 2025 asce1062 View on GitHub 30b1f49
Commit details
### netlify.toml
- Netlify configuration with build settings (Node 22, dist output)
- Local development configuration (Astro dev on port 4321, Netlify Dev on 8888)
- Production, preview, and branch deploy contexts
- Security headers:
- X-Frame-Options: DENY
- X-XSS-Protection, X-Content-Type-Options
- Referrer-Policy: strict-origin-when-cross-origin
- Permissions-Policy for camera, microphone, geolocation
- Cache control headers:
- 1 year cache for immutable assets (JS, CSS, fonts)
- 1 week cache for images (PNG, JPG, WebP)
- 404 redirect handling
- 5 Netlify plugins configured:
* netlify-plugin-cache - Cache node_modules/.astro/dist for faster builds
* @netlify/plugin-sitemap - Automatic sitemap generation
* @netlify/plugin-lighthouse - Performance audits (90% thresholds)
* netlify-plugin-checklinks - Link validation (skips 404 pages)
* netlify-plugin-submit-sitemap - Auto-submit to Google/Bing/Yandex

### package.json
- Added Netlify deployment scripts:
* deploy:netlify - Production deployment
* deploy:netlify:preview - Preview/draft deployment
* preview:netlify - Local dev with Netlify features
- Installed dependencies:
* netlify-cli@^23.9.1 - Netlify command-line interface
* netlify-plugin-cache@^1.0.3 - Build caching plugin
* prettier-plugin-toml@^2.0.6 - TOML formatting support
- Updated lint-staged to include *.toml files for formatting

### .prettierrc
- Added prettier-plugin-toml to plugins array
- Added TOML file formatting override:
* 2 spaces indentation (no tabs)
* Consistent with JSON formatting rules

feat: add comprehensive image optimization configuration

October 16, 2025 asce1062 View on GitHub b2568df
Commit details
Implemented image optimization with responsive breakpoints,
modern formats (WebP/AVIF), and automatic srcset generation for optimal
performance across all devices.

### Image Service Configuration (astro.config.mjs)
- Configured Sharp image processor for high-quality optimization
- Set pixel limit to 268M (~16K image max) for safety
- Added WebP and AVIF format support for modern browsers
- Set default quality to 80 (optimal quality/size balance)

### Configuration Details
```js
image: {
service: {
entrypoint: "astro/assets/services/sharp",
config: { limitInputPixels: 268402689 }
},
formats: ["webp", "avif"], // Modern formats with fallbacks
quality: 80 // Balanced compression
}

### ImageView Component (src/components/ui/ImageView.astro)

- Added responsive srcset with Tailwind breakpoints [640, 768, 1024, 1280, 1536]
- Configured sizes attribute: (max-width: 640px) 100vw, (max-width: 1024px) 80vw, 1024px
- WebP format with quality 80
- Added TypeScript interface for widths and sizes props
- Maintains lazy loading and async decoding

### Post Component (src/components/Post.astro)

- Optimized thumbnail images with widths [144, 288, 432] (1x, 2x, 3x)
- Fixed size attribute: 144px for consistent thumbnails
- WebP format with quality 80
- Responsive images for Retina displays

### PreviewImage Component (src/components/PreviewImage.astro)

- Added responsive widths [640, 768, 1024, 1280]
- Configured sizes: (max-width: 768px) 100vw, (max-width: 1024px) 80vw, 1024px
- Higher quality (85) for hero/preview images
- WebP format for better compression

### Responsive Image Sizes Strategy

- Mobile (< 640px): 100vw (full width)
- Tablet (640-1024px): 80vw (80% width)
- Desktop (> 1024px): 1024px max
- Thumbnails: Fixed 144px with 2x/3x variants

- Standard images: 80 (optimal balance)
- Hero/preview images: 85 (higher quality)
- Thumbnails: 80 (sufficient for small sizes)

All images now support these props:
- widths: Array of image widths for srcset
- sizes: CSS sizes attribute for browser selection
- quality: Compression quality (0-100)
- format: Output format (webp, avif, jpg, png)
- loading: lazy (default) or eager
- decoding: async (default) or sync

feat: codebase refactoring, quality and tooling improvements

October 16, 2025 asce1062 View on GitHub 73b8ca7
Commit details
### TypeScript Configuration (tsconfig.json)
- Removed deprecated baseUrl option
- Updated path aliases to use relative paths (./src/*)
- Enhanced strict mode settings:
- Added noUnusedLocals, noUnusedParameters
- Added noFallthroughCasesInSwitch
- Enabled allowSyntheticDefaultImports
- Enforced forceConsistentCasingInFileNames

### Markdown Configuration (markdown.config.ts)
- Fixed type incompatibilities with VS Code theme imports
- Added type assertions for rehype-pretty-code theme options
- Fixed remark-slug plugin type conflicts
- Resolved rehypeAccessibleEmojis type incompatibility

### Tailwind Configuration (tailwind.config.mjs)
- Integrated with design tokens from src/config/design-tokens.mjs
- Simplified configuration using centralized token system
- Added LightningCSS for faster CSS minification

### ESLint Configuration (eslint.config.mjs)
- Migrated to ESLint v9 flat config format
- Configured @typescript-eslint parser and plugin
- Added astro-eslint-parser for .astro files
- Integrated eslint-plugin-astro with recommended rules
- Set up TypeScript-aware linting with type checking

### Prettier Configuration
- Updated .prettierrc with comprehensive formatting rules
- Added prettier-plugin-astro for Astro file support
- Configured tab width, semi-colons, and quotes preferences
- Updated .prettierignore with proper exclusion patterns

### Configuration Organization
- Moved src/config.ts → src/config/site-config.ts
- Created centralized src/config/ directory for all configuration
- Updated all imports across 4+ files (Layout, MetaTags, OpenGraphTags, RSS)

### UI Components Organization
- Created src/components/ui/ directory for generic components
- Moved reusable components:
- Card.astro
- Columns.astro
- Expand.astro
- ImageView.astro

### Styles Organization by Tailwind Layers
- Reorganized CSS into logical structure:
- src/styles/global.css: Main entry with @layer base and components
- src/styles/components/: Component-specific styles
- avatar.css (Avatar generator)
- guestbook.css (Guestbook entries)
- search.css (Pagefind search)

### Husky Setup
- Installed husky@^9.1.7 and lint-staged@^16.2.4
- Added "prepare": "husky" script for automatic setup
- Created .husky/pre-commit hook
- Configured git hooks path: core.hooksPath = .husky

### Lint-staged Configuration
- JavaScript/TypeScript/Astro files: ESLint --fix + Prettier
- JSON/Markdown/CSS/YAML files: Prettier formatting
- Runs only on staged files (performance optimized)
- Automatically stages fixed files
- Integrates with existing .prettierignore rules

### Added Dependencies
- lightningcss@^1.30.2 (Fast CSS minifier)
- husky@^9.1.7 (Git hooks)
- lint-staged@^16.2.4 (Staged file linting)

### Updated knip.json
- Added lightningcss to ignoreDependencies (used by Vite)
- Added pagefind to ignoreDependencies (used by Astro integration)

## Scripts & Tooling
- Added scripts: format, lint, lint:fix
- Pre-commit hooks now enforce quality before commits

[refactor] Pages refactoring

October 16, 2025 asce1062 View on GitHub 23b66b4
Commit details
### src/lib/api/guestbook.ts
- Guestbook API integration with Netlify Forms
- Type-safe GuestEntry interface for API responses
- Exported utilities:
- getGuestEntries(): Fetch submissions with error handling
- getInitials(): Generate avatar initials from name
- formatEntryDate(): Consistent date formatting
- Environment variable validation
- Centralized error handling

### src/components/GuestbookEntry.astro
- Dedicated component for rendering guestbook entries
- Consumes GuestEntry interface for type safety
- Handles conditional URL linking
- Separates rendering logic from page orchestration

### src/scripts/guestbookCounter.ts
- Nostalgic hit counter logic extraction
- Exported utilities:
- generateCounterValue(): Random 6-digit counter
- initGuestbookCounter(): Initialize counter display
- Follows established scripts pattern (themeManager, keyboardShortcuts)

### src/styles/guestbook.css
- 154 lines of extracted inline styles
- Theme-aware CSS with light/dark mode support
- Nostalgic web effects (blink, marquee, gradient animations)
- Entry layout and bubble styling
- Browser-cacheable separate from page logic

### src/lib/blog/utils.ts
- Shared blog post utilities to eliminate duplication
- Exported utilities:
- formatPostDate(): Consistent date formatting (long/short)
- getPostUrl(): URL generation from post ID
- sortPostsByDate(): Sort posts by pubDate (newest first)
- getAllTags(): Extract unique tags from posts
- Type-safe with CollectionEntry<"blog"> types

Created `knip.json` Configuration

October 16, 2025 asce1062 View on GitHub 07643c3
Commit details
What We're Ignoring (and Why):

- pagefind dependency - Used by astro-pagefind integration (runs via Astro hooks)
- Demo files - public/fonts/icomoon/demo-files/ (IcoMoon preview files)
- Build scripts - scripts/
(deployment utilities like fix-rss.js, pre-deploy.js)
- Public API modules - These export functions intended for external use:
- src/scripts/blogInteractions.ts - Utilities like scrollToTop(), initBackToTop()
- src/scripts/keyboardShortcuts.ts - Public API: registerShortcut(), registerShortcuts()
- src/scripts/themeManager.ts - Theme utilities: getCurrentTheme(), isLightMode(), toggleTheme()
- src/data/navigation.ts - Configuration with public types: NavigationLink, SocialLink

Entry Points Configured:
- markdown.config.ts - Resolves rehype/remark plugin dependencies
- src/pages/**/*.{astro,mdx} - All page files
- src/layouts/**/*.astro - Layout components
- src/components/**/*.astro - Component files

Design Decisions

- All "unused" exports are intentionally part of the public API:
- Modules follow the "library pattern" - they export utilities even if not all are used internally
- Types are exported for consumer type safety
- This enables extensibility - users can import any utility they need
- Follows TypeScript best practices for module design

refactor: Complete refactoring of website codebase

October 16, 2025 asce1062 View on GitHub e30dcd7
Commit details
### Blog Layout Refactoring (BlogLayout.astro)
- Created src/scripts/blogInteractions.ts
- Extracted back-to-top button logic
- Extracted scroll progress bar functionality
- Centralized all blog interaction handlers
- Created reusable blog components:
- src/components/blog/SocialShareButtons.astro
- Supports 6 platforms:
- WhatsApp, Facebook, X, Telegram, Pinterest, Email
- src/components/blog/TableOfContents.astro
- Recursive ToC renderer with 3-level nesting support
- src/components/blog/PostNavigation.astro
- Previous/next post navigation with CollectionEntry types

### Avatar Generator Decomposition (AvatarGenerator.astro)
- Created modular TypeScript modules:
- src/scripts/avatarStateManager.ts
- State management with URL synchronization
- Shareable avatar URLs
- src/scripts/avatarRenderer.ts
- Canvas rendering with image caching
- Thumbnail generation
- Created component directory src/components/avatar/:
- GenderSelector.astro - Male/Female radio buttons
- AvatarCanvas.astro - Canvas element with loading
- LayerTabs.astro - 6 customization tabs
- LayerGrid.astro - Layer item container
- AvatarActions.astro - Randomize, Download, Share
- Created src/styles/avatar.css
- Extracted all avatar-specific styles
- Responsive design patterns

### SEO Meta Tags Extraction (Layout.astro)
- Created src/components/seo/MetaTags.astro
- Core SEO meta tags
- Created src/components/seo/OpenGraphTags.astro
- OG and Twitter Card meta tags

### Inline Styles Migration
- Migrated style="cursor: pointer;" to Tailwind cursor-pointer class
- Zero inline styles remaining in codebase

### CSS Variables Consolidation
- Organized CSS variables in src/styles/global.css with categories:
- Color Palette (9 colors)
- Layout & Spacing
- Typography
- Added 15 section comment headers for better organization:
- Custom Font Faces
- CSS Custom Properties
- Global Selections & Body
- Base Typography
- Layout Elements
- Icon Font Styles
- Responsive Typography
- Component Typography
- Lists
- Interactive Elements
- Content Blocks
- Utility Components
- Code Blocks & Syntax Highlighting
- Prose & Content
- Table of Contents
- Global Utility Styles

### Global CSS Cleanup
- Removed 3 blocks of commented-out code
- Improved documentation and organization
- Better maintainability with clear sections

### Theme Management Extraction
- Created src/scripts/themeManager.ts
- Type-safe theme management (Theme = "light" | "dark")
- Exports: getCurrentTheme(), isLightMode(), toggleTheme()
- Exports: updateThemeIcon(), initThemeSwitcher(), handleThemeToggle()
- Eliminates global function pollution
- Refactored src/components/ThemeSwitcher.astro
- Clean module imports instead of inline scripts
- Proper event handling with DOM manipulation

### Keyboard Shortcuts Extraction
- Created src/scripts/keyboardShortcuts.ts
- Reusable shortcut handler with modifier key support
- Interface: ShortcutConfig with key/modifier mapping
- Exports: registerShortcut(), initSearchShortcut(), registerShortcuts()
- Cross-platform support (Ctrl/Cmd)
- Refactored src/pages/search.astro
- Reduced from inline implementation to 2-line import
- Ctrl+K / Cmd+K search focus functionality

### Navigation Configuration
- Created src/data/navigation.ts
- Single source of truth for all site navigation
- Type-safe interfaces: NavigationLink, SocialLink
- Exported configurations:
- mainNavigation: 8 footer links
- socialLinks: 2 social media links (GitHub, LinkedIn)
- contactLinks: 3 contact/resume links
- siteMetadata: site-wide metadata
- Refactored src/components/Header.astro
- Dynamic rendering from centralized config
- Easy to maintain and update links
- Refactored src/components/Footer.astro
- Dynamic .map() rendering from config
- Animation patterns preserved

### Type Safety Improvements
- Enhanced src/types.d.ts
- Added comprehensive JSDoc documentation
- Added readonly modifiers for immutability
- Created dedicated interfaces:
- ImageMetadata - separate image data interface
- PostProps - Post component props
- ImageViewProps - ImageView component props
- PreviewImageProps - PreviewImage component props
- Improved type reusability across components
- Better IntelliSense/autocomplete support

### Zod Validation Enhancement
- Enhanced src/content/config.ts
- Comprehensive blog collection schema validation:
- Title: 1-100 characters
- Description: 10-200 characters
- Image URL: must start with "/" (relative path)
- Image alt: 5-150 characters
- PubDate: cannot be in future
- Tags: 1-10 tags, auto-lowercase, must be unique
- Optional: draft, featured fields
- Helpful error messages for content validation
- Type inference for better developer experience (DX)

### Script Loading Optimization
- Optimized src/components/SearchField.astro
- Implemented requestIdleCallback for deferred initialization
- Pagefind UI only loads during browser idle time
- Fallback with setTimeout for older browsers
- Reduces main thread blocking, improves Time to Interactive (TTI)
- Added performance documentation to src/components/AvatarGenerator.astro
- Documents Astro's automatic async script bundling
- Notes on DOMContentLoaded initialization

### Image Optimization
- Enhanced 3 components with lazy loading and async decoding:
- src/components/ImageView.astro
- src/components/PreviewImage.astro
- src/components/Post.astro
- Added attributes to all Astro Image components:
- loading="lazy" - lazy load images below fold
- decoding="async" - non-blocking image decode
- Leverages Astro's built-in optimizations:
- Automatic WebP/AVIF generation
- Responsive image sizing
- Width/height inference (prevents CLS)

[feat] - add 8biticon pixel avatar icon generator

October 10, 2025 asce1062 View on GitHub b73be52

* updates

October 9, 2025 asce1062 View on GitHub 2b4ac80
Commit details
  • autofocus search on page load

- guestbook entries layout

* updates

October 8, 2025 asce1062 View on GitHub 7492259
Commit details
  • search quality of life

- update search tips
- add keyboard shortcuts to quickly access search
- add <kbd></kbd> element styles
- add matching functionality
- sort search by date descending
- update pagefind.d.ts
- add date type

* updates

October 7, 2025 asce1062 View on GitHub 808edd9
Commit details
  • avoid data-pagefind-ignore wrapping

- dates, descriptions, tags, titles
- update search pagefind
- add Search Tips
- update footnotes layout

* updates

October 6, 2025 asce1062 View on GitHub 8347330
Commit details
  • update blog

- add one about realignment
- update rss generator
- add search page link to BlogLayout
- add search page link to Footer
  • [feat] - add blog search

- add pagefind, astro-pagefind and pagefind default-ui
- add SearchField component
- add search page
- add search.css to override default-ui styles
- match website theme
- add a declaration file for module '@pagefind/default-ui'
- add pagefind.d.ts

*updates

October 3, 2025 asce1062 View on GitHub d2bd586
Commit details
  • move markdown configs to markdown.config.ts

- Footer component layout
- GitHubContributions layout
- Header link depth to inline-block
- BlogLayout add optional Table of Contents
- add remark-extract-toc package
- add remark-slug package
- add exposed tableOfContents to specific blogs
- Index housekeeping
- styles
- add table-of-contents
- adjust footer
- add Knip to audit unused packages
- remove unused packages from package.json
- re-generate package.lock.json

* update blog layout

October 1, 2025 asce1062 View on GitHub c43ad92
Commit details
  • add share blog section

- add navigate to top
- add blog navigation section
- add permalink frontmatter to posts
- add page scroll progress indicator

remove layout margins

September 30, 2025 asce1062 View on GitHub 21334dd

- add github contributions heatmap

September 30, 2025 asce1062 View on GitHub 9c8488d

- update base layout style

September 30, 2025 asce1062 View on GitHub 0465254
Commit details
  • update code block layout

  • update code block theme

- add rosepine theme from vscode
  • update blog

- add tags to blog page
- use columns component for more flexibility
  • update tags

- use columns component for more flexibility

updates

September 29, 2025 asce1062 View on GitHub f1b6857
Commit details
  • add prettier

- format project
- update libraries
- columns component
- projects lists to 2 columns

updates

September 24, 2025 asce1062 View on GitHub 8466134
Commit details
  • blog

- add one about finding good in everyday
- redirects
- rss feed

Updates

September 16, 2025 asce1062 View on GitHub 3207c51

updates

September 16, 2025 asce1062 View on GitHub e65cb1a
Commit details
  • add section tittles to timeline

- add skills components
- update resume with skills
- update projects data
- update header view resume link

update

September 15, 2025 asce1062 View on GitHub 344d4f0
Commit details
  • add now page

- update icomoon pack
- add now page to Footer
- update guestbook

update resume

September 8, 2025 asce1062 View on GitHub 2996029

update blog

September 5, 2025 asce1062 View on GitHub ca99d7f
Commit details
  • add one about taking it one step at a time

updates:

August 29, 2025 asce1062 View on GitHub 1cdbd5e
Commit details
  • update README

- update code block styling
- wrap content

* updates

August 28, 2025 asce1062 View on GitHub 0cd13ca
Commit details
  • blog layout

- switch to row layout
- footer layout
- privacy policy layout
- add expand component
- update 404 content
- rss feed
- add copyright information

update:

August 22, 2025 asce1062 View on GitHub 10ead6e
Commit details
  • file and folder persmissions

- add _headers
- add _redirects
- add robots.txt
fix:
- rss generator

update:

August 22, 2025 asce1062 View on GitHub fa14940
Commit details
  • rss feed generator

- scripts
- remove rss-fix

update

August 21, 2025 asce1062 View on GitHub 9e8da5a
Commit details
  • rss feed header images

- add astro optimized images
- add rss-fix script
- adds xml:base attribute
- reorder namespaces

* update:

August 21, 2025 asce1062 View on GitHub a9dc911
Commit details
  • dependencies

- icomoon font with rss icon
  • add:

- rss feed for our blog

update: blog

August 21, 2025 asce1062 View on GitHub fa40abd
Commit details
  • add one about if it's not okay its not the end

fix: code block indentation

August 14, 2025 asce1062 View on GitHub 6158685
Commit details
update: tip #7 usage examples headers

update:

August 13, 2025 asce1062 View on GitHub 86fe131
Commit details
  • blog:

- Part 2:
- move saving/restore project tips to part 3
- update links to part 3
- add part 3: IcoMoon Mastery

fix:

August 11, 2025 asce1062 View on GitHub f2d171b
Commit details
  • links to part 2 icomoon workflow

- open-graph image generation font

update:

August 11, 2025 asce1062 View on GitHub a6db4d0
Commit details
  • blog

- part 1: add links to part 2
- add part 2: icomoon workflow
- styles/global.css
- ordered list styling within block quotes

update:

August 11, 2025 asce1062 View on GitHub 0cb5367
Commit details
  • hosting your own site permalinks

* update:

August 11, 2025 asce1062 View on GitHub 9981744
Commit details
  • update astro build config

- specify our assets output directory
- remove leading slash in build output
- update components/Header.astro
- update static link generation logic
- update layouts/Layout.astro
- fix static path links
- Use collections to query blog content
- add content config.ts
- use getCollection() instead of import.meta.glob() for our blog content
- update blog/index.astro
- use use getCollection()
- update pages/tags/[tag].astro
- use getCollection()
- update pages/tags/index.astro
- use getCollection()
- update styles/global.css
- ignore timeline and footnotes in ordered list
- update build and predeploy scripts
- build script: only run build
- predeploy script: remove no longer needed mv and run pre-deploy script commands
- update blogs
- fix verses

update: blog

August 6, 2025 asce1062 View on GitHub 928763b
Commit details
  • add one about letting wounds heal

update:

August 1, 2025 asce1062 View on GitHub 4bbb436
Commit details
  • Libraries:

- astro: 5.9.2 > 5.12.7
- astrojs/mdx: 4.3.0 > 4.3.2
- astrojs/sitemap: 3.4.1 > 3.4.2
- add check script: "npm run check"
- blog:
- add one about how to use IcoMoon to create and integrate high quality vector icon fonts
- ImageView component:
- add support for per image width adjustment
- Global css:
- fix code block responsiveness
- add ordered list styling
- add in-line code styling
- add blockquote styling
- add our IcoMoon generated files to version control
Fix astro check Warnings
- Remove Deprecated: Astro.glob()
- use import.meta.glob() to query source files
- add Frontmatter type

update: header SEO

July 28, 2025 asce1062 View on GitHub 0f7e48f

update: alex.immer project tools

July 28, 2025 asce1062 View on GitHub 6677ee6

* update:

July 28, 2025 asce1062 View on GitHub 010cc5a
Commit details
  • deploy script

- use gh-pages for .jekyll and CNAME options
- blog
- add one about making room for love and peace

update blog

July 24, 2025 asce1062 View on GitHub 716abbd
Commit details
  • add one about flowing with the current of life

- update code snipet in host your own site pt.2
- update case in resume

update: blog

July 17, 2025 asce1062 View on GitHub a8fc701
Commit details
  • add one about being present

Update README.md

July 10, 2025 Alex Mbugua Ngugi View on GitHub 0ffbc5f

Update README.md

July 10, 2025 Alex Mbugua Ngugi View on GitHub addc3a7

update: blog

July 9, 2025 asce1062 View on GitHub 4a39259
Commit details
  • one about getting started, thank yourself later

update layout:

June 30, 2025 asce1062 View on GitHub 2ae1f96
Commit details
  • Header search engine optimizations

- Footer
- fonts
- pre-deploy script
- open all external links in new tabs
update blog:
- add one about authenticity

update: blog

June 27, 2025 asce1062 View on GitHub ef34922
Commit details
  • add one about consistency

update: guestbook and success pages
- improve folder structure
- update image locations

feat: add success page

June 26, 2025 asce1062 View on GitHub 0fcd555
Commit details
  • add success.astro

- update guestbook to use custom redirect page
- add success.png

feat: add guestbook

June 26, 2025 asce1062 View on GitHub c14c863
Commit details
  • add guestbook.astro

- use netlify forms
- add images
- fetch guestbook entries
- style guestbook entries
- add privacy policy
  • switch to deploy using netlify

update: deploy scripts

June 26, 2025 asce1062 View on GitHub e9110b7

update blog

June 24, 2025 asce1062 View on GitHub 5184ec1
Commit details
  • add about theming with jekyll

- update typo in pt.1 host your own site
- update resume

update blog

June 24, 2025 asce1062 View on GitHub d121f85
Commit details
  • add one about perspective

update blog

June 23, 2025 asce1062 View on GitHub 932412d
Commit details
  • add about the gift of hindsight

update ImageView component

add blog: how to host a README.md with github

June 23, 2025 asce1062 View on GitHub 1dee0e9
Commit details
  • add ImageView component

update blog resume: include link to andela profile
- update Timeline component

add link to andela's profile partner view

June 23, 2025 asce1062 View on GitHub 83ee618
Commit details
  • update timeline component

- add optional more information
- update variable names

fix typo

June 22, 2025 asce1062 View on GitHub fa9928f

update tag descriptions

June 21, 2025 asce1062 View on GitHub e2bb220
Commit details
update blog
- update time image
- add about trusting the process
update timeline components
- add typing

update website README

June 20, 2025 asce1062 View on GitHub e7e12be
Commit details
update blog page name
update footer project link
update blog and tag content grouping
open music site on a different tab

add resume blog page

June 19, 2025 asce1062 View on GitHub 1a1d35a
Commit details
add timeline component
add motivation blog

feat: add blog

June 19, 2025 asce1062 View on GitHub 3698459
Commit details
  • add blog page

- add BlogLayout component
- add post component
- add PreviewImage component
- add typing
- add first post
feat: add tags
- add tags page
- add indexed tags page
feat: add OpenGraph images for all pages
- add [..route]
- update all layouts
- update all pages
  • fixes and updates

- update icon pack style and font
- update pre-deploy script
- update header
- fix missing icons in project.json
- fix icon names in project.json

feat: add projects

June 17, 2025 asce1062 View on GitHub ba8a4f6
Commit details
  • add card component

- add column component
- update index page
- add dev icons to fonts
fix: nested files accessing root assets
- update pre-deploy script

- update link share preview

June 17, 2025 asce1062 View on GitHub ab7074c

feat: add showcase section

June 16, 2025 asce1062 View on GitHub 6de1473

update summary language

June 16, 2025 asce1062 View on GitHub 860120a
Commit details
update Resume

icomoon: only export fonts we are using

June 16, 2025 asce1062 View on GitHub 69c0d28
Commit details
  • a huge font repository skews the project language

update README

June 16, 2025 asce1062 View on GitHub 754f68c

update Header

June 16, 2025 asce1062 View on GitHub 27a38b4
Commit details
update fonts with bootstrap icons v1.13.1 set

update Resume

June 15, 2025 asce1062 View on GitHub c295624
Commit details
add link to personal music site

update resume

June 15, 2025 asce1062 View on GitHub 81d5221

FIx: site name

June 14, 2025 asce1062 View on GitHub aed48d9
Commit details
  • update predeploy script

- create and populate CNAME with our address

update resume link on README

June 14, 2025 asce1062 View on GitHub 2910271

update resume.pdf

June 14, 2025 asce1062 View on GitHub 6dc3ee5

update resume

June 14, 2025 asce1062 View on GitHub 96758b6

Feat: artifacts and deployment to separate branch

June 14, 2025 asce1062 View on GitHub c74e8a8
Commit details
  • use gh-pages library to automate push and build

- add .nojekyll to prevent skipping _asset folders
- rename _astro to astro
  • remove _config.yml from root directory

  • update pre-deploy and deploy commands

  • rename post-build scripts

use gh-pages to push and build

June 14, 2025 asce1062 View on GitHub 74c10ff

Create static.yml

June 14, 2025 Alex Mbugua Ngugi View on GitHub 78d418f

remove static files from main branch

June 14, 2025 asce1062 View on GitHub cfda755

- restart workflows

June 13, 2025 asce1062 View on GitHub 84990d7

remove static.yml file

June 13, 2025 asce1062 View on GitHub a08be49

Create CNAME

June 13, 2025 Alex Mbugua Ngugi View on GitHub 0a649da

Delete CNAME

June 13, 2025 Alex Mbugua Ngugi View on GitHub 3657a59

Delete CNAME

June 13, 2025 Alex Mbugua Ngugi View on GitHub 9312d2b

Create CNAME

June 13, 2025 Alex Mbugua Ngugi View on GitHub cad83d3

Create static.yml

June 13, 2025 Alex Mbugua Ngugi View on GitHub e5f9ab9

remove static.yml file

June 13, 2025 asce1062 View on GitHub df7a6ed

remove demo files

June 13, 2025 asce1062 View on GitHub 5ff7e88

Fix: blank page on render

June 13, 2025 asce1062 View on GitHub f3a53af
Commit details
  • use root directory instead

try the root directory

June 13, 2025 asce1062 View on GitHub 8257b0e

Create static.yml

June 13, 2025 Alex Mbugua Ngugi View on GitHub 77f9bff

revert to working point

June 13, 2025 asce1062 View on GitHub c8f1bf3

remove static file

June 13, 2025 asce1062 View on GitHub bd02959

Create CNAME

June 13, 2025 Alex Mbugua Ngugi View on GitHub 72a0f71

move cname and config to static file directory

June 13, 2025 asce1062 View on GitHub 6314b01

Create CNAME

June 13, 2025 Alex Mbugua Ngugi View on GitHub 8818066

Delete CNAME

June 13, 2025 Alex Mbugua Ngugi View on GitHub ece76f1

Delete CNAME

June 13, 2025 Alex Mbugua Ngugi View on GitHub ac04e8c

Feat: add post build script

June 13, 2025 asce1062 View on GitHub f3319b9
Commit details
  • remove leading forward slash to linked generated stylesheets

- move asset links one level up on generated stylesheets
- Copy static files /dist to ../../docs/
Fix: leading slash breaking static path
Fix: generated css static file paths

Create CNAME

June 12, 2025 Alex Mbugua Ngugi View on GitHub 20c105e

feat: rewrite in astro.

June 12, 2025 asce1062 View on GitHub b24c67c

feat: create home page

June 12, 2025 asce1062 View on GitHub b929386
Commit details
  • Use Astro and tailwind for styling

- use icon fonts (iconmoon)
- add light theme

- use bootstrap icons

June 11, 2025 asce1062 View on GitHub 898243b
Commit details
  • align text and icons

add title

June 11, 2025 asce1062 View on GitHub 85777d4

- view only on github

June 11, 2025 asce1062 View on GitHub 81bb6b3

- download or view resume

June 11, 2025 asce1062 View on GitHub e2fd66b

- improve project structure

June 11, 2025 asce1062 View on GitHub fadca0a

- Fix: word wrap on smaller screens

June 11, 2025 asce1062 View on GitHub ddceb12
Commit details
  • make our table and elements more responsive

Bump ossf/scorecard-action from 2.4.0 to 2.4.2

June 10, 2025 dependabot[bot] View on GitHub 0b3da26
Commit details
Bumps ossf/scorecard-action from 2.4.0 to 2.4.2.
  • Release notes

  • Changelog

  • Commits


---
updated-dependencies:
  • dependency-name: ossf/scorecard-action

dependency-version: 2.4.2
dependency-type: direct:production
update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

switch README and website to vertical list

June 10, 2025 asce1062 View on GitHub 9c7022a

Merge remote-tracking branch 'origin/main'

June 10, 2025 asce1062 View on GitHub a5ee431
Commit details
  • origin/main:

Create static.yml

- add resume download

June 10, 2025 asce1062 View on GitHub af8d4a1

Create static.yml

June 10, 2025 Alex Mbugua Ngugi View on GitHub f06fc4d

** maintain separate github and website profiles

June 10, 2025 asce1062 View on GitHub 35d2d8a
Commit details
  • README

- remove reference to github
- re-order contact information
* website
- initial commit
- add index.html
- add styles and fonts

- remove site header

June 10, 2025 asce1062 View on GitHub 029819b

- remove static file workflows

June 10, 2025 asce1062 View on GitHub 3c362c9
Commit details
  • add scorecard

  • add dependabot

  • update website link

Create static.yml

June 10, 2025 Alex Mbugua Ngugi View on GitHub fa07540

- start adding details

June 10, 2025 asce1062 View on GitHub befa8a1
Commit details
  • add Resume

  • add CNAME

Initial commit

June 10, 2025 Alex Mbugua Ngugi View on GitHub e687e80

All 261 commits loaded

All 261 commits fetched at build time. No runtime API calls.

Colophon · Site diagnostics


                                              0d1b039 • • 5/6/2026

Alex's Workstation

stellar console

last seen back the same day

visits 1

signal restoring context

incoming transmission 860×580

Search

Search Tips

Indexed: Search by content, dates, description, excerpts, tags or titles

Exact phrases: Use quotes like "I'm happy you're here"

Fuzzy matching: Partial matches like config will find "configuration"

Multiple terms: Search for using icomoon to find posts containing both words

Shortcuts: Use Ctrl+K or Cmd+K for quick access