Repository navigation
Design review: Activity and News pages #266
Description
Activity
Round 1 brief: Activity page layouts
This is the prompt for round 1: three layout directions for
/activity/, each on a desktop and a mobile artboard. It was written against the Activity data in #265 as of 2026-09-28 (40 entries). If Activity has grown by the time the round starts, refresh the data section at the end first.To use it: copy the prompt below into Claude Design and attach two screenshots taken at 1440px wide. The brief refers to them by these filenames:
Filename Page screenshot-news-1440.pngthe News page screenshot-activity-interim-1440.pngthe interim Activity page: the #265 preview, or quantecon.org/activity once it's merged The round's outputs, the chosen direction and the round 2 brief will follow in this thread.
Claude Design prompt, round 1 (expand, then use the copy button)
# Design brief: the Activity page on quantecon.org ## What to design, this round Design the **Activity page** (`quantecon.org/activity/`) for QuantEcon. This round covers the Activity page only. Please give me **three layout directions**, each drawn as: - a desktop artboard, 1440px wide; - a mobile artboard, 390px wide. Use the data at the end of this brief. Make the three directions differ in **structure**, not only in styling: how entries are grouped, where filters sit, and how detail is disclosed. Leave these for a later round, after we pick a direction: - the component sheet; - the filter and empty states in detail; - the link to Activity on the News page; - any home-page module. Two screenshots are attached for reference: - `screenshot-news-1440.png`: the News page and the real site header. The posts shown predate the split; a post such as "New Julia Lecture: …" would now be an Activity entry. - `screenshot-activity-interim-1440.png`: the current interim Activity page, which your design replaces. ## Context QuantEcon is a NumFOCUS-sponsored open-source project for computational economics. It publishes free lecture series (for example *Intermediate Quantitative Economics with Python*), books, and Python and Julia libraries (for example QuantEcon.py and GameTheory.jl). Some lecture series have translated editions in French, Persian and Simplified Chinese. The audience is economists, students, researchers and teachers. The site has just split its updates into two streams: | | **News** (`/news/`) | **Activity** (`/activity/`, the page you're designing) | |---|---|---| | What goes in | New projects (a new lecture series, book, a library's first public release, or a new language edition), grants and funding, people, workshops, tutorials and talks, partnerships, and changes that affect users | Every library release; changes to existing lecture series (new lectures, sections and exercises, substantive revisions, fixes a reader would notice); updates to translated editions | | Written by | A person | A bot that reads public GitHub activity | | Volume | About one post a month or fewer (6 so far in 2026), long-form | Today about 2–3 entries a week, in bursts (5 releases on one day). Expect **about 6–7 a week** once the bot is fixed (see Volume below) | | Tone | Editorial | A factual log: a sentence plus links | Neither stream carries dependency or CI bumps, build, deploy or publishing-workflow changes, analytics, metadata changes, translation-sync tooling, or website changes. So every Activity entry is something a reader would notice. A library's first public release also gets a News post written by a person, but the release itself still appears in Activity, like every release. A new language edition is announced in News, and later updates to it appear in Activity. Activity must feel **useful and alive, not like a raw commit log**, while staying visibly secondary to News, which carries the announcements. ## Who uses it and what for 1. **Scanning what's new.** "What changed across QuantEcon this week or this month?" This is the default view. 2. **Checking a library.** "What's the latest QuantEcon.py release, and when was it?" The reader filters to one library, or to releases only. 3. **Following a lecture series.** "What's new in *Intermediate Quantitative Economics with Python*?" The reader filters by series. 4. **Following translations.** A reader of a translated edition wants to see what changed in their language. The page must stay usable as the log grows to hundreds of entries. Think about grouping (by week or month), collapsing detail, and how older months or years are reached (for example "show more", a year archive, or a jump list). ## The content Every entry has `date`, `type`, `project` and `url`. There are three types: | Type | What an entry carries | Links to | |---|---|---| | `release` | project and version, e.g. "QuantEcon.py v0.12.0". No summary so far. 17 of the 24 releases are Julia packages (`.jl`). The others are QuantEcon.py, jlgametheory (a Python interface to GameTheory.jl) and gametracer (the C++ engine behind GameTracer.jl). Version strings vary: `v0.12.0`, but `0.2.2` for gametracer. | the release notes on GitHub | | `lectures` | project (a lecture-series name, often long), a one-sentence `summary`, and `changes`: pull-request titles, each a link (1–3 so far; expect 10 or more on some entries, see Volume) | the live lecture site | | `translation` | the same shape as `lectures`. The project is the series name plus the language in brackets, e.g. "Python Programming for Economics and Finance (French)" | the live translated site | **These are the only fields.** There is no separate language field (the language is the part in brackets in `project`), and no link between a translated edition and its English series. There is also no author, avatar, star count, release-note text or lecture thumbnail, so don't design elements that need them. Summaries are plain text, except that text in backticks renders as inline code (e.g. `quantecon`). PR titles are plain text. `summary` and `changes` are optional in the schema: a lectures entry may have neither, and a release may one day carry a summary. ### Volume The data below is everything the page holds today: **40 entries from 12 June to 27 September 2026**. | Measure | Value | |---|---| | By type | 24 releases, 12 lecture updates, 4 translation updates | | By month | June 6, July 15, August 13, September 6 | | Busiest days | 15 July (5 releases); 2 August (4 releases); 3 August (an English lecture update plus three translation updates describing the same change) | | Summaries | 16 in total; 8–35 words (median 13), up to 236 characters | | Distinct projects | 17 so far | | Longest project name | 73 characters: "A First Course in Quantitative Economics with Python (Simplified Chinese)" | | Longest PR title | 83 characters | The current data **under-represents what's coming.** The old bot missed many reader-facing lecture changes, including one July update that added eight new lectures. Once it's fixed, expect: - about one entry per lecture site per day it publishes. The lecture and translation sites published on about 40 days between them in the last eight weeks, so roughly 5 lecture and translation entries a week; - releases at today's rate, about 1–2 a week, often several on one day; - some lecture entries with 10 or more changes (a rough estimate). Design for that volume, not just today's data. ## Design questions each direction should answer - **Grouping:** by month or by week? Do same-day releases collapse into one row, e.g. "4 releases: QuantEcon.jl v0.19.0, GameTheory.jl v0.7.1, …"? - **Filtering:** by type (Releases / Lectures / Translations) and by project. Where do the filters live? Filtering runs client-side in plain JavaScript. - **Detail:** are the PR links shown, collapsed ("5 changes ▾") or hidden? The summary should read first. - **Type markers:** how are the three types told apart? See the pills table and the colour principle below. Answer these in text, one line each: - where Activity belongs in the navigation; - which date format to use; - whether the page should offer an RSS link. ## Constraints **Stack:** a static Jekyll site with Liquid templates. Styling is Bootstrap **5.2** plus custom SCSS, icons are **Bootstrap Icons 1.11.3**, and small vanilla JavaScript is fine. No frameworks, and nothing that needs a single-page app. **Chrome:** draw the existing header as it is; don't restyle it. - **Footer:** it isn't in the screenshots, so don't draw its contents. End each artboard with a plain `#283039` band labelled "Existing footer". The footer already links to Activity from its Resources column (Lectures, Books, Code Libraries, Workshops, News, Activity, Cheatsheets). - **Sponsor bar:** optional and dismissible, `#1e2d3a`, about 34px tall. It reads "Supported by the Chow Institute, Xiamen University | View sponsors →". - **Header:** fixed, `#283039`, 84px tall (15px of padding above and below the logo). - Left: the QuantEcon "hills" logo (a small multi-coloured bar-chart mark, about 100×54px), then the wordmark "QuantEcon" in white Exo 2 at 2rem ("Quant" at weight 200, "Econ" at 400). - Right: the nav in Roboto 15px bold at 70% white: Lectures · Workshops · Books · Projects ▾ · About ▾ · News, then a GitHub icon. The active item is full white with a 2px white underline. - Dropdowns are white panels with an 8px radius. Projects ▾ holds Code Libraries, Infrastructure, Activity (a stopgap) and Cheatsheets. About ▾ holds About QuantEcon, Team, Sponsors, Analytics and Donate. - On /activity/ no nav item looks active today. Projects ▾ is a button, so it doesn't get the white underline (see the Activity screenshot); draw it that way. - Below 992px, a hamburger replaces the nav. - **Interior pages** have **no hero band and no breadcrumbs**. Content sits in a Bootstrap `.container`: max-width 1320px, which leaves 1296px of content on a 1440 artboard. - **Page padding:** 112px at the top, measured from the top of the viewport. - The fixed 84px header covers most of it, so the h1 sits about 28px below the header. - At 576px and below, the top padding is 96px, so the h1 sits about 12px below the header. The sides are 16px plus the container's 12px gutter, which leaves a 334px content column on a 390px artboard. - When the sponsor bar shows, the header and the content both move down by its height. - **Page copy:** the page starts with the h1 "Activity" (Exo 2, 2rem, weight 400) and this intro. You may tighten the intro, but don't add claims: > A running log of what is changing across QuantEcon: library releases, updates to the lecture series, and updates to their translated editions. It is compiled from public activity on GitHub. > > For announcements such as new projects, grants, people and workshops, see News. **No dark mode:** the site has none; don't design one. **Breakpoints:** Bootstrap's 576 / 768 / 992 / 1200 / 1400px. Grids collapse to one column below 768px. **Accessibility:** - WCAG AA contrast, including dates and meta text. - Visible `:focus-visible` outlines (`2px solid #0072bc`, offset 2px). - Filters are real `<button>`s that work with the keyboard. - Links inside running text need an underline or another cue besides colour, because link blue is only 1.9:1 against body text. ## Brand tokens | Token | Value | |---|---| | The four logo colours: blue / red / green / yellow | `#1364AC` / `#D25663` / `#6EAC5B` / `#FCC837` | | Link / primary action | `#0072bc` (hover `#174867`) | | Dark (header, footer, titles) | `#283039` | | Body text | `#444` on white (9.74:1); secondary `#666` (5.74:1) | | Meta grey | The site uses `#888` (3.54:1) and `#999` (2.85:1) for dates and meta. Both **fail WCAG AA** at small sizes, so on Activity use `#666` or darker | | Light section background / hover background | `#f8f9fc` / `#f3f5fa` | | Border / soft divider | `#e2e8f0` / `#edf0f5` | | Soft blue-tinted card (background / border) | `#eef4fb` / `#dbe8f5` | **Fonts** (Google Fonts): - **Exo 2** for headings, section titles and the wordmark. Loaded weights are 200, 300, 400, 600 and 700; 500 is not loaded. - **Roboto** for body, navigation, card titles and badges. Only 400 and 700 are loaded, and a declared 600 renders as 700. **Type scale:** - h1: Exo 2, 2rem, weight 400 - h2: Exo 2, 1.6rem, weight 400 - section title: Exo 2, 1.8rem, weight 400, `#283039` - body: 16px, line-height 1.5 - card title: Roboto, 1–1.1rem, weight 700 - meta: 0.8rem, currently `#888` (fails AA; use `#666` on Activity) **Shape and motion:** - Radii: cards 8px, buttons 6px, pills 12px. - Card hover: `0 4px 12px rgba(0,0,0,.08)` and a 2px lift. The News list uses the lighter `0 2px 8px rgba(0,0,0,.06)`. - Transitions: 0.2s. **Current tag pills** (0.7rem; white text unless noted): | Pill | Colour | Contrast | WCAG AA (4.5:1) | |---|---|---|---| | news | `#0072bc` | 5.08 | passes | | lectures | `#306998` | 5.83 | passes; same blue as the Python badge on lecture cards | | release | `#9558b2` | 4.86 | passes narrowly; same purple as the Julia badge | | translation | `#1f7a70` | 5.15 | passes | | announcement | `#283039` | 13.36 | passes | | tools | `#FCC837` with `#333` text | 8.10 | passes | | books | `#D25663` | 4.00 | fails | | new (on books) | `#e94560` | 3.83 | fails | | workshop | `#6EAC5B` | 2.72 | fails | The three Activity pills pass AA. Two of them collide with the language badges on lecture cards: `lectures` is the Python blue, and `release` is the Julia purple. The `lectures` pill is also used as a tag on News posts. **Type markers, icons and colour:** - Propose type markers that don't collide with those badges and that respect the colour principle below. For example, use a single accent with icons or shapes, rather than three competing colours. - For icons, use Bootstrap Icons, e.g. `bi-box-seam` for releases, `bi-journal-text` for lectures and `bi-translate` for translations. - If you want project logos, the site has square Python, Julia and data-science logos that we'll drop in. Draw them as labelled placeholder squares; don't redraw the logos. ## Existing components to reuse or evolve - **`.qe-badge`:** the small pill used above. - **`.qe-card`:** 1px `#e2e8f0` border, 8px radius, 1.5rem padding, white; the whole card is a link. - **`.qe-btn--outline-dark`:** a 2px `#0072bc` outline button, used for "View all …". - **News list** (see the screenshot): stacked cards that expand in place, each with an uppercase date, a bold title, pills, an excerpt and a chevron. - **`.content-filters`:** a tab row of bold `#0072bc` labels with a 2px underline that grows on hover; the active tab is `#444` with a solid underline. - It's defined in the CSS, but no live page uses it. - It's built on plain `<li>` items with no focus state, so reusing it for filters means rebuilding it on `<button>`s with `aria-pressed` and a focus outline. - **Timeline:** a 2px `#e2e8f0` vertical rule with 12px `#0072bc` dots, used on the Infrastructure page. - **"On this page" column** (in an open pull request for the Team page, not yet live): - a sticky right-hand column, shown at 1200px and wider only; - section links, with a 3px blue scroll-spy marker on the active one; - it could suit a month or year jump list. **The interim Activity page** (see the screenshot), which you are replacing: - Entries are grouped under month headings ("September 2026"; Exo 2, 1.4rem, with a bottom border). - Each row has the date ("Sep 27") in a 4rem left column, then: - a type pill; - the project name as a bold link, with the version for releases; - the summary; - a small bulleted list of PR links. - At 576px and below, the date stacks above the entry. There are no filters. ## Design principles from previous QuantEcon redesigns - Use the real site chrome. Never invent a new shell or navbar. - Allow **one multi-colour moment per page** at most (the four logo colours). Everything else uses a **single brand-blue accent**. Don't cycle colours per card. - Prefer soft blue-tinted surfaces to heavy dark blocks for emphasis. - Keep it modern, calm and content-first. References the team likes: Kaggle, Hugging Face and DrivenData. - **Use only the data below.** Don't invent projects, entries, summaries or counts. Where a direction needs more volume to show how it scales, you may repeat the pattern of real entries, labelled as placeholder rows. ## Deliverables (this round) 1. Three layout directions for the Activity page, each on a desktop (1440) and a mobile (390) artboard, filled with the data below. 2. For each direction, a short note answering the grouping, filtering, detail and type-marker questions, and explaining how it scales to hundreds of entries. 3. One-line recommendations for navigation placement, date format and RSS. ## The data (all 40 entries, newest first, as the page receives them) ```yaml - date: 2026-09-27 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Added three new lectures (Linear Quadratic Mean Field Games, Investment Under Uncertainty, and Optimal Growth Under Uncertainty and Tobin's q), and added exercises to the two auction lectures. changes: - {title: "Two sequels to rational_expectations", url: https://github.com/QuantEcon/lecture-python.myst/pull/1070} - {title: "Add exercises and further reading", url: https://github.com/QuantEcon/lecture-python.myst/pull/1069} - {title: "Add VCG comparison section and exercises", url: https://github.com/QuantEcon/lecture-python.myst/pull/1068} - {date: 2026-09-24, type: release, project: QuantEcon.py, version: v0.12.0, url: https://github.com/QuantEcon/QuantEcon.py/releases/tag/v0.12.0} - {date: 2026-09-23, type: release, project: GameTheory.jl, version: v0.7.2, url: https://github.com/QuantEcon/GameTheory.jl/releases/tag/v0.7.2} - {date: 2026-09-19, type: release, project: jlgametheory, version: v0.3.0, url: https://github.com/QuantEcon/jlgametheory/releases/tag/v0.3.0} - {date: 2026-09-16, type: release, project: GameTracer.jl, version: v0.2.0, url: https://github.com/QuantEcon/GameTracer.jl/releases/tag/v0.2.0} - {date: 2026-09-14, type: release, project: gametracer, version: 0.2.2, url: https://github.com/QuantEcon/gametracer/releases/tag/0.2.2} - date: 2026-08-20 type: translation project: A First Course in Quantitative Economics with Python (Simplified Chinese) url: https://quantecon.github.io/lecture-intro.zh-cn/ summary: Added the Simplified Chinese translation of the Measuring Mobility lecture. changes: - {title: "Add the Measuring Mobility lecture", url: https://github.com/QuantEcon/lecture-intro.zh-cn/pull/299} - date: 2026-08-19 type: lectures project: A First Course in Quantitative Economics with Python url: https://intro.quantecon.org/ summary: Added two new lectures, Measuring Mobility and Bivariate Distributions. changes: - {title: "Add Measuring Mobility lecture", url: https://github.com/QuantEcon/lecture-python-intro/pull/839} - {title: "Add Bivariate Distributions lecture", url: https://github.com/QuantEcon/lecture-python-intro/pull/837} - {date: 2026-08-16, type: release, project: jlgametheory, version: v0.2.0, url: https://github.com/QuantEcon/jlgametheory/releases/tag/v0.2.0} - {date: 2026-08-12, type: release, project: Expectations.jl, version: v1.9.3, url: https://github.com/QuantEcon/Expectations.jl/releases/tag/v1.9.3} - date: 2026-08-06 type: lectures project: A First Course in Quantitative Economics with Python url: https://intro.quantecon.org/ summary: Added a new lecture, Fitting Distributions to Data. changes: - {title: "New lecture: Fitting Distributions to Data", url: https://github.com/QuantEcon/lecture-python-intro/pull/814} - date: 2026-08-03 type: lectures project: Python Programming for Economics and Finance url: https://python-programming.quantecon.org/ summary: Added a language switcher linking to the Persian, French and Simplified Chinese editions. changes: - {title: "Add language switcher support for fa, fr and zh-cn editions", url: https://github.com/QuantEcon/lecture-python-programming/pull/490} - date: 2026-08-03 type: translation project: Python Programming for Economics and Finance (Persian) url: https://quantecon.github.io/lecture-python-programming.fa/ summary: Enabled the language switcher between the English, Persian, French and Simplified Chinese editions. changes: - {title: "Enable the language switcher and fix this edition's site URLs", url: https://github.com/QuantEcon/lecture-python-programming.fa/pull/145} - date: 2026-08-03 type: translation project: Python Programming for Economics and Finance (French) url: https://quantecon.github.io/lecture-python-programming.fr/ summary: Enabled the language switcher between the English, Persian, French and Simplified Chinese editions. changes: - {title: "Enable the language switcher for the French edition", url: https://github.com/QuantEcon/lecture-python-programming.fr/pull/21} - date: 2026-08-03 type: translation project: Python Programming for Economics and Finance (Simplified Chinese) url: https://quantecon.github.io/lecture-python-programming.zh-cn/ summary: Enabled the language switcher between the English, Persian, French and Simplified Chinese editions. changes: - {title: "Enable the language switcher and fix URLs copied from the English config", url: https://github.com/QuantEcon/lecture-python-programming.zh-cn/pull/80} - {date: 2026-08-02, type: release, project: QuantEcon.jl, version: v0.19.0, url: https://github.com/QuantEcon/QuantEcon.jl/releases/tag/v0.19.0} - {date: 2026-08-02, type: release, project: GameTheory.jl, version: v0.7.1, url: https://github.com/QuantEcon/GameTheory.jl/releases/tag/v0.7.1} - {date: 2026-08-02, type: release, project: BasisMatrices.jl, version: v0.8.2, url: https://github.com/QuantEcon/BasisMatrices.jl/releases/tag/v0.8.2} - {date: 2026-08-02, type: release, project: ContinuousDPs.jl, version: v0.3.2, url: https://github.com/QuantEcon/ContinuousDPs.jl/releases/tag/v0.3.2} - {date: 2026-07-26, type: release, project: ContinuousDPs.jl, version: v0.3.1, url: https://github.com/QuantEcon/ContinuousDPs.jl/releases/tag/v0.3.1} - date: 2026-07-26 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Added missing `quantecon` and `jax` installs to nine lectures. changes: - {title: "Add pip install cells for quantecon and jax in lectures that were missing them", url: https://github.com/QuantEcon/lecture-python.myst/pull/1006} - date: 2026-07-23 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Added a new section of ten lectures on Phillips Curve Tradeoffs, and added figure captions and standardized CDF notation in the Incorrect Models lecture. changes: - {title: "Adding Tom's new section on Phillips Curve Tradeoffs", url: https://github.com/QuantEcon/lecture-python.myst/pull/992} - {title: "Add figure captions and use CDF", url: https://github.com/QuantEcon/lecture-python.myst/pull/982} - {date: 2026-07-20, type: release, project: ContinuousDPs.jl, version: v0.3.0, url: https://github.com/QuantEcon/ContinuousDPs.jl/releases/tag/v0.3.0} - {date: 2026-07-15, type: release, project: QuantEcon.py, version: v0.11.4, url: https://github.com/QuantEcon/QuantEcon.py/releases/tag/v0.11.4} - {date: 2026-07-15, type: release, project: GameTheory.jl, version: v0.7.0, url: https://github.com/QuantEcon/GameTheory.jl/releases/tag/v0.7.0} - {date: 2026-07-15, type: release, project: BasisMatrices.jl, version: v0.8.1, url: https://github.com/QuantEcon/BasisMatrices.jl/releases/tag/v0.8.1} - {date: 2026-07-15, type: release, project: ContinuousDPs.jl, version: v0.2.1, url: https://github.com/QuantEcon/ContinuousDPs.jl/releases/tag/v0.2.1} - {date: 2026-07-15, type: release, project: GameTracer.jl, version: v0.1.2, url: https://github.com/QuantEcon/GameTracer.jl/releases/tag/v0.1.2} - {date: 2026-07-13, type: release, project: QuantEcon.jl, version: v0.18.0, url: https://github.com/QuantEcon/QuantEcon.jl/releases/tag/v0.18.0} - {date: 2026-07-08, type: release, project: QuantEcon.py, version: v0.11.3, url: https://github.com/QuantEcon/QuantEcon.py/releases/tag/v0.11.3} - date: 2026-07-07 type: lectures project: Advanced Quantitative Economics with Python url: https://python-advanced.quantecon.org/ summary: Added a new lecture, Dynamic Supply and Demand Curves. changes: - {title: "Adding Tom's lecture on dynamic supply and demand curves", url: https://github.com/QuantEcon/lecture-python-advanced.myst/pull/352} - date: 2026-07-07 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Added missing `pip install` cells to four lectures. changes: - {title: "Add missing pip dependencies", url: https://github.com/QuantEcon/lecture-python.myst/pull/951} - {date: 2026-07-06, type: release, project: ContinuousDPs.jl, version: v0.2.0, url: https://github.com/QuantEcon/ContinuousDPs.jl/releases/tag/v0.2.0} - date: 2026-07-02 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Replaced the LQ Consumption Smoothing lecture with a trilogy of lectures on the LQ permanent income model, and added two lectures on unemployment dynamics, A Linear Model of Unemployment and Unemployment Dynamics with Asymmetric Shocks. changes: - {title: "Add Tom's LQ permanent income trilogy of lectures", url: https://github.com/QuantEcon/lecture-python.myst/pull/943} - {title: "Add unemployment dynamics lectures (linear + nonlinear)", url: https://github.com/QuantEcon/lecture-python.myst/pull/928} - date: 2026-06-22 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Added three new lectures, including The Kalman Filter and Vector Autoregressions and Robust Permanent Income and Pricing. changes: - {title: "Adding Tom's new lectures on Kalman Filter and Robust Income", url: https://github.com/QuantEcon/lecture-python.myst/pull/931} - {date: 2026-06-20, type: release, project: jlgametheory, version: v0.1.2, url: https://github.com/QuantEcon/jlgametheory/releases/tag/v0.1.2} - date: 2026-06-19 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Rewrote the Non-Conjugate Priors lecture, adding notes on NUTS and variational inference, and revised the exposition and notation of Another Look at the Kalman Filter. changes: - {title: "Add explanatory notes to bayes_nonconj: NUTS and variational inference", url: https://github.com/QuantEcon/lecture-python.myst/pull/918} - {title: "Rewrite the Non-Conjugate Priors lecture", url: https://github.com/QuantEcon/lecture-python.myst/pull/913} - {title: "Update exposition of first three sections", url: https://github.com/QuantEcon/lecture-python.myst/pull/903} - {date: 2026-06-14, type: release, project: GameTheory.jl, version: v0.6.0, url: https://github.com/QuantEcon/GameTheory.jl/releases/tag/v0.6.0} - {date: 2026-06-14, type: release, project: GameTracer.jl, version: v0.1.1, url: https://github.com/QuantEcon/GameTracer.jl/releases/tag/v0.1.1} - date: 2026-06-12 type: lectures project: Advanced Quantitative Economics with Python url: https://python-advanced.quantecon.org/ summary: Added three lectures on contract theory under moral hazard and a lecture, Survey Data and Subjective Beliefs in Business Cycle Models. changes: - {title: "Add three lectures on contract theory and one lecture on survey data and robustness", url: https://github.com/QuantEcon/lecture-python-advanced.myst/pull/343} ```
One idea I have is to combine the News and Activity Pages.
Make News the hero on the LHS with 2/3 of the page and then Activity stream on the RHS with 1/3 of the page
Round 1 outcome
Decision:
/news/: Option A, a side rail. News keeps the main column (two-thirds of the page), and a sticky Activity rail (one-third) shows the latest entries and links to the full log.- Home page: c1, the three news cards plus a compact "Latest activity" strip. It should be built as two rows rather than one line; see "Home strip" below.
- Option B, the integrated timeline, is parked for a team discussion in Discussion: an integrated News and Activity timeline on /news/ (Option B) #268.
Why Option A: it keeps announcements first on every screen size, which is the reason for the News/Activity split. It also shows at a glance that the project is active, which was John's aim in #265. It's less busy than the integrated timeline, cheaper to build, and stays the same size as the log grows.
Claude Design's handoff specified Option B and c1. Before building, the handoff was reviewed against the real data and the repo:
- What checks out: every number and label on the Option B and c1 artboards reproduces exactly from the 40 real Activity entries and the site's posts.
- What doesn't: some of the spec's assumptions would break the build or the page. They are listed below, since most of them apply to Option A too.
To carry into the Option A handoff and build
Data and grouping:
-
The data lives in
_data/activity/*.yml, not_data/activity.yml. Merge the files in filename order, then sort whole days rather than entries, as_layouts/activity.htmldoes. Liquid'ssortisn't stable and reorders entries within a day. -
If anything compares an activity date with a post date, compare
YYYY-MM-DDstrings. One example is a rail header such as "N updates since ". A direct comparison stops the Jekyll build ("comparison of Date with Time failed"). Post dates are local to the site, and activity dates are UTC days. -
Compute the grouped rows in a small Jekyll plugin (
_plugins/), tested in CI, rather than in Liquid.- The grouping needs a regex, which Liquid doesn't have.
- It also needs look-ahead grouping, which is brittle in Liquid and can only be tested by building the site.
- Production (GitHub Actions) and the Netlify previews both run a plain
jekyll build, so plugins work in both. - Don't have the bot emit group keys. That would put display logic into the data.
-
Group by key rather than by adjacency:
- same-day releases by date;
- translations by date and series, showing each edition's summary when they differ.
With adjacency, a second Jul 26 release reported in a later file would land after that day's lecture entry and not group with the first release.
-
Drop the "exclude posts tagged
software" rule. Split updates into News and an Activity feed #265 already removes those posts. -
Add two checks to
.github/scripts/check-activity-data.rbin Split updates into News and an Activity feed #265:- a
translationentry'sprojectmust end in(Language); - each change URL must be a GitHub pull-request URL.
The rows take the language from the first and print
#Nfrom the second. - a
Page:
- A sticky rail won't stick as things stand. The site-wide
section { overflow: hidden }rule prevents it. Useoverflow: clipscoped to the News page, as team: add Translators section and section navigation #264 (still open) does for the Team page's contents column. - Explain the page at every width. Keep one reader-facing line that says what the two kinds of update are, e.g. a subtitle on the rail and the mobile panel.
Accessibility:
- News-card focus ring (existing bug). Keyboard focus on news cards can't be seen, because
.news-card { overflow: hidden }clips the outline. Include the change in the/news/rail PR. - Tag pills. The
workshop(2.72:1) andbooks(4.00:1) pills fail WCAG AA and appear on most visible cards.#4a7c3c(4.95:1) and#b83d4b(5.52:1) pass. - Meta greys. Use
#666for meta text instead of#888/#999.
Home strip (c1):
- It wraps at common laptop widths (1280 and 1366px). A two-row strip aligned with the card grid fixes that.
- It drops a translation's language. Showing the full project name (e.g. "… (Simplified Chinese)") or the language after the title fixes that.
Consistency:
-
/activity/: switch it to the same row design as the rail and the strip, so an entry looks the same everywhere. -
Navigation: the designer recommends taking Activity out of Projects ▾ and treating
/activity/as part of News.- Activity would have no menu item of its own, and News would be highlighted on both pages.
- Readers would reach
/activity/from/news/and the footer.
This is still to decide (see the Decisions table). If adopted, it's about a three-line change in
_layouts/default.html, best made in Split updates into News and an Activity feed #265 before it merges.
Missing from the handoff: the
future_idea_c3/folder (the parked activity-chart idea) that its README refers to.Next
- Before Split updates into News and an Activity feed #265 merges: add the two data checks above, and make the navigation change if it's adopted. Both are done in Split updates into News and an Activity feed #265 (318ad25); the navigation change was adopted.
- Round 2: ask Claude Design for an Option A + c1 handoff that includes the points above. The rail was described in round 1 but not specified in the handoff: 6 latest entries grouped by week, filtering by type, a two-line summary per entry, and a collapsed panel on mobile.
- Build in this order once Split updates into News and an Activity feed #265 merges:
- the grouping plugin and a shared row include, with
/activity/switched to it; - the
/news/rail; - the home strip;
- an Activity feed (optional).
- the grouping plugin and a shared row include, with
- added a commit that references this issue
on Sep 28, 2026 Round 2 brief: Option A and c1 handoff
This is the prompt for round 2: a build-ready handoff for the decisions recorded above.
/news/: Option A, the side rail.- Home page: c1, the "Latest activity" strip.
/activity/: restyled with the same row design.
It builds in the corrections from the round 1 outcome and the navigation decision. It also adds acceptance checks and a priority order, in case the round runs short.
It uses the same data as round 1: 40 Activity entries as of 2026-09-28, plus the 8 newest News posts. If Activity has grown by the time the round starts, refresh the data section at the end first.
To use it: copy the prompt below into Claude Design. If you start a fresh Claude Design session rather than continuing round 1, attach the round-1 artboards for Option A and c1 from the round-1 design sheet. The Option A screenshot is also in #268.
The round's outputs, and any decisions they lead to, will follow in this thread.
Claude Design prompt, round 2 (expand, then use the copy button)
# Design brief, round 2: build-ready handoff for Option A and c1 ## Where we are Thank you for round 1. We reviewed the design sheet and the handoff, and made these decisions: - **`/news/`: Option A, the side rail.** The news cards keep the main column (two-thirds of the page), and a sticky Activity rail (one-third) shows the latest activity and links to the full log. It keeps announcements first on every screen size, still shows at a glance that the project is active, and is less busy than the integrated timeline. - **Home page: c1,** the three news cards plus a compact "Latest activity" strip. - **Navigation:** your round-1 recommendation, described below. - **Parked:** Option B (the integrated timeline) is waiting on a team discussion, and c3 (the activity chart) is also parked. Don't design either this round. The round-1 handoff specified Option B and c1, and its numbers were exact against the real data. The review found problems in the spec, and most of them apply to this round too. They're listed under "Corrections from round 1", and the new handoff should build them in. **Everything in this brief describes the site as it will be after a pending change (PR #265) merges.** That change adds the `/activity/` page and the `/news/` intro, removes the old "Software releases" round-up posts from News, and makes the navigation change. Until it merges, quantecon.org still looks like the round-1 starting point. ## What to deliver A **build-ready, high-fidelity handoff** in the same format as round 1: - a `README.md` spec, including the acceptance checks below; - an interactive reference HTML file; - artboards filled with the real data at the end of this brief. Deliver these, and **if you can't finish everything in one round, work in this priority order** and list anything you left out at the top of the README: 1. **The README spec and the shared row rules.** 2. **`/news/` with Option A** at 1440 and 390px, with the mobile panel both collapsed and expanded. 3. **A component sheet:** - every row variant: single release, same-day release group, lecture update with one change, lecture update with several changes, single translation, merged translation; - hover, `:focus-visible`, pressed and expanded states; - the rail's filter states, including "fewer than 6 rows" and an empty filter; - the mobile panel, collapsed and expanded; - the home-strip items; - the news card with the fixes below. 4. **Home page "Latest News" with the c1 strip** at 1440 and 390px. 5. **`/activity/`, the full log, restyled** at 1440 and 390px (details below). 6. **Extra widths:** `/news/` at 1280 and 1024px, and the home page at 1280px, where round 1's one-line strip wrapped. The reference HTML only needs to work for what you drew. ## Option A: the rail on `/news/` - **Breakpoint:** pick one breakpoint where the rail becomes the mobile panel, either 992px (Bootstrap `lg`, where the site's nav also collapses) or 1200px (`xl`), and draw the 1024px artboard to match. - At 1024 the container is 960px, so a one-third rail is about 296px wide. Check that the four filter buttons fit on one line, or say how they wrap. - Below the breakpoint the panel is used at every width, including 768px. - **Content:** the latest 6 activity **rows**, newest first. A merged release or translation row counts as one row. - Rows sit under week headings with fixed dates, e.g. "Sep 21–27". Weeks run Monday to Sunday (UTC). - A heading appears only above a week that has a shown row, so the first heading is the week of the newest row, not the week of the build. Six rows can need up to six headings. - Fixed ranges matter because the site is a static build, so relative labels like "this week" would go stale. - **Filter by type:** All, Releases, Lectures, Translations. - Each filter shows the latest 6 rows of that type, with the week headings recomputed for those rows. - There's no time window, so a filter shows fewer than 6 rows only when fewer exist. With today's data, Translations shows 2 rows: Aug 20, and the Aug 3 row with 3 editions. Draw that state. - A filter is empty only when a type has no entries at all, which can't happen with today's data. Draw it as a labelled placeholder, e.g. "No translation updates yet". - The page renders the latest 6 rows of each type once (14 rows today), and All is the newest 6 of those. - Without JavaScript, hide the filter buttons and show the All view. - The filter isn't remembered between visits. - When the filter changes, a polite live region announces the result, e.g. "Showing 2 translation updates". - **Header:** - the title "Activity"; - a one-line subtitle saying what it is and where it comes from, e.g. "Library releases and updates to the lectures and their translations, compiled from GitHub"; - optionally, a count line such as "28 updates since the last news post (Jul 14, 2026)". This is the best idea from Option B; include it if it fits. - It counts **entries**, not rows, so a group of 4 releases counts as 4. The 28 entries since Jul 14 make 19 rows. - Hide the line when the count is 0. - It always describes all activity, whatever the filter. - **Entry detail:** - type icon and date; - the title, with the version for a release; - the tag: the language for a single translation, "3 editions" for a merged translation, "4 releases · same day" for a release group; - up to two lines of summary. For a merged translation whose editions' summaries differ, say what those two lines show. - PR links, and the per-release and per-edition links, stay on the full log. - **Actions:** "View all activity", going to `/activity/`. Also draw an optional "Activity feed" RSS link; whether we add the feed is still to be decided. - **Sticky behaviour:** the rail is sticky 24px below the fixed header (84px) and, when it's shown, the sponsor bar (`--sponsor-bar-height`, about 33px). - **The rail must never hide its own content.** With real data it can be taller than the space below the header: round 1's rail was about 663px. The Lectures filter (6 rows with two-line summaries under 4 week headings) will be taller still. - State the rail's tallest height, and say what happens when it doesn't fit. For example, it stops being sticky and scrolls with the page rather than cutting off "View all activity". Don't use an inner scrollbar. - **"Older Posts":** say where the year accordion goes, either in the main column beside the rail or full width below both columns. - **Mobile panel:** a collapsed soft-blue panel under the page intro. - Its summary reads "Activity · {N} updates in {month} · latest {date}", which today is "Activity · 6 updates in September · latest Sep 27": - {month} is the calendar month of the newest entry, not the build date; - N counts the entries in that month; - {date} is the newest entry's date. - The summary describes all activity, whatever the filter. The panel expands to the rail's content. - **Explain the page at every width.** Keep the one-line intro under the "News" h1. Today it reads: "Announcements from QuantEcon: new projects, grants, people and workshops. For library releases and lecture updates, see Activity." ("Activity" is a link.) You may tighten it, e.g. to mention translation updates. Don't rely on the rail, which becomes a collapsed panel on smaller screens. ## c1: the home-page strip - **Two rows, not one line:** - row 1: "Latest activity" on the left and "View all activity →" on the right; - row 2: the three newest rows, in the same three-column grid as the news cards above, so they line up under the cards. - **Each item:** the type icon and date on one line, and the title below it, clamped to two lines. - **Tags:** show a translation's language, e.g. "… (French)" or a "French" tag. A merged translation shows "3 editions"; a release group shows "4 releases · same day". - **Mobile (below 768px):** keep round 1's stacked list, with 44px rows, and keep the icons on mobile too. - **Cards:** the dates change to "Jul 14, 2026" in `#666`. ## `/activity/`: the full log, restyled - **Rows:** use the same row anatomy as the rail and the strip (icon, date, title, tag), plus what only the full log has: - the full summary; - one link per release or edition in a merged row; - the PR list: one inline link, or an "N changes" disclosure for two or more. - **Page text:** keep the h1 "Activity" and its current intro: > A running log of what is changing across QuantEcon: library releases, updates to the lecture series, and updates to their translated editions. It is compiled from public activity on GitHub. > > For announcements such as new projects, grants, people and workshops, see News. - **Month headings:** keep them. - **Filter:** add the rail's type filter. Here a filter shows **every** row of that type, and hides any month heading left with no rows. With today's data, Translations shows 2 rows, both in August. - **Day anchors:** give each day an anchor, e.g. `id="activity-2026-08-02"`, matching the page's existing month ids (`activity-2026-09`). - Arriving with a day in the URL resets the filter to All. - The day must land below the fixed header and sponsor bar, not under them. - Say whether a day gets a visible heading, or only the date on its first row. - **Out of scope:** a project filter, a month accordion and year archives. They come later. ## Shared row rules (every page) - **Link targets are the same everywhere:** - a single row's title links to its `url` (the release notes, or the live lecture or translated site); - a merged row links to its day on `/activity/`, e.g. `/activity/#activity-2026-08-02`. - **Merge by key, not by position.** Merged rows are the only kind of grouping inside a list; week and month headings are the other kind. - All `release` entries with the same date merge into one row. - `translation` entries with the same date and the same series merge into one row. The series is the `project` without its trailing " (Language)". - Round 1's "consecutive entries" rule depended on which data file an entry happened to come from. - **Merged translations:** - show one summary when all the editions' summaries are identical; - show each edition's summary when they differ; - list each language once. - **Order within a day:** lecture updates, then translation updates, then releases. - Within a type, sort alphabetically by project. - Inside a merged row, list releases alphabetically by project (ignoring case) and editions alphabetically by language. - Challenge this if you see a better rule, but the spec must state one. - **Dates:** - the short form "Sep 27" in activity rows (rail, home strip and full log), in week headings and in the mobile panel summary; - the long form "Sep 27, 2026" on news cards and in the count line; - a range within one month is "Sep 21–27", across months "Jul 27 – Aug 2", and across years "Dec 28, 2026 – Jan 3, 2027"; - a single-day range shows one date; - always inside a `<time datetime>` element; - never use relative dates. - **Summaries** are plain text, except that text in single backticks renders as inline code. PR titles are plain text. ## Corrections from round 1 (build them into the spec) **Data:** - **Where the data lives.** It's in **`_data/activity/*.yml`**, not a single `_data/activity.yml`. - Each run of the GitHub activity bot writes one file per stream, e.g. `2026-09-24-software.yml`. The `software` stream holds releases; the `lectures` stream holds lecture and translation updates. - An entry's date can be months earlier than its file's date: `2026-09-28-software.yml` backfills releases from Jun 14 to Sep 19. - Entries within a file are in no guaranteed order. - **Specify display rules, not Liquid.** The rows will be computed at build time by a small Jekyll plugin. Don't propose a bot-written group key. - **Drop the rule about excluding posts tagged `software`.** PR #265 deletes those posts, so the rule has nothing left to exclude. **Accessibility and colour:** - **Meta text:** on the pages in scope, use `#666` or darker instead of `#888` and `#999`. That's 5.74:1 on white and 5.45:1 on the rail's `#f8f9fc`. This includes the news-card dates. The news-card chevron is `#aaa` (2.32:1); use `#64748b` (4.76:1). - **Tag pills:** `workshop` and `books` fail AA with white text. Use `#4a7c3c` (4.95:1) and `#b83d4b` (5.52:1). This is a deliberate site-wide change: the same pills appear on individual post pages, and it's the one exception to the scope rule. - **Blue on soft surfaces:** `#0072bc` on `#eef4fb` is only 4.59:1, and on the `#e3edf8` hover it fails (4.29:1). Use `#174867` for text on hover surfaces. - **News-card focus:** keyboard focus on news cards is currently invisible, because `.news-card { overflow: hidden }` clips the outline. Specify a focus style that stays visible, e.g. an outline on the card when its header button has `:focus-visible`. - **Controls:** - filters are `<button aria-pressed>` in a labelled group; - disclosures use `aria-expanded` and `aria-controls`; - say where focus goes after an expand or collapse; - Bootstrap Icons are `aria-hidden`, with a visually hidden type word ("Release:", "Lecture update:", "Translation:"); - mobile targets are at least 44px; - respect `prefers-reduced-motion`. - **No layout jump:** anything collapsed by default must render collapsed from the first paint, with no jump when JavaScript loads (e.g. a `js` class on `<html>` set in `<head>`). Without JavaScript, every row stays reachable. **Implementation notes for the README:** - A sticky element inside `section.inner-page` needs `overflow: clip` scoped to that page, because the site-wide `section { overflow: hidden }` stops `position: sticky` working. - The header is 84px tall, and the sponsor bar sets `--sponsor-bar-height` while it's visible. - Day anchors land under the fixed header unless the page sets `html { scroll-padding-top: calc(84px + var(--sponsor-bar-height, 0px) + 16px) }`. - Anything that compares an activity date with a post date (e.g. the count line) must compare `YYYY-MM-DD` strings. Post dates are in the site's timezone (Australia/Sydney), activity dates are UTC days, and a direct Date/Time comparison stops the build. **Missing file:** the round-1 handoff referred to a `future_idea_c3/` folder that wasn't in the bundle. If you still have it, include it unchanged and marked as parked; if not, remove the reference. Don't do new work on c3. ## Acceptance checks (put these in the README) 1. At a 390×844 viewport, with JavaScript on, the sponsor bar shown and the panel collapsed, the newest news post's whole title is visible on `/news/` without scrolling. 2. There's no horizontal scroll at 320px on `/news/`, the home page or `/activity/`. 3. At 1280×720 with the sponsor bar shown, every part of the rail, including "View all activity", can be reached under every filter. 4. With today's data, the rail shows: - **All:** Intermediate Quantitative Economics with Python (Sep 27), QuantEcon.py v0.12.0, GameTheory.jl v0.7.2, jlgametheory v0.3.0, GameTracer.jl v0.2.0 and gametracer 0.2.2, under "Sep 21–27" and "Sep 14–20"; - **Releases:** Sep 24 back to jlgametheory v0.2.0 (Aug 16); - **Lectures:** Sep 27 back to Jul 23, under four week headings; - **Translations:** 2 rows, Aug 20 and Aug 3 (3 editions). 5. The home strip shows Sep 27 Intermediate Quantitative Economics with Python, Sep 24 QuantEcon.py v0.12.0 and Sep 23 GameTheory.jl v0.7.2. 6. `/activity/#activity-2026-08-02` lands on Aug 2 (4 releases · same day), below the fixed header. 7. Nothing moves when JavaScript loads, and with JavaScript off every row is still reachable. 8. All text meets WCAG AA, including hover and pressed states, and every control shows a visible focus ring, news cards included. ## Navigation (decided) We adopted your round-1 recommendation: - Activity has no menu item of its own. The Projects ▾ menu holds Code Libraries, Infrastructure and Cheatsheets. - The **News** item is active on both `/news/` and `/activity/`. - Readers reach `/activity/` from the `/news/` intro, the rail (and its mobile panel), the home strip and the footer's Resources column. Draw the header that way on every artboard. ## Constraints and tokens - **Stack and chrome:** Jekyll, Bootstrap 5.2, Bootstrap Icons 1.11.3 and a little vanilla JS. Keep the existing header, footer and sponsor bar. - **Colour:** - a single brand-blue accent (`#0072bc`, hover `#174867`), with at most one multi-colour moment per page; - the soft-blue surface is `#eef4fb`, with a `#dbe8f5` border and a `#e3edf8` hover. `#dbe8f5` is a border colour only: `#0072bc` text on it is 4.08:1 and fails AA; - the light surface is `#f8f9fc`; - neutrals: border `#e2e8f0`, soft divider `#edf0f5`, dark `#283039`, body `#444`, meta `#666`. - **Fonts:** Exo 2 for headings, and Roboto 400/700 for everything else. - **Shape:** - radii are 8px for cards, 6px for buttons and 12px for pills; - `.qe-card` hover is `0 4px 12px rgba(0,0,0,.08)` with a 2px lift; - the News list's `.news-card` uses the lighter `0 2px 8px rgba(0,0,0,.06)`, with no lift. - **Scope:** don't restyle anything outside the listed pages, except the tag pills above. - **Data:** use only the data below. Don't invent entries, projects, counts or summaries. - Some variants don't occur in today's newest rows: a merged row in the home strip, a release group in the rail, a merged translation whose summaries differ, a language listed twice, and an empty filter. - Build these from real entries with changed dates or positions, and label them as placeholders. For example, merge the Aug 20 Simplified Chinese entry into the Aug 3 group. ## The data ### News posts (newest first; `/news/` shows 20, the home page shows 3) | Date | Title | Tag | Excerpt | |---|---|---|---| | 2026-07-14 | Tutorial: Computational Methods for Simulation at SciPy 2026 | workshop | QuantEcon delivered a four-hour tutorial on accelerating simulations with NumPy and JAX at SciPy 2026 in Minneapolis. | | 2026-04-13 | Workshop: Advanced Computational Methods at Carnegie Mellon University | workshop | QuantEcon delivered a short course on advanced computational methods for economics at Carnegie Mellon University. | | 2026-03-13 | Dynamic Programming Volume II: General States Now Available | books | Volume II of Dynamic Programming by Thomas J. Sargent and John Stachurski is now available for free download, covering general state space theory and applications. | | 2026-02-23 | Julia Lectures Now Available on Google Colab | lectures | The Julia lecture series now supports Google Colab, allowing you to run Julia notebooks directly in the browser with no local setup required. | | 2026-02-17 | New Tool: MyST Markdown Plugin for Neovim | tools | QuantEcon has released myst-markdown-tree-sitter.nvim, a Neovim plugin that provides syntax highlighting and filetype detection for MyST Markdown files using a tree-sitter backend. | | 2026-02-09 | New Julia Lecture: Differentiable Filters and Enzyme Updates | lectures | A new lecture on differentiable Kalman filters has been added to the Julia series, featuring high-performance coding patterns for both forward-mode and reverse-mode automatic differentiation with Enzyme. | | 2025-12-28 | New Lecture: Gorman Aggregation with Heterogeneous Households | lectures | A new lecture on Gorman aggregation has been added to the Advanced Quantitative Economics series, exploring conditions under which heterogeneous household economies can be represented by a single representative agent. | | 2025-12-17 | New Julia Lecture: Differentiable Simulations with Enzyme | lectures | A new lecture on differentiable simulations has been added to the Julia lecture series, along with Julia 1.12 support and reorganized content across several topics. | Older posts continue back to 2014. The "Older Posts" year accordion is unchanged. ### Activity: all 40 entries, newest first (unchanged from round 1) This is the same data as round 1. The order within each day below follows the data files, so apply the new within-day order rule when you draw it. ```yaml - date: 2026-09-27 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Added three new lectures (Linear Quadratic Mean Field Games, Investment Under Uncertainty, and Optimal Growth Under Uncertainty and Tobin's q), and added exercises to the two auction lectures. changes: - {title: "Two sequels to rational_expectations", url: https://github.com/QuantEcon/lecture-python.myst/pull/1070} - {title: "Add exercises and further reading", url: https://github.com/QuantEcon/lecture-python.myst/pull/1069} - {title: "Add VCG comparison section and exercises", url: https://github.com/QuantEcon/lecture-python.myst/pull/1068} - {date: 2026-09-24, type: release, project: QuantEcon.py, version: v0.12.0, url: https://github.com/QuantEcon/QuantEcon.py/releases/tag/v0.12.0} - {date: 2026-09-23, type: release, project: GameTheory.jl, version: v0.7.2, url: https://github.com/QuantEcon/GameTheory.jl/releases/tag/v0.7.2} - {date: 2026-09-19, type: release, project: jlgametheory, version: v0.3.0, url: https://github.com/QuantEcon/jlgametheory/releases/tag/v0.3.0} - {date: 2026-09-16, type: release, project: GameTracer.jl, version: v0.2.0, url: https://github.com/QuantEcon/GameTracer.jl/releases/tag/v0.2.0} - {date: 2026-09-14, type: release, project: gametracer, version: 0.2.2, url: https://github.com/QuantEcon/gametracer/releases/tag/0.2.2} - date: 2026-08-20 type: translation project: A First Course in Quantitative Economics with Python (Simplified Chinese) url: https://quantecon.github.io/lecture-intro.zh-cn/ summary: Added the Simplified Chinese translation of the Measuring Mobility lecture. changes: - {title: "Add the Measuring Mobility lecture", url: https://github.com/QuantEcon/lecture-intro.zh-cn/pull/299} - date: 2026-08-19 type: lectures project: A First Course in Quantitative Economics with Python url: https://intro.quantecon.org/ summary: Added two new lectures, Measuring Mobility and Bivariate Distributions. changes: - {title: "Add Measuring Mobility lecture", url: https://github.com/QuantEcon/lecture-python-intro/pull/839} - {title: "Add Bivariate Distributions lecture", url: https://github.com/QuantEcon/lecture-python-intro/pull/837} - {date: 2026-08-16, type: release, project: jlgametheory, version: v0.2.0, url: https://github.com/QuantEcon/jlgametheory/releases/tag/v0.2.0} - {date: 2026-08-12, type: release, project: Expectations.jl, version: v1.9.3, url: https://github.com/QuantEcon/Expectations.jl/releases/tag/v1.9.3} - date: 2026-08-06 type: lectures project: A First Course in Quantitative Economics with Python url: https://intro.quantecon.org/ summary: Added a new lecture, Fitting Distributions to Data. changes: - {title: "New lecture: Fitting Distributions to Data", url: https://github.com/QuantEcon/lecture-python-intro/pull/814} - date: 2026-08-03 type: lectures project: Python Programming for Economics and Finance url: https://python-programming.quantecon.org/ summary: Added a language switcher linking to the Persian, French and Simplified Chinese editions. changes: - {title: "Add language switcher support for fa, fr and zh-cn editions", url: https://github.com/QuantEcon/lecture-python-programming/pull/490} - date: 2026-08-03 type: translation project: Python Programming for Economics and Finance (Persian) url: https://quantecon.github.io/lecture-python-programming.fa/ summary: Enabled the language switcher between the English, Persian, French and Simplified Chinese editions. changes: - {title: "Enable the language switcher and fix this edition's site URLs", url: https://github.com/QuantEcon/lecture-python-programming.fa/pull/145} - date: 2026-08-03 type: translation project: Python Programming for Economics and Finance (French) url: https://quantecon.github.io/lecture-python-programming.fr/ summary: Enabled the language switcher between the English, Persian, French and Simplified Chinese editions. changes: - {title: "Enable the language switcher for the French edition", url: https://github.com/QuantEcon/lecture-python-programming.fr/pull/21} - date: 2026-08-03 type: translation project: Python Programming for Economics and Finance (Simplified Chinese) url: https://quantecon.github.io/lecture-python-programming.zh-cn/ summary: Enabled the language switcher between the English, Persian, French and Simplified Chinese editions. changes: - {title: "Enable the language switcher and fix URLs copied from the English config", url: https://github.com/QuantEcon/lecture-python-programming.zh-cn/pull/80} - {date: 2026-08-02, type: release, project: QuantEcon.jl, version: v0.19.0, url: https://github.com/QuantEcon/QuantEcon.jl/releases/tag/v0.19.0} - {date: 2026-08-02, type: release, project: GameTheory.jl, version: v0.7.1, url: https://github.com/QuantEcon/GameTheory.jl/releases/tag/v0.7.1} - {date: 2026-08-02, type: release, project: BasisMatrices.jl, version: v0.8.2, url: https://github.com/QuantEcon/BasisMatrices.jl/releases/tag/v0.8.2} - {date: 2026-08-02, type: release, project: ContinuousDPs.jl, version: v0.3.2, url: https://github.com/QuantEcon/ContinuousDPs.jl/releases/tag/v0.3.2} - {date: 2026-07-26, type: release, project: ContinuousDPs.jl, version: v0.3.1, url: https://github.com/QuantEcon/ContinuousDPs.jl/releases/tag/v0.3.1} - date: 2026-07-26 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Added missing `quantecon` and `jax` installs to nine lectures. changes: - {title: "Add pip install cells for quantecon and jax in lectures that were missing them", url: https://github.com/QuantEcon/lecture-python.myst/pull/1006} - date: 2026-07-23 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Added a new section of ten lectures on Phillips Curve Tradeoffs, and added figure captions and standardized CDF notation in the Incorrect Models lecture. changes: - {title: "Adding Tom's new section on Phillips Curve Tradeoffs", url: https://github.com/QuantEcon/lecture-python.myst/pull/992} - {title: "Add figure captions and use CDF", url: https://github.com/QuantEcon/lecture-python.myst/pull/982} - {date: 2026-07-20, type: release, project: ContinuousDPs.jl, version: v0.3.0, url: https://github.com/QuantEcon/ContinuousDPs.jl/releases/tag/v0.3.0} - {date: 2026-07-15, type: release, project: QuantEcon.py, version: v0.11.4, url: https://github.com/QuantEcon/QuantEcon.py/releases/tag/v0.11.4} - {date: 2026-07-15, type: release, project: GameTheory.jl, version: v0.7.0, url: https://github.com/QuantEcon/GameTheory.jl/releases/tag/v0.7.0} - {date: 2026-07-15, type: release, project: BasisMatrices.jl, version: v0.8.1, url: https://github.com/QuantEcon/BasisMatrices.jl/releases/tag/v0.8.1} - {date: 2026-07-15, type: release, project: ContinuousDPs.jl, version: v0.2.1, url: https://github.com/QuantEcon/ContinuousDPs.jl/releases/tag/v0.2.1} - {date: 2026-07-15, type: release, project: GameTracer.jl, version: v0.1.2, url: https://github.com/QuantEcon/GameTracer.jl/releases/tag/v0.1.2} - {date: 2026-07-13, type: release, project: QuantEcon.jl, version: v0.18.0, url: https://github.com/QuantEcon/QuantEcon.jl/releases/tag/v0.18.0} - {date: 2026-07-08, type: release, project: QuantEcon.py, version: v0.11.3, url: https://github.com/QuantEcon/QuantEcon.py/releases/tag/v0.11.3} - date: 2026-07-07 type: lectures project: Advanced Quantitative Economics with Python url: https://python-advanced.quantecon.org/ summary: Added a new lecture, Dynamic Supply and Demand Curves. changes: - {title: "Adding Tom's lecture on dynamic supply and demand curves", url: https://github.com/QuantEcon/lecture-python-advanced.myst/pull/352} - date: 2026-07-07 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Added missing `pip install` cells to four lectures. changes: - {title: "Add missing pip dependencies", url: https://github.com/QuantEcon/lecture-python.myst/pull/951} - {date: 2026-07-06, type: release, project: ContinuousDPs.jl, version: v0.2.0, url: https://github.com/QuantEcon/ContinuousDPs.jl/releases/tag/v0.2.0} - date: 2026-07-02 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Replaced the LQ Consumption Smoothing lecture with a trilogy of lectures on the LQ permanent income model, and added two lectures on unemployment dynamics, A Linear Model of Unemployment and Unemployment Dynamics with Asymmetric Shocks. changes: - {title: "Add Tom's LQ permanent income trilogy of lectures", url: https://github.com/QuantEcon/lecture-python.myst/pull/943} - {title: "Add unemployment dynamics lectures (linear + nonlinear)", url: https://github.com/QuantEcon/lecture-python.myst/pull/928} - date: 2026-06-22 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Added three new lectures, including The Kalman Filter and Vector Autoregressions and Robust Permanent Income and Pricing. changes: - {title: "Adding Tom's new lectures on Kalman Filter and Robust Income", url: https://github.com/QuantEcon/lecture-python.myst/pull/931} - {date: 2026-06-20, type: release, project: jlgametheory, version: v0.1.2, url: https://github.com/QuantEcon/jlgametheory/releases/tag/v0.1.2} - date: 2026-06-19 type: lectures project: Intermediate Quantitative Economics with Python url: https://python.quantecon.org/ summary: Rewrote the Non-Conjugate Priors lecture, adding notes on NUTS and variational inference, and revised the exposition and notation of Another Look at the Kalman Filter. changes: - {title: "Add explanatory notes to bayes_nonconj: NUTS and variational inference", url: https://github.com/QuantEcon/lecture-python.myst/pull/918} - {title: "Rewrite the Non-Conjugate Priors lecture", url: https://github.com/QuantEcon/lecture-python.myst/pull/913} - {title: "Update exposition of first three sections", url: https://github.com/QuantEcon/lecture-python.myst/pull/903} - {date: 2026-06-14, type: release, project: GameTheory.jl, version: v0.6.0, url: https://github.com/QuantEcon/GameTheory.jl/releases/tag/v0.6.0} - {date: 2026-06-14, type: release, project: GameTracer.jl, version: v0.1.1, url: https://github.com/QuantEcon/GameTracer.jl/releases/tag/v0.1.1} - date: 2026-06-12 type: lectures project: Advanced Quantitative Economics with Python url: https://python-advanced.quantecon.org/ summary: Added three lectures on contract theory under moral hazard and a lecture, Survey Data and Subjective Beliefs in Business Cycle Models. changes: - {title: "Add three lectures on contract theory and one lecture on survey data and robustness", url: https://github.com/QuantEcon/lecture-python-advanced.myst/pull/343} ```
Round 2 outcome
Claude Design delivered the round-2 handoff: the Option A rail on
/news/, the c1 strip on the home page, and/activity/restyled. It was reviewed against the real data and the repo in four independent passes:- the display rules, executed against the data;
- a build spike on the site's own CSS;
- accessibility and visual QA on the live prototypes;
- compliance with the round 2 brief.
Verdict: build-ready, with the decisions and fixes below.
- Every number in the handoff reproduces from the 40 real Activity entries.
- Its date rules agree with Ruby's calendar functions on every day from 1990 to 2060.
- The spike confirmed the sticky rail, the
overflow: clipfix and the phone fold check on the real site. - Nothing needs to go back to the designer.
The handoff's
README.mdis the spec. Where the design sheet's notes disagree with it, the README wins. The decisions below amend it. The README is included at the end of this comment for the record.Decisions (also in the table above)
-
Home strip:
- one compact line at 1200px and wider only;
- the type label (a translation's language, "3 editions", "4 releases · same day") sits outside the truncated title, so it's never cut;
- items are sized to their content, so short titles give their space to long ones;
- a stacked list below 1200px;
- the link reads "View all activity →".
-
Explaining
/news/below 1200px: the collapsed Activity panel gets a short second line, e.g. "Library releases and lecture updates, from GitHub". The desktop page head stays clean, with no intro line. -
Full-height rail panel: build it as designed and judge it on the Netlify preview with all 20 cards. If it looks empty, the fallback is a transparent tall column with the tint on the sticky box only. Either way, add a small "Activity" label inside the sticky part, because the heading scrolls away.
-
Same-day duplicates: lecture sites often publish twice on one day (10 times across 5 sites since June 1). So:
- the plugin merges entries for the same series on the same day into one row, as it already does for translations;
- a release-group title lists each project once.
The reporter will also emit one entry per series per day (noted on QuantEcon/reports-activity#91).
-
NEWbadge: darkened to#d0344f(4.90:1), along with theworkshopandbookspills, in Fix tag-pill contrast and make the news-card focus ring visible #269. -
Recorded product-owner changes in the handoff:
- no intro under the News h1 (decision 2 covers small screens);
- no count line;
- the full-height panel.
-
Activity RSS feed: still open.
Implementation fixes (no design change)
- Order independence. The prototype's rules relied on input order, and Ruby's sort isn't stable. The port uses:
- a complete sort order with explicit tiebreakers;
- a comparator that sorts by the lower-cased string, then the exact string;
- merged-translation PRs listed in edition order.
- Day anchors first. The rail and strip link merged rows to a day on
/activity/, so the/activity/restyle ships before them or with them. - Keyboard focus. Add
scroll-padding-topto/news/as well as/activity/. Otherwise keyboard focus can land under the fixed header while the rail is stuck (WCAG 2.2 SC 2.4.11). - Two spec bugs:
- the "collapsed until JavaScript loads" panel rule must be scoped to below 1200px, because as written it hides the desktop rail;
- the "N changes" lists must not be server-rendered as
hidden, or they're unreachable without JavaScript.
main.js:- guard its
sessionStorageaccess, which can throw and stop everything after it; - put the new code in isolated blocks;
- add a cache-buster to the script URL.
- guard its
- Markup and accessibility:
- a visually hidden
h2before the news list, so screen readers don't file the posts under "Activity"; - on phones, only the title is a link, stretched over the row, so the link doesn't read out the whole summary;
- use the handoff README's markup (
<aside>, lists), not the prototypes'<div>s; - don't copy the prototypes' inline
outline: none.
- a visually hidden
- Tests. They run against a frozen copy of today's data. Checks on live data assert only things that stay true as data is added.
Build plan
- A, Fix tag-pill contrast and make the news-card focus ring visible #269: tag-pill and
NEWbadge contrast, the news-card meta greys, a visible news-card focus ring, and reduced motion. It doesn't depend on Split updates into News and an Activity feed #265. - B: the Activity plugin, which computes rows at build time, with its tests. No visible change.
- C:
/activity/restyled with the shared rows, filters and day anchors. - D: the
/news/rail and mobile panel. - E: the home strip.
- F (optional): an Activity RSS feed, if wanted.
B to F wait for #265 to merge.
Also
- c3, the activity chart: parked in Future idea: add an "activity pulse" (weekly bar chart and latest activity) to the home page's Latest News #267, now updated for accuracy.
- The handoff files (README, prototypes,
activity-data.js) are in the local handoff bundle. The README follows.
Round 2 handoff README (the spec as delivered; amended by the decisions above)
Handoff, round 2:
/news/Option A (side rail), home c1 strip, and the/activity/restyleRelated: #266. Everything here describes the site after PR #265 merges.
Status: everything in the brief is included
All six priorities are drawn in
reference/News and Activity R2.dc.html:- This spec and the shared row rules.
/news/at 1440 and 390px, with the panel collapsed and expanded.- The component sheet.
- The home page (c1) at 1440 and 390px.
/activity/at 1440 and 390px.- The extra widths:
/news/at 1280 and 1024px, and the home page at 1280px.
Changes the product owner asked for during this round (these override the brief)
- No intro paragraph under the "News" h1. The brief asked to keep it.
- Consequence: on screens narrower than 1200px, the page is explained only by the collapsed Activity panel.
- The
/news/intro link to/activity/goes away. Readers still reach it from the rail, the panel, the home strip and the footer.
- No count line ("28 updates since the last news post"). The rail simply shows the most recent activity. Drop
countSinceand the timezone note that went with it. - The rail's panel runs the full height of the news column. Its contents stick inside it (see "Sticky behaviour").
Parked, and not in this handoff
- Option B, the integrated timeline.
- c3, the activity chart. The round-1 folder is included unchanged at
parked/future_idea_c3/. Don't build it.
Files
Path What it is reference/News and Activity R2.dc.htmlThe sheet. Open it in a browser (keep every file in reference/together). Sections 1–5 match the priorities above.reference/NewsPage.dc.html/news/. Opened directly, it responds to the window width.?live=1turns on the sticky header and the rail, as the sheet's live 1280×720 and 390×844 viewports do.reference/HomeNews.dc.html,reference/ActivityLog.dc.htmlHome "Latest News" and /activity/.reference/ActivityRail.dc.html,reference/ActivityRow.dc.htmlThe rail/panel, and the shared row in its three variants: rail, strip and log. reference/activity-data.jsThe real data plus every display rule as plain functions: buildRows,week,range,railRows,byWeek,byMonth,panelSummary. Port these to the Jekyll plugin; they are the executable form of the rules below.The reference files are HTML prototypes (inline styles, a small runtime). Recreate them in the site's stack: Jekyll, Bootstrap 5.2,
assets/main.scss, Bootstrap Icons 1.11.3 and a little vanilla JS. Fidelity is high: the colours, type, spacing and behaviour are final.
1. Data and the shared row rules (every page)
Source
- The data is in
_data/activity/*.yml: one file per bot run per stream, e.g.2026-09-24-software.yml.- The
softwarestream holds releases. Thelecturesstream holds lecture and translation updates.
- The
- Concatenate all files and ignore file names and in-file order:
- an entry's
datecan be months earlier than its file's date; - entries inside a file are in no guaranteed order.
- an entry's
- A small Jekyll generator plugin computes the rows at build time and exposes them to Liquid (e.g.
site.data.activity_rows, plus the grouped views below). Don't add a group key to the bot's output. - Each entry has
date(a UTC calendar day,YYYY-MM-DD),type(release|lectures|translation),project,url, and optionallyversion,summaryandchanges: [{title, url}].
Rows: merge by key, never by position
- Releases: all
releaseentries with the samedateform one row. - Translations:
translationentries with the samedateand the same series form one row.- The series is
projectwith its trailing(Language)removed. Parse it with/^(.*) \(([^)]+)\)$/: group 1 is the series, group 2 the language.
- The series is
- Lectures: always one row per entry.
Order
- Days: newest first.
- Within a day: lecture updates, then translations, then releases.
- Within a type, sort A→Z by
project, ignoring case (localeCompare(…, {sensitivity:'base'})). - Inside a merged release row, list releases A→Z by project, ignoring case.
- Inside a merged translation row, list editions A→Z by language.
- Within a type, sort A→Z by
- Rationale: a lecture change is usually the source of any translation work on the same day (Aug 3 reads naturally), and releases are the least narrative.
Row fields
Kind Title Tag Link target Single release project+version(the version at weight 400)none the release notes, urlSingle lecture update projectnone url(the live lecture site)Single translation series name the language, e.g. Simplified Chineseurl(the translated site)Release group project names joined as "A, B, C and D" (no Oxford comma) 4 releases · same day/activity/#activity-YYYY-MM-DDMerged translation series name 3 editions(the count of unique languages; "1 edition" in the singular)/activity/#activity-YYYY-MM-DDEvery row also has a type word that is visually hidden:
Release:,Lecture update:,Translation:, orReleases:/Translations:for merged rows. The icons (bi-box-seam,bi-journal-text,bi-translate) arearia-hidden="true".Merged translations
- Editions: list each language once, A→Z. An edition's link is the
urlof its entries. - Summary:
- If exactly one distinct summary exists across all the entries, show it once.
- Otherwise, give each edition its own summaries: deduplicate them, sort A→Z, and join them with a space.
- Rail and strip: the two clamped lines show the editions in language order, each prefixed with its language in bold ("French: Enabled… Persian: …"). In practice, the first edition's text fills both lines.
- PR list: all PRs from all the merged entries.
Dates
Formats:
Where Format Example Rows (rail, strip, log), week headings, panel summary short, %b %-d"Sep 27" News cards long, %b %-d, %Y"Sep 27, 2026" Range within one month "Sep 21–27" (en dash, no spaces) Range across months "Jul 27 – Aug 2" (spaced en dash) Range across years "Dec 28, 2026 – Jan 3, 2027" Range of a single day one date Rules:
- Always wrap dates in
<time datetime>:- days use
YYYY-MM-DD; - week headings use the ISO week, e.g.
<time datetime="2026-W39">Sep 21–27</time>. Use Ruby'sDate#cwyear/#cweek: Dec 28, 2026 – Jan 3, 2027 is2026-W53.
- days use
- Weeks run Monday to Sunday, UTC.
- No relative dates.
- Compare dates only as
YYYY-MM-DDstrings. Never compare a post'sTime(Australia/Sydney) with an activityDate: that stops the build.
Summaries are plain text, except that single backticks become
<code>. PR titles are plain text.
2.
/news/: Option ALayout
- Breakpoint: 1200px (Bootstrap
xl).- At 1200px and wider, the rail sits in the right column.
- Below 1200px, it becomes a collapsed panel above the news cards. That covers 1024, 768 and phones.
- Why: at 1024 a one-third rail is only 296px wide, so each two-line summary would hold about 70 characters and titles would run to three lines. Below 1200px the news cards get the full container.
- Filter fit: "All · Releases · Lectures · Translations" (bold, 14px, 18px gaps) is about 270px wide.
- It fits on one line at every rail width: 356px at 1280, 416px at 1440.
- It fits in the panel at 360px and wider.
- Below that the row wraps (
flex-wrap: wrap; column-gap: 18px), and each button keeps its own 2px underline.
- Grid at 1200px and wider, inside the existing
.container:display:grid; grid-template-columns:minmax(0,2fr) minmax(0,1fr); column-gap:3rem— 832 + 416px at 1440, 712 + 356px at 1280;- no margin between the h1 (
margin-bottom:2rem) and the grid.
- Source order: the
<aside class="activity-rail" aria-labelledby="activity-rail-title">comes before the news list in the HTML.- It is placed in column 2 with
grid-column:2; grid-row:1, and the news goes ingrid-column:1; grid-row:1. - So on small screens the panel sits under the h1 with no reordering, and focus order matches the visual order at every width.
- It is placed in column 2 with
- "Older Posts": the accordion stays in the main column, below the 20 cards and unchanged.
- Overflow:
section.inner-pageneedsoverflow: clipon this page. The site-widesection { overflow: hidden }breaksposition: sticky.
Rail, 1200px and wider
- Head (scrolls with the page):
h2#activity-rail-title"Activity": Exo 2, 400, 1.4rem,#283039;- subtitle "Library releases and updates to the lectures and their translations, compiled from GitHub.": 14.4px/1.5,
#666, margin-top 6px; - the filter group, margin-top 14px, with a 1px
#e2e8f0bottom border.
- Panel:
- a box with background
#f8f9fc,1px solid #e2e8f0border, 8px radius and margin-top 16px; - it stretches to the bottom of the news column (
flex: 1 0 autoin a full-height flex column); - an inner wrapper with 20px/22px padding holds the content and is the sticky element.
- a box with background
- Content: the latest 6 rows (a merged row counts as 1), newest first, under week headings.
- A heading appears only above a week that has a shown row.
- Heading style: 12px, 700, uppercase,
.05emletter-spacing,#666, margin0 0 12px(20px above every heading after the first).
- Row (rail variant):
- The timeline is the Infrastructure one: a 2px
#e2e8f0line (the group hasmargin-left:5px; border-left:2px solid #e2e8f0), and each row haspadding:0 0 16px 18px. - The dot is 12px,
#0072bc, with a 2px border in the surface colour andbox-shadow:0 0 0 2px #e2e8f0, positionedleft:-7px; top:3px, andaria-hidden. - Meta line: 12.8px/1.35,
#666, gap 6px. It holds the icon, the hidden type word, the date, and· tagwhen there is one. - Title: 15px/1.35, 700,
#283039, clamped to 2 lines, margin-top 3px. The version is weight 400,#444. Hover:#174867, underlined. - Summary: 14px/1.45,
#444, clamped to 2 lines (-webkit-line-clamp:2). Inline code is 12.5px monospace on#fff, with a#e2e8f0border. - PR links and per-release or per-edition links stay on the full log.
- The timeline is the Infrastructure one: a 2px
- Actions:
- "View all activity": a full-width outline button (2px
#0072bc, 6px radius, 15.2px bold,.6rem 1rempadding, margin-top 8px). Hover: filled#0072bcwith white text. - Optional "Activity feed" link with
bi-rss(14px bold, margin-top 12px), pointing to/activity/feed.xml. Omit it if the feed isn't added.
- "View all activity": a full-width outline button (2px
Filters
Markup and states:
<div role="group" aria-label="Filter activity by type">containing four<button type="button" aria-pressed>: All, Releases, Lectures, Translations.- Default:
#0072bc. - Hover:
#174867, with the existing.content-filtersgrow-in underline (0.3s). - Pressed:
#444, with a 2px#444bar on the group's bottom border. :focus-visible:2px solid #0072bc, offset 2px.
What each filter shows:
- The latest 6 rows of that type, with no time window.
- Today, Translations shows 2 rows: Aug 20, and Aug 3 with 3 editions.
- If a type has no entries at all, show a dashed placeholder instead of the list (
1px dashed #cbd5e1, 8px radius, centred 14.4px#444): "No releases yet", "No lecture updates yet" or "No translation updates yet".
Markup to render:
- The latest 6 rows of each type, once each: 14 rows today.
- Each row gets
data-typeand, if it is among the newest 6 overall,data-all. - Rows sit inside week groups, and a week group is built for every week that contains any of those rows.
- JS sets
hiddenon the rows that don't match and on week groups that have no visible rows. - Without JS: the server-rendered state is the All view, i.e. non-All rows and their empty weeks carry
hiddenin the HTML. Hide the filter group withhtml:not(.js) .activity-filters{display:none}.
Behaviour:
- The filter isn't remembered.
- Focus stays on the pressed button.
- A visually hidden
aria-live="polite"paragraph announces the result:- "Showing the 6 latest updates";
- "Showing 6 releases" / "Showing 6 lecture updates" / "Showing 2 translation updates";
- "No translation updates yet".
Sticky behaviour
- The inner wrapper is sticky; the panel box is the tall column it moves within.
top: min(var(--rail-top), calc(100vh - var(--rail-h) - 24px)), where:--rail-topiscalc(84px + var(--sponsor-bar-height, 0px) + 24px);--rail-his the wrapper's height, set by aResizeObserver(it changes on filter change, font load and resize).
- If the list fits below the header, it sticks 24px under it.
- If it doesn't fit, the negative
topmakes it scroll with the page until its bottom is 24px above the viewport's bottom, and it sticks there. "View all activity" can always be reached, and nothing is cut off. No inner scrollbar. - The head (and so the filters) isn't sticky. Filters can therefore only be clicked when the list is at its natural position, so a filter change never moves a stuck element.
- Apply the sticky rule only under
html.js. Without JS the wrapper is static. - Measured list heights at 1440px (416px rail; add 142px for the head and the 16px gap):
Filter List height All 572px Releases 575px Lectures (tallest) 903px Translations 410px Empty 193px At 1280 the heights are about 10–15% more, because text wraps sooner.
- At 1280×720 with the sponsor bar: 720 − 141 − 24 = 555px is available, so every state except Translations and Empty sticks by its bottom edge.
- Try it in the sheet's live 1280×720 viewport (section 1d).
Mobile panel, below 1200px
- Box:
#eef4fb, with a1px solid #dbe8f5border and 8px radius. It sits directly under the h1, with 20px before the first card. - Toggle:
<h2><button aria-expanded aria-controls></button></h2>, full width, min-height 60px, padding12px 16px, laid out as a grid:bi-activity(20px,#0072bc), then the label, then a chevron (#444).- Hover background:
#e3edf8. Text on it is only#283039and#444, never blue.
- Hover background:
- Label: "Activity · 6 updates in September · latest Sep 27".
- Below 576px, the part after "Activity" drops to a second line and the "·" separator is removed.
- {month} is the calendar month of the newest entry; N counts the entries in that month; {date} is the newest entry.
- It always describes all activity, whatever the filter.
- Body: the rail's content on the soft-blue surface:
- the subtitle (
#444); - the filters (min-height 44px, 14.4px);
- week groups, with headings in
#444, the timeline line and dot ring in#dbe8f5, and the dot border in#eef4fb; - "View all activity" (white fill, min-height 44px);
- the optional feed link.
- the subtitle (
- Mobile rows: on phones each whole row is one link, min-height 44px.
- First paint: the panel renders collapsed. Set
document.documentElement.classList.add('js')in<head>, and use.js .activity-panel:not(.is-open) .activity-panel__body{display:none}.- Without JS: hide the toggle, show a plain
<h2>Activity</h2>, and show the body expanded.
- Without JS: hide the toggle, show a plain
- Focus stays on the toggle after an expand or a collapse.
- One
<aside>serves both modes. CSS shows either the rail head's h2 (1200px and wider) or the toggle (below 1200px, with JS).display:nonekeeps the hidden one out of the accessibility tree.
News cards (
.news-card)- The markup is unchanged, except:
- the date colour changes from
#888to#666; - the chevron changes from
#aaato#64748b.
- the date colour changes from
- Focus ring:
.news-card:has(> .news-card-header:focus-visible){outline:2px solid #0072bc;outline-offset:2px}plus.news-card-header:focus-visible{outline:none}.- Fallback where
:hasisn't supported (@supports not selector(:has(*))): an inset ring on the header,outline:2px solid #0072bc; outline-offset:-4px.
- Fallback where
- Tag pills, changed site-wide:
workshop:#6EAC5B(2.72:1) →#4a7c3c(4.95:1);books:#D25663(4.00:1) →#b83d4b(5.52:1).
3. Home "Latest News" with the c1 strip (
_layouts/home.html,#news)- Cards:
- the 3 latest posts;
- the date is "Jul 14, 2026" (
%b %-d, %Y) in#666; - everything else is unchanged:
.qe-card, badge, excerpt truncated to 25 words, hover lift.
- Strip, 768px and wider: one compact line (the product owner asked for compact, clean and modern):
- box: margin-top 24px,
display:flex; align-items:center; gap:20px; min-height:48px; padding:0 18px, background#f8f9fc,1px solid #e2e8f0border, 8px radius, 14px text; - label:
<h3>"Latest activity": 12px, 700, uppercase,.06emletter-spacing,#666, with a 14pxbi-activityicon in#0072bc,flex:none; - items: a
<ul>of the three newest rows (display:flex; flex:1 1 auto; min-width:0). Each<li>takes an equal share (flex:1 1 0; min-width:0), haspadding:0 20pxand a1px solid #e2e8f0left divider, and is one link:- 12px type icon (
#0072bc), the hidden type word, the date (13px,#666), then the bold title (#283039); - titles use
nowrapand an ellipsis, so the strip never wraps, and the full text sits intitle; - hover:
#174867, underlined.
- 12px type icon (
- Item count: 3 items at 1200px and wider; 2 items from 768 to 1199px, so titles stay readable.
- right: "View all →" (13.6px, bold,
#0072bc,margin-left:auto), linking to/activity/.
- box: margin-top 24px,
- Tags inline: a single translation appends its language, "… (French)". A merged row appends its tag, "… · 3 editions" or "… · 4 releases · same day". Merged rows link to their day on
/activity/. - Items: the three newest rows, which today are:
- Sep 27 · Intermediate Quantitative Economics with Python;
- Sep 24 · QuantEcon.py v0.12.0;
- Sep 23 · GameTheory.jl v0.7.2.
- Below 768px:
- box padding
14px 16px 0; - the h3, then a stacked
<ul>. Each<li>has padding8px 0and a1px solid #dbe8f5top border, and its whole item is one link with min-height 44px. The icons stay. - Then "View all activity →" (min-height 48px, top border).
- "View all news" becomes full width, with min-height 44px and margin-top 20px.
- box padding
4.
/activity/: the full log, restyled- Unchanged: the h1 "Activity" and both intro paragraphs (exact text in the brief).
- Width: the log column has
max-width: 880px. - Filter:
- the same four buttons as the rail (16px, 28px gaps, min-height 44px), margin-top 28px;
- a filter shows every row of its type and hides months left with no rows;
- a live region announces the result, e.g. "Showing 2 translation updates".
- Months:
<section id="activity-YYYY-MM" aria-labelledby>, margin-top 36px (28px below 576px);<h2>"September 2026": Exo 2, 1.4rem,#283039, padding-bottom 10px,1px solid #e2e8f0bottom border;- all months are open.
- Days:
<ol>of<li id="activity-YYYY-MM-DD">, each wrapping an<ol>of that day's rows.- No visible day heading. Every row shows its own date, so the anatomy matches the rail.
- Row (log variant):
- padding
18px 0 20px, with a1px solid #edf0f5bottom border; - meta line: 13.6px,
#666: icon (#0072bc), hidden type word, date,· tag; - title: 16.8px/1.4, 700,
#283039.- Single rows: one link to
url. - Release groups: the title is the list of links, "BasisMatrices.jl v0.8.2, ContinuousDPs.jl v0.3.2, … and QuantEcon.jl v0.19.0", one link per release, each underlined in
#94a3b8. - Merged translations: the series name, not a link.
- Single rows: one link to
- Summary: the full text, 16px/1.55,
#444, max-width 760px.- If a merged translation's summaries differ, show a list with one item per edition: the language as a link, then its summaries.
- Edition links (merged translation with identical summaries): chips.
- Style:
1px solid #e2e8f0, 6px radius,4px 10pxpadding, 14px bold#0072bc. - Hover:
#f3f5fabackground,#174867text. - Mobile: min-height 44px.
- Style:
- PR list:
- One PR:
bi-github(#666), then an underlined PR-title link, then#1070in#666. - Two or more:
<button aria-expanded aria-controls>readingbi-github+ "3 changes" + chevron (14px, bold,#0072bc; mobile min-height 44px), followed by<ul hidden>.- The list has a
2px solid #e2e8f0left border and 14px left padding. Each item is an underlined link, then#num. - Focus stays on the button.
- The list has a
- One PR:
- padding
- Anchors:
html{scroll-padding-top:calc(84px + var(--sponsor-bar-height,0px) + 16px)};- on load and on
hashchange, if the hash matches#activity-\d{4}-\d{2}, reset the filter to All before scrolling; /activity/#activity-2026-08-02lands on the Aug 2 row ("4 releases · same day").
- Footer: "The log begins on Jun 12, 2026." (14px,
#666, margin-top 40px). - Not in this round: a project filter, a month accordion and year archives.
5. Accessibility, first paint and motion
Contrast:
- All meta text is
#666or darker: 5.74:1 on white, 5.45:1 on#f8f9fc. #0072bcis used only on#fff,#f8f9fcand#eef4fb(4.59:1). It is never used on#e3edf8or#dbe8f5; use#174867for text on hover surfaces.
Controls:
- The visible focus ring is
2px solid #0072bc, offset 2px, on every control. News cards get theirs via:has(see section 2). - Mobile targets are at least 44px.
- Inline links inside sentences (release lists, PR titles) are exempt from the target size and are underlined.
Markup:
- Icons and timeline dots are
aria-hidden. - Each row starts with a visually hidden type word.
- Rails and logs are lists (
<ol>); week headings are<h3>; month headings are<h2>.
First paint and motion:
- No layout jump: set the
jsclass in<head>before first paint, and render everything that's collapsed by default already collapsed. - Without JS every row is reachable: the panel is expanded, the log is fully open, and the rail shows All.
@media (prefers-reduced-motion: reduce)removes the tab-underline, button and card-lift transitions.
6. Tokens
Brand #0072bc· hover#174867Text dark #283039· body#444· meta#666Surfaces light #f8f9fc· soft blue#eef4fb(border#dbe8f5, hover#e3edf8) · hover tint#f3f5faLines border #e2e8f0· divider#edf0f5· dashed and inline-link underline#cbd5e1/#94a3b8Pills workshop #4a7c3c· books#b83d4b· lectures#306998· tools#FCC837on#333Type Exo 2 400 (h1 2rem, section 1.8rem, rail and month 1.4rem) · Roboto 400/700 Shape cards 8px · buttons 6px · pills 12px · .qe-cardhover0 4px 12px rgba(0,0,0,.08)with a 2px lift ·.news-cardhover0 2px 8px rgba(0,0,0,.06), no liftChrome header 84px (fixed) · sponsor bar ≈ 33px, sets --sponsor-bar-height7. Acceptance checks
- At 390×844, with JS on, the sponsor bar shown and the panel collapsed, the newest post's whole title is visible on
/news/.- In the reference its bottom is at about 405px (see the red fold line in 1b).
- There's no horizontal scroll at 320px on
/news/, the home page or/activity/. - At 1280×720 with the sponsor bar shown, every part of the rail, including "View all activity", can be reached under every filter. This works through bottom-edge stickiness.
- With today's data, the rail shows:
- All: IQ (Sep 27), QuantEcon.py v0.12.0, GameTheory.jl v0.7.2, jlgametheory v0.3.0, GameTracer.jl v0.2.0 and gametracer 0.2.2, under "Sep 21–27" and "Sep 14–20";
- Releases: Sep 24 back to jlgametheory v0.2.0 (Aug 16), under Sep 21–27, Sep 14–20 and Aug 10–16;
- Lectures: Sep 27, Aug 19, Aug 6, Aug 3, Jul 26 and Jul 23, under Sep 21–27, Aug 17–23, Aug 3–9 and Jul 20–26;
- Translations: 2 rows, Aug 20 (Simplified Chinese) and Aug 3 (3 editions).
- The home strip shows Sep 27 IQ, Sep 24 QuantEcon.py v0.12.0 and Sep 23 GameTheory.jl v0.7.2.
/activity/#activity-2026-08-02lands on Aug 2 ("4 releases · same day") below the header and sponsor bar, with the filter reset to All.- Nothing moves when JS loads. With JS off, every row is reachable.
- All text meets WCAG AA, including hover and pressed states, and every control shows a visible focus ring, news cards included.
- The mobile panel reads "Activity · 6 updates in September · latest Sep 27".
- The full log has 30 rows across 4 months: September 6, August 8, July 11, June 5.
- added a commit that references this issue
on Sep 29, 2026 The design review is complete: both Claude Design rounds are recorded here, and every decision is in the Decisions table above. The build continues in #271, where this issue is the Phase 2 item.
- added a commit that references this issue
on Sep 29, 2026
Part of #271 (Phase 2).
#265 splits the site's updates into two streams. News carries announcements people write: new projects, grants, people and workshops. Activity is a new page for library releases and lecture updates, generated by the reporter bot. The Activity page ships with interim styling, and the News page hasn't changed since the #194 redesign, even though it now carries far fewer posts. This issue tracks a design pass over both pages, done with Claude Design and then implemented here.
Gate: the design work starts once John approves the stream definitions in #265, so the design is built on settled rules.
How this issue works
This issue is the home of the design review for both pages.
Decisions
/news//news/and/activity/. It's reached from the rail and its mobile panel, the home strip and the footer<time>element, never relativebooktype in #284). Below 1200px, a collapsed panel above the news cards/news/_data/activity/*.yml, ported from the handoff'sactivity-data.jsand tested in CIworkshop#4a7c3c,books#b83d4bandNEW#d0344fpills;#666meta text; a#64748bcard chevron; a visible news-card focus ring; reduced motion/activity/feed.xmlfor Activity entries, linked from the rail./feed.xmlstays News-onlyPlan
/activity/,/news/and the home page from the round 1 brief. See the round 1 outcome./news/, and c1 on the home page.Activity page: questions to settle
lecturespill uses the Python-badge blue, andreleaseuses the Julia-badge purple. Pick markers that don't collide, within the single-accent principle below.News page: questions to settle
workshop(#6EAC5B, 2.72:1),books(#D25663, 4.00:1) andnew(#e94560, 3.83:1) fail WCAG AA with white text.#888(3.54:1) and#999(2.85:1), which fail AA at their sizes. Activity already uses#666./news/. Is that enough, or does it need a stronger treatment?Across both pages
Related