From 31e7b2b6c19e4fbf6c4fdcd1a2008e684b2cb30e Mon Sep 17 00:00:00 2001 From: Evan Gress <106449014+evangress@users.noreply.github.com> Date: Sat, 7 Nov 2026 12:04:36 -0500 Subject: [PATCH 1/2] Add a nonprofit starter site (starters/nonprofit) A 13-page static site for a small nonprofit (home, about, programs, events, news, get involved, donate, contact, financials, privacy, 404), built with `tagkit build` from shared includes and copied with `npx degit kovirlabs/tagkit/starters/nonprofit`. It uses the whole family: TagBrush.css layout and components, TagAction behaviors (sortable and filterable tables, local times, relative dates, a live gift total, dialogs, a popover, row cloning, a remembered FAQ, a table of contents), and TagCheck in the build and in an included GitHub Pages workflow. Forms post to a form service and the donate form goes to a payment link, so it works on any static host. Tests build the starter and check every page with TagCheck (including contrast and phone overflow), TagAction, links, and JavaScript off. The README, llms.txt (and the agent files built from it), CHANGELOG, and the npm package list it. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + README.md | 2 + ai/AGENTS.md | 4 + ai/claude/tagkit/SKILL.md | 4 + ai/cursor/tagkit.mdc | 4 + llms.txt | 4 + package.json | 1 + .../nonprofit/.github/workflows/deploy.yml | 47 +++++++ starters/nonprofit/.gitignore | 3 + starters/nonprofit/README.md | 64 +++++++++ starters/nonprofit/package.json | 14 ++ starters/nonprofit/site/404.html | 27 ++++ starters/nonprofit/site/_includes/footer.html | 28 ++++ starters/nonprofit/site/_includes/head.html | 11 ++ starters/nonprofit/site/_includes/nav.html | 12 ++ starters/nonprofit/site/about.html | 99 +++++++++++++ starters/nonprofit/site/contact.html | 71 ++++++++++ starters/nonprofit/site/donate.html | 90 ++++++++++++ starters/nonprofit/site/events.html | 67 +++++++++ starters/nonprofit/site/get-involved.html | 119 ++++++++++++++++ starters/nonprofit/site/images/logo.svg | 6 + starters/nonprofit/site/index.html | 117 ++++++++++++++++ starters/nonprofit/site/news/index.html | 42 ++++++ .../nonprofit/site/news/walk-in-cooler.html | 60 ++++++++ .../site/news/winter-coat-drive.html | 59 ++++++++ starters/nonprofit/site/privacy.html | 37 +++++ starters/nonprofit/site/programs.html | 66 +++++++++ .../site/reports/annual-report-2023.pdf | Bin 0 -> 695 bytes .../site/reports/annual-report-2024.pdf | Bin 0 -> 695 bytes .../site/reports/annual-report-2025.pdf | Bin 0 -> 695 bytes .../nonprofit/site/reports/audit-2025.pdf | Bin 0 -> 700 bytes .../nonprofit/site/reports/form-990-2025.pdf | Bin 0 -> 691 bytes starters/nonprofit/site/transparency.html | 84 +++++++++++ tests/starters.spec.mjs | 131 ++++++++++++++++++ 34 files changed, 1274 insertions(+) create mode 100644 starters/nonprofit/.github/workflows/deploy.yml create mode 100644 starters/nonprofit/.gitignore create mode 100644 starters/nonprofit/README.md create mode 100644 starters/nonprofit/package.json create mode 100644 starters/nonprofit/site/404.html create mode 100644 starters/nonprofit/site/_includes/footer.html create mode 100644 starters/nonprofit/site/_includes/head.html create mode 100644 starters/nonprofit/site/_includes/nav.html create mode 100644 starters/nonprofit/site/about.html create mode 100644 starters/nonprofit/site/contact.html create mode 100644 starters/nonprofit/site/donate.html create mode 100644 starters/nonprofit/site/events.html create mode 100644 starters/nonprofit/site/get-involved.html create mode 100644 starters/nonprofit/site/images/logo.svg create mode 100644 starters/nonprofit/site/index.html create mode 100644 starters/nonprofit/site/news/index.html create mode 100644 starters/nonprofit/site/news/walk-in-cooler.html create mode 100644 starters/nonprofit/site/news/winter-coat-drive.html create mode 100644 starters/nonprofit/site/privacy.html create mode 100644 starters/nonprofit/site/programs.html create mode 100644 starters/nonprofit/site/reports/annual-report-2023.pdf create mode 100644 starters/nonprofit/site/reports/annual-report-2024.pdf create mode 100644 starters/nonprofit/site/reports/annual-report-2025.pdf create mode 100644 starters/nonprofit/site/reports/audit-2025.pdf create mode 100644 starters/nonprofit/site/reports/form-990-2025.pdf create mode 100644 starters/nonprofit/site/transparency.html create mode 100644 tests/starters.spec.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cd826e..3b5b15c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- A nonprofit starter site (`starters/nonprofit/`): 13 pages for a small nonprofit, built with `tagkit build` from shared includes, with donation and volunteer forms for static hosts, sortable and filterable event and budget tables, a live gift total, dialogs, a popover, a remembered FAQ, and a GitHub Pages workflow that runs TagCheck before publishing. Copy it with `npx degit kovirlabs/tagkit/starters/nonprofit`. Tests build it and check every page with TagCheck (including contrast and phone overflow), TagAction, links, and JavaScript off. - Tested with TagBrush.css 1.2.0. - The blog post template's lead photo opens in TagAction's viewer: its link now ends in `.jpg`, since TagAction only treats links to image files as photos. A test checks every linked photo. Found by the family agent evaluation. - The gallery (the GitHub Pages site) wears the Tag family brand: the family bar, the shared theme from kovirlabs.github.io/tagstack/brand.css, and a footer linking the family and the Jekyll and WordPress themes. The linked-photo test skips links that have text beside an image, like the family bar's. diff --git a/README.md b/README.md index b30d2ac..458e86f 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ TagKit is part of the Tag family. Its HTML is styled by [TagBrush.css](https://g **Snippets** (`snippets/`): hero, feature grid, pricing table, testimonials, FAQ, card grid, stat tiles, page header, data table, search bar, confirm dialog, user menu, contact form, callouts, sidebar layout, docs layout, footer columns. Each file starts with a comment that says what it is and where it goes. Most go inside `
`; ones marked `(body)` are page-level. +**Starter sites** (`starters/`): a whole multi-page site to copy and make your own. The [nonprofit starter](starters/nonprofit/) has 13 pages (home, about, programs, events, news, get involved, donate, contact, financials, privacy, 404), with donation and volunteer forms that work on any static host, built with `tagkit build`, checked with TagCheck, and published to GitHub Pages by an included workflow: `npx degit kovirlabs/tagkit/starters/nonprofit my-site`. + **Themes**: a [Pandoc template](themes/pandoc/) that turns Markdown, Word, or AI-written documents into a styled page with one command, a [Jekyll theme for GitHub Pages](https://github.com/kovirlabs/tagkit-jekyll) used with one config line (`remote_theme: kovirlabs/tagkit-jekyll`), an [MkDocs theme](themes/mkdocs/) for documentation sites, a [Hugo theme](themes/hugo/) for blogs and sites, and a [WordPress block theme](https://github.com/kovirlabs/tagkit-wordpress). ## Build-time includes diff --git a/ai/AGENTS.md b/ai/AGENTS.md index a1683ad..a9cc363 100644 --- a/ai/AGENTS.md +++ b/ai/AGENTS.md @@ -27,6 +27,10 @@ Share a header, nav, and footer between static pages without a framework. In eac Then build: `npx @kovirlabs/tagkit build site/ public/` (`--check` also runs TagCheck). `file="…"` is relative to the page and `virtual="/…"` to the site folder. Pages get their includes filled in; other files are copied; names starting with `_` are left out. Links to the page being built get `aria-current="page"`, and root links (`/about.html`) in included pieces become relative, so write links in shared pieces from the site root. Don't use JavaScript or iframes to include headers and footers. +### Starter sites + +- [Nonprofit](https://github.com/kovirlabs/tagkit/tree/main/starters/nonprofit): a 13-page static site for a small nonprofit (home, about, programs, events, news, get involved, donate, contact, financials, privacy, 404). Copy it with `npx degit kovirlabs/tagkit/starters/nonprofit my-site`, then `npm install && npm run build` (writes `public/` and runs TagCheck). Shared pieces are in `site/_includes/` (`head.html` holds the brand color). Forms post to a form service such as Formspree and the donate form goes to a payment link; search for `your-` to find the addresses to replace. Includes a GitHub Pages workflow. Guide: https://raw.githubusercontent.com/kovirlabs/tagkit/main/starters/nonprofit/README.md + ### Themes - [Pandoc template](https://raw.githubusercontent.com/kovirlabs/tagkit/main/themes/pandoc/template.html): turn Markdown, Word, or any Pandoc input into a styled page: `pandoc notes.md --standalone --toc --template https://raw.githubusercontent.com/kovirlabs/tagkit/main/themes/pandoc/template.html -o notes.html`. Front matter `primary-color` sets the brand color; `no-tagaction: true` leaves out the script. Add `--mathjax` for equations. diff --git a/ai/claude/tagkit/SKILL.md b/ai/claude/tagkit/SKILL.md index c9b1fc5..33fa70e 100644 --- a/ai/claude/tagkit/SKILL.md +++ b/ai/claude/tagkit/SKILL.md @@ -32,6 +32,10 @@ Share a header, nav, and footer between static pages without a framework. In eac Then build: `npx @kovirlabs/tagkit build site/ public/` (`--check` also runs TagCheck). `file="…"` is relative to the page and `virtual="/…"` to the site folder. Pages get their includes filled in; other files are copied; names starting with `_` are left out. Links to the page being built get `aria-current="page"`, and root links (`/about.html`) in included pieces become relative, so write links in shared pieces from the site root. Don't use JavaScript or iframes to include headers and footers. +## Starter sites + +- [Nonprofit](https://github.com/kovirlabs/tagkit/tree/main/starters/nonprofit): a 13-page static site for a small nonprofit (home, about, programs, events, news, get involved, donate, contact, financials, privacy, 404). Copy it with `npx degit kovirlabs/tagkit/starters/nonprofit my-site`, then `npm install && npm run build` (writes `public/` and runs TagCheck). Shared pieces are in `site/_includes/` (`head.html` holds the brand color). Forms post to a form service such as Formspree and the donate form goes to a payment link; search for `your-` to find the addresses to replace. Includes a GitHub Pages workflow. Guide: https://raw.githubusercontent.com/kovirlabs/tagkit/main/starters/nonprofit/README.md + ## Themes - [Pandoc template](https://raw.githubusercontent.com/kovirlabs/tagkit/main/themes/pandoc/template.html): turn Markdown, Word, or any Pandoc input into a styled page: `pandoc notes.md --standalone --toc --template https://raw.githubusercontent.com/kovirlabs/tagkit/main/themes/pandoc/template.html -o notes.html`. Front matter `primary-color` sets the brand color; `no-tagaction: true` leaves out the script. Add `--mathjax` for equations. diff --git a/ai/cursor/tagkit.mdc b/ai/cursor/tagkit.mdc index 5f7b254..1eda5d3 100644 --- a/ai/cursor/tagkit.mdc +++ b/ai/cursor/tagkit.mdc @@ -33,6 +33,10 @@ Share a header, nav, and footer between static pages without a framework. In eac Then build: `npx @kovirlabs/tagkit build site/ public/` (`--check` also runs TagCheck). `file="…"` is relative to the page and `virtual="/…"` to the site folder. Pages get their includes filled in; other files are copied; names starting with `_` are left out. Links to the page being built get `aria-current="page"`, and root links (`/about.html`) in included pieces become relative, so write links in shared pieces from the site root. Don't use JavaScript or iframes to include headers and footers. +## Starter sites + +- [Nonprofit](https://github.com/kovirlabs/tagkit/tree/main/starters/nonprofit): a 13-page static site for a small nonprofit (home, about, programs, events, news, get involved, donate, contact, financials, privacy, 404). Copy it with `npx degit kovirlabs/tagkit/starters/nonprofit my-site`, then `npm install && npm run build` (writes `public/` and runs TagCheck). Shared pieces are in `site/_includes/` (`head.html` holds the brand color). Forms post to a form service such as Formspree and the donate form goes to a payment link; search for `your-` to find the addresses to replace. Includes a GitHub Pages workflow. Guide: https://raw.githubusercontent.com/kovirlabs/tagkit/main/starters/nonprofit/README.md + ## Themes - [Pandoc template](https://raw.githubusercontent.com/kovirlabs/tagkit/main/themes/pandoc/template.html): turn Markdown, Word, or any Pandoc input into a styled page: `pandoc notes.md --standalone --toc --template https://raw.githubusercontent.com/kovirlabs/tagkit/main/themes/pandoc/template.html -o notes.html`. Front matter `primary-color` sets the brand color; `no-tagaction: true` leaves out the script. Add `--mathjax` for equations. diff --git a/llms.txt b/llms.txt index cf291b6..f22e968 100644 --- a/llms.txt +++ b/llms.txt @@ -25,6 +25,10 @@ Share a header, nav, and footer between static pages without a framework. In eac Then build: `npx @kovirlabs/tagkit build site/ public/` (`--check` also runs TagCheck). `file="…"` is relative to the page and `virtual="/…"` to the site folder. Pages get their includes filled in; other files are copied; names starting with `_` are left out. Links to the page being built get `aria-current="page"`, and root links (`/about.html`) in included pieces become relative, so write links in shared pieces from the site root. Don't use JavaScript or iframes to include headers and footers. +## Starter sites + +- [Nonprofit](https://github.com/kovirlabs/tagkit/tree/main/starters/nonprofit): a 13-page static site for a small nonprofit (home, about, programs, events, news, get involved, donate, contact, financials, privacy, 404). Copy it with `npx degit kovirlabs/tagkit/starters/nonprofit my-site`, then `npm install && npm run build` (writes `public/` and runs TagCheck). Shared pieces are in `site/_includes/` (`head.html` holds the brand color). Forms post to a form service such as Formspree and the donate form goes to a payment link; search for `your-` to find the addresses to replace. Includes a GitHub Pages workflow. Guide: https://raw.githubusercontent.com/kovirlabs/tagkit/main/starters/nonprofit/README.md + ## Themes - [Pandoc template](https://raw.githubusercontent.com/kovirlabs/tagkit/main/themes/pandoc/template.html): turn Markdown, Word, or any Pandoc input into a styled page: `pandoc notes.md --standalone --toc --template https://raw.githubusercontent.com/kovirlabs/tagkit/main/themes/pandoc/template.html -o notes.html`. Front matter `primary-color` sets the brand color; `no-tagaction: true` leaves out the script. Add `--mathjax` for equations. diff --git a/package.json b/package.json index 7ec7a6c..1fb9036 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "templates/", "snippets/", "themes/", + "starters/", "snippets.json", "llms.txt", "ai/" diff --git a/starters/nonprofit/.github/workflows/deploy.yml b/starters/nonprofit/.github/workflows/deploy.yml new file mode 100644 index 0000000..c5bab0b --- /dev/null +++ b/starters/nonprofit/.github/workflows/deploy.yml @@ -0,0 +1,47 @@ +# Builds the site with TagKit, checks it with TagCheck, and publishes it to GitHub Pages +# on every push to main. One-time setup: Settings > Pages > Source: "GitHub Actions". + +name: Deploy site + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + + - run: npm install + + # Fills in the shared header and footer, then runs TagCheck: a page with errors stops the deploy. + - run: npm run build + + - uses: actions/upload-pages-artifact@v3 + with: + path: public + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/starters/nonprofit/.gitignore b/starters/nonprofit/.gitignore new file mode 100644 index 0000000..e9f09fd --- /dev/null +++ b/starters/nonprofit/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +public/ +.DS_Store diff --git a/starters/nonprofit/README.md b/starters/nonprofit/README.md new file mode 100644 index 0000000..317e58f --- /dev/null +++ b/starters/nonprofit/README.md @@ -0,0 +1,64 @@ +# Nonprofit starter site + +Use this when you need a website for a small nonprofit that you can host anywhere as plain files: no CMS, no framework, no page scripts to maintain. + +It is a complete example site for a fictional food bank, Riverbend Food Share, with 13 pages written in plain semantic HTML. [TagBrush.css](https://github.com/kovirlabs/tagbrush) styles it (dark mode included), [TagAction](https://github.com/kovirlabs/tagaction) adds the interactive parts, [TagKit](https://github.com/kovirlabs/tagkit) fills in the shared header and footer at build time, and [TagCheck](https://github.com/kovirlabs/tagcheck) checks every page before it goes live. + +## Start + +```sh +npx degit kovirlabs/tagkit/starters/nonprofit my-nonprofit +cd my-nonprofit +npm install +npm run build # writes public/ and checks it; open public/index.html +npm run watch # rebuild as you edit +``` + +Open `public/index.html` straight from disk; links work without a server. + +## What's inside + +| Page | Shows off | +|---|---| +| `index.html` | Hero with photo, impact numbers as stat tiles, program cards with icons, testimonials, news cards with "3 days ago" dates, newsletter sign-up | +| `about.html` | Mission cards, history with a photo that enlarges, staff cards, a sortable board table, annual report downloads | +| `programs.html` | Page title with actions, callouts in three colors, a schedule table with status badges | +| `events.html` | Sortable, filterable event table with times shown in each visitor's own time zone, an "access info" popover | +| `get-involved.html` | Volunteer form with validation, a switch, "Add another person" rows, a character counter, a "What to expect" dialog, and an FAQ that remembers what's open | +| `donate.html` | Gift amounts with a live total, a monthly switch, a meter, other ways to give, a mailing-address dialog | +| `contact.html` | Address, phone, and email cards; a contact form | +| `news/` | A news index and two posts with breadcrumbs, a data table, and previous/next links | +| `transparency.html` | Table of contents that follows the scroll, sortable income and spending tables, tax filings and audits | +| `privacy.html`, `404.html` | A plain-language privacy page and a "page not found" page | + +Shared pieces live in `site/_includes/`: `head.html` (stylesheet, script, brand color), `nav.html` (the top bar), and `footer.html`. Change them once and every page follows. Folders starting with `_` aren't published. + +## Make it yours + +1. **Name, address, and EIN:** search the `site/` folder for `Riverbend`, `214 Mill Street`, `00-0000000`, `555`, and `example.org`. +2. **Color and logo:** change `--color-primary` in `site/_includes/head.html` (a light and a dark value), and replace `site/images/logo.svg`. +3. **Donations:** the form in `site/donate.html` sends the visitor to `https://donate.stripe.com/your-payment-link`. Replace it with your Stripe Payment Link, Givebutter, Donorbox, PayPal, or bank giving page. If your provider can't take the amount in the link, use a plain link instead (the comment above the form shows how). +4. **Forms:** the contact, volunteer, and newsletter forms post to `https://formspree.io/f/your-…-form-id`. Create forms at [Formspree](https://formspree.io), Basin, Getform, or your newsletter provider and paste their addresses into the `action`. On Netlify, you can use Netlify Forms instead (`
`). +5. **Photos:** the photos come from picsum.photos as placeholders. Put your own in `site/images/` and change the `src` (and the link around the photo, if it has one) and `alt` text. +6. **Reports:** replace the placeholder PDFs in `site/reports/`. +7. **Pages:** delete pages you don't need, and remove their links from `nav.html` and `footer.html`. To add a page, copy one that's close and keep the include lines. + +Write links in `_includes/` from the site root (`/donate.html`); TagKit makes them relative for each page and marks the current page in the nav. In pages themselves, use relative links (`donate.html`, or `../donate.html` from `news/`). + +Run `npm run build` after editing. It stops with an error if a page has a problem (a missing label or alt text, a broken reference, a duplicate id), and tells you the file and line. `npm run check` also checks contrast in light and dark mode and phone layouts; it needs Playwright (`npx playwright install chromium`). + +## Publish + +- **GitHub Pages:** push to a repository, then in Settings > Pages set Source to "GitHub Actions". `.github/workflows/deploy.yml` builds, checks, and publishes on every push to `main`. +- **Netlify or Cloudflare Pages:** build command `npm run build`, publish directory `public`. +- **Any web host:** run `npm run build` and upload the contents of `public/` by FTP or your host's file manager. + +The 404 page's links are relative, so they work for missing pages at the top level of the site (`/missing.html`) but not deeper ones (`/news/missing.html`). + +## Versions + +The pages load TagBrush.css 1.x and TagAction 0.x from jsDelivr, so they get fixes automatically. To lock exact versions, change `tagbrush@1` and `tagaction@0` in `site/_includes/head.html` to full versions such as `tagbrush@1.2.0`, and add `integrity` attributes if you want the browser to verify the files. + +## License + +Apache-2.0, like TagKit. The text and organization are fictional; replace them with your own. diff --git a/starters/nonprofit/package.json b/starters/nonprofit/package.json new file mode 100644 index 0000000..19009f2 --- /dev/null +++ b/starters/nonprofit/package.json @@ -0,0 +1,14 @@ +{ + "name": "riverbend-food-share-site", + "private": true, + "description": "A static website for a small nonprofit, built from plain HTML with TagKit, TagBrush.css, TagAction, and TagCheck.", + "scripts": { + "build": "tagkit build site public --check", + "watch": "tagkit build site public --watch", + "check": "tagcheck public --browser" + }, + "devDependencies": { + "@kovirlabs/tagcheck": "^0.1.1", + "@kovirlabs/tagkit": "^0.1.0" + } +} diff --git a/starters/nonprofit/site/404.html b/starters/nonprofit/site/404.html new file mode 100644 index 0000000..5f225db --- /dev/null +++ b/starters/nonprofit/site/404.html @@ -0,0 +1,27 @@ + + + + +Page not found · Riverbend Food Share + + + +
+ +
+
+ +
+ + + diff --git a/starters/nonprofit/site/_includes/footer.html b/starters/nonprofit/site/_includes/footer.html new file mode 100644 index 0000000..c1167b2 --- /dev/null +++ b/starters/nonprofit/site/_includes/footer.html @@ -0,0 +1,28 @@ + diff --git a/starters/nonprofit/site/_includes/head.html b/starters/nonprofit/site/_includes/head.html new file mode 100644 index 0000000..389fba8 --- /dev/null +++ b/starters/nonprofit/site/_includes/head.html @@ -0,0 +1,11 @@ + + + + + + + diff --git a/starters/nonprofit/site/_includes/nav.html b/starters/nonprofit/site/_includes/nav.html new file mode 100644 index 0000000..da12fbf --- /dev/null +++ b/starters/nonprofit/site/_includes/nav.html @@ -0,0 +1,12 @@ + diff --git a/starters/nonprofit/site/about.html b/starters/nonprofit/site/about.html new file mode 100644 index 0000000..b118a8f --- /dev/null +++ b/starters/nonprofit/site/about.html @@ -0,0 +1,99 @@ + + + + +About us · Riverbend Food Share + + + +
+ +
+
+ +
+

About us

+

Neighbors feeding neighbors in Riverbend since 2009.

+
+ +
+

Our mission

+

Riverbend Food Share makes sure no one in our town goes hungry, and that getting help with food is as easy and as dignified as shopping with friends.

+
+

Dignity first

+

No forms to prove need, no lines outside. Shoppers choose their own food, like at any market.

+
+
+

Fresh, not just filling

+

More than half of what we give out is produce, dairy, or protein, bought from local farms when we can.

+
+
+

Run by the community

+

Four staff and more than 600 volunteers. A third of our volunteers once shopped at the market.

+
+
+ +
+

Our story

+

We started in 2009 as a folding table in the basement of the Mill Street church, handing out canned food to forty families after the paper mill closed. In 2016 we moved to our warehouse on Mill Street and opened the Saturday Market. Weekend Bags followed in 2018, and Home Delivery began in the spring of 2020, when our older shoppers couldn't safely come to us.

+
+ The first Saturday Market in the new warehouse, 2016 +
The first Saturday Market in our warehouse, May 2016.
+
+
+ +
+

Staff

+
+ Portrait of Rosa Delgado +

Rosa Delgado

+

Executive director. Rosa joined as a volunteer in 2011 and has led the Food Share since 2017.

+
+
+ Portrait of Marcus Webb +

Marcus Webb

+

Operations manager. Marcus runs the warehouse, the delivery routes, and our relationships with farms.

+
+
+ Portrait of Hana Sato +

Hana Sato

+

Volunteer coordinator. Hana matches 600 volunteers with the shifts that suit them.

+
+
+ +
+

Board of directors

+

Our board is made up of volunteers who meet every other month. Minutes are posted on our financials page.

+
+ + + + + + + + + + + +
NameRoleOn the board since
James OkoroChair2018
Linda ParkTreasurer2020
Samuel ReyesSecretary2022
Grace WhitfieldMember2019
Tomás HerreraMember, former shopper2024
+
+
+ +
+

Annual reports

+ +
+
+ + + diff --git a/starters/nonprofit/site/contact.html b/starters/nonprofit/site/contact.html new file mode 100644 index 0000000..ea51d6e --- /dev/null +++ b/starters/nonprofit/site/contact.html @@ -0,0 +1,71 @@ + + + + +Contact · Riverbend Food Share + + + +
+ +
+
+ +
+

Contact us

+

Write, call, or stop by. A real person reads every message.

+
+ +
+

Reach us

+
+

Visit

+
214 Mill Street
Riverbend, ST 00000
+

Office open Monday to Friday, 9 to 4.

+
+
+

Call

+

(555) 010-0200

+

Leave a message after hours; we call back the next working day.

+
+ +
+ +
+

Send a message

+
+ + + + + + + We reply within two working days. + + + + + + + +
+
+
+ + + diff --git a/starters/nonprofit/site/donate.html b/starters/nonprofit/site/donate.html new file mode 100644 index 0000000..263c64b --- /dev/null +++ b/starters/nonprofit/site/donate.html @@ -0,0 +1,90 @@ + + + + +Donate · Riverbend Food Share + + + +
+ +
+
+ +
+

Feed a neighbor this week

+

We buy food at wholesale prices, so every dollar you give goes three times as far as it would at the store.

+
+ +
+

Choose your gift

+
+ +
+
+ Amount + + + + +
+ + +

Your gift: $50

+

You'll finish on our payment partner's page. We never see or store your card number.

+ +
+
+
+ +
+

Where the money goes

+

87 cents of every dollar we spend goes straight to food and programs. See the full budget.

+

87% Programs: 87%

+
+ +
+

Other ways to give

+
+

By check

+

Mail a check made out to Riverbend Food Share.

+
+
+
+

Employer matching

+

Many employers double their staff's gifts. Ask your HR team, and use our EIN, 00-0000000.

+
+
+

Stock and donor-advised funds

+

Give appreciated stock or recommend a grant from your fund. Write to us for transfer details.

+
+
+

Food

+

Drop off unopened food at 214 Mill Street, Monday to Friday, 9 to 4. Our most-needed list: peanut butter, canned fish, cooking oil, and diapers in sizes 4 to 6.

+
+
+ + +
+
+

Mail a check

+ +
+
Riverbend Food Share
214 Mill Street
Riverbend, ST 00000
+

Include your email address if you'd like a receipt for taxes.

+
+
+
+
+ + + diff --git a/starters/nonprofit/site/events.html b/starters/nonprofit/site/events.html new file mode 100644 index 0000000..71d51cc --- /dev/null +++ b/starters/nonprofit/site/events.html @@ -0,0 +1,67 @@ + + + + +Events · Riverbend Food Share + + + +
+ +
+
+ +
+
+

Events

+

Food drives, volunteer days, and a few parties. Everyone is welcome.

+
+
+ Sign up to help +
+
+ +
+

Upcoming

+

Times are shown in your own time zone. Click a column heading to sort.

+
+

Access at our events: the warehouse is step-free, with an accessible restroom and parking by the side door. Ask us about ASL interpretation at least a week ahead.

+
+ + + +
+ + + + + + + + + + + + +
EventStartsWhereKind
Winter coat drive drop-off214 Mill StreetDrive
Thanksgiving market (extended hours)214 Mill StreetMarket
New volunteer orientationOnlineTraining
Holiday food drive at Riverbend HighRiverbend High SchoolDrive
Weekend Bags packing night214 Mill StreetVolunteer
Soup Supper fundraiserGrange Hall, 9 Elm RoadFundraiser
+
+
+ +
+

Earlier this year

+
    +
  • : Harvest Day at Hillside Farm. 80 volunteers gleaned 9 tons of squash and apples.
  • +
  • : Back-to-school backpack giveaway. 420 backpacks filled and handed out.
  • +
  • : Stamp Out Hunger with the letter carriers. 31,000 pounds of food collected.
  • +
  • : Soup Supper. Raised $48,200 for Home Delivery.
  • +
+
+
+ + + diff --git a/starters/nonprofit/site/get-involved.html b/starters/nonprofit/site/get-involved.html new file mode 100644 index 0000000..b7db5f3 --- /dev/null +++ b/starters/nonprofit/site/get-involved.html @@ -0,0 +1,119 @@ + + + + +Get involved · Riverbend Food Share + + + +
+ +
+
+ +
+

Get involved

+

Six hundred neighbors give a few hours a month. There's a shift that fits your week.

+
+ +
+

Ways to help

+
+ +

Volunteer a shift

+

Stock shelves, greet shoppers, or check people out at the Saturday Market. Ages 14 and up.

+
+
+ +

Drive deliveries

+

Two hours on a Tuesday or Thursday, in your own car. We cover mileage on request.

+
+
+ +

Run a food drive

+

At work, school, or your place of worship. We lend the bins and pick up the food.

+
+
+ +
+
+

Sign up to volunteer

+ +
+
+ +
+
+ About you + + + + + + + Only for shift reminders. We never share it. + +
+
+ When can you help? + + + + +
+
+ Coming with others? (optional) +
    +
  • + +
+ +
+ + + Languages you speak, access needs, or skills (forklift, Spanish, accounting…). + +
+
+ +
+
+

Your first shift

+ +
+

Arrive ten minutes early and ask for the shift lead at the front desk. Wear closed-toe shoes. We'll give you an apron, a name tag, and a ten-minute tour before you start.

+
+
+
+
+ +
+

Questions

+
+ How old do I need to be? +

14 for market shifts, or any age with a parent. Delivery drivers need to be 18 with a valid license and insurance.

+
+
+ Is there a minimum number of hours? +

No. Some people come every week; others come twice a year. Sign up for the shifts you can make.

+
+
+ Can I get community service hours? +

Yes. We sign school and court service forms. Bring yours to the front desk at the end of your shift.

+
+
+ Can my company volunteer as a team? +

Yes, for groups of up to twelve on weekday packing nights. Add your teammates in the form above, or write to us for larger groups.

+
+
+
+ + + diff --git a/starters/nonprofit/site/images/logo.svg b/starters/nonprofit/site/images/logo.svg new file mode 100644 index 0000000..2358843 --- /dev/null +++ b/starters/nonprofit/site/images/logo.svg @@ -0,0 +1,6 @@ + + Riverbend Food Share + + + + diff --git a/starters/nonprofit/site/index.html b/starters/nonprofit/site/index.html new file mode 100644 index 0000000..08efcfa --- /dev/null +++ b/starters/nonprofit/site/index.html @@ -0,0 +1,117 @@ + + + + +Riverbend Food Share: good food for every neighbor + + + +
+ +
+

Good food for every neighbor

+

We run a free weekly market, send weekend meals home with schoolkids, and deliver groceries to neighbors who can't get out. Run by volunteers, paid for by people like you.

+
+
+ Give a gift + Volunteer with us +
+
+ Fresh vegetables laid out on a market table +
+
+
+
+
+

Last year

+

What your support did in 2025

+
+
+
Meals shared
412,000
+18% on 2024
+
Families served each week
1,350
+210 on 2024
+
Volunteer hours
26,800
+9% on 2024
+
Of every dollar spent on food and programs
87¢
See our financials
+
+
+ +
+
+

Programs

+

Three ways we get food to people

+
+
+ +

Saturday Market

+

Fresh produce, dairy, and pantry staples every Saturday morning. Shop like any market; everything is free.

+
+
+ +

Weekend Bags

+

Kid-friendly food that goes home in backpacks every Friday from eleven local schools.

+
+
+ +

Home Delivery

+

Volunteer drivers bring a week of groceries to seniors and neighbors with disabilities.

+
+
+ +
+

In their words

+
+
+

When my hours were cut, the Saturday Market meant my kids still had fruit in their lunches. Nobody made me feel small for being there.

+
Dana, a market shopper since 2024
+
+
+
+
+

I drive deliveries on Tuesdays. Mr. Alvarez has coffee ready for me every week; some weeks I'm the only person he sees.

+
Priya Raman, volunteer driver
+
+
+
+
+

On Mondays I can tell which kids got a weekend bag. They're ready to learn instead of hungry.

+
Mr. Hollis, fourth-grade teacher
+
+
+
+ +
+

Latest news

+
+ Volunteers sorting donated coats on long tables +

Our winter coat drive is back

+

Drop off clean, warm coats at the warehouse through December 13. Last year you gave 640.

+
+
+ +
+ +
+

Get our monthly update

+

One email a month: what we did, what we need, and when to show up. No spam, unsubscribe any time.

+ +
+
+ + +
+
+
+ +
+

$50 feeds a family for a week

+

Every gift buys food at wholesale prices, so your dollar goes three times as far as it would at the store.

+

Donate now

+
+
+ + + diff --git a/starters/nonprofit/site/news/index.html b/starters/nonprofit/site/news/index.html new file mode 100644 index 0000000..97f8617 --- /dev/null +++ b/starters/nonprofit/site/news/index.html @@ -0,0 +1,42 @@ + + + + +News · Riverbend Food Share + + + +
+ +
+
+ +
+

News

+

What we're up to, what we need, and the people who make it happen.

+
+ +
+

Recent posts

+
+ Volunteers sorting donated coats on long tables +

Our winter coat drive is back

+

Drop off clean, warm coats at the warehouse through December 13. Last year you gave 640.

+
+
+ +
+
+ + + diff --git a/starters/nonprofit/site/news/walk-in-cooler.html b/starters/nonprofit/site/news/walk-in-cooler.html new file mode 100644 index 0000000..02d9f8a --- /dev/null +++ b/starters/nonprofit/site/news/walk-in-cooler.html @@ -0,0 +1,60 @@ + + + + +A new walk-in cooler doubles our fresh food · Riverbend Food Share + + + +
+ +
+
+
+ +
+

A new walk-in cooler doubles our fresh food

+

By Marcus Webb, operations manager ·

+
+
+ Crates of apples in a cold storage room +
The first delivery into the new cooler: apples from Hillside Farm.
+
+

For years we had to turn down fresh food. Farms and grocery stores offered us pallets of milk, greens, and fruit, and we had nowhere cold to keep them. That changed in September, when our new walk-in cooler was switched on.

+ +

What changes for shoppers

+

The cooler holds 12 pallets, twice what our old refrigerators held together. In its first month, fresh food at the Saturday Market went from 41% to 58% of everything we gave out.

+
+ + + + + + + + + +
FoodSeptember 2025September 2026Change
Produce18,400 lb31,200 lb+70%
Dairy and eggs6,100 lb11,800 lb+93%
Meat and fish2,900 lb5,200 lb+79%
+
+ +

Thank you

+

The cooler cost $64,000, paid for by a grant from the Riverbend Community Fund and 212 individual donors who gave to our spring appeal. Installation was donated by Mill Street Mechanical.

+ + + +
+
+ + + diff --git a/starters/nonprofit/site/news/winter-coat-drive.html b/starters/nonprofit/site/news/winter-coat-drive.html new file mode 100644 index 0000000..7cfd1d7 --- /dev/null +++ b/starters/nonprofit/site/news/winter-coat-drive.html @@ -0,0 +1,59 @@ + + + + +Our winter coat drive is back · Riverbend Food Share + + + +
+ +
+
+
+ +
+

Our winter coat drive is back

+

By Hana Sato, volunteer coordinator ·

+
+
+ Volunteers sorting donated coats on long tables +
Volunteers sorted 640 coats at last year's drive.
+
+

Riverbend gets cold fast. Last winter, you gave 640 coats, and every one of them was gone by the second week of January. This year we're hoping for 800.

+ +

What we need most

+
    +
  • Children's coats, sizes 4 to 14
  • +
  • Adult coats in large and extra large
  • +
  • New hats, gloves, and socks (we can't accept used ones)
  • +
+ + +

Where to drop off

+

Bring coats to 214 Mill Street, Monday to Friday from 9 to 4, or to the Saturday Market. There's also a bin in the lobby of Riverbend Public Library until December 13.

+ +

Where the coats go

+

Coats are handed out free at the Saturday Market from December 5, and our Home Delivery drivers bring them to neighbors who ask. Anything left in February goes to the Riverbend shelter.

+
+

My son outgrew his coat in October. Getting a new one here, one he picked himself, meant a lot to both of us.

+
A Saturday Market shopper
+
+ + +
+
+ + + diff --git a/starters/nonprofit/site/privacy.html b/starters/nonprofit/site/privacy.html new file mode 100644 index 0000000..a98ab36 --- /dev/null +++ b/starters/nonprofit/site/privacy.html @@ -0,0 +1,37 @@ + + + + +Privacy · Riverbend Food Share + + + +
+ +
+
+
+
+

Privacy

+

Last updated

+
+ + +

What we collect

+

This website has no ads, no tracking cookies, and no analytics. We only get information you choose to send us:

+
    +
  • Your name, email, and message when you use the contact or volunteer forms.
  • +
  • Your email address when you sign up for our monthly update.
  • +
  • Your gift details when you donate. Payment is handled by our payment partner; we never see your card number.
  • +
+ +

Who sees it

+

Our staff, to answer you. Our forms are delivered by a form service and our donations by a payment processor, which store what you send under their own privacy policies. We never sell, rent, or trade your information.

+ +

Your choices

+

Unsubscribe from any email with the link at the bottom. To see, correct, or delete what we hold about you, write to privacy@example.org, and we'll do it within 30 days.

+
+
+ + + diff --git a/starters/nonprofit/site/programs.html b/starters/nonprofit/site/programs.html new file mode 100644 index 0000000..507b8a9 --- /dev/null +++ b/starters/nonprofit/site/programs.html @@ -0,0 +1,66 @@ + + + + +Programs · Riverbend Food Share + + + +
+ +
+
+ +
+
+

Programs

+

Free food, no paperwork. Anyone who lives or works in Riverbend is welcome.

+
+
+ See the calendar + Ask us a question +
+
+ +
+

Saturday Market

+

Every Saturday from 9 to 12, our warehouse at 214 Mill Street becomes a free market. Pick up a cart, choose what your household will eat, and check out with a volunteer. There's no sign-up and no proof of income.

+
    +
  • Fresh produce, eggs, milk, bread, and pantry staples every week
  • +
  • Halal, vegetarian, and gluten-free shelves
  • +
  • Diapers and personal care items on the first Saturday of the month
  • +
+ + +

Weekend Bags

+

Every Friday during the school year, students at eleven Riverbend schools take home a bag of kid-friendly food for the weekend: cereal, milk boxes, fruit, and easy meals they can make themselves. Families sign up through the school counselor, and bags go home discreetly in backpacks.

+ + +

Home Delivery

+

Volunteer drivers bring a week of groceries to neighbors who can't get to the market: seniors, people with disabilities, and anyone recovering from illness. Deliveries happen on Tuesdays and Thursdays.

+

To sign yourself or someone else up, call (555) 010-0200 or use the contact form.

+ + +

Where and when

+
+ + + + + + + + + +
ProgramWhenWhereStatus
Saturday MarketSaturdays, 9:00–12:00214 Mill StreetOpen to all
Weekend BagsFridays, school yearEleven schoolsThrough schools
Home DeliveryTuesdays and ThursdaysYour doorWaiting list
+
+
+
+ + + diff --git a/starters/nonprofit/site/reports/annual-report-2023.pdf b/starters/nonprofit/site/reports/annual-report-2023.pdf new file mode 100644 index 0000000000000000000000000000000000000000..78c99e987d105717d5302a4872b30ff889dc2653 GIT binary patch literal 695 zcmZWnO;5r=5WV+TybB2)u-($45JDm~P_2k=Jl z6>Q~$Yk_&Ikeg-m%ypi6y6a53zBjnli&;c#=N2c literal 0 HcmV?d00001 diff --git a/starters/nonprofit/site/reports/annual-report-2024.pdf b/starters/nonprofit/site/reports/annual-report-2024.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2dafc3d38c9852d85680623ce8c3683ce75ecd46 GIT binary patch literal 695 zcmZWnO;5r=5WV+TybB2)u-($45JDm~P_2k=JbBE+Wp*6`AV)> z>Z5kNTUrI&-yr%v=%r~l#R@;MKKw7LpICbSFQycGl5>QM6JD%8u_WOcA7ajGuHO2+ en-`yi9?#SmS(*L5)lOUIeWof7TCMAcN$>^zEWD!t literal 0 HcmV?d00001 diff --git a/starters/nonprofit/site/reports/annual-report-2025.pdf b/starters/nonprofit/site/reports/annual-report-2025.pdf new file mode 100644 index 0000000000000000000000000000000000000000..12184eb95b36fd13b1a1e3be62f99773af0a04ca GIT binary patch literal 695 zcmZWnO;5r=5WV+TybB2)u-($45JDm~P_2k=JbBE+Wp*6`AV)> z>Z5kNTUrI&-yr%v=%r~l#R@;MKKw7LpICbSFQycGl5>QM6JD%8u_WOcA7ajGuHO2+ en-`yi9?#SmS(*L5)lOUIeWof7TCMAcN$>^!lDwn< literal 0 HcmV?d00001 diff --git a/starters/nonprofit/site/reports/audit-2025.pdf b/starters/nonprofit/site/reports/audit-2025.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f956ce0d01e5dc6c8a35a12d8733c0a61375be73 GIT binary patch literal 700 zcmZWnO>Y`85WVlOco(EpYO;7)LlQ+CXoFg{RT1nh>cQXv9BtOf>&-`heP#?PH1WwE zzj^P?M{o9Zdaf?YOra0Iyw7fKkXJ7|LjJ`>Q~M3_nb}Z_f&p`k#~C$Nfb#x7VUNpy zINRcGAn-rT;=3k7og~W7$3&3{#L&G?{)?q7CIjkk}G^%0P~&AYO|uPuPudZ1lq|H zaqC*FT}^m$?B|6Gf`4jY{i=Il=8HskTS@B=E)PSH8sDnfPc3yIUv$fuhA2UWd}3PK z|9qqRk)m6flb$>WT4&tktpD#|sP#Z&jbrQz=@-p0rY}FllwwbEPH;uZ+x0G1mZM`V k2E)~dw0sNqmoVhPdM|r(Sh_Zv5R*@>Mp>_S`+J(b0!fO#X#fBK literal 0 HcmV?d00001 diff --git a/starters/nonprofit/site/reports/form-990-2025.pdf b/starters/nonprofit/site/reports/form-990-2025.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a4bba4c2fc163ead83c65d6231f2b9106493ead6 GIT binary patch literal 691 zcmZWn!A`_R zj|?;Ti$dxFg8@r7)TQjG{y^2rt)Y^x0BUDRZ-QaQGzxKqY>6Jr$}Pvqq1nze literal 0 HcmV?d00001 diff --git a/starters/nonprofit/site/transparency.html b/starters/nonprofit/site/transparency.html new file mode 100644 index 0000000..b8fbb2a --- /dev/null +++ b/starters/nonprofit/site/transparency.html @@ -0,0 +1,84 @@ + + + + +Financials and transparency · Riverbend Food Share + + + +
+ +
+
+ +
+ +
+

