Replace text action buttons (Add to Collection, Add to Thread) with
icon-only buttons on mobile. Uses plus and message-square-plus icons.
All icon buttons have aria-label and 44px touch targets.
Replace text action buttons (Add Items, Public/Private toggle, Delete
Setup) with icon-only buttons on mobile. Migrate inline SVGs to
LucideIcon component (plus, globe, trash-2). All icon buttons have
aria-label and 44px touch targets.
Replace text action buttons (Edit, Pick as winner, Delete) with
icon-only buttons on mobile viewports (below md: breakpoint). Desktop
retains full text+icon buttons. All icon buttons have aria-label and
44px touch targets.
Replace text action buttons (Duplicate, Delete, Edit) with icon-only
buttons on mobile viewports (below md: breakpoint). Desktop retains
full text buttons. All icon buttons have aria-label and 44px touch targets.
Show ImageCropEditor after successful upload when onCropChange
callback is provided. Editor replaces image preview temporarily.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Zoom+pan editor using react-easy-crop with zoom slider, save/cancel
buttons, and dominant color background. Returns crop coordinates
for persistence.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace object-cover on item detail, global item detail, candidate
detail, global items index, and LinkToGlobalItem. Detail pages use
dominant color backgrounds. LinkToGlobalItem uses cover mode for
32px thumbnails.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace object-cover with GearImage across ComparisonTable,
CatalogSearchOverlay (2 instances), and ImageUpload preview.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace object-cover with GearImage for fit-within rendering on
candidate cards and list items.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace object-cover with GearImage component for fit-within rendering.
Add dominantColor and crop props to both card components.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Renders images with object-contain by default (letterbox/pillarbox),
object-cover when cover prop is set, or CSS transform when crop
values are present. Parent container uses dominant color background.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add dominantColor, cropZoom, cropX, cropY to createItemSchema,
createCandidateSchema, and upsertGlobalItemSchema.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both POST /api/images and POST /api/images/from-url now return
dominantColor in their response body.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
extractDominantColor() resizes image to 1x1 pixel for weighted average
color. Integrated into fetchImageFromUrl to return dominantColor.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add dominant_color, crop_zoom, crop_x, crop_y columns to items,
global_items, and thread_candidates tables.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds Profile link to UserMenu dropdown (above Settings), extends /me
endpoint to return user's createdAt for member-since display, and
updates AuthState interface with optional createdAt field.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds /profile route with four sections: profile info (reuses ProfileSection),
account info (email + member since), security (password change/set), and
danger zone (account deletion with typed confirmation). Removes ProfileSection
from settings page per D-01.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Creates /api/account routes with password change (verifies current first),
email update, has-password check, and account deletion with public setup
anonymization. Adds Zod validation schemas and registers routes in index.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements LogtoManagementClient with token caching, password verification,
password update, email update, user deletion, and has-password check.
All methods proxy to Logto Management API via M2M credentials.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Two-row sticky toolbar: search input + view toggle (Row 1), tag/weight/price filter pills (Row 2)
- Tag filter popover with click-outside close via useRef/useEffect
- Weight and price range filter popovers with min/max sliders
- Active filter removable pills + Clear all button
- Grid view uses existing GlobalItemCard, list view uses Link-based GlobalItemListRow
- SkeletonGrid and SkeletonList loading states
- Empty state with context-aware message (query vs no catalog items)
- Search input pre-fills from ?q= URL param, debounces 300ms
- No framer-motion, no manual entry mode, no Add buttons
- Add validateSearch with z.object({ q }) to route definition
- Use Route.useSearch() to get q param instead of local state
- Remove duplicate search input UI, debounce state and useEffect
- Show "Showing results for X" label when q is present
- Update empty state text based on whether q param exists
- Replace fake button with real text input and search icon
- Navigate to /global-items?q=query on Enter or icon click
- Clear input after navigation
- Remove openCatalogSearch usage from TopNav (FAB/BottomTabBar flows unchanged)
- Replace arrow entity + "Dashboard" back link with ArrowLeft icon + "Discover"
- Consolidate title and search into a single flex row (wraps on mobile)
- Reduce outer padding from py-6 to py-4
- Remove subtitle paragraph and separate mb-6/mb-8 section margins
- Delete HeroSection function (Discover Gear heading, search bar, Go to Collection link)
- Remove unused imports: Link, Search (lucide-react), useAuth, useUIStore
- LandingPage now starts directly with PopularSetupsSection
- Search now exclusively in TopNav bar
- Replace TotalsBar import with TopNav and BottomTabBar imports
- Remove isDashboard and totalsBarProps variables
- Render TopNav instead of TotalsBar
- Add /setups to isPublicRoute for anonymous direct navigation
- Wrap FabMenu in hidden md:block for mobile hiding
- Add BottomTabBar after FAB block (md:hidden in component itself)
- Add pb-16 md:pb-0 to root div to prevent content occlusion by bottom tab bar
- Fixed bottom tab bar for mobile (md:hidden) with z-20 stacking
- 4 tabs: Home, Collection, Setups, Search with Lucide icons
- Collection and Setups fire openAuthPrompt for anonymous users
- Search tab calls openCatalogSearch('collection') to open overlay
- Active route highlighting via useMatchRoute
- Framer Motion entry animation (y slide + fade)
- iOS safe area padding with env(safe-area-inset-bottom)
[Rule 1 - Bug] Used 'house' icon instead of 'home': lucide-react has no 'Home' icon (only 'House')
- Sticky top nav bar replacing TotalsBar with full navigation
- Logo, Home/Collection/Setups links, search bar, and user avatar
- NavLinkOrButton helper: button for anon users on protected routes, Link for authenticated
- Active route highlighting via useMatchRoute
- Desktop search bar triggers openCatalogSearch('collection')
- Desktop nav links hidden on mobile (hidden md:flex)
- Uses LucideIcon wrapper, not direct lucide-react imports
[Rule 1 - Bug] Used 'house' icon fallback check: plan specified 'home' which does not exist in lucide-react; 'search' and 'layers' verified present
Remove unused functions and imports from route tests, fix array index key
warnings in skeleton components, apply biome formatting.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace DashboardPage with LandingPage using discovery hooks
- Add HeroSection with Discover Gear heading and catalog search trigger
- Add PopularSetupsSection using useDiscoverySetups with PublicSetupCard
- Add RecentItemsSection using useDiscoveryItems with GlobalItemCard
- Add TrendingCategoriesSection using useDiscoveryCategories with pills
- Conditional Go to Collection CTA for authenticated users
- Loading skeletons with animate-pulse for all three sections
- Empty state handling: sections return null when no data
- SectionSkeleton helper for consistent loading states
- All clickable elements have cursor-pointer
- Create src/server/routes/discovery.ts with GET /setups, /items, /categories handlers
- Register discoveryRoutes in src/server/index.ts with browseTier rate limiting
- Add auth skip for /api/discovery/* GET requests in auth middleware
- Create tests/routes/discovery.test.ts with 10 tests covering all endpoints and pagination
- GlobalItem interface extended with sourceUrl, imageCredit, imageSourceUrl fields
- Attribution block below image: Photo credit and source link when present
- Product page link (sourceUrl) at bottom of detail page
- Image div mb-6 moved to attribution paragraph for consistent spacing
- New catalog.ts with catalogToolDefinitions and registerCatalogTools
- upsert_catalog_item: single item upsert with full attribution fields (SEED-03)
- bulk_upsert_catalog: batch upsert up to 100 items with created/updated counts
- Registered in createMcpServer after image tools
- 6 new MCP catalog tool tests passing
- POST /api/global-items upserts single item via upsertGlobalItem service
- POST /api/global-items/bulk upserts up to 100 items via bulkUpsertGlobalItems service
- Zod validation via @hono/zod-validator with upsertGlobalItemSchema and bulkUpsertGlobalItemsSchema