Commit Graph

6 Commits

Author SHA1 Message Date
football2801 5fcfb806be feat: ship as a real iOS-installable PWA, restructure bottom nav, fix safe-area
CI / test (push) Has been cancelled
- Add manifest.webmanifest with standalone display + warm-craft theme colors,
  apple-touch-icon, and 192/512/512-maskable icons (frame-with-sunset glyph).
- Add PWA meta tags + viewport-fit=cover so add-to-home-screen produces a
  true standalone app on iOS instead of a Safari bookmark.
- Drop the Shared bottom-nav tab; the in-page sub-tabs already cover that.
  Three nav tabs total (Home / Library / Settings); pending-share badge
  moves to the Library tab. Predicate-based isActive() now correctly
  disambiguates /library vs /library?tab=shared.
- Safe-area handling: bottom nav, bottom sheet, upload overlay, and #app
  respect env(safe-area-inset-*); sticky Library tabs anchor below the
  iPhone status bar. Introduces --bottom-nav-height token consumed by
  Settings, Library, and the toast.
- LibraryView reactively follows route.query.tab so deep-linking
  /library?tab=shared lands on the right sub-tab.
- Theme-color meta syncs client-side via useTheme.applyTheme so the
  user's chosen theme follows them into Android Chrome's chrome bar.

Test suite expanded to 278 tests / 100% line coverage (99.84% statements,
99.78% branches). Remaining gaps are unreachable defensive code.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 18:07:16 -04:00
football2801 52e85703f7 feat: orientation toggle and mismatch indicator in crop editor
CI / test (push) Has been cancelled
The crop tool now exposes a landscape/portrait toggle next to the
device-name label, and the canvas crop frame snaps to the chosen
aspect when toggled. Choosing an orientation that does not match
the target frame's current orientation surfaces a yellow informational
chip — purely informational, no action required, clears as soon as
the user toggles back to the matching orientation (or changes the
frame in Settings).

The chosen orientation rides along on the upload/reprocess request
as a new cropOrientation form field and is persisted on the Image
entity, so the library view and rotation logic can later surface
the same mismatch state for already-uploaded photos. Existing photos
without a stored orientation get null and are unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 14:45:59 -04:00
football2801 12245759ac chore: stage all in-progress work before repo split
CI / test (push) Has been cancelled
Web app: new entities (Image, RenderedAsset, SharedImage, Token,
DeviceImageHistory), enums, repositories, controllers, message handlers,
migrations, tests, frontend upload/library/sticker UI, Vue components.

Firmware: EPD background screen binaries + gen scripts, setup_bg header.

Infra: ddev config, test bundle, gitignore coverage dir.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 12:11:31 -04:00
football2801 6c891d6fad feat: orientation model, password confirm, frontend build
- Collapse orientation to landscape/portrait (ribbon left = portrait standard)
- Add OrientationPicker component and wire settings sheet in HomeView
- Add password confirmation field to registration form (RepeatedType)
- Build frontend SPA to public/build/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 16:59:03 -04:00
football2801 6c7c7a1a6f feat(story-2.4): home screen device list with FrameCard component
- FrameCard: large (single device, 5:3 preview + Add Photo CTA) and
  compact (52px thumb + name + count + icon pill) variants; WCAG-
  compliant offline/sync-fail status (color + text, never color alone)
- devices Pinia store: fetchDevices() → GET /api/devices
- HomeView: 0 devices → dashed empty-state card; 1 device → large
  FrameCard; 2+ → compact stack; add-photo wired (Epic 3 stub)
- Fix Device type: rotationInterval → rotationIntervalHours to match API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 00:50:46 -04:00
football2801 a55b3bd187 feat(story-1.2): Vue 3 SPA scaffold, base component library, User entity, SpaController
Frontend:
- Vue 3 + Vite + TypeScript strict in frontend/; builds to public/build/
- Vue Router (hash-history, requiresAuth guard → /login) and Pinia
- Global SCSS design tokens with 6 full themes (Warm Craft, Playful Pop, Sage & Cream, Dusty Mauve, Ocean Dusk, Honey & Slate)
- Base components: BaseButton (5 variants), BaseInput (floating label, error state),
  BaseBottomSheet (slide-up, focus trap, tap-outside dismiss), BaseCard, BaseChip,
  BaseToast (2.5s auto-dismiss, aria-live polite), BottomNav (4 tabs, hides at 960px)
- Type stubs for all API shapes: User, Device, Image, StickerLayer, RenderedAsset, Token

Backend:
- SpaController catch-all serves public/build/index.html; excludes api/setup/token/login/register
- User entity (email+password+roles+theme); UserRepository with PasswordUpgrader
- SecurityController with /login, /logout, /register stubs; Twig login form
- security.yaml: form_login firewall, remember_me, role_hierarchy, access_control
- Migration: create user table

Verified: npm run build succeeds, GET / → 302 /login (unauthenticated)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 23:21:29 -04:00