docs(31): create execution plans for mobile icon buttons
This commit is contained in:
210
.planning/phases/31-mobile-polish/31-01-PLAN.md
Normal file
210
.planning/phases/31-mobile-polish/31-01-PLAN.md
Normal file
@@ -0,0 +1,210 @@
|
||||
---
|
||||
phase: 31-mobile-polish
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- src/client/routes/items/$itemId.tsx
|
||||
- src/client/routes/threads/$threadId/candidates/$candidateId.tsx
|
||||
autonomous: true
|
||||
requirements: [D-01, D-02, D-03, D-04]
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- Item detail shows icon-only action buttons below md breakpoint
|
||||
- Item detail shows text action buttons at md and above
|
||||
- Candidate detail shows icon-only action buttons below md breakpoint
|
||||
- Candidate detail shows text action buttons at md and above
|
||||
- All icon-only buttons have aria-label attributes
|
||||
- All icon-only buttons have minimum 44px touch targets
|
||||
artifacts:
|
||||
- src/client/routes/items/$itemId.tsx (modified)
|
||||
- src/client/routes/threads/$threadId/candidates/$candidateId.tsx (modified)
|
||||
key_links:
|
||||
- LucideIcon component used for all icons (not inline SVGs)
|
||||
- md: breakpoint matches BottomTabBar responsive pattern
|
||||
---
|
||||
|
||||
<objective>
|
||||
Add responsive icon-based action buttons to item detail and candidate detail pages.
|
||||
|
||||
Purpose: Replace text-label action buttons with icon-only buttons on mobile viewports (below md: breakpoint) for better mobile UX. Desktop retains full text buttons.
|
||||
Output: Modified item detail and candidate detail pages with responsive action buttons.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/31-mobile-polish/31-CONTEXT.md
|
||||
@.planning/phases/31-mobile-polish/31-UI-SPEC.md
|
||||
|
||||
@src/client/components/BottomTabBar.tsx
|
||||
@src/client/lib/iconData.tsx
|
||||
</context>
|
||||
|
||||
<interfaces>
|
||||
<!-- Key types and contracts the executor needs -->
|
||||
|
||||
From src/client/lib/iconData.tsx:
|
||||
```typescript
|
||||
export function LucideIcon({ name, size, className, strokeWidth }: {
|
||||
name: string;
|
||||
size?: number;
|
||||
className?: string;
|
||||
strokeWidth?: number;
|
||||
}): React.ReactElement;
|
||||
```
|
||||
|
||||
From src/client/components/BottomTabBar.tsx:
|
||||
```
|
||||
// Responsive breakpoint reference: md:hidden (mobile), hidden md:flex (desktop)
|
||||
```
|
||||
</interfaces>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Add responsive icon buttons to item detail page</name>
|
||||
<files>src/client/routes/items/$itemId.tsx</files>
|
||||
|
||||
<read_first>
|
||||
- src/client/routes/items/$itemId.tsx (current action button implementation, lines ~189-213)
|
||||
- src/client/components/BottomTabBar.tsx (responsive breakpoint pattern reference)
|
||||
- src/client/lib/iconData.tsx (LucideIcon component API)
|
||||
- .planning/phases/31-mobile-polish/31-UI-SPEC.md (icon mapping and color contract)
|
||||
</read_first>
|
||||
|
||||
<action>
|
||||
In src/client/routes/items/$itemId.tsx, modify the action button group (the `div` with `flex items-center gap-2` containing Duplicate, Delete, and Edit buttons, visible when `!isEditing`).
|
||||
|
||||
For each button, create a paired desktop/mobile pattern:
|
||||
|
||||
**Duplicate button:**
|
||||
- Desktop (hidden on mobile): `<button className="hidden md:inline-flex items-center gap-1.5 px-3 py-1.5 text-sm text-gray-500 hover:text-gray-700 hover:bg-gray-50 rounded-lg transition-colors" ...>Duplicate</button>`
|
||||
- Mobile (hidden on desktop): `<button className="md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-50 rounded-lg transition-colors" aria-label="Duplicate" title="Duplicate" ...><LucideIcon name="copy" size={16} /></button>`
|
||||
|
||||
**Delete/Remove button:**
|
||||
- Desktop: `<button className="hidden md:inline-flex items-center gap-1.5 px-3 py-1.5 text-sm text-red-400 hover:text-red-600 hover:bg-red-50 rounded-lg transition-colors" ...>{isReference ? "Remove from Collection" : "Delete"}</button>`
|
||||
- Mobile: `<button className="md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2 text-red-400 hover:text-red-600 hover:bg-red-50 rounded-lg transition-colors" aria-label={isReference ? "Remove from Collection" : "Delete"} title={isReference ? "Remove from Collection" : "Delete"} ...><LucideIcon name="trash-2" size={16} /></button>`
|
||||
|
||||
**Edit button:**
|
||||
- Desktop: `<button className="hidden md:inline-flex items-center gap-1.5 px-4 py-1.5 text-sm font-medium text-white bg-gray-700 hover:bg-gray-800 rounded-lg transition-colors" ...>Edit</button>`
|
||||
- Mobile: `<button className="md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2 text-white bg-gray-700 hover:bg-gray-800 rounded-lg transition-colors" aria-label="Edit" title="Edit" ...><LucideIcon name="pencil" size={16} /></button>`
|
||||
|
||||
Ensure LucideIcon is already imported (it is — check line ~8). Keep all existing onClick handlers and disabled states. The Cancel/Save buttons in edit mode remain unchanged (text buttons on all viewports).
|
||||
|
||||
Per D-01: Apply icon-based action buttons on mobile to item detail page.
|
||||
Per D-02: Desktop keeps text buttons, mobile switches to icons at md: breakpoint.
|
||||
Per D-03: Standard icon mapping — pencil for Edit, trash-2 for Delete, copy for Duplicate.
|
||||
</action>
|
||||
|
||||
<acceptance_criteria>
|
||||
- `$itemId.tsx` contains `aria-label="Duplicate"` on an icon button
|
||||
- `$itemId.tsx` contains `aria-label="Edit"` on an icon button with `md:hidden` class
|
||||
- `$itemId.tsx` contains `<LucideIcon name="copy"` for Duplicate icon
|
||||
- `$itemId.tsx` contains `<LucideIcon name="trash-2"` for Delete icon
|
||||
- `$itemId.tsx` contains `<LucideIcon name="pencil"` for Edit icon
|
||||
- `$itemId.tsx` contains `min-w-[44px]` for touch target sizing
|
||||
- `$itemId.tsx` contains `hidden md:inline-flex` on desktop text buttons
|
||||
- Cancel and Save buttons in edit mode do NOT have `md:hidden` responsive splitting
|
||||
</acceptance_criteria>
|
||||
|
||||
<verify>
|
||||
<automated>grep -c "aria-label" src/client/routes/items/\$itemId.tsx | grep -q "[3-9]" && grep -c "md:hidden" src/client/routes/items/\$itemId.tsx | grep -q "[3-9]" && echo "PASS" || echo "FAIL"</automated>
|
||||
</verify>
|
||||
|
||||
<done>Item detail page shows icon-only Duplicate/Delete/Edit buttons on mobile, full text buttons on desktop. All icon buttons have aria-label and 44px minimum touch targets.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Add responsive icon buttons to candidate detail page</name>
|
||||
<files>src/client/routes/threads/$threadId/candidates/$candidateId.tsx</files>
|
||||
|
||||
<read_first>
|
||||
- src/client/routes/threads/$threadId/candidates/$candidateId.tsx (current action buttons — header Edit at line ~282, bottom actions at lines ~530-548)
|
||||
- .planning/phases/31-mobile-polish/31-UI-SPEC.md (icon mapping and color contract)
|
||||
</read_first>
|
||||
|
||||
<action>
|
||||
In src/client/routes/threads/$threadId/candidates/$candidateId.tsx, modify action buttons in two locations:
|
||||
|
||||
**Location 1: Header Edit button (line ~282-289)**
|
||||
Currently shows `<LucideIcon name="pencil" size={14} />` + "Edit" text. Split into:
|
||||
- Desktop: `<button className="shrink-0 hidden md:inline-flex items-center gap-1.5 px-3 py-1.5 text-sm text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-lg transition-colors" ...><LucideIcon name="pencil" size={14} />Edit</button>`
|
||||
- Mobile: `<button className="shrink-0 md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-lg transition-colors" aria-label="Edit" title="Edit" ...><LucideIcon name="pencil" size={16} /></button>`
|
||||
|
||||
**Location 2: Bottom action buttons (lines ~530-548)**
|
||||
Currently shows "Pick as winner" with trophy icon and "Delete" with trash-2 icon. Split each:
|
||||
|
||||
**Pick as Winner:**
|
||||
- Desktop: `<button className="hidden md:inline-flex items-center gap-1.5 px-4 py-2 bg-amber-50 hover:bg-amber-100 text-amber-700 text-sm font-medium rounded-lg transition-colors" ...><LucideIcon name="trophy" size={14} />Pick as winner</button>`
|
||||
- Mobile: `<button className="md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2 bg-amber-50 hover:bg-amber-100 text-amber-700 rounded-lg transition-colors" aria-label="Pick as winner" title="Pick as winner" ...><LucideIcon name="trophy" size={16} /></button>`
|
||||
|
||||
**Delete:**
|
||||
- Desktop: `<button className="hidden md:inline-flex items-center gap-1.5 px-4 py-2 text-sm text-red-500 hover:text-red-600 hover:bg-red-50 rounded-lg transition-colors" ...><LucideIcon name="trash-2" size={14} />Delete</button>`
|
||||
- Mobile: `<button className="md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2 text-red-500 hover:text-red-600 hover:bg-red-50 rounded-lg transition-colors" aria-label="Delete" title="Delete" ...><LucideIcon name="trash-2" size={16} /></button>`
|
||||
|
||||
Keep all existing onClick handlers. The edit mode buttons (Cancel, Save) remain unchanged.
|
||||
|
||||
Per D-01: Apply to candidate detail page.
|
||||
Per D-02: Desktop text, mobile icons at md: breakpoint.
|
||||
Per D-03: Standard icon mapping — pencil for Edit, trash-2 for Delete, trophy for Pick as winner.
|
||||
</action>
|
||||
|
||||
<acceptance_criteria>
|
||||
- `$candidateId.tsx` contains `aria-label="Edit"` on an icon button with `md:hidden`
|
||||
- `$candidateId.tsx` contains `aria-label="Pick as winner"` on an icon button
|
||||
- `$candidateId.tsx` contains `aria-label="Delete"` on an icon button
|
||||
- `$candidateId.tsx` contains `min-w-[44px]` for touch target sizing (at least 3 occurrences)
|
||||
- `$candidateId.tsx` contains `hidden md:inline-flex` on desktop text buttons (at least 3 occurrences)
|
||||
- Edit mode Cancel/Save buttons do NOT have responsive splitting
|
||||
</acceptance_criteria>
|
||||
|
||||
<verify>
|
||||
<automated>grep -c "aria-label" src/client/routes/threads/\$threadId/candidates/\$candidateId.tsx | grep -q "[3-9]" && grep -c "md:hidden" src/client/routes/threads/\$threadId/candidates/\$candidateId.tsx | grep -q "[3-9]" && echo "PASS" || echo "FAIL"</automated>
|
||||
</verify>
|
||||
|
||||
<done>Candidate detail page shows icon-only Edit/Pick as winner/Delete buttons on mobile, full text+icon buttons on desktop. All icon buttons have aria-label and 44px minimum touch targets.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
No new trust boundaries introduced. This plan only modifies client-side rendering of existing buttons. No new API calls, no new data flows, no new authentication paths.
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|-------------|-----------------|
|
||||
| T-31-01 | Information Disclosure | Icon buttons | accept | Icon buttons show same actions as existing text buttons — no new information exposed. aria-label text matches existing button text. |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `bun run lint` passes with no errors in modified files
|
||||
- `bun test` passes (no test regressions)
|
||||
- Manual: Open item detail at mobile viewport (< 768px) — see icon-only buttons
|
||||
- Manual: Open item detail at desktop viewport (>= 768px) — see text buttons
|
||||
- Manual: Open candidate detail at mobile viewport — see icon-only buttons
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Item detail page renders icon-only Duplicate/Delete/Edit buttons on mobile
|
||||
- Candidate detail page renders icon-only Edit/Pick as winner/Delete buttons on mobile
|
||||
- Desktop rendering unchanged (text buttons with optional icons)
|
||||
- All icon buttons have aria-label for accessibility
|
||||
- All icon buttons have min-w-[44px] min-h-[44px] for comfortable touch targets
|
||||
- md: breakpoint used consistently (matching BottomTabBar pattern)
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/31-mobile-polish/31-01-SUMMARY.md`
|
||||
</output>
|
||||
224
.planning/phases/31-mobile-polish/31-02-PLAN.md
Normal file
224
.planning/phases/31-mobile-polish/31-02-PLAN.md
Normal file
@@ -0,0 +1,224 @@
|
||||
---
|
||||
phase: 31-mobile-polish
|
||||
plan: 02
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- src/client/routes/setups/$setupId.tsx
|
||||
- src/client/routes/global-items/$globalItemId.tsx
|
||||
autonomous: true
|
||||
requirements: [D-01, D-02, D-03, D-04]
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- Setup detail shows icon-only action buttons below md breakpoint
|
||||
- Setup detail shows text action buttons at md and above
|
||||
- Global item detail shows icon-only action buttons below md breakpoint
|
||||
- Global item detail shows text action buttons at md and above
|
||||
- All icon-only buttons have aria-label attributes
|
||||
- All icon-only buttons have minimum 44px touch targets
|
||||
- Setup page inline SVGs replaced with LucideIcon component
|
||||
artifacts:
|
||||
- src/client/routes/setups/$setupId.tsx (modified)
|
||||
- src/client/routes/global-items/$globalItemId.tsx (modified)
|
||||
key_links:
|
||||
- LucideIcon component used for all icons (not inline SVGs)
|
||||
- md: breakpoint matches BottomTabBar responsive pattern
|
||||
---
|
||||
|
||||
<objective>
|
||||
Add responsive icon-based action buttons to setup detail and global item detail pages, and migrate setup page inline SVGs to LucideIcon.
|
||||
|
||||
Purpose: Complete the mobile icon button rollout across all remaining detail pages. Also clean up inline SVGs on setup page by migrating to the project's LucideIcon component for consistency.
|
||||
Output: Modified setup detail and global item detail pages with responsive action buttons.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/31-mobile-polish/31-CONTEXT.md
|
||||
@.planning/phases/31-mobile-polish/31-UI-SPEC.md
|
||||
|
||||
@src/client/components/BottomTabBar.tsx
|
||||
@src/client/lib/iconData.tsx
|
||||
</context>
|
||||
|
||||
<interfaces>
|
||||
<!-- Key types and contracts the executor needs -->
|
||||
|
||||
From src/client/lib/iconData.tsx:
|
||||
```typescript
|
||||
export function LucideIcon({ name, size, className, strokeWidth }: {
|
||||
name: string;
|
||||
size?: number;
|
||||
className?: string;
|
||||
strokeWidth?: number;
|
||||
}): React.ReactElement;
|
||||
```
|
||||
|
||||
Available icon names needed:
|
||||
- "plus" — Add Items button
|
||||
- "globe" — Public/Private toggle
|
||||
- "trash-2" — Delete Setup button
|
||||
- "message-square-plus" — Add to Thread button (verify exists in lucide-react)
|
||||
</interfaces>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Add responsive icon buttons to setup detail page and migrate inline SVGs to LucideIcon</name>
|
||||
<files>src/client/routes/setups/$setupId.tsx</files>
|
||||
|
||||
<read_first>
|
||||
- src/client/routes/setups/$setupId.tsx (current action buttons at lines ~155-210, inline SVGs for plus and globe icons)
|
||||
- src/client/lib/iconData.tsx (LucideIcon component — confirm import path)
|
||||
- .planning/phases/31-mobile-polish/31-UI-SPEC.md (icon mapping and color contract)
|
||||
</read_first>
|
||||
|
||||
<action>
|
||||
In src/client/routes/setups/$setupId.tsx:
|
||||
|
||||
**Step 1: Add LucideIcon import.**
|
||||
Add `import { LucideIcon } from "../../lib/iconData";` at the top of the file (if not already present).
|
||||
|
||||
**Step 2: Migrate inline SVGs to LucideIcon.**
|
||||
- Replace the inline plus SVG in the "Add Items" button (lines ~162-175) with `<LucideIcon name="plus" size={16} />`
|
||||
- Replace the inline globe SVG in the Public/Private toggle button (lines ~188-198) with `<LucideIcon name="globe" size={16} />`
|
||||
|
||||
**Step 3: Add responsive icon/text splitting to all action buttons.**
|
||||
|
||||
**Add Items button:**
|
||||
- Desktop: `<button className="hidden md:inline-flex items-center gap-2 px-4 py-2 bg-gray-700 hover:bg-gray-800 text-white text-sm font-medium rounded-lg transition-colors" ...><LucideIcon name="plus" size={16} />Add Items</button>`
|
||||
- Mobile: `<button className="md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2 bg-gray-700 hover:bg-gray-800 text-white rounded-lg transition-colors" aria-label="Add Items" title="Add Items" ...><LucideIcon name="plus" size={16} /></button>`
|
||||
|
||||
**Public/Private toggle:**
|
||||
- Desktop: `<button className="hidden md:inline-flex items-center gap-1.5 px-3 py-2 text-sm font-medium rounded-lg transition-colors {conditional classes}" ...><LucideIcon name="globe" size={16} />{setup.isPublic ? "Public" : "Private"}</button>`
|
||||
- Mobile: `<button className="md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2 rounded-lg transition-colors {conditional classes}" aria-label={setup.isPublic ? "Public" : "Private"} title={setup.isPublic ? "Public" : "Private"} ...><LucideIcon name="globe" size={16} /></button>`
|
||||
- Keep the conditional color classes: `text-green-700 bg-green-50 hover:bg-green-100` when public, `text-gray-500 bg-gray-50 hover:bg-gray-100` when private.
|
||||
|
||||
**Delete Setup button:**
|
||||
- Desktop: `<button className="hidden md:inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-red-600 bg-red-50 hover:bg-red-100 rounded-lg transition-colors" ...>Delete Setup</button>`
|
||||
- Mobile: `<button className="md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2 text-red-600 bg-red-50 hover:bg-red-100 rounded-lg transition-colors" aria-label="Delete Setup" title="Delete Setup" ...><LucideIcon name="trash-2" size={16} /></button>`
|
||||
|
||||
Keep all existing onClick handlers, disabled states, and conditional rendering logic. The `flex-1` spacer between toggle and delete buttons remains.
|
||||
|
||||
Per D-01: Apply to setup detail page.
|
||||
Per D-02: Desktop text, mobile icons at md: breakpoint.
|
||||
Per D-03: Standard icon mapping — plus for Add, globe for toggle, trash-2 for Delete.
|
||||
</action>
|
||||
|
||||
<acceptance_criteria>
|
||||
- `$setupId.tsx` contains `import { LucideIcon }` or `import { LucideIcon` from iconData
|
||||
- `$setupId.tsx` contains `<LucideIcon name="plus"` (replacing inline plus SVG)
|
||||
- `$setupId.tsx` contains `<LucideIcon name="globe"` (replacing inline globe SVG)
|
||||
- `$setupId.tsx` contains `<LucideIcon name="trash-2"` for Delete Setup icon
|
||||
- `$setupId.tsx` contains `aria-label="Add Items"` on an icon button
|
||||
- `$setupId.tsx` contains `aria-label="Delete Setup"` on an icon button
|
||||
- `$setupId.tsx` contains `min-w-[44px]` for touch target sizing (at least 3 occurrences)
|
||||
- `$setupId.tsx` contains NO inline `<svg` elements (all migrated to LucideIcon)
|
||||
- `$setupId.tsx` contains `hidden md:inline-flex` on desktop text buttons
|
||||
</acceptance_criteria>
|
||||
|
||||
<verify>
|
||||
<automated>grep -c "aria-label" src/client/routes/setups/\$setupId.tsx | grep -q "[3-9]" && grep -c "LucideIcon" src/client/routes/setups/\$setupId.tsx | grep -q "[3-9]" && ! grep -q "<svg" src/client/routes/setups/\$setupId.tsx && echo "PASS" || echo "FAIL"</automated>
|
||||
</verify>
|
||||
|
||||
<done>Setup detail page shows icon-only Add Items/Public toggle/Delete Setup buttons on mobile, full text buttons on desktop. Inline SVGs replaced with LucideIcon. All icon buttons have aria-label and 44px minimum touch targets.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Add responsive icon buttons to global item detail page</name>
|
||||
<files>src/client/routes/global-items/$globalItemId.tsx</files>
|
||||
|
||||
<read_first>
|
||||
- src/client/routes/global-items/$globalItemId.tsx (current action buttons at lines ~167-193)
|
||||
- src/client/lib/iconData.tsx (LucideIcon component, verify "message-square-plus" icon exists in lucide-react)
|
||||
- .planning/phases/31-mobile-polish/31-UI-SPEC.md (icon mapping and color contract)
|
||||
</read_first>
|
||||
|
||||
<action>
|
||||
In src/client/routes/global-items/$globalItemId.tsx:
|
||||
|
||||
**Step 1: Add LucideIcon import.**
|
||||
Add `import { LucideIcon } from "../../lib/iconData";` at the top of the file (if not already present).
|
||||
|
||||
**Step 2: Add responsive icon/text splitting to action buttons.**
|
||||
|
||||
The action buttons section (`flex gap-3 mb-6` containing "Add to Collection" and "Add to Thread") needs responsive variants:
|
||||
|
||||
**Add to Collection button:**
|
||||
- Desktop: `<button className="hidden md:inline-flex items-center gap-2 bg-gray-700 text-white rounded-lg px-5 py-2.5 text-sm font-medium hover:bg-gray-800 transition-colors" ...>Add to Collection</button>`
|
||||
- Mobile: `<button className="md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2.5 bg-gray-700 text-white rounded-lg hover:bg-gray-800 transition-colors" aria-label="Add to Collection" title="Add to Collection" ...><LucideIcon name="plus" size={16} /></button>`
|
||||
|
||||
**Add to Thread button:**
|
||||
First, verify that "message-square-plus" exists in lucide-react. If it does not, use "message-square" instead. Check by running: `grep -r "message-square-plus" node_modules/lucide-react/dist/ 2>/dev/null | head -1`
|
||||
- Desktop: `<button className="hidden md:inline-flex items-center gap-2 bg-white text-gray-700 border border-gray-200 rounded-lg px-5 py-2.5 text-sm font-medium hover:bg-gray-50 transition-colors" ...>Add to Thread</button>`
|
||||
- Mobile: `<button className="md:hidden inline-flex items-center justify-center min-w-[44px] min-h-[44px] p-2.5 bg-white text-gray-700 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors" aria-label="Add to Thread" title="Add to Thread" ...><LucideIcon name="message-square-plus" size={16} /></button>`
|
||||
|
||||
Keep all existing onClick handlers (including the auth check that calls `openAuthPrompt()` for unauthenticated users).
|
||||
|
||||
Per D-01: Apply to catalog/global item detail page.
|
||||
Per D-02: Desktop text, mobile icons at md: breakpoint.
|
||||
Per D-03: Standard icon mapping — plus for Add to Collection, message-square-plus for Add to Thread.
|
||||
</action>
|
||||
|
||||
<acceptance_criteria>
|
||||
- `$globalItemId.tsx` contains `import { LucideIcon }` from iconData
|
||||
- `$globalItemId.tsx` contains `<LucideIcon name="plus"` for Add to Collection icon
|
||||
- `$globalItemId.tsx` contains `<LucideIcon name="message-square` for Add to Thread icon
|
||||
- `$globalItemId.tsx` contains `aria-label="Add to Collection"` on an icon button
|
||||
- `$globalItemId.tsx` contains `aria-label="Add to Thread"` on an icon button
|
||||
- `$globalItemId.tsx` contains `min-w-[44px]` for touch target sizing (at least 2 occurrences)
|
||||
- `$globalItemId.tsx` contains `hidden md:inline-flex` on desktop text buttons (at least 2 occurrences)
|
||||
</acceptance_criteria>
|
||||
|
||||
<verify>
|
||||
<automated>grep -c "aria-label" src/client/routes/global-items/\$globalItemId.tsx | grep -q "[2-9]" && grep -c "LucideIcon" src/client/routes/global-items/\$globalItemId.tsx | grep -q "[2-9]" && echo "PASS" || echo "FAIL"</automated>
|
||||
</verify>
|
||||
|
||||
<done>Global item detail page shows icon-only Add to Collection/Add to Thread buttons on mobile, full text buttons on desktop. All icon buttons have aria-label and 44px minimum touch targets.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
No new trust boundaries introduced. This plan only modifies client-side rendering of existing buttons. No new API calls, no new data flows, no new authentication paths.
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|-------------|-----------------|
|
||||
| T-31-02 | Information Disclosure | Icon buttons | accept | Icon buttons show same actions as existing text buttons — no new information exposed. aria-label text matches existing button text. |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `bun run lint` passes with no errors in modified files
|
||||
- `bun test` passes (no test regressions)
|
||||
- Manual: Open setup detail at mobile viewport (< 768px) — see icon-only buttons
|
||||
- Manual: Open global item detail at mobile viewport — see icon-only buttons
|
||||
- Manual: Open both pages at desktop viewport — see text buttons
|
||||
- No inline `<svg` elements remain in setup detail page
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Setup detail page renders icon-only Add Items/Public toggle/Delete Setup buttons on mobile
|
||||
- Global item detail page renders icon-only Add to Collection/Add to Thread buttons on mobile
|
||||
- Desktop rendering unchanged (text buttons with optional icons)
|
||||
- Setup page inline SVGs fully replaced with LucideIcon component
|
||||
- All icon buttons have aria-label for accessibility
|
||||
- All icon buttons have min-w-[44px] min-h-[44px] for comfortable touch targets
|
||||
- md: breakpoint used consistently across both pages
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/31-mobile-polish/31-02-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user