docs(35-02): complete image lazy loading and skeleton plan
- SUMMARY.md created for 35-02 (FIX-03) - STATE.md advanced to plan 2 of 3 complete, added 35-02 decisions - ROADMAP.md updated (2 of 3 summaries) - REQUIREMENTS.md marked FIX-03 complete
This commit is contained in:
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
- [x] **FIX-01**: User clicking "Add Candidate" on a thread page opens the add-candidate modal (not the wrong modal)
|
- [x] **FIX-01**: User clicking "Add Candidate" on a thread page opens the add-candidate modal (not the wrong modal)
|
||||||
- [x] **FIX-02**: Item images display correctly on collection overview cards (no broken/missing images)
|
- [x] **FIX-02**: Item images display correctly on collection overview cards (no broken/missing images)
|
||||||
- [ ] **FIX-03**: Catalog and collection images load without noticeable delay (slow image loading resolved)
|
- [x] **FIX-03**: Catalog and collection images load without noticeable delay (slow image loading resolved)
|
||||||
- [x] **FIX-04**: Clicking the sign-in button on an auth prompt redirects the user directly to the Logto login page
|
- [x] **FIX-04**: Clicking the sign-in button on an auth prompt redirects the user directly to the Logto login page
|
||||||
- [ ] **FIX-05**: All clickable and interactive elements show a pointer cursor on hover throughout the app
|
- [ ] **FIX-05**: All clickable and interactive elements show a pointer cursor on hover throughout the app
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
|-------------|-------|--------|
|
|-------------|-------|--------|
|
||||||
| FIX-01 | Phase 35 | Complete |
|
| FIX-01 | Phase 35 | Complete |
|
||||||
| FIX-02 | Phase 35 | Complete |
|
| FIX-02 | Phase 35 | Complete |
|
||||||
| FIX-03 | Phase 35 | Pending |
|
| FIX-03 | Phase 35 | Complete |
|
||||||
| FIX-04 | Phase 35 | Complete |
|
| FIX-04 | Phase 35 | Complete |
|
||||||
| FIX-05 | Phase 35 | Pending |
|
| FIX-05 | Phase 35 | Pending |
|
||||||
| ROLE-01 | Phase 36 | Pending |
|
| ROLE-01 | Phase 36 | Pending |
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ Plans:
|
|||||||
|
|
||||||
Plans:
|
Plans:
|
||||||
- [x] 35-01-PLAN.md — Thread modal fix, ItemWithCategory type extension, login auto-redirect (FIX-01, FIX-02, FIX-04)
|
- [x] 35-01-PLAN.md — Thread modal fix, ItemWithCategory type extension, login auto-redirect (FIX-01, FIX-02, FIX-04)
|
||||||
- [ ] 35-02-PLAN.md — Lazy loading + image skeleton states on GearImage and all card components (FIX-03)
|
- [x] 35-02-PLAN.md — Lazy loading + image skeleton states on GearImage and all card components (FIX-03)
|
||||||
- [ ] 35-03-PLAN.md — Cursor-pointer audit across ItemCard, FabMenu, BottomTabBar (FIX-05)
|
- [ ] 35-03-PLAN.md — Cursor-pointer audit across ItemCard, FabMenu, BottomTabBar (FIX-05)
|
||||||
|
|
||||||
**UI hint**: yes
|
**UI hint**: yes
|
||||||
@@ -318,7 +318,7 @@ Plans:
|
|||||||
| 32. Setup Sharing System | v2.3 | 4/4 | Complete | 2026-04-15 |
|
| 32. Setup Sharing System | v2.3 | 4/4 | Complete | 2026-04-15 |
|
||||||
| 33. Currency System | v2.3 | 6/6 | Complete | 2026-04-13 |
|
| 33. Currency System | v2.3 | 6/6 | Complete | 2026-04-13 |
|
||||||
| 34. i18n Foundation | v2.3 | 8/8 | Complete | 2026-04-18 |
|
| 34. i18n Foundation | v2.3 | 8/8 | Complete | 2026-04-18 |
|
||||||
| 35. Bug Fixes | v2.4 | 1/3 | In Progress| |
|
| 35. Bug Fixes | v2.4 | 2/3 | In Progress| |
|
||||||
| 36. Admin Role & Panel Foundation | v2.4 | 0/TBD | Not started | - |
|
| 36. Admin Role & Panel Foundation | v2.4 | 0/TBD | Not started | - |
|
||||||
| 37. Admin — Global Item Management | v2.4 | 0/TBD | Not started | - |
|
| 37. Admin — Global Item Management | v2.4 | 0/TBD | Not started | - |
|
||||||
| 38. Admin — Tag Management | v2.4 | 0/TBD | Not started | - |
|
| 38. Admin — Tag Management | v2.4 | 0/TBD | Not started | - |
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ gsd_state_version: 1.0
|
|||||||
milestone: v2.4
|
milestone: v2.4
|
||||||
milestone_name: Admin Foundation
|
milestone_name: Admin Foundation
|
||||||
status: executing
|
status: executing
|
||||||
stopped_at: "Phase 35 planned — 3 plans ready to execute (wave 1: all parallel)"
|
stopped_at: Completed 35-01-PLAN.md — FIX-01, FIX-02, FIX-04 resolved
|
||||||
last_updated: "2026-04-19T17:43:31.083Z"
|
last_updated: "2026-04-19T17:48:30.721Z"
|
||||||
last_activity: 2026-04-19 — Phase 35 planned (3 plans, verification passed)
|
last_activity: 2026-04-19
|
||||||
progress:
|
progress:
|
||||||
total_phases: 20
|
total_phases: 20
|
||||||
completed_phases: 7
|
completed_phases: 7
|
||||||
total_plans: 32
|
total_plans: 32
|
||||||
completed_plans: 30
|
completed_plans: 31
|
||||||
percent: 94
|
percent: 97
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -26,11 +26,11 @@ See: .planning/PROJECT.md (updated 2026-04-19)
|
|||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 35 — Bug Fixes
|
Phase: 35 — Bug Fixes
|
||||||
Plan: 1 of 3 complete
|
Plan: 2 of 3 complete
|
||||||
Status: In progress — 35-01 complete, 35-02 and 35-03 remaining
|
Status: In progress — 35-01 and 35-02 complete, 35-03 remaining
|
||||||
Last activity: 2026-04-19 — 35-01 complete (FIX-01, FIX-02, FIX-04)
|
Last activity: 2026-04-19 — 35-02 complete (FIX-03)
|
||||||
|
|
||||||
Progress: [███░░░░░░░] 33%
|
Progress: [██████████] 97%
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
@@ -70,16 +70,26 @@ Phase 35 decisions (35-01):
|
|||||||
- FIX-02: ItemWithCategory type extended client-side only — server already returns image fields via withImageUrls()
|
- FIX-02: ItemWithCategory type extended client-side only — server already returns image fields via withImageUrls()
|
||||||
- FIX-04: Login page is a server pass-through; no client auth check or card UI needed
|
- FIX-04: Login page is a server pass-through; no client auth check or card UI needed
|
||||||
|
|
||||||
|
Phase 35 decisions (35-02):
|
||||||
|
|
||||||
|
- FIX-03: Browser-native loading=lazy used for image deferral — no library needed, zero bundle overhead
|
||||||
|
- FIX-03: Skeleton is absolute inset-0 overlay removed on onLoad (not conditional branch swap) for stable layout
|
||||||
|
- FIX-03: GearImage accepts optional onLoad prop forwarded to all three img render paths
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
- Investigate slow image loading — Phase 35 (FIX-03, plan 35-02)
|
|
||||||
- Cursor pointer on all clickable links — Phase 35 (FIX-05, plan 35-03)
|
- Cursor pointer on all clickable links — Phase 35 (FIX-05, plan 35-03)
|
||||||
|
|
||||||
Resolved in 35-01:
|
Resolved in 35-01:
|
||||||
|
|
||||||
- Fix Add Candidate button shows wrong modal on thread page — DONE (FIX-01)
|
- Fix Add Candidate button shows wrong modal on thread page — DONE (FIX-01)
|
||||||
- Fix item image not showing on collection overview — DONE (FIX-02)
|
- Fix item image not showing on collection overview — DONE (FIX-02)
|
||||||
- Auth prompt sign-in button should redirect directly to Logto — DONE (FIX-04)
|
- Auth prompt sign-in button should redirect directly to Logto — DONE (FIX-04)
|
||||||
|
|
||||||
|
Resolved in 35-02:
|
||||||
|
|
||||||
|
- Investigate slow image loading — DONE (FIX-03)
|
||||||
|
|
||||||
### Blockers/Concerns
|
### Blockers/Concerns
|
||||||
|
|
||||||
None.
|
None.
|
||||||
@@ -99,5 +109,5 @@ Items carried forward from v2.3:
|
|||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-19
|
Last session: 2026-04-19
|
||||||
Stopped at: Completed 35-01-PLAN.md — FIX-01, FIX-02, FIX-04 resolved
|
Stopped at: Completed 35-02-PLAN.md — FIX-03 (image lazy loading + skeleton) resolved
|
||||||
Resume file: .planning/phases/35-bug-fixes/35-02-PLAN.md
|
Resume file: .planning/phases/35-bug-fixes/35-03-PLAN.md
|
||||||
|
|||||||
113
.planning/phases/35-bug-fixes/35-02-SUMMARY.md
Normal file
113
.planning/phases/35-bug-fixes/35-02-SUMMARY.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
---
|
||||||
|
phase: 35-bug-fixes
|
||||||
|
plan: "02"
|
||||||
|
subsystem: ui
|
||||||
|
tags: [react, tailwind, skeleton, lazy-loading, image, s3]
|
||||||
|
|
||||||
|
# Dependency graph
|
||||||
|
requires:
|
||||||
|
- phase: 35-bug-fixes
|
||||||
|
provides: FIX-02 image URL resolution (withImageUrls on server)
|
||||||
|
provides:
|
||||||
|
- GearImage lazy loading with onLoad callback forwarding
|
||||||
|
- Animated skeleton placeholder (bg-gray-100 animate-pulse) on ItemCard, CandidateCard, GlobalItemCard
|
||||||
|
- Fade-in transition (opacity-0 to opacity-100) on image load
|
||||||
|
affects: [any future plan touching GearImage, ItemCard, CandidateCard, GlobalItemCard]
|
||||||
|
|
||||||
|
# Tech tracking
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns: [image-skeleton-pattern, lazy-loading-native]
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created: []
|
||||||
|
modified:
|
||||||
|
- src/client/components/GearImage.tsx
|
||||||
|
- src/client/components/ItemCard.tsx
|
||||||
|
- src/client/components/CandidateCard.tsx
|
||||||
|
- src/client/components/GlobalItemCard.tsx
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "FIX-03: Use browser-native loading=lazy (no library) for image deferral"
|
||||||
|
- "FIX-03: Skeleton is absolute-positioned overlay removed on onLoad, not conditional render swap"
|
||||||
|
- "FIX-03: Fade-in via className prop on GearImage forwarded to img elements — no wrapper div needed in GearImage itself"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Image skeleton pattern: relative wrapper + absolute inset-0 bg-gray-100 animate-pulse + opacity transition on GearImage className"
|
||||||
|
- "onLoad forwarding: GearImage accepts optional onLoad prop, passes it to all three img render paths"
|
||||||
|
|
||||||
|
requirements-completed: [FIX-03]
|
||||||
|
|
||||||
|
# Metrics
|
||||||
|
duration: 3min
|
||||||
|
completed: 2026-04-19
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 35 Plan 02: Image Lazy Loading and Skeleton Summary
|
||||||
|
|
||||||
|
**Browser-native lazy loading on all GearImage img elements with animated pulse skeleton and opacity fade-in on ItemCard, CandidateCard, and GlobalItemCard**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** 3 min
|
||||||
|
- **Started:** 2026-04-19T18:04:32Z
|
||||||
|
- **Completed:** 2026-04-19T18:07:14Z
|
||||||
|
- **Tasks:** 2
|
||||||
|
- **Files modified:** 4
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
- Added `loading="lazy"` and optional `onLoad` prop to GearImage, forwarded to all three img render paths (cover, hasCrop, default)
|
||||||
|
- Added `useState(false)` loaded state and skeleton overlay to ItemCard, CandidateCard, and GlobalItemCard
|
||||||
|
- Images fade in via `transition-opacity duration-200` once `onLoad` fires; skeleton is removed simultaneously
|
||||||
|
- No-image placeholders (category icon on bg-gray-50) unchanged in all three cards
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Each task was committed atomically:
|
||||||
|
|
||||||
|
1. **Task 1: Add loading=lazy and onLoad prop to GearImage** - `2d2259a` (feat)
|
||||||
|
2. **Task 2: Add image skeleton to ItemCard, CandidateCard, GlobalItemCard** - `88db308` (feat)
|
||||||
|
|
||||||
|
**Plan metadata:** (docs commit below)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
- `src/client/components/GearImage.tsx` - Added `onLoad?: () => void` to props, destructured and forwarded to all three `<img>` elements alongside `loading="lazy"`
|
||||||
|
- `src/client/components/ItemCard.tsx` - Added `useState` import, `loaded` state, skeleton overlay, and fade-in className on GearImage
|
||||||
|
- `src/client/components/CandidateCard.tsx` - Same skeleton pattern as ItemCard
|
||||||
|
- `src/client/components/GlobalItemCard.tsx` - Same skeleton pattern; SVG icon placeholder preserved unchanged
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
- Used browser-native `loading="lazy"` — no third-party library needed, zero bundle overhead
|
||||||
|
- Skeleton is an `absolute inset-0` overlay (not a conditional branch swap) so layout is stable during load
|
||||||
|
- Import order fixed for Biome's `organizeImports` rule: `@tanstack/react-router` before `react` before `react-i18next`
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Rule 1 - Bug] Fixed Biome import order violations in all three card files**
|
||||||
|
- **Found during:** Task 2 (after adding `useState` import)
|
||||||
|
- **Issue:** Biome `organizeImports` requires alphabetical order — `"react"` placed before `"@tanstack/react-router"` caused lint errors
|
||||||
|
- **Fix:** Reordered imports: `@tanstack/react-router` → `react` → `react-i18next` in ItemCard and CandidateCard; `@tanstack/react-router` → `react` in GlobalItemCard
|
||||||
|
- **Files modified:** ItemCard.tsx, CandidateCard.tsx, GlobalItemCard.tsx
|
||||||
|
- **Verification:** `bunx @biomejs/biome check` on all 4 files — no errors
|
||||||
|
- **Committed in:** 88db308 (Task 2 commit)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Total deviations:** 1 auto-fixed (Rule 1 — import order)
|
||||||
|
**Impact on plan:** Necessary for lint compliance. No logic or behavior changes.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
- Pre-existing lint errors in `scripts/crawl-all.ts`, `scripts/crawl-manufacturer.ts`, and `tests/services/manufacturer.service.test.ts` are unrelated to this plan — logged as out-of-scope, not fixed.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
None - no external service configuration required.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
- FIX-03 resolved — all card types now show skeleton while presigned S3 URLs resolve, then fade in
|
||||||
|
- Ready for 35-03 (FIX-05: cursor pointer on clickable links)
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 35-bug-fixes*
|
||||||
|
*Completed: 2026-04-19*
|
||||||
Reference in New Issue
Block a user