diff --git a/_bmad-output/planning-artifacts/library-many-frames-design-ideas.md b/_bmad-output/planning-artifacts/library-many-frames-design-ideas.md new file mode 100644 index 0000000..aa6e622 --- /dev/null +++ b/_bmad-output/planning-artifacts/library-many-frames-design-ideas.md @@ -0,0 +1,159 @@ +# Library page β€” scaling to many frames + +**Date:** 2026-05-14 +**Facilitated by:** BMAD design team +**Active personas:** 🎨 Sally (UX), 🎨 Maya (Design Thinking), πŸ“‹ John (PM), πŸ—οΈ Winston (Architect) +**Brief from {{user_name}}:** Library doesn't scale beyond 1-2 frames. Need design ideas. + +--- + +## 1. The problem, stated by the user reading the screen + +🎨 **Sally:** *"Picture Aunt Carol. She's gifted PictureFrame units to her two grown kids and three grandkids β€” five frames in the wild. She opens the Library page, ready to approve last weekend's birthday photos. Each photo card stacks five 'Living Room', 'Kitchen', 'Bedroom', 'Mom's Place', 'Cabin' chips PLUS five lock chips. With twenty photos on screen that's two hundred buttons. She squints, taps the wrong one, undoes it. The page feels broken β€” and Aunt Carol is the literal target user."* + +The current per-photo layout (` + + + + +
+ πŸ… Each photo card is just the image + a one-line status. The lock + is a corner badge on the photo (lock-icon). Tap any photo to open the + bottom sheet with device approvals + per-device lock β€” same UI we already + use for upload. +
+ +
+
+
+
+
πŸ”’
+
+
+ 3/5 frames + +
+
+
+
+
+
+
+ 2/5 frames + +
+
+
+
+
+
+
+ 5/5 frames + +
+
+
+
+
+
πŸ”’
+
+
+ 2/5 frames + +
+
+
+
+
+
+
+ 2/5 frames + +
+
+
+
+
+
+
+ 3/5 frames + +
+
+
+ + +
+
+
Manage frames for this photo
+
+
Living Room
Online Β· last sync 2m ago
+ + +
+
+
Kitchen
Online Β· last sync 5m ago
+ + +
+
+
Bedroom
Online Β· last sync 1m ago
+ + +
+
+
Mom's Place
Online Β· last sync 3m ago
+ + +
+
+
Cabin
Offline Β· last seen 2h ago
+ + +
+ +
+ + + diff --git a/public/mockups/library/concept-b.html b/public/mockups/library/concept-b.html new file mode 100644 index 0000000..8dc32bb --- /dev/null +++ b/public/mockups/library/concept-b.html @@ -0,0 +1,172 @@ + + + + + +Concept πŸ…‘ β€” Device-first + + + + +
+
+

Library

+
+ + +
+
+ +
+ + +
+ +
+ πŸ…‘ Group photos by frame, not the other way around. Each row is a + frame β€” name, status, locked photo, scroll of approved photos, and a + big + button to add more. Answers "what's on Grandma's frame?" + in one glance. +
+ +
+
+
+
Living Room
+
8 photos Β· πŸ”’ Birthday cake
+
+ +
+
+
πŸ”’
+
+
+
+
+
+
+ 5 more
+
+ +
+
+
+
Kitchen
+
12 photos Β· rotating
+
+ +
+
+
+
+
+
+
+
+
+ 9 more
+
+ +
+
+
+
Bedroom
+
3 photos Β· rotating
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
Mom's Place
+
6 photos Β· πŸ”’ Family dinner
+
+ +
+
+
πŸ”’
+
+
+
+
+
+
+ 3 more
+
+ +
+
+
+
Cabin
+
2 photos Β· offline 2h
+
+ +
+
+
+
+
+
+
+
+ + +
+ + diff --git a/public/mockups/library/concept-c.html b/public/mockups/library/concept-c.html new file mode 100644 index 0000000..b4bc682 --- /dev/null +++ b/public/mockups/library/concept-c.html @@ -0,0 +1,131 @@ + + + + + +Concept πŸ…’ β€” Multi-select bulk + + + + +
+
+ 3 selected +
+ + + + +
+
+ +
+ πŸ…’ Long-press any photo to enter selection mode (this mockup is + pre-entered). Top bar morphs to action bar. Tick multiple photos, hit + "Send to β–Έ" β€” opens the DevicePicker once for the batch. J1 ("send to + all my frames") becomes two gestures instead of N Γ— 5. +
+ +
+
+
+
+
βœ“
+
+
3/5 frames
+
+
+
+
+
+
+
2/5 frames
+
+
+
+
+
βœ“
+
+
5/5 frames
+
+
+
+
+
+
+
2/5 frames
+
+
+
+
+
βœ“
+
+
2/5 frames
+
+
+
+
+
+
+
3/5 frames
+
+
+
+
+
+
+
1/5 frames
+
+
+
+
+
+
+
4/5 frames
+
+
+ + +
+ + diff --git a/public/mockups/library/concept-d.html b/public/mockups/library/concept-d.html new file mode 100644 index 0000000..96d11ad --- /dev/null +++ b/public/mockups/library/concept-d.html @@ -0,0 +1,146 @@ + + + + + +Concept πŸ…“ β€” Chip filter + dots + + + + +
+
+

