feat(tools): design pass on the tools directory and tool pages - #6510
feat(tools): design pass on the tools directory and tool pages#6510tsahimatsliah wants to merge 4 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
tsahimatsliah
left a comment
There was a problem hiding this comment.
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
ToolDiscussion— the anonymous-visitor bug narrative and the regression test's premise.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_changedand both test packages - Traced
AuthContextto check the claimed anonymoususerbehaviour - Checked
useUserStack/useProfileShowcasegating for anonymous visitors (enabled: !!userId— no stray request, since contextuseris null when logged out) - Not verified by me: preview at 375px, and the discussion section as a real logged-out visitor
Reviewed by AI.
766ce06 to
f331508
Compare
f331508 to
e6f8ee7
Compare
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>
e6f8ee7 to
a27dff9
Compare
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>
Design pass over
/toolsand/tools/[slug], based on review feedback. Based onclaude/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
getStaticPropsfetches 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 debouncedsearch toolsevent records usage, and result clicks carrysearched: trueso 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__.getStaticPropswarns 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). Addeddescriptionto 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 oneuseAddToolToStackhook 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 Cloudinarye_colorizewould 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-whiteon logos is already the established pattern for sponsored creatives inUserStackItem.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
isLoggedIninstead of!!user— equivalent in behaviour, sinceAuthContextalready exposes a nulluserfor anonymous visitors; it just states the intent directly. An earlier revision of this PR claimed the!!usergate caused a never-resolving skeleton for visitors; review correctly tracedAuthContextand showed that state is unreachable. The test fixtures now mirror the provider honestly: anonymous = no user, logged-in = theloggedUserfixture withisLoggedInderived from it.Review resolutions
isLoggedInrefactor kept, misleading comments removed.user+isLoggedIn: falsepairing removed; two honest fixtures, anonymous default, plus a logged-in test covering the verification gate.opacity-100belowtablet, hover-revealed above it.useAddToolToStack(origin)extracted; both pages consume it.originparam gone;searched: trueon result clicks; debouncedLogEvent.SearchToolswith query + result count.aria-disabled+ no-op guard, so "In your stack" can actually show;aria-presseddropped.as PublicProfilecasts — consolidated into the hook as(user ?? null) as PublicProfile | null, keeping the null path visible.Verification
opacity: 1), no horizontal overflow; card anchors expose "title, N in stacks"/tagsequally) — 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