Skip to content

Combined release: 16 PRs ready to merge - #249

Merged
engleek merged 17 commits into
mainfrom
chore/combined-release
Oct 4, 2026
Merged

engleek merged 17 commits into
mainfrom
chore/combined-release

Conversation

@engleek

@engleek engleek commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Combines the open PRs into one branch, one commit per PR, so they can land together. Merge with "Rebase and merge" to keep the per-PR commits. Their Fixes #… lines then close #34, #196, #197, #198, #201, #202, #204, #205, #206, #207 and #208.

Included

PR Change
#243 Keep seeded places away from the poles
#221 Keep counts out of section headings
#222 Label org types "Studio" and "Association" everywhere
#223 Render game tags as lists
#226 Show event attendees' avatars
#230 Make the country filter searchable
#231 Search and sort the games list
#233 Store place names in English (+ backfill script)
#234 Merge duplicate tags and normalise tags on input (migration)
#241 Schema cleanup, stage 1 (migration: drops unused tables/columns, adds org status and role)
#240 Event times in the event's own time zone (migration + backfill script)
#244 Page descriptions and share images
#245 Announce new members on Discord
#246 Hide empty sections, hint members to fill them
#247 Org Bluesky handles (migration)
#248 React Router 7.18.4 + npm audit fix (supersedes #238)
#235–#237 Dependabot bumps: valibot and baseline-browser-mapping were already at the new versions; the vite range is bumped in the last commit

Left out:

Conflict resolution

The conflicts were in imports (each PR added its own) and in e2e specs (each PR appended tests). Both sides were kept everywhere. The old TYPES_COLORS constant is gone (replaced by utils/orgTypes). playwright.config.js sets TZ, DISCORD_NOTIFICATION_WEBHOOK and BLUESKY_API together. The last commit removes ogUrl imports that pageMeta made unused.

Testing

On a fresh database (all migrations from scratch, then seeded):

  • react-router build ✅
  • vitest: 137/137 ✅
  • Playwright: 73/73 ✅, in two consecutive runs

🤖 Generated with Claude Code

engleek and others added 17 commits October 4, 2026 14:11
The seed drew latitudes from the whole -90°..90° range, but Web Mercator
maps stop near ±85°: past that the tile row is negative and pigeon-maps
loads no tiles. About one place in twenty landed there, so the map-tile
e2e test failed whenever the first event happened to be one (#222's run
37188728932). Real places never are; keep seeded latitudes within ±80°.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The org page's "Games" and "Hosted events", the event page's "Games" and
/places' "Locations" headings held their count badge inside the heading,
so their text and accessible name read "Games23" for screen readers, the
document outline and crawlers.

A SectionHeading component puts the heading and its count side by side,
looking the same as before, and announces the count as "23 games".

Fixes #197.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cards showed the raw "studio" and an ad-hoc "assoc", and the org page
the bare enum value: Chakra v2's Badge upper-cased these, v3's doesn't.
The type colours were defined four times over.

One orgTypes module now holds each type's label, short label and colour
palette. Cards show "Studio" / "Assoc." on their small thumbnail badge,
the org page "Studio" / "Association", and the form and map markers
take their labels and colours from the same place.

Fixes #202.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Game cards and the game page showed tags as bare chips in a <div>,
spaced only by margins, so screen readers, copy-paste and text tools got
one run-on word ("soloplatformroguelikeaction").

A TagList component renders them as a list labelled "Tags", one item per
tag, spaced with gap; on the game page each tag still links to the
filtered games list (its name is now URL-encoded). They look the same.

Fixes #201.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The event page reads each attendee's avatar.thumbnail_url, but the
loader passed the raw image row, which has no such field, so every
attendee fell back to their initial (the stray "y" on live event pages).
computeEvent now turns participants' avatars into image links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The studio, association and event lists filtered by country with a
native select listing every country (about a hundred on live data),
which can't be searched beyond jumping to a first letter.

CountryCombobox replaces it: type to narrow the countries, shown with
their flag and count; picking one or clearing it submits the form as
before (?country=<CODE>, or no parameter), through a hidden input.

Fixes #205.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/games could only be filtered by tag and always listed recently updated
games first.

Add a search box (?q=, debounced, matching name or description, case-
insensitive) and a sort control (?sort= updated, newest or name; unknown
values fall back to updated, and orderBy is picked from a whitelist).
Both combine with the tag filters, which now keep the other parameters
when toggled, and with infinite scroll; an id tiebreak keeps pages from
overlapping.

Fixes #206.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The location picker queried Mapbox without a language, which answers
with each place's local name, so locations were saved as "Warszawa",
"Genève" or "京都市" next to English ones.

- geocodingUrl() builds every Mapbox geocoding request with language=en
  (and encodes the query); the picker uses it.
- scripts/backfill-place-names.mjs re-geocodes existing locations from
  their coordinates: dry run by default, --write to apply, paced, and it
  merges a renamed row into an identical existing one.
- The place parser referenced an undefined `address` whenever a result's
  context held an address; it reads the context entry instead.
- PhotonAutocomplete was unused (the issue first blamed it); removed.

