Skip to content

feat(tools): design pass on the tools directory and tool pages - #6510

Open
tsahimatsliah wants to merge 4 commits into
claude/docker-design-review-pi3eydfrom
claude/tools-pages-design-pass
Open

feat(tools): design pass on the tools directory and tool pages#6510
tsahimatsliah wants to merge 4 commits into
claude/docker-design-review-pi3eydfrom
claude/tools-pages-design-pass

Conversation

@tsahimatsliah

@tsahimatsliah tsahimatsliah commented Aug 23, 2026

Copy link
Copy Markdown
Member

Design pass over /tools and /tools/[slug], based on review feedback. Based on claude/docker-design-review-pi3eyd (the in-progress design-review branch this iterates on) so the diff shows only this work — intentional stack order; that branch gets its own PR when it stabilises.

What changed

Directory search. One field in the hero, mirroring the tags directory — live client-side filtering by title, category and website domain, no results page. The catalogue is under a hundred tools, so getStaticProps fetches each category whole and the same data powers the sections and the search index. A charm empty state with a "Clear search" action covers the no-match case, a debounced search tools event records usage, and result clicks carry searched: true so they are distinguishable from browsed clicks.

Single-copy payload. Sections and rails reference the catalogue by id instead of embedding full tool objects, so each tool ships once in __NEXT_DATA__. getStaticProps warns when a category hits the fetch limit, so search truncation cannot happen silently as the catalogue grows.

Squad cards. Squads on a tool page use the Squad directory's card layout (avatar, name, description, @handle · N members). Added description to the squad query.

Inline "add to my stack". Tool cards carry the tags directory's affordance — a persistent check when the tool is already in your stack, a + otherwise. Hover-revealed on pointer devices, always visible below the tablet breakpoint so touch users never face an invisible-but-tappable control. The whole add flow (auth gate, log event, modal, toasts) is one useAddToolToStack hook shared by the directory and the tool page.

Sections, panels, surfaces. Section rules run out of the heading; stat tiles and the adoption chart share one panel; card surfaces are outlined, matching the tag pages.

Logo contrast

23 of the 88 logos in the catalogue are near-black Simple Icons assets — Angular #0F0F11, Express/Cursor/Vercel/Next.js/Rust #000000, GitHub #181717 — and were invisible, not merely low-contrast, on dark surfaces.

