Skip to content

activity: restyle /activity/ with the shared rows, a type filter and day links - #290

Merged
mmcky merged 2 commits into
mainfrom
activity-log-restyle
Sep 30, 2026
Merged

mmcky merged 2 commits into
mainfrom
activity-log-restyle

Conversation

@mmcky

@mmcky mmcky commented Sep 30, 2026

Copy link
Copy Markdown
Collaborator

What changes

/activity/ now reads the rows plugin's view (site.data.activity_view, from #285) instead of flattening the data files, and takes the design in section 4 of the round-2 handoff (#266).

  • Months and days. Each month is a <section id="activity-2026-08"> with an <h2>, holding an <ol> of days whose ids (activity-2026-08-02) are the anchors that group and editions rows link to. Each day holds its rows in the view's order. There is no visible day heading: every row shows its own date.
  • Rows. A meta line (type icon, visually hidden type word, date and tag), then the title: one link for a single release, lecture, book or translation; a link for each release in a release group ("BasisMatrices.jl v0.8.2, … and QuantEcon.jl v0.19.0"); the series name for an editions row, with its editions as chips, or as a list with each edition's own summary when they differ. Then the summary, with backtick spans as <code>, and the PRs: one on a line, or two or more behind an "N changes" toggle.
  • Shared includes in _includes/activity/: meta.html, title.html and summary.html, which the rail and the strip can use too, and log-row.html. Every field is escaped, attributes included.
  • A type filter: All, Releases, Lectures, Translations and Books, as <button aria-pressed> in a labelled group. It hides the days and months it leaves empty, shows an empty state for a type with no rows, and a polite live region, empty at load, announces the result.
  • Without JavaScript the filter and the toggles are hidden, and every row and all 23 PR links show. With it, CSS keyed on a js class that <head> sets before first paint shows the filter and collapses the PR lists, so nothing moves when the scripts run.
  • Day and month links land below the fixed header and the sponsor bar. Following one on the page resets the filter to All first.
  • Groundwork on every page (the first commit): the head js class; main.js's sessionStorage access wrapped in try/catch (where site data is blocked it threw and stopped the menu, the header state and back-to-top); and a ?v= build stamp on the main.js URL, like the CSS's.
  • Removed: the interim .activity-* styles and the release and translation pills, which only the old page used. README describes the page as it now is, and AGENTS.md lists the includes and documents the js class pattern and mathjax_ignore.