Library

+
+ + +
+
+ +
+ + + + + + +
+ +
+ πŸ…“ A horizontally-scrolling chip bar at the top filters the grid + by frame. Each photo shows little colour dots representing the frames it's + on (initials, lock-flag for the locked frame). Tap a photo to manage in + a sheet. Works at any N because the dots can scroll-truncate. +
+ +
+
+
+
+
+ LR + KT + MP + BR + CA +
+
+
+
+
+
+
+ LR + BR + KT + MP + CA +
+
+
+
+
+
+
+ LR + KT + BR + MP + CA +
+
+
+
+
+
+
+ MP + KT + LR + BR + CA +
+
+
+
+
+
+
+ LR + CA + KT + BR + MP +
+
+
+
+
+
+
+ LR + KT + BR + MP + CA +
+
+
+
+ + +
+ + diff --git a/public/mockups/library/current.html b/public/mockups/library/current.html new file mode 100644 index 0000000..a2cace3 --- /dev/null +++ b/public/mockups/library/current.html @@ -0,0 +1,129 @@ + + + + + +Library β€” current state + + + + +
+
+

Library

+
+ + +
+
+ +
+ Pain point: each photo card stacks two rows of 5 chips + (approve Β· lock). At 10 photos Γ— 5 frames that's 100 buttons on screen. +
+ +
+ +
+
+
+ + + + + +
+
+ + + +
+
+
+
+
+ + + + + +
+
+ + +
+
+
+
+
+ + + + + +
+
+ + + + + +
+
+
+
+
+ + + + + +
+
+ + +
+
+
+
+
+ + + + + +
+
+ + +
+
+
+
+
+ + + + + +
+
+ + + +
+
+
+ + +
+ + diff --git a/public/mockups/library/index.html b/public/mockups/library/index.html new file mode 100644 index 0000000..2151972 --- /dev/null +++ b/public/mockups/library/index.html @@ -0,0 +1,60 @@ + + + + + +Library β€” design concepts + + + + +
+

Library page β€” scaling to many frames

+

Static HTML wireframes for the five concepts in the BMAD design memo. Each + uses the same design tokens as the real Vue app, fake content set at five + devices and ten photos so chip-count pain is visible.