Fixes #208.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tag list had spelling and translation variants side by side
(coop/co-op, platform/platforms/plaftorm/platformer, aventure/adventure,
shoot'em'up/shoot 'em up…), and input was only split, trimmed and lower-
cased: a trailing comma could add an empty tag and a repeated tag made
the save fail on the game_tag key.

- Migration: a tag_alias table, and merge_tag_variant(variant, canonical),
  which moves a variant's games to the canonical tag (once), deletes it
  and keeps it as an alias. It merges the pairs agreed on #207 (roguelite
  and shoot 'em up stay separate genres) and deletes nameless tags.
- Input: tags are normalised (case, spaces, apostrophes, "'em"), empty
  and repeated ones dropped, and aliases mapped to their tag, on game
  create and edit.

Fixes #207.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Part of #150, as decided there:
- Drop entity_image, entity_member, game_author and reset_token, and
  game.tag_list, game_event.tags, person.github_id, steam_id and
  password_hash (passwords are dropped: sign-in moves to Bluesky).
- Remove the sign-up, forgot and reset routes, their forms and password
  inputs, SendGrid, and the GitHub profile links (no GitHub sign-in).
- Org deletion no longer clears members; /admin/missing lists games
  without studios.
- Add entity.status (#39: active, closed, hiatus; default active) and
  game_entity.role (#40: developer, co_developer, publisher, porting,
  support; default developer). UI follows.
- Index foreign keys and filtered columns.

The migration drops with IF EXISTS / CASCADE so it doesn't depend on
production's constraint names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Event dates were formatted with whatever locale and time zone the code ran
in: cards in the viewer's (12-hour, no year), the event page in English
24-hour, so server and browser disagreed (#183's hydration errors) and
visitors abroad saw their own clock. The form sent wall-clock times
without an offset and the server read them in its own zone, so on a UTC
host every edit from France would have shifted the event.

- event.time_zone (IANA, default Europe/Paris), set from the location's
  coordinates on create and edit (offline lookup).
- eventTime.js: one formatter (en, 24-hour, year only when not the
  current one, plain spaces, hand-built ranges) and zone-aware
  conversion for datetime-local values; nothing depends on the process'
  time zone. Cards, the date label, the event page, its meta
  description and the game page's event list use it, and the form
  shows and reads times in the event's zone.
- <time dateTime> attributes used Date#toString (process time zone):
  now ISO strings.
- e2e runs the server in UTC.
- scripts/backfill-event-time-zones.mjs sets existing events' zones and
  re-reads their times as typed (saved as Europe/Paris), dry run first.

Fixes #204.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
React Router 7 doesn't merge a route's meta with its parent's, so pages
that only set a title (/games) had no description at all, the homepage,
/about and /events shared the events tagline, game and org pages built
`${about}.` ("." or "null." when empty), and only detail pages with an
image had one when shared.

pageMeta() builds the whole set in one place: title, description, Open
Graph (type, site name, absolute URL, image) and Twitter tags, with the
large card whenever there is an image. summarize() turns an "about" into
a description (Markdown stripped, one line, cut at a word around 160
characters, never just punctuation). Every public route uses them:
- list pages each get their own description;
- game, org and event pages use their about, else a generated sentence
  ("Indie game by X, tagged Y.", "Video game studio in Rennes, FR.",
  the event's date and place);
- pages without their own image share public/og-default.png, rendered
  from the logo.

The charset and viewport tags stay in Layout only.

Fixes #196.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
member's username and first name (never their email) to the existing
Discord webhook, with a link to the members page when BASE_URL is set.
Both sign-in strategies call it right after creating an account, so
signing in again doesn't repeat it; Bluesky sign-in (#157) will call it
too.

Every webhook message now sets allowed_mentions to none: game, event,
org and member names are typed by people, and one called "@everyone"
would have pinged the whole server.

Fixes #34.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
people see a short hint where there's something they can add.

- Game page: "Made by" only appears with studios, or for signed-in
  people, who get "Who made this game? Add a studio or association."
  next to the existing add button.
- Event page: "Games" and "Organizers" already showed only with content
  or to members; empty, they now hint at what to add. "Related events"
  (computed, nothing to add) is hidden when there are none.
- Org page: empty "Games" and "Hosted events" stay hidden from visitors;
  members see how to add them.

EmptyHint keeps the wording's look consistent.

Fixes #198.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sign-in): an optional bsky_handle on entity, edited in the org form and
linked from the org page with the Bluesky icon.

What people type is normalised ("@Studio.bsky.social" or a bsky.app
profile URL becomes "studio.bsky.social") and checked with Bluesky's
public resolveHandle when saving; a malformed or unknown handle is
refused with a message instead of being stored. The API base URL is
configurable (BLUESKY_API), so the e2e tests use a local stand-in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Moves the whole React Router family together, so there's one copy of
react-router (Dependabot's #238 bumped only one package and left two).
Fixes GHSA-8x6r-g9mw-2r78 (DoS via __manifest) and GHSA-84g9-w2xq-vcv6
(CSRF on PUT/PATCH/DELETE), plus the semver-compatible fixes from
npm audit fix. Audit count goes from 63 to 34.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Takes Dependabot's #236 vite range (#235's valibot 1.5.0 and #237's
baseline-browser-mapping 2.11.27 are already in the lockfile), re-syncs
the lockfile after #240's dependency, and removes the ogUrl imports the
game and event pages no longer use since pageMeta.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Notify when someone signs up

1 participant