Conversation
Complete frontend rebuild of ClawHub into a marketplace-style discovery hub inspired by HuggingFace and npm. No backend changes. Navigation: - Two-row header: brand + search bar + user actions on top, content type tabs (Skills, Plugins) with count badges below - Inline search in navbar navigates to /search - Mobile: search collapses behind icon, tabs scroll horizontally Home page: - Value-prop hero with Browse/Publish CTAs (no duplicate search) - Trending section (8 skills by downloads) - Recently updated section (8 skills by update time) - Staff picks grid (6 highlighted skill cards) - Browse by category grid (8 categories with Lucide icons) - Skeleton loading rows while data fetches Browse pages (Skills + Plugins): - Full-width search bar above sidebar+results grid - Left sidebar with sort options, categories, filter checkboxes (proper ARIA: fieldset/legend, role=radiogroup, aria-checked) - List view uses compact SkillListItem rows (owner/name/summary/meta) - Card view with hover border feedback - View toggle (List/Cards) - Better empty states with guidance text Skill detail page: - README tab as default (was Files) - Two-column layout: tabs+comments on left, metadata sidebar on right - Removed duplicate README from Files tab - Removed duplicate Download button from header (kept in sidebar) - Removed SkillInstallCard from header (license info in sidebar) - Nix/config snippets moved inside two-column layout - Friendly "No README available" instead of raw Convex errors Unified search (/search): - Real search results page (was redirect-only) - Type tabs: All / Skills / Plugins with counts - useUnifiedSearch hook fires skill search + plugin catalog in parallel - Consistent SkillListItem rendering for results Dashboard: - Welcome state for new users with empty dashboard - Simplified header copy Profiles & Footer: - Richer user profiles: large avatar, stat row, SkillListItem for published/starred skills - Multi-column footer: Browse / Publish / Community / Platform Design system: - Spacing tokens: --space-1 (4px) through --space-8 (64px) - Typography scale: --fs-xs through --fs-3xl (8 values, was 42) - Radius tokens: --r-lg/md/sm/xs/pill (renamed from --radius-* to avoid Tailwind CSS v4 variable collision) - Flat buttons (killed gradient, removed hover lift/shadow) - Complete markdown styles: tables, blockquotes, lists, images, hr, heading hierarchy with h1/h2 bottom borders (npm-style) - Removed decorative elements: body gradient backgrounds, card shadows, brand mark animation, category card glow New components: - SkillListItem — compact HF-style row - BrowseSidebar — faceted filter sidebar with ARIA - SkillMetadataSidebar — detail page right sidebar - useUnifiedSearch — parallel search hook - timeAgo — relative time formatter - categories — static skill category taxonomy Seed data: - seedDemo.ts with 20 realistic skills, 5 publishers - repairHighlightedBadges for skillBadges table - repairGlobalStats for correct count Test updates: - Updated 5 test files for new text, class names, and prop changes - All 122 test files, 915 tests passing
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis is a substantial frontend-only marketplace UI overhaul — new discovery hub home page, faceted browse sidebar, unified search page, and HuggingFace/npm-style list rows. All the home-page and Header data-fetching has been correctly migrated to Key issues found:
Confidence Score: 3/5Safe to merge after fixing the Score lowered from 5 primarily due to the
Prompt To Fix All With AIThis is a comment left during a code review.
Path: convex/seedDemo.ts
Line: 3
Comment:
**Wrong import — bypasses trigger wrapping**
`internalMutation` is imported from `./_generated/server`, but `convex/functions.ts` exports a wrapped version that includes trigger/`wrapDB` context. Per the project's CLAUDE.md:
> All mutations import from `convex/functions.ts` (not `convex/_generated/server`) to get trigger wrapping.
`convex/functions.ts` line 380 confirms the wrapped export exists:
```ts
export const internalMutation = customMutation(rawInternalMutation, customCtx(triggers.wrapDB));
```
Seeding through the un-wrapped version means denormalized/trigger-synced tables (e.g. `skillSearchDigest` or stats rollups) won't be kept in sync if trigger handlers are registered on these tables.
```suggestion
import { internalMutation } from "./functions";
```
This applies to all three exported mutations in this file (`seedDemoSkills`, `repairGlobalStats`, `repairHighlightedBadges`).
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: src/routes/skills/index.tsx
Line: 134
Comment:
**`activeCategory` is hardcoded to `undefined` — category selection has no visual feedback**
`activeCategory={undefined}` is a constant, so the "All" radio option always renders with `aria-checked="true"` regardless of which category the user clicked. `handleCategoryChange` correctly updates the search query via `model.onQueryChange`, but there is no inverse mapping from the current `model.query` back to a category slug.
As a result: clicking "MCP Tools" sets the search query to `"mcp"` but the sidebar continues to show "All" as selected. This is both a broken ARIA state (`aria-checked` on the actual category button stays `false`) and a visual UX regression.
A minimal fix is to derive `activeCategory` from the current query:
```ts
const activeCategory = useMemo(() => {
if (!model.query) return undefined;
return (
SKILL_CATEGORIES.find((c) =>
c.keywords.some((k) => k === model.query.trim().toLowerCase()),
)?.slug ?? undefined
);
}, [model.query]);
```
Then pass `activeCategory={activeCategory}` to `<BrowseSidebar>`.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: convex/seedDemo.ts
Line: 369-376
Comment:
**JS filtering after `.collect()` scans the full `skillSearchDigest` table**
The index query on `by_active_updated` already constrains `softDeletedAt === undefined`, so the additional `!d.softDeletedAt` JS check is redundant. More importantly, the `moderationStatus === "active"` condition is applied entirely in JavaScript after collecting all documents, which reads and bills for the full table. Per AGENTS.md:
> `.filter().collect()` without an index causes full table scans — every doc is read and billed.
Consider using a Convex `.filter()` call to push the predicate server-side:
```ts
const count = await ctx.db
.query("skillSearchDigest")
.withIndex("by_active_updated", (q) => q.eq("softDeletedAt", undefined))
.filter((q) => q.eq(q.field("moderationStatus"), "active"))
.collect()
.then((r) => r.length);
```
Even as a repair utility this can time-out on large deployments and hits the 32K document read limit once the real catalog grows.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: convex/lib/githubActionsOidc.test.ts
Line: 3
Comment:
**Unused `vi` import**
`vi` is imported from `vitest` but is never referenced in this file. This will cause a lint warning under the project's Biome / oxlint setup.
```suggestion
import { describe, expect, it } from "vitest";
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "feat: marketplace UI overhaul — HuggingF..." | Re-trigger Greptile |
- Import internalMutation from convex/functions (not _generated/server) to get trigger wrapping per CLAUDE.md rules - Derive activeCategory from current search query so sidebar category selection shows correct visual/ARIA state - Push moderationStatus filter server-side in repairGlobalStats to avoid full table scan - Reset skillCount/pluginCount to 0 in useUnifiedSearch catch block to prevent stale badge values after search errors
- Remove unused imports (v, getRuntimeEnv) from seedDemo.ts and SkillHeader.tsx - Replace `as any` casts with proper Id<"publishers"> types in seedDemo.ts - Prefix unused params with underscore (_clawdis, _osLabels, _nixSystems, _listDoneLoading) - Remove unused convexSiteUrl variable from SkillHeader
- Switch light theme from warm beige (#f8f2ed) to neutral white (#fafafa) with neutral gray ink (#1a1a1a) and borders (rgba black) - Switch dark theme from warm brown to neutral dark (#111111) with neutral gray borders (rgba white) - Replace fake category grid (8 keyword-search cards) with curated quick links (Most starred, New this week, Browse plugins, Staff picks) - Add "What are skills?" explainer paragraph below hero CTAs - Add fadeIn animation on results list when data arrives - Add "Clear" button in browse results toolbar when filters are active - Tighten browse layout gap from 24px to 16px
Complete visual redesign to a dark, monochrome, terminal-inspired aesthetic inspired by Warp, modern TUI tools, and blueprint designs. Color system: - Default is now dark (#0a0a0a bg, #e0e0e0 ink, #141414 surface) - All accent colors removed — monochrome only (white as accent) - Borders use rgba(255,255,255,0.08) for subtle separation - Light theme available as optional override via [data-theme="light"] Typography: - All fonts now IBM Plex Mono (display, body, code all monospace) - Brand name is lowercase monospace - Section titles are uppercase monospace with letter-spacing - Tags and badges use monospace font Geometry: - All border-radius reduced to 1-2px (sharp TUI corners) - No shadows anywhere (--shadow: none) - No backdrop-filter blur on navbar - Cards, buttons, inputs all have sharp edges Components: - Buttons: transparent bg with border, monospace text - Primary buttons: white on black (inverted) - Tags: border-only, no colored backgrounds - Cards: dark surface with subtle border - Brand mark: 24px square instead of 28px circle Layout: - Replaced category grid with simple quick links - Removed all warm color references - Home section titles are small uppercase labels - Skill list item names use --ink (no accent color)
Theming (P0): - Removed all 78 [data-theme="dark"] override selectors (dark is now default, these were dead code with conflicting warm colors) - Replaced 56 instances of rgba(255,107,74,x) warm coral with rgba(255,255,255,x) monochrome equivalents - Replaced hard-coded warm hex colors (#c35640, #ff6b4a, etc.) with gray monochrome values - CSS file reduced from ~6300 to 5909 lines Touch targets (P1): - Added min-height: 36px to .btn (was ~24px) - Added min-height: 36px to .navbar-tab (was ~27px) - Added min-height: 32px to .sidebar-option and .sidebar-checkbox - Increased padding on buttons and tabs Accessibility (P2/P3): - Comprehensive prefers-reduced-motion: reduce rule — disables all animations AND transitions for users who prefer reduced motion - Covers shimmer, fadeIn, fadeUp, and all CSS transitions
- Home page sections only render when data arrives (no skeleton flash)
- Removed SkeletonRows component from home page (unused)
- Skeleton bars simplified: static gray bars, no shimmer animation
- Skeleton row padding matches list item padding
- Hero padding tightened (48px top → 32px)
- Hero subtitle made concise ("20 skill bundles... Browse, install, publish.")
- Removed redundant explainer paragraph
- Browse results count shows em dash while loading (not "Loading...")
- .section class uses spacing tokens
- .section-title uses monospace font at --fs-lg
- .section-subtitle uses --fs-sm
- results-list removed fadeIn animation (subtle state changes only)
- Replace ~20 remaining warm hex colors in upload/form styles (#ffddc9, #9a3a24, #fff3ec, etc.) with monochrome equivalents - Fix 2 lint errors: remove unused Link import (search.tsx), prefix unused parseDir with underscore (souls/index.tsx) - Add aria-label to PluginListItem and UserListItem for screen reader identification
Summary
Complete frontend rebuild of ClawHub into a marketplace-style discovery hub inspired by HuggingFace and npm. No backend changes.
--fs-*and--r-*to avoid Tailwind CSS v4 variable collisionNew components
SkillListItem— compact HF-style rowBrowseSidebar— faceted filter sidebar with proper ARIASkillMetadataSidebar— detail page right sidebaruseUnifiedSearch— parallel search hooktimeAgo/categories— utilitiesTest plan
npx vite build— clean, no errorsnpx vitest run— 122 files, 915/915 tests passingbunx convex run seedDemo:seedDemoSkills)