* feat: add jump-to-page dialog on pagination ellipsis
- Replace pagination windowing algorithm with a tighter 5-item window
(curr-1 / curr / curr+1, clamped at edges) and hide-on-mobile for
pages more than 1 step away from the current page
- Ellipsis spans now carry the pagination-jump-trigger class and open
a native <dialog> on click instead of being static decorations
- Add <dialog id="pagination-jump-dialog"> with number input, Go button,
and Enter-key hint; data-total / data-first-url / data-format-url
attributes on <nav> give the JS all it needs to build the target URL
- Add assets/ts/pagination.ts: setupPaginationJump() with Fisher-Yates
backdrop-click and ESC handling, animated open/close via .closing class
- Wire setupPaginationJump() into Stack.init() in main.ts
- Extend pagination.scss with .hide-on-mobile, .pagination-jump-trigger
hover style, and the full #pagination-jump-dialog styling + keyframe
scale-up/scale-down animations
- Add [pagination] i18n keys (jumpToPage / jump / pressEnter) to
en / zh / zh-hant-tw / zh-hant-hk / ja
* style: align pagination code with upstream conventions
- pagination.html: collapse multi-line span/class/aria attrs to single
lines; use HTML5 void element syntax; fix hint div indentation
- pagination.scss: 2-space indent → 4-space indent
- pagination.ts: tab indent → 4-space indent; export const arrow fn →
export function declaration
* chore: update layouts/_partials/pagination.html
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* chore: add aria-labelledby attrributes for better accesibility
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: use { once: true } for the listener and guard against re-entry when .closing is already set.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* style: replace hardcoded values with design tokens and improve dialog UX
- Replace all hardcoded px spacing in .page-link with --spacing-* tokens
- Use @include card-style in #pagination-jump-dialog; override with --shadow-l2
- Replace padding: 24px with var(--card-padding) for responsive dialog padding
- Align header title/subtitle to space-between for cleaner layout
- Replace hardcoded gaps/padding in form with spacing tokens
- Fix input/button border-radius from 8px to 6px (better proportion for 44px height)
- Fix focus ring: use color-mix(accent-color 20%) so it's visible in dark mode
- Add :focus-visible + outline:none to fully suppress native browser outline
- Remove translateY from button hover for more restrained interaction
- Scope transition to specific properties (border-color, box-shadow, background-color)
* chore: add pagination test articles for easier debugging
* style: enhance backdrop animations for pagination jump dialog
* style: replace pagination ellipsis spans with buttons for improved accessibility
* fix: check if browser supports dialog API before continue with pagination jump setup
* fix: retain focus on last active element when closing pagination jump dialog
* fix: style for page-link button (pagination-jump)
* style: adjust width of pagination jump dialog, add container padding
* style: simplify
* refactor: simplify pagination link logic
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jimmy Cai <jimmy@cai.im>
* feat: add GDPR cookie consent banner
Add a GDPR-compliant cookie consent banner that gates analytics (Google
Analytics) and functional cookies (comments) until user consent is given.
Features:
- Theme-consistent styling using CSS variables (light/dark mode)
- Settings panel with category toggles (necessary, analytics, functional)
- Consent stored in cookie for 365 days
- Google Analytics only loads after analytics consent
- Comments only load after functional consent
- Translations for all 32 supported languages
- Accessible with proper ARIA attributes and focus management
Configuration in hugo.yaml:
params:
cookies:
enabled: true
categories:
analytics: true
functional: true
When cookies.enabled is false, scripts load normally without consent gating.
Closes#412
* refactor: move consent-gated GA to cookies/analytics.html
Move Google Analytics consent logic to avoid shadowing Hugo's internal
`_internal/google_analytics.html` template.
Changes:
- Rename google_analytics.html → cookies/analytics.html
- Update head.html to conditionally load:
- cookies.enabled=true: cookies/analytics.html (consent-gated)
- cookies.enabled=false: Hugo's _internal/google_analytics.html
- Align cookies/analytics.html with Hugo's internal template:
- Support Privacy.GoogleAnalytics.Disable setting
- Support Privacy.GoogleAnalytics.RespectDoNotTrack setting
- Add UA- prefix deprecation warning
Note: Custom JS is required for consent-gated GA because Hugo templates
render at build time, but consent happens at runtime. We cannot call
Hugo's internal template after the user grants consent - we must
dynamically inject the GA script via JavaScript.
* style: indent cookies/analytics.html
* refactor: don't use default, put default configurations in params.toml
* fix: don't use `description` as translation key because it's reserved and will throw error
* fix: remove footer/components/custom-font.html call
* fix: banner showSettings key
* style: indent comments/include
* Add missing article.alert translation back
* style: format i18n toml files
* style: indent head/head.html
* style adjustment
* style: add missing -
* style: format demo/config/params.toml
* style: remove redundant comments from cookies.scss
* style: update box-shadow for cookie banner content
---------
Co-authored-by: delize <4028612+delize@users.noreply.github.com>
Co-authored-by: Jimmy Cai <jimmy@cai.im>
* fix: improve Mermaid diagram implementation (#1213)
This commit addresses multiple issues with Mermaid diagram rendering
and adds significant improvements to the user experience.
- Fix `<br/>` tags rendering as literal text instead of line breaks
- Fix flash of raw mermaid code before diagram renders
- Fix Gantt chart rendering issues in dark mode
- Fix diagrams briefly showing during theme switch re-render
- Fix expand modal showing diagram left-aligned before centering
- Add fullscreen expand modal with pan/zoom functionality
- Add toolbar with zoom controls (zoom in/out, reset, fit to screen)
- Add keyboard support (Escape to close modal)
- Add per-diagram transparent background via `%%transparent%%` directive
- Add comprehensive configuration options:
- `look`: classic or handDrawn (sketch style)
- `lightTheme`/`darkTheme`: theme selection per mode
- `lightThemeVariables`/`darkThemeVariables`: custom theme colors
- `securityLevel`, `htmlLabels`, `maxTextSize`, `maxEdges`
- `fontSize`, `fontFamily`, `curve`, `logLevel`
- Switch from ESM to UMD bundle for faster initial load (~1s vs 2s+)
- Lazy-load panzoom library only when expand modal is opened
- Pre-render alternate theme during idle time for instant theme switching
- Cache rendered diagrams to avoid re-rendering on theme toggle
- Move all inline CSS to article.scss using SCSS nesting
- Extract helper functions for better maintainability
- Use data attributes and event delegation for cleaner handlers
- Reduce mermaid.html from 411 to 177 lines (57% reduction)
- Add comprehensive mermaid-diagrams example post with all diagram types
- Document all configuration options in hugo.yaml
* refactor: extract mermaid inline JS to TypeScript module
Move ~155 lines of inline JavaScript from mermaid.html partial into
assets/ts/mermaid.ts. The partial shrinks from 179 to 36 lines and now
only contains modal HTML markup and Hugo Pipes build/import logic.
- Deduplicate initWithTheme() and renderOffscreen() helpers
- Enable minification via Hugo Pipes js.Build in production
- Remove user-configurable mermaid version from params.toml
---------
Co-authored-by: delize <4028612+delize@users.noreply.github.com>
* Use ResizeObserver to detect changes in the size of .article-content
This code is for handling changes in position caused by content rendered as part of post-processing, such as Mermaid diagrams
* Add debounced to resizeHandler
* refactor(i18n): simplify the structure of the translation file
* chore: prepare repository for v4.0.0-alpha
* chore: modify go.mod to v4
* refactor: migrate theme configuration to TOML
* fix: exampleSite not using correct theme
* feat: add favicon from assets folder
* refactor: drop linear grandient background feature
remove node-vibrant from dependencies
* feat: use Hugo's code block render hook to implement code copy button
Now it can have i18n support
* refactor: delete color.ts
* refactor: delete Emoji support post from example site
* refactor: drop support for `hidden` field in front matter
* feat: upgrade to PhotoSwipe v5
* chore: bump the required hugo version to 0.100.0
* refactor: remove PhotoSwipe from external.yaml
* fix: extra margin in search result
* fix: incorrect markdown heading level in example site
* refactor: remove some usages of `default` in template
No longer needed thanks to Hugo's configuration merge
* fix: one line codeblock style in firefox
closes https://github.com/CaiJimmy/hugo-theme-stack/issues/564
* feat: add style to new codeblock
* feat: i18n support for codeblock copy text
* fix(menu): jitter when closing menu
It's caused by flexbox gap property, which can't animate
* fix(search): long text overflows under the Search icon
closes https://github.com/CaiJimmy/hugo-theme-stack/issues/515
* Add first try at scrollspy (broken right now)
* Scrollspy actually works now
* Fix VS Code errors by setting JS version
* Recompute offsets when window size changes
* Improve list compatibility for toc active selection
Support up to 6 levels of indentation, properly support <ol>
* Remove debug string
* Add more docs in smoothAnchors
* Use a map to match ids to navigation elements
* refactor(search): avoid issue with one character keyword
closes https://github.com/CaiJimmy/hugo-theme-stack/issues/184
* Remove keyword sorts
* fix typo: secion -> section
* fix(search): avoid matching html entity
* Use | operator to concatenate keywords
Idea from https://github.com/CaiJimmy/hugo-theme-stack/pull/436
* Add missing `matchCount`
* Limit preview length
* Don't add ellipsis to title
* add comment to `processMatches`
* Initialize DOMParser only once
* Remove marker function
* Deal with blank search
* Use const keyword for constant arrays
* fix: take out [data-scheme="dark"] from :root
Taking out the [data-scheme="dark"] from :root allows us to fix the
precedence of CSS when the [data-scheme="dark"] is placed in the <html>
tag. This is needed in order to make the dark styles accesible from the
<html> elment, this will allow us to change the vertical scrollbar
styles following the dark and light schemes.
* change document.body.dataset.scheme to document.documentElement.dataset.scheme
When the dark mode is on or when the light mode is on, the
[data-scheme="light"] or [data-scheme="dark"], respectively, will be
placed in the <html> tag. Allowing us to access the dark and light color
schemes from the <html> to change the vertical scrollbar styles
according to the current color scheme.
* feat: change the page vertical scrollbar styles
This change will make the vertical scrollbar styles to follow the dark
and light color scheme modes. Also, this change will make the vertical
scrollbar to look consistent in both, Chromium and Firefox.
* make the scrollbar-track background-color transparent
The body has this transition: 'transition: background-color 0.3s ease
0s'. Making the scrollbar-track background-color transparent allow us to
appreciate that transition in the scrollbar-track when switching the
background-color.
* Move [data-scheme=dark] back to :root block
* fix(comment/waline): detect dark mode from html tag
* feat: apply custom scrollbar style to all elements
Co-authored-by: Jimmy Cai <jimmehcai@gmail.com>