Skip to content

feat: add dismissible announcement banner#404

Open
mmcky wants to merge 6 commits into
mainfrom
feature/announcement-banner
Open

feat: add dismissible announcement banner#404
mmcky wants to merge 6 commits into
mainfrom
feature/announcement-banner

Conversation

@mmcky

@mmcky mmcky commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a site-wide announcement banner configured from _config.yml (or conf.py) — for notices like a software upgrade with a link to changelog notes. Readers can dismiss it, and it can auto-expire on a date. The banner defaults to empty/off, so existing sites are unaffected.

sphinx:
  config:
    html_theme_options:
      announcement: 'We upgraded to <strong>Anaconda 2026.06</strong> — see the <a href="/status.html">CHANGELOG</a>.'
      announcement_expires: "2026-07-01"   # optional ISO date

Behavior

  • Rich message — the value is HTML, so emphasis and a link are supported. Rendered as a strip at the top of the page content that scrolls away with the content.
  • Dismissal that respects new messages — the × button hides the banner and the choice persists in localStorage. Dismissal is keyed to a hash of the message text, so when you edit announcement the banner re-appears for everyone, including readers who dismissed the old one.
  • Expiry, two ways — an optional announcement_expires (ISO YYYY-MM-DD, shown through the end of that day) hides the banner client-side so it disappears for visitors even without a rebuild, and is also skipped at build time so an already-expired notice is omitted from the generated HTML. An unparseable date logs a build warning and fails open (the banner keeps showing) so a typo never silently hides an active notice.
  • Dark mode + RTL styled.

Design note: built to be additive

Per-page announcements are intentionally not in this PR (global was the priority), but the internals are built so they can be added additively without reworking this code: the template loops over a list of notices, announcement.js evaluates each row independently (own content-hash dismissal + own expiry), and the localStorage dismissed-set already tracks multiple IDs. Tracked in #403, where the open question is whether per-page should be config-keyed or authored in MyST frontmatter.

Changes

Area File
Options theme.confannouncement, announcement_expires
Python __init__.py_build_announcements (content hash + build-time expiry skip), _parse_iso_date, validate_announcement (fail-open)
Template layout.html — hidden bar looping over notices at the top of .qe-page
JS assets/scripts/announcement.js (new) + wired into index.js
Styles assets/styles/_announcement.scss (new) + @forward in index.scss
Tests tests/test_announcement.py (new) — 24 unit tests
Docs docs/user/announcements.md (new), configuration cross-ref, CHANGELOG

Testing

  • 24 new unit tests pass, covering the content hash, ISO date parsing, build-time expiry skip, fail-open validation, and the empty-default no-op.
  • webpack build is clean and the new JS/CSS appears in the compiled bundles (the bundles are gitignored and built at packaging time, so they are not in this diff).
  • The end-to-end Sphinx build-regression test (test_build.py) was not run locally — it needs the theme installed via its entry point, which is blocked by a pre-existing stale .nodeenv (node v18.18.0 vs the v20.18.0 sphinx-theme-builder expects). This is independent of the change and will run in CI. A separate maintenance PR will fix the local testing setup. With the default empty config the template renders nothing ({% if announcements %}), so the file-regression baseline is unchanged.

🤖 Generated with Claude Code

Add a site-wide announcement banner configured via the new `announcement`
theme option (HTML allowed, so it can include emphasis and a link to
changelog notes). Readers dismiss it with a ×; the dismissal persists in
localStorage and is keyed to a content hash, so editing the message
re-shows the banner for everyone who dismissed the previous one.

An optional `announcement_expires` ISO date auto-hides the banner after
that day — enforced client-side (disappears for visitors even without a
rebuild) and at build time (an already-expired notice is omitted from the
HTML). An invalid expiry date logs a warning and fails open.

The banner defaults to empty/off, so existing sites are unchanged. The
renderer iterates a list of notices internally so per-page announcements
can be added additively later (tracked in #403).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 19, 2026 03:21
@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot temporarily deployed to pull request June 19, 2026 03:22 Inactive
@codecov

codecov Bot commented Jun 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.59459% with 2 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@e635acb). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/quantecon_book_theme/__init__.py 94.59% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #404   +/-   ##
=======================================
  Coverage        ?   51.41%           
=======================================
  Files           ?        2           
  Lines           ?      459           
  Branches        ?        0           
=======================================
  Hits            ?      236           
  Misses          ?      223           
  Partials        ?        0           
Flag Coverage Δ
pytests 51.41% <94.59%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new, site-wide (theme-option driven) announcement banner to the QuantEcon Book Theme, including template markup, styling, client-side dismissal/expiry behavior, Python-side option handling, and documentation.