Financials and transparency

+

You trust us with your money. Here's exactly what we do with it.

+
+ +

At a glance

+
+
2025 income
$1.84M
+11% on 2024
+
Spent on programs
87%
+2 pts on 2024
+
Months of reserves
4.2
−0.3 on 2024
+
+ +

Where the money comes from

+

Fiscal year ending December 31, 2025. Click a column heading to sort.

+
+ + + + + + + + + + + + +
SourceAmountShare
Individual donors$742,00040.3%
Donated food (fair value)$516,00028.0%
Foundation grants$318,00017.3%
Events$96,0005.2%
Businesses and congregations$121,0006.6%
Government contracts$47,0002.6%
+
+ +

Where it goes

+
+ + + + + + + + + + +
CategoryAmountShare
Food purchased and donated$1,104,00062.4%
Program staff and warehouse$434,00024.6%
Administration$139,0007.9%
Fundraising$90,0005.1%
+
+ + +

Tax filings and audits

+

Riverbend Food Share is a 501(c)(3) public charity, EIN 00-0000000. Our Form 990 filings are public.

+ + +

Governance

+

Our board of directors meets every other month. It approves the budget, reviews the audit, and sets the executive director's pay. We have conflict-of-interest and whistleblower policies; ask us for a copy.

+
+
+ + + diff --git a/tests/starters.spec.mjs b/tests/starters.spec.mjs new file mode 100644 index 0000000..7a17cc5 --- /dev/null +++ b/tests/starters.spec.mjs @@ -0,0 +1,131 @@ +import { test, expect } from '@playwright/test'; +import { spawnSync } from 'node:child_process'; +import { existsSync, readFileSync, readdirSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { checkFiles } from '@kovirlabs/tagcheck'; + +// Starter sites: a site/ folder built with `tagkit build`. Each is tested as built. +const STARTER = 'starters/nonprofit'; +const OUT = 'test-results/starter-nonprofit'; + +const walk = (folder) => readdirSync(folder, { withFileTypes: true }) + .flatMap((e) => (e.isDirectory() ? walk(join(folder, e.name)) : [join(folder, e.name)])); + +async function open(page, path, { javaScript = true } = {}) { + await page.route(/tagbrush@[^/]+\/tagbrush(\.min)?\.css/, (r) => r.fulfill({ path: 'node_modules/tagbrush/tagbrush.css', contentType: 'text/css' })); + await page.route(/tagaction@[^/]+\/tagaction(\.min)?\.js/, (r) => (javaScript ? r.fulfill({ path: 'node_modules/tagaction/tagaction.js', contentType: 'text/javascript' }) : r.abort())); + await page.route(/picsum\.photos/, (r) => r.fulfill({ contentType: 'image/svg+xml', body: '' })); + await page.goto(pathToFileURL(resolve(OUT, path)).href); + if (javaScript) await expect.poll(() => page.evaluate(() => typeof window.TagAction)).toBe('object'); +} + +test.describe('nonprofit starter', () => { + test.describe.configure({ mode: 'serial' }); // one build, shared by these tests + let pages; + test.beforeAll(() => { + const result = spawnSync(process.execPath, ['bin/tagkit.mjs', 'build', `${STARTER}/site`, OUT, '--check'], { encoding: 'utf8' }); + expect(result.status, result.stdout).toBe(0); + expect(result.stdout).toContain('TagCheck: 0 errors, 0 warnings'); + pages = walk(OUT).filter((f) => f.endsWith('.html')).map((f) => f.slice(OUT.length + 1)); + }); + + test('builds every page with no include comments left', () => { + expect(pages.sort()).toEqual(['404.html', 'about.html', 'contact.html', 'donate.html', 'events.html', 'get-involved.html', 'index.html', + 'news/index.html', 'news/walk-in-cooler.html', 'news/winter-coat-drive.html', 'privacy.html', 'programs.html', 'transparency.html']); + for (const path of pages) expect(readFileSync(join(OUT, path), 'utf8'), path).not.toContain(' + + + + + + + + + +
InvoiceClientAmountActions
#1042Harbor Bakery$420.00
#1041Lumen Studio$1,250.00
#1040North Fork Farm$86.50
+ +
+

Void invoice #1042?

+

Harbor Bakery won't be able to pay it. This can't be undone.

+
+ + +
+
+
+ +
+

Void invoice #1041?

+

Lumen Studio won't be able to pay it. This can't be undone.

+
+ + +
+
+
+ +
+

Void invoice #1040?

+

North Fork Farm won't be able to pay it. This can't be undone.

+ +
+
diff --git a/tests/kit.spec.mjs b/tests/kit.spec.mjs index a030a38..5943a0c 100644 --- a/tests/kit.spec.mjs +++ b/tests/kit.spec.mjs @@ -74,6 +74,26 @@ test.describe('with TagAction', () => { await expect(page.getByRole('dialog')).toBeHidden(); }); + test('each table row opens its own confirm dialog, after sorting too, and without JavaScript', async ({ page, browser }) => { + await open(page, 'preview/row-confirm.html'); + await page.getByRole('button', { name: 'Amount', exact: true }).click(); // sorting moves the rows, not the dialogs + await expect(page.getByRole('button', { name: 'Actions' })).toHaveCount(0); // unsortable column + await page.getByRole('button', { name: 'Void invoice #1041' }).click(); + const dialog = page.getByRole('dialog'); + await expect(dialog).toHaveCount(1); + await expect(dialog).toContainText('Lumen Studio'); + await expect(dialog.locator('form')).toHaveAttribute('action', '/invoices/1041/void'); + await page.keyboard.press('Escape'); + await expect(dialog).toHaveCount(0); + + const context = await browser.newContext({ javaScriptEnabled: false }); + const noJs = await context.newPage(); + await open(noJs, 'preview/row-confirm.html'); + await noJs.getByRole('button', { name: 'Void invoice #1040' }).click(); + await expect(noJs.getByRole('dialog')).toContainText('North Fork Farm'); + await context.close(); + }); + test('the dashboard account menu drops down and closes with Escape', async ({ page }) => { await open(page, 'templates/dashboard.html'); const button = page.getByRole('button', { name: 'Maya Lin' });