Recolouring isn't available: the fill sits on the root <svg> of an <img>-loaded asset, so CSS can't reach it, and a Cloudinary e_colorize would flatten the multi-colour and raster logos too. What makes the plate safe is that no logo in the catalogue is white — the six "light" ones are saturated yellows and cyans (JS #F7DF1E, React #61DAFB) that stay legible on white. bg-white on logos is already the established pattern for sponsored creatives in UserStackItem.

Discussion section

A tool with no discussion yet shows the charm empty state (with a loading state while the post is created) instead of a bare input-looking button. The gates read isLoggedIn instead of !!userequivalent in behaviour, since AuthContext already exposes a null user for anonymous visitors; it just states the intent directly. An earlier revision of this PR claimed the !!user gate caused a never-resolving skeleton for visitors; review correctly traced AuthContext and showed that state is unreachable. The test fixtures now mirror the provider honestly: anonymous = no user, logged-in = the loggedUser fixture with isLoggedIn derived from it.

Review resolutions

  • ToolDiscussion root cause — narrative retracted (see above); isLoggedIn refactor kept, misleading comments removed.
  • Test fixture — impossible user + isLoggedIn: false pairing removed; two honest fixtures, anonymous default, plus a logged-in test covering the verification gate.
  • Touch — stack button is opacity-100 below tablet, hover-revealed above it.
  • DuplicationuseAddToolToStack(origin) extracted; both pages consume it.
  • Analytics — dead origin param gone; searched: true on result clicks; debounced LogEvent.SearchTools with query + result count.
  • Payload — id references + single catalogue; limit-hit warning instead of silent truncation.
  • Tooltip on disabled button — button stays enabled with aria-disabled + no-op guard, so "In your stack" can actually show; aria-pressed dropped.
  • Search empty state / match fields — charm empty state with clear action; matching extended to category + domain.
  • as PublicProfile casts — consolidated into the hook as (user ?? null) as PublicProfile | null, keeping the null path visible.
  • Card link a11y — stack count folded into the anchor's accessible name. Text stays unselectable in favour of whole-card clickability.
  • Comment pass — narrative comments stripped throughout; only behavioural notes remain.

Verification

  • 11/11 tests pass across both specs (4 new: search filtering, category/domain matching, clear-search flow, logged-in verification gate)
  • Lint clean on every changed file; typecheck unchanged at the branch's 17 pre-existing errors, none in tools code
  • Mobile at 375px: stack control visible (opacity: 1), no horizontal overflow; card anchors expose "title, N in stacks"
  • Local dev-server hydration is flaky in this worktree (Turbopack workspace-root quirk, affects untouched pages like /tags equally) — interactive search flows are covered by the jest specs and worth a click-through on the Vercel preview

🤖 Generated with Claude Code

Preview domain

https://claude-tools-pages-design-pass.preview.app.daily.dev

@vercel

vercel Bot commented Aug 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
daily-webapp Ready Ready Preview Aug 23, 2026 1:45pm
storybook Building Building Preview Aug 23, 2026 1:45pm

Request Review

@tsahimatsliah tsahimatsliah left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Solid design pass — the outlined surfaces, merged adoption panel and the shared squad card all read as consistency wins, and the section-rule treatment matches the tags directory. Two things I'd resolve before merge: the stated root cause of the discussion bug doesn't match what AuthContext actually exposes (and the new default test fixture encodes a state the provider cannot produce), and the inline stack button is invisible-but-tappable on touch. Rest is non-blocking.

Also worth confirming: this targets claude/docker-design-review-pi3eyd, which has no open PR of its own — so merging this lands in an unreviewed branch. Intentional stack order?

Needs resolution

  1. ToolDiscussion — the anonymous-visitor bug narrative and the regression test's premise.
  2. ToolCard — hover-only + on touch devices.

Non-blocking

Duplicated add-to-stack flow, search analytics + dead origin param, searchIndex payload duplication, tooltip on a disabled button, search empty state and match fields, as PublicProfile casts, link-name/selectability on the new card.

Verification

  • CI green, including typecheck_strict_changed and both test packages
  • Traced AuthContext to check the claimed anonymous user behaviour
  • Checked useUserStack / useProfileShowcase gating for anonymous visitors (enabled: !!userId — no stray request, since context user is null when logged out)
  • Not verified by me: preview at 375px, and the discussion section as a real logged-out visitor

Reviewed by AI.

Comment thread packages/webapp/components/tools/ToolDiscussion.tsx
Comment thread packages/webapp/__tests__/ToolPage.spec.tsx Outdated
Comment thread packages/webapp/components/tools/ToolCard.tsx Outdated
Comment thread packages/webapp/pages/tools/index.tsx Outdated
Comment thread packages/webapp/pages/tools/index.tsx
Comment thread packages/webapp/pages/tools/index.tsx Outdated
Comment thread packages/webapp/components/tools/ToolCard.tsx Outdated
Comment thread packages/webapp/pages/tools/index.tsx Outdated
Comment thread packages/webapp/pages/tools/index.tsx Outdated
Comment thread packages/webapp/components/tools/ToolCard.tsx Outdated
Search, squad cards, inline stack actions and a set of visual fixes across
/tools and /tools/[slug].

- Search the whole catalogue from the directory hero, mirroring the tags
  directory: one field, live client-side filtering by title, category and
  website domain, a charm empty state with a clear action when nothing
  matches, and a debounced `search tools` event. Result clicks carry
  `searched: true` so they are distinguishable from browsed clicks.
- The page payload ships each tool once: sections and rails reference the
  catalogue by id instead of embedding full copies, and the catalogue also
  serves as the search index. getStaticProps warns when a category hits the
  fetch limit so search truncation cannot happen silently.
- Squads on a tool page render as directory-style cards (avatar, name,
  description, handle + members). Needed `description` on the squad query.
- Tool cards carry an inline "add to my stack" control, revealed on hover
  on pointer devices and always visible below the tablet breakpoint so
  touch users never face an invisible-but-tappable control. The add flow is
  one hook (useAddToolToStack) shared by the directory and the tool page.
- Section rules run out of the heading; stat tiles and the adoption chart
  share one panel; card surfaces are outlined, matching the tag pages.
- Tool logos sit on a light plate. 23 of the 88 logos in the catalogue are
  near-black Simple Icons assets (Angular #0F0F11, Express #000000, ...)
  and were invisible on dark surfaces. The fill is on the root <svg> of an
  img-loaded asset so CSS cannot recolour it, and no logo in the catalogue
  is white, so a light plate helps all of them without breaking any.
- Hero: logo fills its tile, actions drop to Small, the vote pair uses the
  same Float buttons as Discuss/Share, and a tool with no discussion yet
  shows the charm empty state (with a loading state while the discussion
  post is being created) instead of a bare input-looking button.
- Discussion gates read `isLoggedIn` instead of `!!user`. Equivalent in
  behaviour - AuthContext already exposes a null user for anonymous
  visitors - but it states the intent directly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Same treatment as the tag pages: HorizontalFeed inside EntityRailWithFade,
fed by TAG_FEED_QUERY on the tool's keyword, replacing the vertical list
rows. The SSG topPosts fetch stays - it still powers the JSON-LD ItemList
and gates the section so a tool without posts shows no empty rail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The tool page mounted MainLayout without FeedLayoutProvider, so FeedContext
fell back to its default numCards of 1 and the horizontal grid sized every
card at 100% of the rail. Use the same FeedLayout the tag pages use, which
provides viewport-derived numCards.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
FeedLayoutProvider derives the column count from the viewport on the
assumption that the feed spans the page, but the tool page's content box is
capped at max-w-screen-laptop - on wide screens up to six columns got
crammed into a ~976px rail. Scope the provider to the rail with
maxNumCards={3} (its documented purpose) and drop the page-level FeedLayout
switch it replaces.

Co-Authored-By: Claude Opus 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.

1 participant