Changes:

  • Introduces announcement / announcement_expires theme options and Python helpers to build the announcement render context and validate expiry dates.
  • Adds a server-rendered (initially hidden) announcement bar to layout.html, with new JS to reveal/clear rows based on dismissal and expiry, plus new SCSS styling (dark mode + RTL).
  • Adds new docs and changelog entry, plus a new test module covering parsing, build-time behavior, and wiring.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/test_announcement.py New tests covering option registration, wiring, date parsing, build-time skip, and fail-open validation.
src/quantecon_book_theme/theme/quantecon_book_theme/theme.conf Registers the new theme options so Sphinx accepts them.
src/quantecon_book_theme/theme/quantecon_book_theme/layout.html Renders the announcement bar/rows (hidden by default) when announcements exist.
src/quantecon_book_theme/assets/styles/index.scss Forwards the new announcement SCSS partial.
src/quantecon_book_theme/assets/styles/_announcement.scss New styles for the banner (including dark mode + RTL adjustments).
src/quantecon_book_theme/assets/scripts/index.js Wires initAnnouncement() into the theme’s JS initialization.
src/quantecon_book_theme/assets/scripts/announcement.js New JS module implementing dismissal persistence and client-side expiry.
src/quantecon_book_theme/init.py Adds _parse_iso_date, _build_announcements, and validate_announcement; injects announcements into page context.
docs/user/index.md Adds “announcements” to the user guide TOC.
docs/user/configuration.md Documents the new theme options in the configuration reference.
docs/user/announcements.md New dedicated user documentation page for behavior/details.
CHANGELOG.md Adds an Unreleased changelog entry describing the feature.

Comment thread src/quantecon_book_theme/assets/scripts/announcement.js
Comment thread src/quantecon_book_theme/__init__.py Outdated
@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

🎭 Visual Regression Test Results

failed  92 failed
passed  11 passed
skipped  3 skipped

Details

stats  106 tests across 1 suite
duration  16 minutes, 48 seconds
commit  00ede48

Failed tests

desktop-chrome › theme.spec.ts › Visual Regression Tests › intro - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › intro - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › typography - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › typography - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › typography - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › definition-lists - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › definition-lists - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › definition-lists - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › code-blocks - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › code-blocks - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › code-blocks - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › math - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › math - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › math - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › admonitions - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › admonitions - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › admonitions - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › exercises - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › exercises - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › exercises - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › proofs - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › proofs - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › proofs - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › tables - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › tables - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › tables - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › figures - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › figures - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › figures - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › toc-deep-nesting - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › toc-deep-nesting - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › toc-deep-nesting - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › long-page - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › long-page - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › long-page - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › cross-references - full page screenshot
desktop-chrome › theme.spec.ts › Visual Regression Tests › cross-references - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › cross-references - sidebar region
desktop-chrome › theme.spec.ts › Visual Regression Tests › prob-matrix - header region
desktop-chrome › theme.spec.ts › Visual Regression Tests › prob-matrix - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › intro - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › intro - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › typography - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › typography - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › typography - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › definition-lists - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › definition-lists - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › definition-lists - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › code-blocks - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › code-blocks - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › code-blocks - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › math - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › math - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › math - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › admonitions - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › admonitions - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › admonitions - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › exercises - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › exercises - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › exercises - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › proofs - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › proofs - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › proofs - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › tables - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › tables - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › tables - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › figures - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › figures - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › figures - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › toc-deep-nesting - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › toc-deep-nesting - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › toc-deep-nesting - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › long-page - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › long-page - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › long-page - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › cross-references - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › cross-references - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › cross-references - sidebar region
mobile-chrome › theme.spec.ts › Visual Regression Tests › prob-matrix - header region
mobile-chrome › theme.spec.ts › Visual Regression Tests › prob-matrix - sidebar region
desktop-chrome › theme.spec.ts › Theme Features › dark mode toggle
desktop-chrome › theme.spec.ts › Theme Features › code block styling
desktop-chrome › theme.spec.ts › Theme Features › f-string interpolation styling
desktop-chrome › theme.spec.ts › Theme Features › math equation rendering
mobile-chrome › theme.spec.ts › Theme Features › dark mode toggle
mobile-chrome › theme.spec.ts › Theme Features › math equation rendering
desktop-chrome › theme.spec.ts › Typography Styling › bold text styling
desktop-chrome › theme.spec.ts › Typography Styling › italic text styling
desktop-chrome › theme.spec.ts › Definition Lists › definition list rendering
desktop-chrome › theme.spec.ts › Definition Lists › glossary rendering
mobile-chrome › theme.spec.ts › Definition Lists › definition list rendering
mobile-chrome › theme.spec.ts › Definition Lists › glossary rendering