+ + +
+ + diff --git a/public/mockups/library/shared.css b/public/mockups/library/shared.css new file mode 100644 index 0000000..40b2e60 --- /dev/null +++ b/public/mockups/library/shared.css @@ -0,0 +1,109 @@ +/* Design tokens cloned from frontend/src/styles/global.scss so mockups + feel native without the full Vue app shell. */ +:root { + --text-xs: 11px; --text-sm: 13px; --text-base: 15px; --text-md: 17px; + --text-lg: 20px; --text-xl: 24px; --text-2xl: 28px; + --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; + --space-5: 20px; --space-6: 24px; --space-8: 32px; + --radius-sm: 6px; --radius-md: 12px; --radius-lg: 20px; --radius-full: 9999px; + --color-bg: #fdf6ee; --color-surface: #fff9f2; --color-surface-2: #f5ead8; + --color-border: #e8d9c4; --color-text: #3a2e22; --color-text-muted: #8a7060; + --color-primary: #c97c3a; --color-primary-fg: #ffffff; + --color-secondary: #e8d9c4; --color-destructive: #c0392b; + --color-lock: #c49a20; + --shadow-card: 0 2px 4px rgba(58, 46, 34, 0.06); +} +* { box-sizing: border-box; } +body { + margin: 0; padding: 0; background: var(--color-bg); color: var(--color-text); + font-family: -apple-system, BlinkMacSystemFont, system-ui, sans-serif; + font-size: var(--text-base); +} +button { font-family: inherit; cursor: pointer; } + +/* Mac-friendly viewport β€” show the mobile width centered on a wide screen */ +.frame { + max-width: 420px; + margin: 0 auto; + min-height: 100dvh; + background: var(--color-bg); + border-left: 1px solid var(--color-border); + border-right: 1px solid var(--color-border); + position: relative; +} + +/* Topbar */ +.topbar { + position: sticky; top: 0; z-index: 5; + background: var(--color-surface); + border-bottom: 1px solid var(--color-border); + padding: var(--space-4) var(--space-4) var(--space-2); +} +.topbar h1 { font-size: var(--text-xl); margin: 0; font-weight: 700; } +.topbar__tabs { display: flex; gap: var(--space-2); margin-top: var(--space-3); } +.topbar__tab { + background: transparent; border: 0; + padding: var(--space-2) var(--space-3); + font-size: var(--text-sm); font-weight: 600; + color: var(--color-text-muted); + border-radius: var(--radius-sm); +} +.topbar__tab--active { color: var(--color-text); background: var(--color-surface-2); } + +/* Generic chip / button */ +.chip { + display: inline-flex; align-items: center; gap: 4px; + padding: 5px 10px; + border-radius: var(--radius-full); + background: var(--color-surface-2); + border: 1px solid var(--color-border); + font-size: var(--text-xs); font-weight: 600; + color: var(--color-text-muted); +} +.chip--on { background: var(--color-primary); color: var(--color-primary-fg); border-color: var(--color-primary); } +.chip--lock { background: #fff4d1; border-color: var(--color-lock); color: #6b5210; } +.chip--lock-on { background: var(--color-lock); color: white; border-color: var(--color-lock); } +.chip--device { padding: 3px 8px; font-size: var(--text-xs); } + +/* Photo placeholder β€” colored gradient so each one is visually distinct */ +.photo { + display: block; width: 100%; aspect-ratio: 1/1; + border-radius: var(--radius-sm); + background: linear-gradient(135deg, #d4a37e, #8c5a3a); + position: relative; overflow: hidden; +} +.photo--p1 { background: linear-gradient(135deg, #c97c3a, #6b3e1e); } +.photo--p2 { background: linear-gradient(135deg, #3a8a6e, #1f4d3d); } +.photo--p3 { background: linear-gradient(135deg, #8c6fc1, #4c3a82); } +.photo--p4 { background: linear-gradient(135deg, #e0a85c, #a5602c); } +.photo--p5 { background: linear-gradient(135deg, #5e9bb0, #2f5f72); } +.photo--p6 { background: linear-gradient(135deg, #d4a37e, #8c5a3a); } +.photo--p7 { background: linear-gradient(135deg, #6f8c5e, #3e5630); } +.photo--p8 { background: linear-gradient(135deg, #c1715a, #6e3a2d); } +.photo--p9 { background: linear-gradient(135deg, #a08fb1, #62506f); } +.photo--p10{ background: linear-gradient(135deg, #d3a87b, #84583a); } + +/* Portrait-aspect variant for the photo simulating a portrait crop */ +.photo--portrait { aspect-ratio: 3/4; } + +/* Footer nav (decorative, just to look like the real PWA) */ +.bottomnav { + position: sticky; bottom: 0; + background: var(--color-surface); + border-top: 1px solid var(--color-border); + padding: var(--space-3); display: flex; gap: var(--space-4); + justify-content: space-around; font-size: var(--text-xs); + color: var(--color-text-muted); +} +.bottomnav__item { display: flex; flex-direction: column; align-items: center; gap: 2px; } +.bottomnav__item--active { color: var(--color-primary); } + +/* Mockup note panel */ +.note { + background: #fff5dc; + border: 1px dashed var(--color-lock); + border-radius: var(--radius-sm); + padding: var(--space-3); margin: var(--space-3) var(--space-4); + font-size: var(--text-sm); color: #6b5210; +} +.note b { color: #3a2e22; }