Defaults to review on the preview

  • Books last, with text-only buttons and bi-book on book rows. The decision reads: Add a fifth filter button, "Books", with a book icon. I read the icon as the book type's icon on book rows (bi-book, beside bi-box-seam, bi-journal-text and bi-translate), and kept all five buttons text-only, as the handoff draws them. Measured on phones (14.4px text, 14px gaps): text only needs 309.5px, one line from a 366px viewport; bi-book on the Books button needs 329.9px, one line from 386px, or 403px before the web font arrives, so 390 and 393px phones would jump from two lines to one; icons on all four type buttons need 391.2px, one line only from 448px. Switching is a small change.
  • Phone sizes. Below 576px the filter is 14.4px with 14px gaps (the handoff's text says 16px with 28px gaps, its prototype 14.4px with 18px). It holds one line from 366px. At 320 to 365px Books wraps to a second line, and each button keeps its own bar. With 14px gaps, 390 and 393px stay on one line through the font swap (the fallback font needs 325.8px of the 334px available); only 366 to 381px (375px phones) go from two lines to one when Roboto arrives.
  • The live region counts rows, as decided: "Showing all 30 updates", "Showing 16 releases", "Showing 12 lecture updates", "Showing 2 translation updates", singular forms, and "No book updates yet" for an empty type. "Showing 16 releases" sits beside 24 release links, because each same-day group counts as one row. An alternative is "Showing releases on 16 days".
  • Books has no rows yet, in the fixture or in today's data, so pressing it hides every month and shows a dashed box, "No book updates yet". An alternative is to hide the Books button until a book row exists.
  • The intro's text is unchanged, as the handoff says, though it predates the book type. An alternative first paragraph: "A running log of what is changing across QuantEcon: library releases, updates to the lecture series and their translated editions, and updates to books. It is compiled from public activity on GitHub." Its two links are now underlined, as the prototype draws them: in the #444 text their colour alone is 1.9:1, short of the 3:1 that a link marked only by colour needs. Elsewhere on the site, links in text are underlined only on hover.
  • Each month is a <section> named by its heading, as the handoff has it, so screen readers list every month as a region landmark: four today, and one more each month. Dropping aria-labelledby would keep the landmark list short and leave the <h2> headings as the way to move between months.
  • mathjax_ignore on the log. MathJax loads on every page and typesets a pair of $ in a summary as mathematics (from $5 to $10 came out as 5to10). The class stops it; tex2jax_ignore does nothing with MathJax 3.
  • Scroll padding scoped to the page, html:has(.activity-log), rather than on bare html as the handoff has it: site-wide it would add to /team/'s scroll-margin-top and put its section links 133px lower. Browsers without :has() (Firefox before 121, Safari before 15.4) get no padding, so there a day link lands under the header.
  • The script is inline at the end of _layouts/activity.html, as /team/'s is, rather than in main.js, whose only change is the sessionStorage guard. It runs before main.js, and if it throws it removes the js class, so every row and PR link shows.
  • 44px-tall targets on phones for the filter buttons, toggles, chips and title links. The prototype pulled the title links up with negative margins, which draws the focus ring through the date; here a title link gains 10px above and below instead, so on phones those rows are about 20px taller than the prototype's. The filter buttons keep the width of their text, so All is 17px wide: its 14px gaps pass WCAG 2.5.8's spacing test, and a 44px minimum width would put the filter on two lines at 390 and 393px (it would need 339.7px, against 334 and 337px).

How it was tested

  • Which data. The preview builds this branch, cut from 8cba18b, whose _data/activity/ is identical to the fixture, so it shows the fixture's 30 rows until main is merged in. The fixed numbers were checked on a fixture build (a data_dir: .github/scripts/fixtures config overlay): 30 rows in 4 months (6/8/11/5), 27 day anchors, Aug 2's "4 releases · same day", 23 PR links (8 on a line, 15 in 6 disclosures), the footer "The log begins on Jun 12, 2026.", and per filter Releases 16, Lectures 12, Translations 2 (August only) and Books 0 with its empty state.
  • Checks. The data check, both test suites (38 and 51 tests) and a production build pass. Ids are unique, every aria-controls points at its list, and nothing is rendered hidden but the empty state.
  • Hostile and unusual data, in a scratch data set: <, &, quotes, backticks and $ in titles, summaries, PR titles and URL query strings all render escaped, and MathJax typesets nothing. Also a book row, an editions row with differing summaries (one edition without), a two-release group, a row with no summary or PRs, long unbroken names (they wrap rather than being clipped), and no data at all ("No activity has been recorded yet.").
  • Headless Chrome 154 at 320, 360, 390, 576, 768, 1280 and 1440px:
    • no horizontal scroll, and nothing past the log's right edge, in every filter with every PR list open;
    • /activity/#activity-2026-08-02 lands 16 to 17px below the header with the sponsor bar shown and dismissed, after Translations was active (reset to All, announced), and when arriving from another page; a month anchor too; /team/#translators lands as it does on main;
    • with JavaScript off, 30 rows and 23 PR links, and no filter or toggles;
    • with main.js held back, the page is already final (lists collapsed, filter shown), and nothing in the log moves when it runs;
    • a throw in the inline script leaves every row and link visible;
    • with sessionStorage blocked, the menu, the header state, back-to-top and the bar work, where on main they don't;
    • every control shows the 2px focus ring, phone targets are 44px tall, every text pair passes AA including hover and pressed (lowest 5.08:1), and reduced motion removes the filter bar's and the chevron's transitions.
  • Fidelity. At 1440px every day, month heading and the filter group have the prototype's heights exactly.
  • Build diff against main. Besides the head script and the ?v= stamps on every page, only /activity/, /README.md, main.css (and its map) and main.js change.

Please look in iOS Safari and Firefox. Everything above ran in Chrome. The filter's fit at 390px depends on font metrics, VoiceOver should read the lists as lists (they carry role="list"), and the scroll padding needs :has().

Pre-existing, not changed here

  • The sponsor bar pops in when main.js runs, moving the page down by 33 to 82px, and its height is measured once, so it goes stale after a resize or a rotation.
  • The intro re-wraps when the web fonts swap in.
  • At a 992px viewport with classic scrollbars, the footer's row overflows by 4px.

Notes for #278, #279 and #280

  • The includes. meta.html takes row, and tag=false leaves the tag out (for the strip); title.html takes row, and the caller supplies the link; summary.html takes text. They escape everything, and they prefix their Liquid variables with activity_, since assignments leak into the caller.
  • The classes. .activity-filters and .activity-filter carry the filter's shared states (colours, the bar, the focus ring, hidden without JavaScript), and the log's sizes sit under .activity-log, so the rail sets its own. .activity-meta and .activity-row__version are the other shared rules; everything else is scoped to .activity-log.
  • The head js class and the html:not(.js) pattern, now in AGENTS.md: keep content in the HTML, collapse it with CSS under .js, and have the script remove the class if it fails.
  • mathjax_ignore belongs on the rail and the strip too, as AGENTS.md now says.
  • The anchors are now a public contract: activity-YYYY-MM and activity-YYYY-MM-DD, which group and editions rows link to. Link to them as /activity/#…, never as a bare #…: main.js's smooth-scroll handler swallows those, and no hashchange fires.

Closes #277.
Part of #271.

🤖 Generated with Claude Code

mmcky and others added 2 commits September 30, 2026 12:50
The groundwork the restyled /activity/ page needs first, on every page:

- default.html sets a js class on <html> before first paint, so styles for
  states that need JavaScript (a collapsed list, a filter bar) apply from
  the start and nothing moves when scripts run. Nothing uses it yet.
- main.js reads and writes sessionStorage inside try/catch. Where site data
  is blocked the read threw and stopped the rest of main.js: the mobile
  menu, the header state, back-to-top and the smooth scroll.
- main.js's URL carries the same ?v= build stamp as the CSS, so a deploy
  doesn't pair new pages with a cached main.js.

Part of #277.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…day links

The log now reads site.data.activity_view instead of flattening the data
files: months, newest first, each an <ol> of days whose ids
(activity-2026-08-02) are the anchors that group and editions rows link
to, each holding that day's rows in the view's order.

- Row includes in _includes/activity/: meta.html (icon, hidden type word,
  date and tag; tag=false leaves the tag out), title.html and summary.html
  (escaped, backtick spans as <code>), to be shared with the /news/ rail
  and the home strip; log-row.html is the log's row. Every field is
  escaped, attributes included.
- A type filter: All, Releases, Lectures, Translations and Books as text
  buttons with aria-pressed in a labelled group. It hides the days and
  months it leaves empty, shows an empty state for a type with no rows,
  and a polite live region announces the rows shown.
- "N changes" disclosures: the PR lists are in the HTML, open. With
  JavaScript, CSS keyed on the head's js class collapses them from the
  first paint; without it, every PR link shows and the toggles are hidden.
- Day and month anchors land below the header and the sponsor bar, with
  scroll padding scoped to this page, and following one on the page
  resets the filter to All first.
- The behaviour is one inline script at the end of the layout. If it
  fails, it removes the js class, so every row and link shows.
- mathjax_ignore on the log keeps MathJax from typesetting a "$" in a
  summary.
- The intro's two links are underlined, as the release and PR links are:
  their colour alone is only 1.9:1 against the text.
- The interim styles and the release and translation pills are removed.
- README describes the page as it now is. AGENTS.md lists the includes
  and documents the js class pattern and mathjax_ignore for Activity
  views.

Part of #277.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@netlify

netlify Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for grand-swan-ca5201 ready!

Name Link
🔨 Latest commit e5dbf08
🔍 Latest deploy log https://app.netlify.com/projects/grand-swan-ca5201/deploys/6abc896890186a00075cadc5
😎 Deploy Preview https://deploy-preview-290--grand-swan-ca5201.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@mmcky
mmcky marked this pull request as ready for review September 30, 2026 04:27
Copilot AI balanced review requested due to automatic review settings September 30, 2026 04:27

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.

Copilot review overview

🔵 Needs a closer look

It is a large UI/accessibility change spanning a rewritten layout, new JS behavior, ~300 lines of CSS, and a cross-page anchor contract whose correctness depends on browser/visual verification that cannot be performed here.

Review effort: Balanced
Findings: None

What changed in this PR

This PR restyles the /activity/ log to render from the build-time rows plugin (site.data.activity_view, added in #285) instead of flattening the raw data files in Liquid, and implements section 4 of the round-2 design handoff (#266). It introduces reusable Activity-row includes that the upcoming /news/ rail (#278) and home strip (#279) will share, a client-side type filter with an accessible live region, day/month anchors, and a "N changes" disclosure for PR links — all built to degrade gracefully without JavaScript. It also lays shared groundwork used site-wide: a js class set on <html> before first paint, a try/catch guard around main.js's sessionStorage access, and a ?v= cache-buster on the main.js URL. Closes #277.

Changes:

  • Rewrite _layouts/activity.html to read the view (months → days → rows), add a labelled type-filter button group, a polite live region, a day/month anchor script, and a no-JS-safe fallback.
  • Add shared includes _includes/activity/{meta,title,summary,log-row}.html that escape every field and prefix their Liquid variables with activity_.
  • Replace the interim .activity-* styles and the release/translation pills in assets/main.scss with the new log/filter styles; guard sessionStorage in main.js; add the head js class and cache-buster in _layouts/default.html; update README and AGENTS.md.
File Description
_layouts/​activity.html Renders the view by month/day/row; filter, live region, "N changes" toggles, and anchor/scroll script
_includes/​activity/​meta.html Row meta line: type icon, visually-hidden type word, date, optional tag
_includes/​activity/​title.html Row title with optional single-release version span
_includes/​activity/​summary.html Escaped summary with backtick spans turned into <code>
_includes/​activity/​log-row.html One log row: release group, editions, single title, summary, per-edition/chips, and PRs
assets/​main.scss Removes interim styles and pills; adds shared filter + .activity-log styles, :has() scroll padding, reduced-motion rules
assets/​js/​main.js Wraps sessionStorage get/set in try/catch so blocked storage no longer halts the script
_layouts/​default.html Adds head js class before first paint and a ?v= build stamp on the main.js URL
README.md Describes the page as view-driven; removes the interim-page note
AGENTS.md Documents the includes, the js/html:not(.js) pattern, and mathjax_ignore

The implementation is consistent with the documented view contract (filter keys, row types, type_word, kind, editions/per_edition/changes), all referenced Sass variables and the visually-hidden/Bootstrap-icon classes exist, removed classes have no remaining references, and both sessionStorage call sites are guarded. I found no objective defects to flag.


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@mmcky
mmcky merged commit 88beeef into main Sep 30, 2026
6 checks passed
@mmcky
mmcky deleted the activity-log-restyle branch September 30, 2026 04:35
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.

Restyle /activity/ with the shared rows, a type filter and day links

2 participants