Skipped tests

desktop-chrome › theme.spec.ts › Visual Regression Tests › prob-matrix - full page screenshot
mobile-chrome › theme.spec.ts › Visual Regression Tests › prob-matrix - full page screenshot
mobile-chrome › theme.spec.ts › Theme Features › f-string interpolation styling

Two correctness fixes from the #404 review:

- announcement.js: parse the expiry `YYYY-MM-DD` with an explicit regex into
  local-time date components and expire at 23:59:59.999, instead of
  `new Date("...T23:59:59")`. Removes the ~1s-early cutoff and any
  cross-engine ambiguity in how the date string is parsed.

- __init__.py: the build-time expiry skip compared a UTC "today" against the
  expiry date, while the client-side check is the reader's local end-of-day —
  so a rebuild just after UTC midnight could omit a banner that's still the
  expiry day in Americas timezones. The skip now keeps a one-day UTC grace so
  a notice is never dropped from the HTML while it's still "today" anywhere;
  the client side hides it precisely per-reader. Tests and the expiry docs
  updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bump FIXTURES_SHA in both ci.yml and update-snapshots.yml to the fixtures
commit that adds an announcement to the fixtures _config.yml, so this PR's
Netlify preview and visual build show the new banner. Both workflows are
kept in sync so regenerated snapshots are produced against the same input.

The banner shifts every page's layout, so the visual job is expected to fail
until the baselines are regenerated via /update-snapshots.

See QuantEcon/quantecon-book-theme-fixtures#1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot temporarily deployed to pull request June 19, 2026 03:58 Inactive
Make the announcement banner's look selectable via a new announcement_style
theme option, so the team can choose between two styles (and switch the
default in one place):

- bar (default): a thin, full-width strip with centred text that sits just
  below the toolbar and scrolls away — discreet, for standing notices.
- callout: the original boxed in-column notice with an accent border —
  preserved as a style so nothing is lost.

Both share the same markup, JS, and global dismissal; only the styling
differs, and both adapt to dark mode and RTL. The value is validated at
build start (unknown values warn and fall back to bar), mirroring
color_scheme.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot temporarily deployed to pull request June 19, 2026 04:23 Inactive
Pull the bar-style strip up to sit flush beneath the fixed toolbar (closing
the ~13px gap left by .qe-page's 4rem top padding vs the 50px+1px toolbar) so
it reads as a second tier of the header, and slim it down (thinner vertical
padding, slightly smaller text).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot temporarily deployed to pull request June 19, 2026 04:43 Inactive
@mmcky

mmcky commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Announcement banner — two styles, which should be default?

@jstac, @DrDrij

The banner now supports two looks via a new announcement_style theme option. Both are dismissible and can expire by date (dismiss once → hidden site-wide until the message changes), adapt to dark mode and RTL, and carry the same content — only the styling differs. So we can ship whichever the team prefers and switch the default in one line.

The use case: Announcing updates to anaconda=2026.06 for example. (we can also work on per-page for page specific updates -- but I've left that to be driven by demand -- do we need it?)

Side-by-side on the fixtures site (top = bar, bottom = callout; left = light, right = dark):

announcement-styles-grid
bar — provisional default callout
Look Thin full-width strip, centered text, hairline Boxed in-column notice with an accent border
Placement Full-bleed, just below the toolbar, scrolls away In the content column, scrolls away
Feel Discreet "system" notice Prominent in-page callout

Switching is a one-liner in html_theme_optionsannouncement_style: bar (default) or callout.

Vote: I like the bar - it is similar to what we have on quantecon.org for announcements along the top.

mmcky added a commit to QuantEcon/quantecon-book-theme-fixtures that referenced this pull request Jun 19, 2026
Sets html_theme_options.announcement so the dismissible announcement banner
(QuantEcon/quantecon-book-theme#404) renders across the fixtures site — visible
in the Netlify preview and covered by the visual regression snapshots.

No announcement_expires is set on purpose, so the banner always renders and
visual snapshots stay stable (an expiry date would eventually pass and silently
change the build output).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
fixtures #1 merged the announcement-banner demo into the fixtures config on
main. Re-pin FIXTURES_SHA in both ci.yml and update-snapshots.yml from the
(now-merged) branch commit to the squash-merge commit on fixtures main, so
the pin tracks a durable commit rather than a deletable branch tip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mmcky

mmcky commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

/update-snapshots

@github-actions

Copy link
Copy Markdown
Contributor

✅ All visual snapshots have been regenerated and committed to this PR.

📦 Download snapshot-update-diff artifact to review before/after images.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants