Webtrotion (github link) now renders proper footnotes and supports inline citations with BibTeX (for details, take a look at Introducing Webtrotion and
Making Webtrotion). You get hover previews and backlinks, and you keep the optional sitewide "All Footnotes" index (as before). Everything renders at build time and is controlled from a single config file, which you can now easily create/modify through a UI interface as well, thanks to Gemini 3.
I finally shipped two things I've wanted since day one: footnotes [a]
Why I Built This
Footnotes make the page calmer. They keep the main thread clean while preserving context and side-quests. And I do have many side quests. Citations are the other half: you get to attribute ideas properly, link sources, and still keep readers in the flow with hover previews and a clean reference section at the end. You could just use footnotes for citing stuff, but I like my bib files, so I built proper citation parsing too.
All of this renders statically during the build, which is how I like it.
Moving to JSON5 Config
One more thing: Webtrotion's configuration file now uses JSON5 format. This means you can finally have comments directly in your config file [d]constants-config.json5 instead of constants-config.json.
constants-config.json5 file. Don't try to just copy-paste your old values because the key names have changed too. JSON5 lets you:
- Add inline comments to explain what each setting does
- Use trailing commas without breaking things
- Write cleaner, more readable config files
The configuration structure has also changed significantly. Instead of a flat structure, settings are now organized into logical sections like notion, site-info, collections-and-listings, theme, tracking, comments, block-rendering, shortcodes, and auto-extracted-sections. This makes the config much more navigable, especially as the file has grown to support more features.
Font Configuration Simplified
One big change: fonts are now way simpler to configure. This now uses the Astro Experimental Fonts API.
Old way:
- Main fonts: You had to provide a
combined-urlwith the full Google Fonts URL, escape spaces in font names (Roboto\\ Mono), and pick between sans/serif/mono - OG image fonts: You had to provide
title-font-urlandfootnote-font-urlwith full Google Fonts URLs
New way:
- Main fonts: Just type the font name.
"sans-font-name": "Roboto"and"mono-font-name": "Roboto Mono". No URLs, no escaping. Webtrotion auto-loads weights [400, 500, 600, 700] and styles [normal, italic] [e][e].It is fine if you donβt have all the weights or styles in your chosen font, it will fallback gracefully. - OG image fonts: Just type the font name and weight for both the title and the footnote. Example:
"title-font-name": "Kreon"and"title-font-weight": 500.
The system handles all the URL generation and loading for you now.
How Footnotes Work in Webtrotion
Handling footnotes in digital writing can be a pain. You want the context without derailing the paragraph. Webtrotion's buildβtime footnote system lets you choose the authoring style that fits your workflow.
Configuration: footnotes
Here's the relevant section from constants-config.json5:
// === Footnotes Configuration ===
// Settings for both manual (sitewide) and automatic (in-page) footnotes.
footnotes: {
// The slug for a single, dedicated page that contains all footnotes for the entire site.
// This is a legacy method for manual footnote management.
"sitewide-footnotes-page-slug": "_all-footnotes",
// Settings for the modern, automatic in-page footnote system.
"in-page-footnotes-settings": {
enabled: true,
// Defines where the system should look for footnote content.
// Important: Only ONE of these source options can be 'true' at a time.
source: {
// Looks for definitions at the end of a text block, like `[^ft_1]: My footnote content.`Sepearate it by two soft new lines (using shift+enter). This is the method that will work when you export Notion content to Markdown.
"end-of-block": true,
// Uses inline LaTeX-style footnote command: \footnote{content here}. Use \{ and \} for literal braces (useful for LaTeX compatibility).
"inline-latex-footnote-command": false,
// Treats the first n set of child block(s) indented under a parent block as the footnote content. (n = number of footnote markers in the parent block)
"start-of-child-blocks": false,
// Uses Notion comments on a block as footnote content.
// Requires granting "Read comments" permission to your Notion integration. Else falls back to 'end-of-block' method.
"block-comments": false,
// Not yet implemented.
"block-inline-text-comments": false,
},
// The prefix for footnote markers in your Notion text. e.g., `[^ft_1]` for a prefix of `ft_`.
"marker-prefix": "ft_",
// If true, a collated list of all footnotes will be automatically generated at the bottom of the page.
"generate-footnotes-section": true,
// (Recommended) On large screens, displays footnotes in the margin. On smaller screens, it falls back to a popover.
"show-in-margin-on-large-screens": true,
},
},Key Settings for Footnotes
-
sitewide-footnotes-page-slug: Legacy manual collector (e.g.,_all-footnotes). The inβpage system is recommended for most occurences. -
enabled: Toggle inβpage footnotes. -
source: Pick exactly one of the three modes as defined here. -
marker-prefix: Default isft_. Change tonote_if you want markers like[^note_1]. -
generate-footnotes-section: Autoβcollate the footnote section at page bottom (also generates backlinks with popovers to where the footnotes came from). -
show-in-margin-on-large-screens: Shows footnotes in the margin on large screens, falls back to popovers on smaller screens. Set to false for popovers everywhere.
Pick One Source Mode
footnotes β in-page-footnotes-settings β source in constants-config.json5. Only one should be true at a time. - The Markdownβfriendly way (
end-of-block)Portability first. If you export to Markdown later, your footnotes will still make sense. Put the definitions at the end of the block, separated by two newlines (made using
Shift+Enter).In Notion, this is some text with a footnote[f]
[f]. It's a really interesting topic.This is the content of the footnote. It can be long and detailed and have links.In Notion, this is some text with a footnote[^ft_desc]. It's a really interesting topic. [^ft_desc]: This is the content of the footnote. It can be long detailed and have links. - The LaTeX inline way (
inline-latex-footnote-command)
Uses inline LaTeX-style footnote command:\footnote{content here}. Use\{and\}for literal braces (useful for LaTeX compatibility) inside the footnote content. Make sure that the footnote command is not inside inline code [g][g]. This method allows you to write footnotes directly inline with your text using LaTeX syntax, which can be particularly useful if you're already familiar with LaTeX or planning to copy your content to LaTeX format later.For example, the way the marker at start of this paragraph is written wonβt work, it needs to be in normal text. - The structured way (
start-of-child-blocks)Prefer a tidier Notion outline or want footnotes with varying kinds of content? Indent child blocks as the footnote content. For
nmarkers in a block, the firstnchild block(s) become the note. These child blocks can contain any block type and can have their own nested children.This is how youβll write it. Some text with a first footnote [^ft_a1] and a second footnote [^ft_b1].[^ft_a1]: This is the content of the footnote, written in a child block.And this will be part of the footnote
[^ft_b1]: This is the second footnote
And this child is not a footnote.
Note: The above will not be rendered because my config is set toend-of-block. - The Notionβnative way (
block-comments)Permissions: Your Notion integration needs "Read comments" permission for this mode to work.Use Notion comments as your footnote source to keep the notion document even more cleaner and you can have attachments in your footnotes this way. Highlight text/block [^ft_a2] with the marker definition [h]
[h], add a comment, and start it with your marker definition. Comments can include attachments, which will be rendered in the footnote.We need this because Notion API only returns block ids, not the text span that was commented on. When that is fixed, Iβll implementblock-inline-text-comments.Note: The above will not be rendered because my config is set toend-of-block.
Choose Your Own Marker Prefix
The marker-prefix setting is just a namespace for your footnote markers. By default it's ft_, so your markers look like [^ft_1], [^ft_note] [i]
Why have a prefix at all? Because if you're using standard Markdown footnote syntax elsewhere (like [^1]), you don't want collisions. The prefix keeps Webtrotion's footnotes separate. You can change it to note_ or fn_ or anything you want. Just keep it consistent across your site.
Maybe Show a Collated Footnote Section at The End of Page
Set generate-footnotes-section to true and Webtrotion will automatically collect all your footnotes and dump them in a neat little section at the bottom of the page. It's like endnotes in a website or a white paper. Each one gets a popover based backlink so readers can jump back to where the footnote was mentioned.
If you set it to false, footnotes only exist as inline popovers or margin notes. No bottom section at all. I keep mine on because some people like to scroll down and read all the tangents at once.
Choose Footnote Display Mode
Set show-in-margin-on-large-screens to control how footnotes appear.
Margin notes on large screens (show-in-margin-on-large-screens: true): This is the option I use. On desktop or tablets with enough space, footnotes appear in the right margin β like marginalia. On phones, they fall back to popovers because there's no margin space.
Always popover (show-in-margin-on-large-screens: false): Every footnote marker, when hovered (on larger screens) or clicked (on smaller screens), shows a little popover overlay. Simple, consistent across all screen sizes.
The Older Sitewide Footnotes Page
This is the legacy method, from before I built the automatic in-page system. You'd create a single dedicated Notion page (like "All Footnotes") and manually add your footnote content there, then reference it from other pages. Set the slug in sitewide-footnotes-page-slug.
The in-page system is way better β it's automatic, it's per-page, and you don't have to maintain a giant footnote index manually. I'm keeping the sitewide option around for backwards compatibility, as well as for situations where you need to reference the same βfootnoteβ at multiple places.
Citations with BibTeX
For students, researchers, and anyone who writes with sources, the citation system should be useful. Manage citations in a standard .bib file and have them rendered with in-text markers and an optional bibliography section. All processing happens at build time, and you get hover or click previews just like with footnotes.
For example, I can cite where the tufte style footnotes came from, they originated here [1]. Note how if the citation has a URL, which it does in this case, it also renders the URL as a clickable link.
This is how it renders:
Configuration: citations
Here's the relevant section from constants-config.json5:
// === Citations Configuration ===
"auto-extracted-sections": {
citations: {
// If true, a "Cite this page" section will be added to each page.
"add-cite-this-post-section": false,
// Configure how BibTeX citations are extracted and processed.
"extract-and-process-bibtex-citations": {
// If true, enables BibTeX citation processing.
enabled: false,
// Supported .bib file sources: GitHub Gist, GitHub repo file, Dropbox, and Google Drive public share links.
"bibtex-file-url-list": [
// Example: "https://gist.githubusercontent.com/username/gist-id/raw/file.bib"
],
// The pattern for in-text citations. Only one format is supported at a time.
"in-text-citation-format": "[@key]", // or "\cite{key}" or "#cite(key)"
// The citation style for the bibliography. Only one format is supported at a time.
"bibliography-format": {
"simplified-ieee": true, // For ICML/NeurIPS style
apa: false, // For ACL-style academic writing
},
// If true, a collated bibliography section will be automatically generated at the bottom of the page.
"generate-bibliography-section": false,
// If true, show citations in the right margin on large screens (β₯1024px). On smaller screens, citations will display as popovers.
"show-in-margin-on-large-screens": false,
},
},
}Key Settings for Citations
-
add-cite-this-post-section: Autoβadd a "Cite this page" block with a preβformatted reference, so that people can add your post to their own bibtex file. -
enabled: Turn on BibTeX processing. -
bibtex-file-url-list: One or more.bibfile URLs. Supports GitHub Gist, GitHub repo files, Dropbox, and Google Drive public share links. Note: Google Drive and Dropbox links don't provide public last-updated timestamps, so these files will be fetched and processed on every build. -
in-text-citation-format: Choose your marker pattern. Supports[@key](pandoc),\cite{key}(LaTeX), or#cite(key)(Typst). -
bibliography-format:simplified-ieee(for ICML/NeurIPS style) orapa(for ACL-style academic writing). -
generate-bibliography-section: Autoβadd a bibliography to the page. -
show-in-margin-on-large-screens: Shows citations in the margin on large screens, falls back to popovers on smaller screens. Set to false for popovers everywhere.
Add "Cite this page" Section
Set add-cite-this-post-section to true if you want Webtrotion to automatically add a "Cite this page" section at the end of each page. This generates a pre-formatted BibTeX entry for the page itself, making it easy for readers to cite your work in their own papers or bibliographies.
The generated entry includes your page title, author (from your config), the publication date, and the URL. Handy if you're publishing research notes, technical articles, or anything citation-worthy. I keep mine off because most of my posts are informal, but if you're writing academic content, turn it on.
Enable BibTeX citation processing
This is the master switch. Set enabled to true under extract-and-process-bibtex-citations to turn on the entire citation extraction system. If this is false, none of the citation processing happens β no parsing, no formatting, no bibliography generation. Everything else in this section only matters if this is true.
Simple on/off toggle. Turn it on when you need citations, leave it off if you don't.
Link your BibTeX files
The bibtex-file-url-list is where you tell Webtrotion where to find your .bib files. You can have one or multiple files, and they need to be publicly accessible URLs.
Supported Hosting Options for .bib Files
"bibtex-file-url-list": [
"https://gist.githubusercontent.com/username/gist-id/raw/file.bib",
"https://gist.github.com/username/gist-id",
"https://github.com/username/repo/raw/main/references.bib",
"https://www.dropbox.com/s/xyz/references.bib?dl=0",
"https://drive.google.com/uc?export=download&id=FILE_ID",
],GitHub Gist (recommended): Supports smart caching via last-modified timestamps. Use the raw URL or the Gist page URL.
GitHub repo file (recommended): Same smart caching as Gist. Use the raw URL or the file URL.
Dropbox: Public share links work (dl=0 or dl=1). No last-modified timestamp, so it fetches every build.
Google Drive: Use the export URL format shown above. Fetches every build like Dropbox.
Why use Dropbox or Google Drive? Better bib can auto-sync from Zotero to these.
Performance Note
Webtrotion doesn't parse your entire 6,000-entry .bib file and convert it all to JSON. That was the first version and it crashed immediately. Instead, it only parses and caches the entries actually cited on each page.
On subsequent builds, if the .bib file hasn't changed (based on last-modified timestamp for GitHub sources), Webtrotion skips the fetch entirely. This keeps build times fast even with large bibliographies.
Dropbox and Google Drive don't provide public last-modified timestamps, so those get fetched on every build. If build speed matters and you have a large .bib file, use GitHub or Gist instead.
Example BibTeX File
Here's what a typical .bib file looks like:
@book{sweig42,
title = {The Impossible Book},
author = {Stefan Sweig},
year = 1942,
month = mar,
publisher = {Dead Poet Society}
}
@article{steward03,
title = {Cooking behind bars},
author = {Martha Steward},
year = 2003,
publisher = {Culinary Expert Series}
}
@book{impossible,
title = {The impossible book},
author = {Stefan Sweig},
year = 1942,
month = mar,
publisher = {Dead Poet Society}
}You can use any standard BibTeX entry types: @article, @book, @inproceedings, @misc, etc. Webtrotion parses the common fields (author, title, year, publisher, journal, booktitle, etc.) and formats them appropriately.
Choose your Citation Syntax
The in-text-citation-format setting controls which syntax you use in your Notion text to mark citations. You have three options, and they all produce the same output β pick whichever feels natural.
Standard Markdown/pandoc style ([@key]): If you're used to writing in Markdown or use pandoc elsewhere, this will feel familiar. This is also supported by Typst. Example: [@sweig42]
LaTeX style (\cite{key}): For the LaTeX users, muscle memory is real. Example: \cite{sweig42}
Typst style (#cite(key)): If you use Typst for typesetting, this is especially handy because using the @ symbol in Notion triggers the annoying date/page popup. Example: #cite(sweig42)
The key is whatever you defined in your BibTeX entry. For example, if your .bib file has:
@book{sweig42,
title = {The Impossible Book},
author = {Stefan Sweig},
year = 1942,
month = mar,
publisher = {Dead Poet Society}
}Then you'd cite it in Notion as [@sweig42], \cite{sweig42}, or #cite(sweig42), depending on which format you chose in your config.
During the build, Webtrotion will:
- Find all citation markers in your Notion content
- Look up each key in your
.bibfiles - Format the in-text citation based on your chosen
bibliography-format - Collect and de-duplicate all citations for the bibliography section
Pick your bibliography style
The bibliography-format setting controls how citations are formatted both in-text and in the bibliography. You have two options:
simplified-ieee: Numbered citations in square brackets. In-text: [1], [2], etc. Good for NeurIPS, ICML style. The bibliography lists entries in citation order with [1], [2] prefixes (de-duplicated for multiple occurences).
apa: Author-year style. In-text: [Sweig, 1942], [Steward, 2003]. Better for humanities and social sciences, ACL-style papers. The bibliography lists entries alphabetically by author.
Both formats get hover previews. Readers can click or hover over [1] or [Sweig, 1942] to see the full reference in a popover, and then click through to jump to the bibliography if you have generate-bibliography-section enabled.
Generate the bibliography section
Set generate-bibliography-section to true and Webtrotion collects all citations from the page and builds a formatted bibliography at the end. Each entry gets backlink buttons that jump you to where you cited it β same UX as footnotes, but better because one source can be cited multiple times.
If you set it to false, citations still format properly and you still get hover previews, just no collected references section. Good for informal writing where you want to drop paper links without the formality of a bibliography.
The "Back to Content" button
When you click a citation to jump to the bibliography, you get a dynamic "back to content" button that takes you right back to where you were reading. I hate one-way jumps in PDFs, so I made sure this works smoothly.
Choose Citation Display Mode
Set show-in-margin-on-large-screens to control how the first occurrence of citations appear. That is, you get margin notes on large screens if true, otherwise theyβre always popovers. For multiple occurrences of the same citation key, theyβre always popovers after the first one.
Some Other Things That I Worked On
Here are the commit messages for the past 12-ish months in descending order on this repository. I work in bursts when other things in my life aren't going great, so this has been in bursts; in late December 2024 (cache deletion workflow), late January (Notion page embedding and SEO fixes), the last week of February (Tailwind v4 migration and HTML caching), early September (UI improvements like tags redesign and search from query parameters), and then the biggest push in late October through early November 2025 (the main 2.0 release with footnotes, citations, JSON5 config, and pagespeed optimizations).
Around the same time last year, I wrote
One year of Webtrotion. Of course, they're pretty messy, almost non-descriptive, and sometimes just merges from the branches I worked on, but they do give me a rough idea of the work I did.
Around the same time last year, I wrote
Mon Nov 03 2025: add extra delay because that didn't work well enough on long pages like this one
Mon Nov 03 2025: wait for fonts and RAF before initializing margin notes in second phase
Sun Nov 02 2025: show margin notes even if just on for citations and citations are enabled
Sun Nov 02 2025: citations are now extracted inside footnotes and shown in margin if the setting is enabled
Sat Nov 01 2025: set pagefind weight to 10 for title and remove pagefind for citethispage
Sat Nov 01 2025: fix bluesky tab not found on idle rather than click
Sat Nov 01 2025: preload only few fonts instead of all fonts
Sat Nov 01 2025: simpler config for fonts of og image
Sat Nov 01 2025: simplify font config and usage
Sat Nov 01 2025: keep jump backs to "Jump to"
Sat Nov 01 2025: custom emojis, files and external links for icons now work in callout and page icons.
Sat Nov 01 2025: optimize ncode mermaid loading
Sat Nov 01 2025: improve pageinsights by using astro experimental font api and removing googlefontsoptimizer
Fri Oct 31 2025: att2 at improving pagespeed
Fri Oct 31 2025: aim to fix pagespeed insights
Fri Oct 31 2025: do not show jump to bibliography, cite this page, footnotes section at the end of the post preview full component
Fri Oct 31 2025: fix citation caching issue
Fri Oct 31 2025: weird parsing bug fix in github actions att1
Fri Oct 31 2025: don't show url in formatted citation text
Fri Oct 31 2025: support url in formatted citations
Fri Oct 31 2025: fix footnote positioning, and feed pages show footntoe popovers on hover on large screens
Thu Oct 30 2025: load margin notes after font load and fix caching for bib
Thu Oct 30 2025: avoiding duplicate footnote/citation IDs when the same content appears multiple times in a page in popovers
Thu Oct 30 2025: simplify key for footnote display
Wed Oct 29 2025: fix marker extraction for citation
Wed Oct 29 2025: do not parse markers from inline code for citations and footnotes
Wed Oct 29 2025: style: update footnote and citation display terminology from 'popup' to 'popover' for consistency
Tue Oct 28 2025: fix-citation-storage
Tue Oct 28 2025: style: remove Cite This Page component from PostPreviewFull and [...page] for cleaner layout
Tue Oct 28 2025: style: disable citation features in configuration for general use
Tue Oct 28 2025: style: remove unsupported feature note in citations configuration and clarify in-text citation pattern description
Tue Oct 28 2025: Merge pull request #35 from nerdymomocat-templates/add-and-process-citations
Tue Oct 28 2025: cleaned up unsused code
Tue Oct 28 2025: style: simplify author formatting logic in formatCitation function for APA in-text citations
Tue Oct 28 2025: style: update version and cacheVersion in package.json for release 2.1.0
Tue Oct 28 2025: style: reorder citation and footnotes sections for improved clarity and consistency
Tue Oct 28 2025: style: refactor footnote handling to utilize FootnoteContent component for improved structure and readability and handle all attachment types consistently
Tue Oct 28 2025: style: update footnote handling to show popovers in footnotes section
Tue Oct 28 2025: style: update footnote source options and improve footnote rendering
Tue Oct 28 2025: style: update footnote and citation marker styles for improved readability
Mon Oct 27 2025: style: update font styles for citation and footnote markers
Mon Oct 27 2025: refactor: update import paths for NBlocksPopover, Icon, BibliographySection, and CiteThisPage components
Mon Oct 27 2025: npm run format
Mon Oct 27 2025: move citation marker component to popover folder
Mon Oct 27 2025: Merge branch 'main' into add-and-process-citations
Mon Oct 27 2025: Merge pull request #34 from nerdymomocat-templates/re-arrange-components
Mon Oct 27 2025: refactor: remove unused imports and clean up code across multiple components
Mon Oct 27 2025: move files around
Mon Oct 27 2025: match citation marker and footnote marker to nblocks popover
Mon Oct 27 2025: refactor: remove debug logging from popover click event handling
Mon Oct 27 2025: Attemptt 1 for bibliography
Sun Oct 26 2025: plan: update in-text citation format and bibliography configuration for improved citation processing
Sun Oct 26 2025: Merge branch 'main' of github.com:nerdymomocat-templates/webtrotion-astro-notion-cms-website-blog into add-and-process-citations
Sun Oct 26 2025: refactor: move linked content symbol logic to utils and update footnote display to use alphabetical indexing
Sun Oct 26 2025: feat: update citations configuration and desired plan
Sun Oct 26 2025: feat: update citations configuration and implementation plan to support new features and processing options
Sun Oct 26 2025: feat: add initial citations configuration and processing documentation
Sun Oct 26 2025: Merge pull request #33 from nerdymomocat-templates/fix-footnotes-not-on-pages-only-posts
Sun Oct 26 2025: refactor: remove unused footnote functions and integrate footnotes handling in main page (menu bar pages) content
Sun Oct 26 2025: Merge branch 'main' of github.com:nerdymomocat-templates/webtrotion-astro-notion-cms-website-blog
Sun Oct 26 2025: Remove 'v' query parameter from Notion links to ensure correct page and block link parsing.
Sun Oct 26 2025: Merge pull request #32 from nerdymomocat-templates/fix-nested-popovers-for-footnote-content-and-popover-show-for-margin-content
Sun Oct 26 2025: refactor: streamline popover creation and visibility handling
Sun Oct 26 2025: refactor: optimize popover event handling, popovers work for margin notes and improve device-specific selectors
Sun Oct 26 2025: refactor: remove breaking prettier-ignore comments from BaseHead and PostComments components
Sun Oct 26 2025: fix: specify event types for repository creation trigger in GitHub Actions workflow
Sun Oct 26 2025: Merge pull request #31 from nerdymomocat-templates/refractor--change-references-to-interlinked-content
Sat Oct 25 2025: refrac formatting errors
Sat Oct 25 2025: feat: add citations configuration for processing BibTeX citations and in-text citation formatting
Sat Oct 25 2025: refactor: update footnotes and interlinked content references to use new auto-extracted sections structure
Sat Oct 25 2025: refractor base.astro by moving scripts into their own files and moving style to global css and updating popover scripts to use latest versions of their libraries and remove config for headings (instead use constant)
Sat Oct 25 2025: npm run format
Sat Oct 25 2025: refactor: remove popovers configuration and simplify related components for cleaner code
Sat Oct 25 2025: fix: handle errors in cache file access checks and improve logging comments
Sat Oct 25 2025: changed name reference to interlinked content in constants and usage in files
Sat Oct 25 2025: run format
Sat Oct 25 2025: feat: update popover styles and dynamic background color generation for improved UI consistency
Sat Oct 25 2025: refactor: enhance workflow clarity by restructuring jobs and improving comments; streamline cleanup and build processes
Sat Oct 25 2025: feat: add shallow checkout step to improve workflow speed during initialization
Sat Oct 25 2025: fix: enhance cleanup detection logic for upstream template sync; implement robust checks for push events and SHA comparison
Sat Oct 25 2025: fix: enhance cleanup detection logic for upstream template sync; improve commit message parsing
Sat Oct 25 2025: feat: streamline GitHub Actions workflow by consolidating initialization and cleanup steps; enhance clarity and efficiency
Sat Oct 25 2025: feat: consolidate template cleanup logic into main workflow; remove redundant template-cleanup.yml
Sat Oct 25 2025: feat: add automated template cleanup workflow for new repository initialization and upstream sync
Sat Oct 25 2025: fix: improve footnotes styling and enhance comments in constants-config.json5; aim to fix margin note positioning on load
Sat Oct 25 2025: npm run format aftermath
Sat Oct 25 2025: Add upgrade notice for version 2.0.0
Sat Oct 25 2025: Merge pull request #30 from nerdymomocat-templates/claude-code-features-and-fixes-webtrv2-fix
Sat Oct 25 2025: webtrotion v.2.0.0
Sat Oct 25 2025: fix: fix rss links and footnote links (space issue)
Sat Oct 25 2025: add comments for: 1 level Nested table of contents for headings (callouts, toggles, columns) [apparently was already implemented]
Sat Oct 25 2025: dark mode and theme correction for footnotes
Sat Oct 25 2025: implement json5 reading for constants-config
Sat Oct 25 2025: failed: Theme change animation
Sat Oct 25 2025: fix: Fix symbols in interconnected stuff to also include combos and not just repetitions so that the length remains smaller
Sat Oct 25 2025: fix: Descriptions in OG images for tags and collections
Sat Oct 25 2025: fix: Links inside simple tables are not read right now
Sat Oct 25 2025: updated docs
Sat Oct 25 2025: completed-implementation
Fri Oct 24 2025: almost everything works
Thu Sep 11 2025: Merge pull request #26 from nerdymomocat-templates/feature/replace-numeric-iterator-with-symbols
Thu Sep 11 2025: fix: update tmpHTMLCache version from vC to vD
Thu Sep 11 2025: feat: Update linkText to "Jump to" for specific sections
Thu Sep 11 2025: feat: Update symbols, rename functions, and fix sr-only issue
Thu Sep 11 2025: feat: Replace numeric iterators with Unicode symbols for interlinked content
Thu Sep 11 2025: Merge pull request #25 from nerdymomocat-templates/feature/query-param-search
Thu Sep 11 2025: feat: Implement search from query parameter
Thu Sep 11 2025: Merge pull request #24 from nerdymomocat-templates/feature/update-tags-page-ui
Thu Sep 11 2025: fix: adjust padding for tag count display in tags index
Thu Sep 11 2025: feat: Update tags UI across the site
Thu Sep 11 2025: feat: Update tags UI across the site
Thu Sep 11 2025: feat: Update tags UI across the site
Thu Sep 11 2025: feat: Update tags UI across the site
Thu Sep 11 2025: feat: Update tags page UI
Thu Sep 11 2025: feat: Update tags page UI
Thu Sep 11 2025: Merge pull request #23 from nerdymomocat-templates/fix-twitter-bookmark-error-emoji
Thu Sep 11 2025: fix(bookmark): prevent twitter emoji from being displayed as image
Thu Sep 11 2025: Merge pull request #22 from nerdymomocat-templates/fix/def-inject-render-shortcode-wraps-to-newline
Thu Sep 11 2025: fix: Add robust, commented handling for newlines in code directives
Wed Sep 10 2025: fix: add checkout step to recover cache workflow
Wed Sep 10 2025: feat: add GitHub Actions workflow to recover cache based on user-defined key
Wed Sep 10 2025: Merge pull request #21 from nerdymomocat-templates/remove-pnpm-mentions
Wed Sep 10 2025: Merge branch 'main' into remove-pnpm-mentions
Wed Sep 10 2025: Merge pull request #20 from nerdymomocat-templates/fix-inline-code-background
Thu Sep 11 2025: Fix(style): Retain inline code background color from Notion
Wed Sep 10 2025: chore: update .gitignore and .prettierignore to remove pnpm references; modify package.json and package-lock.json to remove pnpm version
Thu Sep 04 2025: Merge pull request #19 from nerdymomocat-templates/gemini-update-to-new-notion-api
Thu Sep 04 2025: fix: update @notionhq/client version to 5.0.0
Tue Sep 02 2025: refactor: npm run format
Tue Sep 02 2025: refactor: enhance getBlock function to support forced refresh
Tue Sep 02 2025: refactor: remove unused AppBskyFeedDefs import from utils.ts
Tue Sep 02 2025: refactor: move giscus to first position
Tue Sep 02 2025: refactor: update data source caching to use dynamic file naming based on resolved data source ID
Tue Sep 02 2025: refactor: update Notion client integration to use data source ID and improve data retrieval logic
Tue Aug 26 2025: Merge pull request #18 from nerdymomocat-templates/update-and-cleanup
Tue Aug 26 2025: chore: update dependencies and improve buildcache directory handling
Tue Apr 29 2025: chore: update HTML cache version in package.json
Tue Apr 29 2025: refactor: rename checkbox icon keys for consistency in style helpers
Sat Mar 01 2025: Update README.md
Sat Mar 01 2025: refactor: shorten readme, remove netlify.toml and update .editorconfig for tab indentation and final newline settings
Fri Feb 28 2025: refactor: fix typo in echo message and update cache clearing condition in Astro workflow
Fri Feb 28 2025: refactor: update cache clearing condition for constants-config in Astro workflow
Fri Feb 28 2025: refactor: remove unnecessary condition for saving cached constants-config in Astro workflow
Fri Feb 28 2025: refactor: update cleanup logic for constants-config cache to add all trimming if constants-config changed
Fri Feb 28 2025: refactor: improve cache cleanup messages in Astro workflow for clarity
Fri Feb 28 2025: refactor: enhance caching logic for constants-config in workflows and always try to process files
Fri Feb 28 2025: refactor: update caching logic for old_package.json in workflows
Fri Feb 28 2025: refactor: update cache handling in Astro workflow to improve file trimming logic
Fri Feb 28 2025: Merge pull request #17 from nerdymomocat-templates/segmented-caching-and-invalidation
Fri Feb 28 2025: refactor: enhance caching logic in GitHub Actions workflows and update package.json cache versioning
Fri Feb 28 2025: refactor: remove console log statements in blocksHtmlCacher integration
Fri Feb 28 2025: refractor: fix headings setup and add predev and prebuild-local scripts to remove html-cache
Fri Feb 28 2025: refactor: simplify cache removal condition in GitHub Actions workflow (cache-hit is not true for partial match so we just check if tmp exists)
Fri Feb 28 2025: refactor: remove unnecessary console log for cache value in ReferencesSection component
Fri Feb 28 2025: Merge pull request #16 from nerdymomocat-templates/notion-blocks-html-cache
Fri Feb 28 2025: refactor: invalidating the HTML cache not only when a blog post is updated but also when any linked pages (referenced within the post) are modified. ideally just slug, title & excerpt, but couldn't do that rn.
Fri Feb 28 2025: refactor: enhance caching mechanism for static references and blocks in ReferencesSection component
Fri Feb 28 2025: refactor: rename headings cache directory for consistency in PostPreviewFull and related files
Fri Feb 28 2025: refactor: update import paths to use tsconfig based paths for improved clarity and consistency, @ doesn't work with astro integrations (other than type imports)
Fri Feb 28 2025: refactor: standardize indentation and formatting in [...page].astro
Fri Feb 28 2025: refactor: improve JSX formatting and consistency in MentionLink component
Fri Feb 28 2025: refactor: remove unused jsxImportSource directive in MentionLink component
Fri Feb 28 2025: refactor: change imports to use type imports for Mention and RichText interfaces
Fri Feb 28 2025: refactor: replace hardcoded paths with BUILD_FOLDER_PATHS constants for improved maintainability
Fri Feb 28 2025: refactor: add directory creation integration for cache and output paths
Fri Feb 28 2025: feat: implement headings caching with superjson for improved performance
Fri Feb 28 2025: feat: use HTML caching for blog posts to try to imp??? performance
Fri Feb 28 2025: feat: add block HTML caching integration to optimize build process
Fri Feb 28 2025: move to superjson for date parrsing (fixing ogimage read) and setup for html cache
Thu Feb 27 2025: feat: add helper function to transform GitHub Gist URLs for embedding
Thu Feb 27 2025: feat: enhance theme toggle functionality with system preference support
Thu Feb 27 2025: theme toggle now actually works with system preference listener
Tue Feb 25 2025: fix: add data-pagefind-ignore attribute for non-mermaid code blocks
Tue Feb 25 2025: remove unused deps
Tue Feb 25 2025: fix: increase request timeout from 2000ms to 10000ms for improved reliability
Mon Feb 24 2025: fix: remove request timeout constant and set default timeout to 2000ms
Mon Feb 24 2025: fix: update color variables to use color-mix for improved theming consistency
Mon Feb 24 2025: run format
Mon Feb 24 2025: fix: update BASE_PATH constant to include BASE environment variable
Mon Feb 24 2025: fix: update RSS stylesheet link generation to use BASE_PATH and clean up logging
Mon Feb 24 2025: testing base path issues in integration
Mon Feb 24 2025: fix: correct syntax for retry parameters in Notion API client
Mon Feb 24 2025: fix: add logging for base path in RSS styles and configure retry parameters for Notion API calls
Mon Feb 24 2025: fix: normalize basePath in redirect paths and adjust mobile button indentation
Mon Feb 24 2025: fix: update RSS stylesheet link generation to use dynamic navigation helper
Mon Feb 24 2025: chore: remove commented-out integrations from astro.config.ts for cleaner code
Mon Feb 24 2025: Merge pull request #15 from nerdymomocat-templates/tailwind-v4
Mon Feb 24 2025: fix huge rss issue that happened due to trailing slash in slug
Mon Feb 24 2025: style: update mobile button class for improved layout consistency
Mon Feb 24 2025: fix border upgrade
Mon Feb 24 2025: style: clean up unused CSS properties and enhance datatable styling for better layout
Mon Feb 24 2025: fix: update simple-datatables to use latest version for improved stability
Mon Feb 24 2025: chore: remove Tailwind CSS configuration file
Mon Feb 24 2025: run format
Mon Feb 24 2025: style: adjust iframe scaling for better responsiveness in NotionEmbed component
Mon Feb 24 2025: feat: add color normalization function for theme colors in CSS
Mon Feb 24 2025: style: improve CSS for better touch action and scroll behavior
Mon Feb 24 2025: style: enhance datatable sorter styles for better visibility in dark mode
Mon Feb 24 2025: run format
Mon Feb 24 2025: add cursor pointer to buttons for improved interactivity
Mon Feb 24 2025: increase text size in footer
Mon Feb 24 2025: Merge remote-tracking branch 'origin/main' into tailwind-v4
Mon Feb 24 2025: refactor print styles for SocialList component for improved visibility
Mon Feb 24 2025: refactor print styles for improved layout consistency across components
Mon Feb 24 2025: fix screen print query issue kinda, still issue in codeblock
Mon Feb 24 2025: update media query syntax for responsive font size in theme CSS
Mon Feb 24 2025: add custom variant for dark mode in theme CSS
Mon Feb 24 2025: at least it runs now and ran format
Mon Feb 24 2025: Update Callout.astro to show border when color is default
Fri Jan 31 2025: changed mentions -- config file still needs to be corrected
Thu Jan 30 2025: run format
Thu Jan 30 2025: Merge pull request #14 from nerdymomocat-templates/fix-trailing-slashes
Thu Jan 30 2025: fix trailing slashes for seo
Thu Jan 30 2025: fix: simplify Notion embed URL validation with regex pattern
Fri Jan 24 2025: update astro
Fri Jan 24 2025: add notion page emedding and run formatter
Mon Dec 23 2024: fix: improve cache deletion regex for better matching of keys
Mon Dec 23 2024: fix: update site-page-link class to use text-link for better styling consistency
Mon Dec 23 2024: fix: add support for cache deletion using a GitHub token in workflows
Mon Dec 23 2024: test: if new gh cli actions work with actions workflow token
Mon Dec 23 2024: fix: update cache deletion logic to use repository context instead of repository ID
Mon Dec 23 2024: test: update cache clearing logic to include both 'web' and 'blog' trotion and test
Mon Dec 23 2024: fix new no cache yml
Mon Dec 23 2024: try adding deletion in actions workflow -- might revert
Sun Dec 22 2024: refactor: remove font-weight classes from link elements for consistency
Sat Dec 14 2024: refactor: clean up unused functions and imports in various modules
Tue Dec 10 2024: update all packagesPerformance and Pagespeed
The footnotes and citations features, as well as the other features I'd added before, added a lot of JavaScript and content to pages, which initially tanked my PageSpeed Insights scores. So I spent a few days fixing that. I think given that Webtrotion is optimized for text-heavy websites and not marketing sites with shaders and such, it should have a good enough pagespeed score.
Font loading: I switched to Astro's experimental Font API and ditched the Google Fonts optimizer. Now I only preload the fonts actually needed instead of loading everything upfront. This alone made a noticeable difference.
Icon handling: Instead of using img src for icons (even Notion's default ones), I now download and serve them locally. This reduces external requests and improves load times, plus it means less calls to notionβs own tracking.
Caching strategy: I implemented HTML caching for rendered blog posts and added BibTeX file caching so the site doesn't re-parse citation data on every build. The cache also invalidates when linked pages change, not just when the post itself updates.
Margin notes timing: This was tricky. Margin notes need to calculate their position, but if they initialize before fonts load, the positioning breaks. So now they wait for fonts and requestAnimationFrame before initializing. I also added extra delays for really long pages because even that wasn't enough sometimes.
GitHub Actions improvements: Rewrote the caching workflow and added template cleanup workflows to be smarter. They now detect when config changes and invalidate the right caches automatically. Also added a workflow that lets you manually delete caches using a personal github API key, which is useful if you do not like to see clutter.
Conditional preconnects: Added smart preconnects for external resources that are conditionally loaded. If you have simple-datatables enabled for tables, glightbox for image galleries, or giscus for comments, the site now adds <link rel="preconnect"> tags, and only adds them when those features are actually used on the page. This means the browser can start establishing connections to those domains earlier, but only when needed, keeping the critical path lean for pages that don't use those features.
Other optimizations: Optimized Mermaid diagram loading, adjusted Pagefind search weights so titles rank higher, and cleaned up a bunch of unnecessary components from the preview layouts. I also made sure that all external scripts (like glightbox) and external CSS (for example, for simple-datatables) are imported dynamically and avoid the critical path.
It's not perfect, but the scores are way better now and the site still feels snappy.
Improving UI Components
While working on footnotes and citations, I ended up fixing a bunch of smaller UI issues that had been bothering me.
Icon improvements: Custom emojis, files, and external links now work for callout and page icons. Before, you were limited to Notion's default emoji set, but now you can use any custom emoji or even link to external icon files, same as you can in the Notion UI.
Tags redesign: The tags page got a complete refresh. The old design felt cluttered and the tag counts were hard to read. Now it's cleaner, with better spacing and more consistent styling across the site. Also the tags on the side show the number of posts with that tag too!
Theme toggle with system preference: The theme toggle now has an option that respects system preferences. If your OS is set to dark mode, the site defaults to dark mode too. It also listens for system theme changes, so if you switch your OS theme while the site is open, it updates automatically.
Search from query parameter: You can now trigger search directly from the URL. Useful for linking to specific search results or building search-based workflows. Just add ?search=your-query to any page URL and it will open the desired pagefind dialog.
Dark mode polish: A lot of small dark mode issues got fixed. Data table sorters weren't visible enough in dark mode, and some interactive elements weren't obvious as clickable. Added cursor pointers to buttons and improved the overall consistency of hover states.
Responsive improvements: Fixed iframe scaling in embedded content so it doesn't break the layout on mobile. Improved touch interactions and scroll behavior across the board. Also spent time on print styles because apparently some people still print web pages, and the old print layout was embarrassingly broken.
Small fixes: Twitter bookmark embeds were showing an emoji as an image, which looked ridiculous. Fixed that. Also cleaned up a bunch of unused CSS and tightened up the datatable styling so it doesn't feel so cramped.
Better Notion Fidelity
Notion page embedding: Added support for embedding Notion pages (including database pages and database views) directly into your posts. This is useful when you want to reference or showcase other Notion pages within your blog content. And this is especially nice with the new maps view!
Styling improvements: Made the site match Notion's styling more closely in a few places [j]
How It Was Built
I built this with AIs' help; mostly Claude Code for the heavy lifting (core implementation, complex logic) and Gemini-CLI for cleanup, refactoring, and writing this post. Claude Code handled the architecture well. Gemini-CLI is less useful for big-picture stuff but fine for smaller tasks.
Some bugs that came up:
- The Ghost Popover on Mobile: This was a hair-pulling bug. On mobile, the citation popovers would appear, but you couldn't click on anything inside them. Clicks were just passing right through to the content behind it. After many false leads (was it a Tailwind class? Padding? Z-index?), I discovered the solution was to reuse the exact same Astro component that was already working for other popovers (
NBlocksPopover) and ensure the DOM structure was identical, right down to an empty<span>with a special data attribute. I still do not know why the original error was happening. - Nested Popovers: Getting popovers to work when footnote content itself contained popovers (like links or mentions) was trickier than expected. The event handling kept interfering with itself. After several attempts at streamlining popover creation and visibility handling, I finally got it working with careful device-specific selectors. Desktop and mobile needed different interaction patterns, and getting both to work without breaking each other took multiple tries.
- Performance Boost: Initially, I had three separate functions that traversed the entire block tree to find footnotes, citations, and interlinked content. This was inefficient. I refactored this into a single, unified
extractPageContentfunction that collects everything in one pass, making the build process significantly faster. - The "Back to Citation" Button: After getting the core feature working, I realized that jumping to the bibliography was a one-way trip. And I always hate that when I read papers in pdf. So, I added the "Back to citation" button that dynamically appears on the bibliography entry you jumped from, making for a much smoother user experience.
- The BibTeX β JSON Cache Overflow: Claude Code had it initially set up such that it tried to convert and cache the entire
.bibfile into JSON. When I tested it with 6,000 entries, everything crashed. I had to walk the AI through fixing that to only parse the citations actually used in each page. - Tailwind v4 Migration: Upgrading to Tailwind v4 was more painful than expected. It's a breaking change that required rewriting a lot of styling code. Media query syntax changed, dark mode variants needed updating, and there were CSS issues everywhere. One commit message I made said "at least it runs now" which pretty much sums up how that went. Had to fix dozens of small styling issues after the initial upgrade.
- Cache Deletion Workflow: Getting GitHub Actions to properly delete caches took way too many attempts. The GitHub CLI and API kept changing requirements for authentication and permissions. First tried using the default workflow token, then had to switch to using the repository context instead of repository ID, then finally got it working with a personal access token. Ended up with a separate workflow that lets you manually delete caches when things get stuck.
- RSS Trailing Slash Bug: Discovered a huge bug where RSS feeds were completely broken due to trailing slash inconsistencies in slug formatting. This affected how URLs were generated across the entire site and took a while to track down because the error only showed up in the RSS feed, not on the actual pages.
- Same id for footnote/citation popovers: Claude Code fixed this immediately (gemini-cli went on a wild unproductive chase). This is because I [k][k]was assigning random ids to normal popovers but not here.The term I here is claude code, but I approved that code, so π€·ββοΈ
- BibTeX caching: The amount of errors I had to fix here made me think I was dealing with a 2023 AI model, not clade sonnet 4.5. I don't know why it believes it should complicate everything, but it did. Gemini cli is good enough to fix targeted issues like these.
- Handling Margin Notes: The more conditions you have, the harder it is to get AI to code something without missing edge cases. I wanted to support both footnotes and citations in the margin, with each being toggleable. But this creates a cascade of questions [l][l], like: What happens if a citation is inside a footnote? Does it show up in the margin or not? Unlike footnotes, citations can repeat - does only the first occurrence show in the margin, or all of them? What about subsequent occurrences - do they become popovers? What if citations are shown in the margin but footnotes aren't, and the first occurrence of a citation is inside a footnote? Do we show it in the margin anyway? And if the second occurrence is in the main content but we only show first occurrences in the margin, what then? Oh, and then what if the same citation appeared in the same block multiple times and that block is the first occurrence of that citation? How do we handle that? π€¦ββοΈI think AI is a boon and curse here. People say AI helps them quickly figure out what looks good, I think AI helped me figure out if the code complexity (because it wasn't able to implement it quickly) was worth the outcome and if I really even wanted the outcome.
- Using native
<Image />components in Astro: One of the persistent issues in the build was content layout shift caused by storing all images inpublic. And adding all notion image to downloads topublicmeant I had to manually write code to optimize images towebpwhen optimization was enabled, handle different URL patterns based on optimization settings, and couldn't reliably determine layout sizes or generate mobile-specificsrcsetattributes. So I refactored the code to use Astro's native Image component, which turned out to be far from straightforward. Why? First, I was downloading files during the post-build process rather than before, but Vite needed to glob all these files beforehand. Second, my hacky HTML caching system skips Astro component calls, so I had to copy optimized files from the previous build intodistto account for that. Third,distalso carries the original files as a fallback, but I didnβt want that increased size, so I wrote an integration to delete those [m][m]. Finally, Astro doesn't natively support settingLooked at the options here.srcsetwith just mobile width and original size, so I had to hack that functionality into the code.
It was a great learning experience, and it's incredibly rewarding to see these powerful features come to life in Webtrotion.
Footnotes
- [a]Just like these ones!
- [b]Well, maybe besides universal page blocks and universal task blocks.
- [c]I've done something similar with html injects before using shortcodes.
- [d]I should have done this from the very start rather than relying on readme or webpages for configuration help.
- [e]It is fine if you donβt have all the weights or styles in your chosen font, it will fallback gracefully.
- [f]This is the content of the footnote. It can be long and detailed and have links.
- [g]For example, the way the marker at start of this paragraph is written wonβt work, it needs to be in normal text.
- [h]We need this because Notion API only returns block ids, not the text span that was commented on. When that is fixed, Iβll implement
block-inline-text-comments. - [i]Or whatever your heart desires β€οΈ
- [j]I tried to make it so that inline code now retains its background color from Notion instead of getting stripped out, but the API doesn't provide the color for inline code background π
- [k]The term I here is claude code, but I approved that code, so π€·ββοΈ
- [l]I think AI is a boon and curse here. People say AI helps them quickly figure out what looks good, I think AI helped me figure out if the code complexity (because it wasn't able to implement it quickly) was worth the outcome and if I really even wanted the outcome.
- [m]Looked at the options here.



