feat(ui): /noodles archive page#2779
Conversation
Introduces a public archive for every noodle (seasonal/event logo variants) shown on npmx, plus a contributor-friendly layout for adding new ones. What's new - /noodles lists every entry as a card (logo preview + date range or "always available" badge for permanent noodles). - /noodles/[slug] renders a per-noodle markdown page with hero logo, story body, authors, and an image gallery with click-to-lightbox. - modules/noodles.ts scans app/pages/noodles/*.md, validates frontmatter with valibot, resolves Bluesky avatars at build time, and exposes #noodles/entries. - app/components/Noodle/index.ts now derives ACTIVE/PERMANENT noodle arrays from #noodles/entries, so contributors only edit the .md file and the logo registry. - New NoodleGallery + NoodleLightbox (custom dialog-based, no external lib) and NoodleListCard for the archive grid. - Dedicated NoodlePostWrapper registered by the noodles module with a scoped include pattern, so blog and noodle markdown files don't share a wrapper. Blog module's include narrowed to pages/blog/. Other touches - Footer "Other" section now links to /noodles. - canonical-redirects.global.ts allowlist gains /noodles so the server middleware doesn't shortcut it to /package/noodles. - a11y test coverage for the four new components. - i18n keys under noodles.* (English only; CI syncs other locales). Seed Two stub .md files (press, kawaii) marked draft: true ship with this commit so the archive has content immediately. Gallery images should live under public/noodle-gallery/[key]/ — keeping them out of public/noodles/ avoids shadowing the /noodles route in dev.
- Landing /noodles hero: solid filled "bowl" (thick theme-aware border, inner + outer shadow), npmx sticker overlapping, thicker dark stripe background with wider gaps. Headings bumped to mono text-xl semibold uppercase per the Figma spec. - Individual noodle pages: restructured into an agency-style case study — full-bleed hero with the bowl, credits row (avatar + name + @handle, N authors), tombstone strip (dates · status), prose body, editorial numbered Figures section, footer back link. - New Noodle/Figures.vue: numbered Fig.NN editorial figure list with lightbox, replaces the 4-tile gallery on individual noodle pages. - New Noodle/BuildLog.vue: scroll-snap drafts → shipped strip, ready to wire once noodles get an authored drafts schema. - ListCard icon: maximize-2 → arrow-up-right (clearer "navigate to"). - Kawaii noodle: gave it active dates (no more "always available"), removed the /?kawaii parenthetical from the body stub. - Press noodle: populated with multi-author credits, real excerpt, 4-section body (brief · decisions · process · cuts), and a 4-image gallery so the case-study layout has something to render. - i18n (en): added noodles.credits, status, status_draft, status_shipped, figures. - Gitignore public/noodle-avatar/ (Bluesky avatars are fetched at build time, mirrors the existing public/blog/avatar pattern).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a noodle archive and Valibot schema, new logo components and a central resolver, list/detail Nuxt pages with pagination and SEO, a carousel and list card UI, a Nuxt module to cache Bluesky avatars to public/noodle-avatar, and app integration including header/footer links, i18n and accessibility tests. ChangesNoodles Feature — Logo Doodles Archive
Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Lunaria Status Overview🌕 This pull request will trigger status changes. Learn moreBy default, every PR changing files present in the Lunaria configuration's You can change this by adding one of the keywords present in the Tracked Files
Warnings reference
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
- Add a11y tests for Noodle/Figures and Noodle/BuildLog. - Remove unused Noodle/Gallery (replaced by Noodle/Figures). - Drop unused i18n keys noodles.credits and noodles.gallery.
Team feedback: noodle write-ups would become a blocker, and the current detail content is placeholder anyway. Strip the case-study scaffolding — keep the /noodles archive landing page only. - Delete NoodlePostWrapper, BuildLog, Figures, Lightbox. - Delete press.md and kawaii.md (and the markdown vite plugin that turned them into routes). - Replace the noodles Nuxt module with a hand-edited TS registry at app/noodles.ts. Adding a noodle is now: drop a logo, register it in Noodle/index.ts, append an entry. No frontmatter required. - Slim shared/schemas/noodle.ts to a single Noodle type — only key, title, slug are required; date/dateTo/timezone/tagline/prUrl/draft optional. - ListCard: when prUrl is set the card becomes an external link to the shipping PR; otherwise it's a non-interactive tile (no broken link to a detail page). - Drop unused i18n keys (status, figures, lightbox, gallery, etc.). - Drop a11y tests for the removed components. - Revert storybook .md ignore + .gitignore noodle-avatar entries.
Team feedback: per-noodle write-ups would become a blocker, and the existing detail content was placeholder anyway. Strip the case-study scaffolding — keep the /noodles archive landing page only. - Delete NoodlePostWrapper, BuildLog, Figures, Lightbox. - Delete press.md and kawaii.md (and the markdown vite plugin that turned them into routes). - Replace the noodles Nuxt module with a hand-edited TS registry at app/noodles.ts. Adding a noodle is now: drop a logo, register it in Noodle/index.ts, append an entry. No frontmatter required. - Slim shared/schemas/noodle.ts to a single Noodle type — key, title, slug, date required; dateTo/timezone/tagline/prUrl optional. - Drop the "permanent noodle" concept entirely — all noodles are historical (have a date). Query param ?<key> still triggers any noodle regardless of date; otherwise activation falls back to the noodle's date range. - ListCard: when prUrl is set the card becomes an external link to the shipping PR; otherwise it's a non-interactive tile. - Drop unused i18n keys (status, figures, lightbox, gallery, etc.). - Drop a11y tests for the removed components. - Revert storybook .md ignore + .gitignore noodle-avatar entries.
…on blend - Restore the artemis noodle from npmx PR npmx-dev#2421/npmx-dev#2424. The light/dark SVGs were already in public/extra/; the SFC was removed when press was added. Registered in Noodle/index.ts and app/noodles.ts with the original April 2026 date range. - Drop the `?<key>` query-param branch from IntroHeader — all noodles are historical now, so activation is purely date-based. - Match Kawaii's hover/scale animation on Press, so all three noodles feel consistent on the homepage. - Remove the press-day tooltip — it leaks into the /noodles archive card on hover. - Bowl moon image was showing its black/white rectangle background in the bowl on /noodles. Add `mix-blend-lighten light:mix-blend-darken` so it dissolves into the bowl bg in both themes (same trick the artemis logo uses). - Stamp prUrl on press + artemis so their cards link to the shipping PR.
Per Alex's note: detail page always exists, but content is non-blocking. - New dynamic route app/pages/noodles/[slug].vue. Required content: hero bowl + title + occasion one-liner + dates. Optional sections only render when the registry entry has them filled in (description, processImages). - Schema gains optional `occasion`, `description`, `processImages`. Each existing entry now ships with an `occasion` line; the rest is blank and can be added per-noodle later. - Archive ListCard links back to the detail page (instead of jumping straight to the PR). The PR link moves to the detail page tombstone. - Cool "empty bowl" 404 — when /noodles/<unknown> is hit, the page still renders the bowl shape and a "this noodle never made it out of the bowl" message with a path back to /noodles. Server returns a 404 status to crawlers; humans see the friendly UI. Note on the missing "pride" noodle: no standalone pride PR exists. The cute-transgender variant in public/extra/ is a revision of the kawaii noodle (PR npmx-dev#2349), not a separate noodle. Surfaced in the kawaii entry's `occasion` line.
…wl content - Add Noodle/KawaiiPride/Logo.vue using npmx-cute-transgender.svg. - Original Kawaii reverts to npmx-cute.svg (pink/peach), tied to PR npmx-dev#2346 — the same-day pride revision (PR npmx-dev#2349) now lives as a distinct registry entry so both ship in the archive as history. - Detail-page bowl gains `flex items-center justify-center` so the logo / 404 ? glyph centers properly inside the circle.
…nsive pass - Restore the "what is noodles" section on /noodles landing — Alex flagged it had gone missing during the slim-down. Body simplified to a single paragraph (the previous copy was repeated 5x). - Authors field on noodles. Default duo Alex (alexdln.com) + Alfon (alfon.dev) credited on all four current noodles since they paired on both design and shipping PRs. - Credits column on the detail-page tombstone — name + linked @handle, flex-wrap so multiple authors stay tidy. - Load-more pagination on /noodles. Default shows the latest 10, a "Load N more" button reveals the next page. Renders nothing when the archive fits in one screen. - Responsive tweaks: smaller bowl (w-60 → w-96), thinner bowl border (10px → 14px), smaller hero title (text-3xl → text-6xl) and sticker (w-20 → w-40) on mobile; detail-page header/title scale down too. Tombstone goes one column on mobile, three on sm+. - Drop the duplicate what_is/what_is_body i18n keys. - max-w-prose removed from the what-is paragraph per request.
- Replace `container` on noodle main with plain px-4 sm:px-6 — the container utility was disturbing the bowl hero layout. Padding is what we actually needed. - Credits now render via the shared AuthorList expanded variant (same component the blog uses) — avatar + name + @handle, flex-wrap. Authors registry entries stay minimal: { name, blueskyHandle }. Avatars fall back to initials when not resolved. - Drop the manual credits column from the tombstone; tombstone is back to two columns (dates · shipped in). - Default duo Alex (alexdln.com) + Alfon (alfon.dev) credited on all four noodles per the team — they pair on design + shipping.
Per feedback, credits don't belong above the title — they live in the metadata row alongside dates / shipped-in. Switched to the compact AuthorList variant so the row stays tight (stacked avatars + names), tombstone is now three columns on sm+, one on mobile. Also drop the px-4 sm:px-6 from main: padding belongs on the content article, so the hero spans full bleed without negative margins.
- Tombstone is two columns again (dates · shipped in). Credits sits on its own row below with col-span-full, so multi-author noodles no longer crowd the dates/PR columns. Switch back to the expanded AuthorList variant since we have the horizontal room. - Add px-4 sm:px-6 to /noodles landing article so cards + headings don't hug the viewport edge on mobile. - Remove the px-4 sm:px-6 I left on the [slug].vue main; padding lives on content blocks now (consistent with landing), hero stays full-bleed.
Addresses team feedback on PR npmx-dev#2779: - New Noodle/Carousel.vue — horizontal scroll-snap carousel with prev/next chevrons and pagination dots. Replaces the stacked figures section on the noodle detail page. - Press noodle seeded with dummy processImages so the carousel is reachable for review at /noodles/press. - Mobile nav: /noodles link added to the About & Policies group. Was missing from the mobile menu (only existed in the footer). - All four noodle Logo SFCs: drop the hover:scale-105 zoom (Alex's note that hover-zoom-without-fullscreen-open is confusing) and the mb-8 bottom margin (was throwing the archive card centering off, especially on mobile). - Artemis reverted to wordmark-only — the moon overlay was fighting the bowl/card layout. We can reintroduce it as a parent-positioned backdrop on the homepage hero later if needed.
- /noodles landing bowl: stop rendering the moon image in light mode. The PNG has a hard black rectangle bg and mix-blend can't make black drop out cleanly against a near-white bowl — fix is just to skip it in light. Dark mode still gets the moon with mix-blend-lighten. - Artemis logo gets its moon overlay back (per Alex / further design discussion).
Per Graphieros — the bowl reads like a magnifying glass, so use it as one. Logo + processImages now scroll horizontally inside the bowl; the lens stays fixed, slides pass under it. Drops the separate Process section since it's redundant now. - Lens chrome (rounded clip, border, inset shadow, drop shadow) is unchanged — just hosts a snap-x scroller now. - Logo is slide 1; each processImage follows. - Chevrons float off the lens edges; dots sit below the bowl. Both only render when there are 2+ slides, so single-logo noodles read as before. - New i18n: noodles.lens_label, noodles.lens_slide.
- Lens carousel now loops infinitely. Slides are rendered 3× so native scroll-snap can wrap seamlessly: on mount the scroll position lands in the middle copy, and a scrollend handler snaps us back when the user crosses either edge. Prev/next pick the shortest-path direction so wrapping always feels like a single step. Chevrons are no longer disabled at the extremes. - Carousel only mounts the scroller when the noodle has process images. Without process images, the bowl statically renders the logo (no scroll container, no chevrons, no dots). - Keyboard navigation: scroller is focusable (tabindex=0) with ArrowLeft/ArrowRight to step through slides, Home/End to jump to first/last. Focus ring uses the accent token, applied with focus-visible only so mouse users don't see it. - ARIA: role=region + aria-roledescription=carousel on the scroller; each visible slide gets role=group + an aria-label like "Slide N of M". Duplicate copies are aria-hidden so screen readers don't read the same content three times.
- prefers-reduced-motion is honored when scrolling between slides (uses VueUse's useMediaQuery — same pattern as the rest of the codebase). Drops the inline matchMedia setup. - Pagination dots get a focus-visible ring (accent-coloured, offset from the bowl bg) — they were keyboard-focusable already but the focus state was invisible. - New sr-only aria-live=polite region under the dots: announces "Slide N of M" when activeSlide changes, since focus stays on the scroller while slides move under it. - Drop aria-label="404" from the 404 page's kicker text — was overriding the visible "404 — empty bowl" string for screen readers; visible text is fine to read as-is.
- New OgImage/Noodle.takumi template renders the noodle's posterImage alongside title + occasion. Detail page picks Noodle.takumi when an entry has a posterImage, falls back to Page.takumi otherwise. - /noodles landing also gets a Page.takumi og image so the archive link previews properly. - posterImage stamped on every noodle: dark press PNG for press, the cute SVG for kawaii, trans SVG for kawaii-pride, dark artemis SVG for artemis. - Chevrons: hidden on mobile (touch swipe is the primary input there), bigger and pushed off the lens on desktop (-inset-is-16 / lg:-24, text-3xl, larger padding). - Comment pass per request: dropped redundant <!-- HERO/BODY/404 --> labels, collapsed multi-line explanations to single lines where the WHY needed surfacing, and trimmed the JSDoc blocks on the noodle registry + schema since the types already convey shape.
OgBrand uses Nuxt's auto-imported `computed` — when nuxt-og-image re-loads the component via its og-image-depth pipeline, the auto- imports don't apply and rendering throws "computed is not defined". Inlining the logo keeps the template self-contained.
The flex layout had max-w-[60%] + max-w-[40%] + gap-12 which sums above 100% and pushed the poster image off the right edge of the OG canvas. Switched to a flex-1 left + shrink-0 fixed-width right arrangement, and used explicit inline styles for the poster's object-fit to be safe under Takumi rendering.
Takumi/Satori doesn't support mix-blend-mode, which is what the landing/detail bowl uses to drop the moon image's black rectangle against the dark bowl bg. Without it, the OG card showed the bare photo rectangle. Keeping the schema's optional posterBackdrop field — works as soon as we ship a properly alpha-channelled moon asset.
- Detail page is now a two-column grid inside the striped hero:
- Left: the lens (bowl + chevrons + dots + sr-live region),
sticky from lg: so it stays in view while the right column
grows with description content.
- Right: a rounded card holding title, occasion, optional
description, then a divider and the dates / shipped-in /
credits metadata.
- 404 reuses the exact same shell (lens with a `?` glyph, card
with the empty-bowl message), so missing slugs feel like the
same page rather than a separate template.
- "Back to all noodles" lives at the top of the hero, inside the
striped band, replacing the bottom footer link.
- Chevrons stay as the big buttons next to the lens; dots and the
live region hang under the bowl.
…point - Hero section now flex-1 inside a flex-col main, so the striped background fills the viewport instead of stopping at the content and leaving a black void above the footer on tall screens. - Two-column grid + sticky lens kick in at xl: (1280px) instead of lg: (1024px). iPad Pro 1024 was hitting the desktop layout too early and looked cramped — that breakpoint now stacks like md.
Section is now flex flex-col with the nav pinned at the top and the grid in flex-1 + content-center so the lens/card sit in the middle of the remaining vertical space. Stops the lens from hugging the top with a huge striped void below.
Centering broke the sticky scroll feel. Grid is back to items-start so the lens column anchors to the top — and stays there via xl:sticky xl:top-24 while the card scrolls past on tall content.
- Remove overflow-x-hidden from the detail page main. overflow-x: hidden with overflow-y: visible computes overflow-y as auto per spec, which turned main into a scroll container and trapped the sticky lens so it never engaged on page scroll. - Strip the dummy processImages and description from the press entry now that previews are no longer needed.
When I moved the carousel into the lens, the standalone Noodle/Carousel.vue stopped being imported (knip + a11y coverage flagged it) and the noodles.process heading was never re-used (i18n flagged it as unused). Removing both.
A place to look back at noodles we've shipped — a little museum for past npmx logos.
/noodlesis the archive grid. Each card opens a detail page with the full-size logo, the day/event it ran for, dates, the PR it shipped in, and credits.The detail page is intentionally light: only the basics are required (title, slug, date, a one-line occasion). Longer write-ups and process images are optional, so adding a noodle never gets blocked on having a story written for it.
Highlights
/noodlesarchive grid, latest 10 shown with a load-more button./noodles/:slug) with a friendly bowl 404 for unknown slugs.app/noodles.ts— drop a logo, register it, add an entry.AuthorListthe blog does; avatars resolved at build time via a smallmodules/noodles.ts.Screenshots
Landing — /noodles archive
Screen.Recording.2026-05-22.at.16.33.17.mov