Repository navigation
Theme refresh + Umami analytics - #12
Merged
Merged
Conversation
…debar
- Trim global.scss to only Bootstrap imports (remove old fixed footer and .bio { display: block } rules)
- Change footer.js to use site-footer class and remove Bootstrap utility classes
- Make .global-wrapper a flex column layout with min-height 100vh
- Add .global-wrapper > .row flex rule to push footer to bottom
- Add .site-footer styling with border-top, centered text, and hover states
Fixes footer overlapping on short pages and sidebar layout being flattened by CSS cascade.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_$(uuidgen | head -c 8)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
… Bootstrap Card styling
- Rewrite PostsListCard to render plain <article className="post-card"> instead of react-bootstrap Card
- Update index.js to use PostsList component and query edges { node { ... } } instead of nodes
- Add category to GraphQL query fields (was missing from homepage)
- Replace .post-list-item CSS rules with .post-card styling that matches category/tag pages
- Homepage now uses identical markup and styling as category/tag pages
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
The pinned footer restore in the previous commit dropped the centering that used to come from Bootstrap's text-center utility class on the old JSX. Add it back directly in the CSS.
Replaces the stock Gatsby favicon/manifest icon with a generated mark
(">" chevron + cursor bar) matching the new theme, and swaps the plain
site-title header for a "$ happyphpdev_" wordmark styled the same way.
.main-heading was sized for a short plain-text title (fontSize-7); the 13-character "$ happyphpdev_" wordmark overflowed the narrow col-md-3 sidebar at that size. Also drop the now-unused .brand flex wrapper.
vertical-align (text-bottom, then baseline) kept looking off by a few pixels depending on the font's descender metrics. Switch to flexbox cross-axis centering on the .brand wrapper instead, which centers the cursor against the line box rather than a glyph baseline/descender line -- much less sensitive to font-specific metric quirks. Also: blink the cursor on hover (steps(1) 1s infinite), disabled under prefers-reduced-motion, per user request.
The cursor was a distinct inline-block flex item, so browsers could independently decide it didn't fit the remaining line width and wrap it onto its own line -- confirmed happening in Firefox but not Chrome at the sidebar's width, a classic atomic-inline-box wrapping edge case. Using the U+2588 full-block character as plain text content instead means it's part of the same run as "happyphpdev": it wraps exactly like any other character (predictably, identically across browsers) and never detaches from the word.
Extract the category list out of Bio (which was only fetching it via a second query alongside author data) into a dedicated Categories component, and render it in the sidebar right under the primary nav (home/rss) instead of after the bio block, per request. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Was left disabled in a pre-existing uncommitted change; user confirmed it should render. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
"// categories" was a separate <p> in its own block, visually disconnected from the "> home" / "> rss" menu above it (different prefix width, extra margin between blocks). Categories now returns an <li> rendered directly inside the same <ul> as home/rss, and a shared .menu-marker fixed-width (3ch) prefix wrapper makes "home", "rss", and "categories" all start at the same column regardless of the ">" vs "//" prefix length. Vertical rhythm between all three now comes from the single shared .sidebar-nav li margin-bottom rule instead of a separate heading margin. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Reuses the shared .menu-marker fixed-width prefix so individual category links line up with the rest of the menu, since they're links too. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Kept but disabled per request while its design/usage is reconsidered. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
fields.slug already comes with leading/trailing slashes from Gatsby's
createFilePath (e.g. "/2026/08/mikrotik-backup/"), so wrapping it again as
`/${fields.slug}/` produced "//2026/08/mikrotik-backup//" -- a leading //
in an href is parsed as a protocol-relative URL, so browsers were
resolving these links to a bogus host named "2026" instead of the post.
Pre-existing bug (not introduced by this refresh), previously only hit
category/tag pages since the homepage had its own separate, correct
markup; became visible everywhere once the homepage was unified onto
this shared component.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Non-root pages showed both a "\xe2\x86\x90 home" text link in the header and a "> home" item in the nav menu right below it -- two links to the same place. Show the "\$ happyphpdev_" wordmark everywhere instead (it already links home), and drop the now-redundant header-link-home link/CSS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Drop the leftover react-bootstrap Container and empty .category-container/.tag-container wrappers (zero CSS, inconsistent spacing vs. the rest of the theme) and the plain "Category: x" / "Tag: x" heading in favor of a styled archive-header matching the site's other eyebrow+title patterns. Also stop repeating the category on every card on a category page -- it's already the page you're on. New showCategory prop (default true) on PostsList/PostsListCard, set to false only from category.js. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Replace the full PostsList (meta line, excerpt, "read more" link) with a new minimal PostTitleList component on category/tag archive pages, per request -- these are browsing pages, not the homepage, so just the titles as a clickable list is enough. Trims category.js/tag.js's GraphQL queries down to only fields.slug + frontmatter.title (dropping excerpt, timeToRead -- which was already dead, never rendered -- and date). Also reverts the showCategory prop added to PostsList/PostsListCard earlier today: it was only ever passed false from category.js, which no longer renders PostsList at all, so the prop was dead weight. Verified against a real `gatsby build` output (dev mode's page shell can't show this), since it's a GraphQL query shape change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
PostsList now interleaves a "+1 post" fake diffstat (flanked by short lines) between cards instead of giving each card its own border-bottom. Only renders between cards, not after the last one -- verified via a real gatsby build (7 cards, 6 dividers) since dev mode's page shell can't show this. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Missed carrying justify-content: center over from the mockup -- both flex lines cap at max-width: 3rem, so without it the leftover space had nowhere to go and the whole row sat left-aligned by default. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Same treatment as the homepage divider concepts -- extends the site's existing // comment language instead of a plain rule. Verified against a real gatsby build (no <hr> left in the article body, "// EOF" text present). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Adds a Revolut link and a BTC on-chain address with a QR code (new qrcode.react dependency, React 19 compatible). Verified against a real gatsby build (dev mode's page shell can't show a client-rendered SVG QR code either). Deliberately left out for now, with TODOs in the source: - Lightning: the value provided was a BOLT11 invoice, not a Lightning Address -- invoices are single-use and expire (usually within an hour), so embedding one statically would silently stop working for every visitor after that. Needs an actual name@walletprovider.com address. - A coffee-tip link (Ko-fi vs Buy Me a Coffee) -- platform not decided yet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Replace the plain link + inline QR with small 8-bit-style badge buttons (clip-path corner notches, dark terminal surface, bright green glyph) -- Revolut is a plain outbound link, Bitcoin opens a modal with the QR code and address. Clicking either the QR or the address copies it via navigator.clipboard, with brief "copied to clipboard" feedback. Verified against a real gatsby build: SSR renders the two banners with the modal correctly absent (React state starts closed, no hydration mismatch) since dev mode's page shell can't show this either. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
"Enjoyed the post? A tip's always welcome." above the banner buttons, per request. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Covers what Adminer is, why it's preferable to phpMyAdmin, how to run it in Docker Compose for local dev, and a warning against exposing it on production. Notes from the site owner. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
"git remotes" isn't a real command -- it's "git remote -v". Also fixed several grammar rough spots (title, description, intro sentence, "GIT" -> "Git" capitalization) and clarified the Bitbucket screenshot's lead-in sentence. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Rest of the post is solid already, this is the only nit -- both spellings work (git config keys are case-insensitive) but the docs convention is excludesFile. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Bootstrap's own "a { color: ...; text-decoration: underline; }" rule has
the same specificity as ours and was loading later (global.scss, which
imports Bootstrap, comes after style.css in gatsby-browser.js), so every
link on the site -- including markdown body links -- rendered in
Bootstrap's default blue with a permanent underline instead of the site's
green/no-underline treatment.
Tried reordering the stylesheet imports first, but that flips the winner
for every selector Bootstrap and the theme both define, not just links,
and visibly changed fonts/other elements. Reverted that and used a
targeted specificity bump instead ("body a" beats a bare "a" regardless
of source order) so only the link rule is affected.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
… cards The homepage post cards were showing frontmatter.description (meant for SEO meta tags) instead of actual article content. Now they always use Gatsby's excerpt field, and authors can mark exactly where an excerpt should end with an "<!-- more -->" separator in the markdown body (configured via gatsby-transformer-remark's excerpt_separator option -- note the snake_case key name, "excerptSeparator" silently does nothing). Posts without the marker fall back to the default prune-length excerpt, same as before. description remains untouched for its SEO/meta-description purpose (Seo component, blog-post.js). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Without one, the homepage card's excerpt bled straight into the raw error-message code block instead of stopping after the intro sentence. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
This post was just a bare Dockerfile with no explanation, and its frontmatter description was a copy-paste leftover from the Doctrine Collections post (wrong topic entirely, would have shown up as a misleading SEO meta description). Added an intro paragraph, a closing note on the --allow-untrusted flags, and an excerpt marker so the homepage card doesn't lead with a raw code block. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Adds why the generic key/value types matter and, more importantly, that this is pure PHPDoc: PHP ignores it at runtime, it only helps when an IDE or a static analysis tool (PHPStan, Psalm) is actually reading it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Only posts that explicitly opt in with "<!-- more -->" get truncated with a "Read more" link. Posts without the marker (short announcements, etc.) now show their complete content on the card and skip the "Read more" link entirely, instead of silently falling back to a 140-char prune -- which was never the intent. Determined by checking rawMarkdownBody for the separator string, since Gatsby's excerpt field doesn't expose whether it actually found one. Verified against a real gatsby build: only the two posts carrying the marker show "Read more", the rest render their full HTML. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
post-card--note: inset panel (surface background, bordered, green left accent) so short announcement-style posts visually read as a different kind of content from regular article cards, not just another list item. Verified against a real gatsby build (5 note-styled, 2 regular, matching the 5 posts without a marker vs 2 with one). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXxyPkq7xMErj3CmKamPKk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Universal Analytics stopped collecting data in 2024; Umami replaces it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The deploy workflow ran on Node 18, which can't require() ES modules used by gatsby-transformer-remark's deps, so every main deploy failed. Pin Node via .nvmrc for both workflows, run make lint/test instead of missing npm scripts, and build on PRs (deploy stays main-only). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
gatsby-ssr.js; Google Analytics plugin removed (Universal Analytics stopped collecting data in 2024)Test plan
gatsby buildsucceeds in Dockerpublic/index.htmlcontains the Umami script and no Google Analytics tagprettier --checkflags pre-existing formatting insrc/components/support.tsxandsrc/layouts/base.js🤖 Generated with Claude Code