UI Architecture
UI Architecture
Skill in use: ui-architecture — documenting entry points, composition, state, and PWA behaviors from code.
1. UI entry points
src/main.jsxmounts<App />insideReact.StrictModeand importstokens.css+styles.css, so all UI and theming originate here.src/App.jsxis the single page shell: it gates auth (AuthScreen), readiness, and renders the multi-pane layout plus Settings/action sheets; there is no router or lazy-loading boundary.- Auth flows originate in
src/AuthScreen.jsx(three-zone layout post-SUR-261: whitespace top → centred<HomeHero />→ CTA stack pinned above safe-area inset). The primary CTA callssignInWithGoogle()fromsrc/supabase.js; a secondary “Use a different account” CTA openssrc/components/BottomSheet.jsxcontaining the email-OTP sign-in flow, which callsrequestEmailOtp(email)thenverifyEmailOtp(email, token)(nosignUp—shouldCreateUser:falserejects unknown emails with a friendly waitlist CTA). Platform detection (TWA / standalone PWA → 6-digit code; desktop → magic link) lives insrc/lib/platform.js. The hero is the shared<HomeHero />component (src/components/HomeHero.jsx), also used byHomeScreen.jsx. The resulting session is handed back to<App />. - Shared hooks such as
useAuth,useUI,useNoteForm,useSettings,useNoteActions, anduseToast(all undersrc/hooks/) act as service locators for state; components receive pre-wired props rather than owning data fetching. - When
window.location.pathname === '/how-it-works',<App />short-circuits all other routing logic and renderssrc/components/HowItWorksPage.jsx, feeding it the structured content defined insrc/content/howItWorksContent.jsso copy/media placeholders live in one file. LandingPage.jsx(logged-out marketing surface) andSettingsModal.jsx(in-app help) now expose aHow Surfc workslink that deep-links to/how-it-works?source=landing|settingswhile recording entry events viauseAnalytics.
2. Screen/module structure
flowchart LR App[src/App.jsx] -->|auth gating| AuthScreen[src/AuthScreen.jsx] App -->|state props| Home[components/HomeScreen.jsx] App --> Capture[components/CaptureScreen.jsx] App --> Review[components/ReviewScreen.jsx] App --> NoteForm[components/NoteForm.jsx] App --> Library[components/Library.jsx] App --> Index[components/IndexScreen.jsx] App --> Sidebar[components/IdeasSidebar.jsx] App --> Detail[components/IdeaDetail.jsx] App --> Settings[components/SettingsModal.jsx] App --> NoteAction[components/NoteActionSheet.jsx] App --> IdeaAction[components/IdeaActionSheet.jsx]- Screens:
HomeScreen,CaptureScreen,ReviewScreen, andIndexScreenmap to the mobile tab states managed byuseUI(mobileViewstate insrc/hooks/useUI.js). Desktop rendering keeps the sidebar (IdeasSidebar) and detail pane (IdeaDetail) persistently visible, while mobile swaps panels via conditional rendering insideApp. - Notes + Library:
NoteForm(new note composer) andLibrary(list view usingNoteCard.jsx) share prop-driven dependencies for books, notes, tagging, and callbacks. - Idea interactions:
IdeasSidebarsurfaces canonical + custom ideas and usesuseLongPress(src/hooks/useLongPress.js) to open edit/delete sheets;IdeaDetail.jsxshows counts, note excerpts, and rediscovery triggers via props. - Settings + modals:
SettingsModal.jsxis always rendered but hidden whenshowSettingsis false; it multiplexes account info, API key editing, custom idea CRUD, and import/export.NoteActionSheet.jsx,NoteEditForm.jsx,IdeaActionSheet.jsx, andIdeaEditForm.jsxare toggled via state variables inApp.jsx. - Navigation controls: Bottom nav buttons in
App.jsxcalluseUIhelpers (goToHome,goToCapture,goToIndex, etc.), so navigation is purely stateful rather than URL-based. - Public help surface:
HowItWorksPage.jsxconsumes theHOW_IT_WORKS_CONTENTobject to render hero/section/FAQ/CTA blocks with responsive.hiw-*styles (seesrc/styles.css). The component keeps anonymous access by reading, but not requiring,useAuthsession state and drives PostHog events (how_it_works_viewed,how_it_works_cta_click) for marketing attribution.
3. State and data access patterns
useAuth(src/hooks/useAuth.js) is the root state provider: it loads Dexie vialoadAll, tracks Supabase session/online status, triggers sync (seesyncFromCloud), and exposesbooks,notes,customIdeas,apiKey, plus acloudWritehelper to downstream hooks.useUI(src/hooks/useUI.js) owns presentation-only state such asmobileView,selectedIdea, search text, settings modal, and lightbox image; it derivesideaCountsandnotesForIdeafrom current notes.useNoteForm(src/hooks/useNoteForm.js) composes Dexie mutations (saveBook,saveNote), Supabase writes (viacloudWriteanduploadImage), and AI calls (callTranscribeImage,callDiscoverIdeas). It threads callbacks (goToLibrary,selectIdea) supplied byuseUI, so the hook bridges local state, sync, and AI ingestion explicitly.useSettings(src/hooks/useSettings.js) couples Dexie operations (custom idea CRUD, import/export, API key persistence) with UI flows; renaming custom ideas cascades throughdbUpdateNoteandsyncPendingTagRename.useNoteActions(src/hooks/useNoteActions.js) provides note edit/delete/rediscover behaviors, combining Dexie updates,cloudWrite, and additional AI tagging when “Rediscover Ideas” is used.- Toast notifications are managed by
useToast(src/hooks/useToast.js, a simple timer state) and displayed at the bottom ofApp. useAnalytics(src/hooks/useAnalytics.js) wrapsposthog-js/react; LandingPage, SettingsModal, and HowItWorksPage emithow_it_works_entry_click,how_it_works_viewed, andhow_it_works_cta_clickevents to PostHog for attribution.- Because there is no context/provider system,
<App />calls each hook once and threads dozens of props to leaf components, keeping data ownership centralized but increasing prop drilling.
4. PWA behavior
vite.config.jsregisters@vitejs/plugin-reactplusVitePWAwithregisterType: 'autoUpdate', Google Fonts runtime caches, and a manifest (standalone display, custom theme/background colors, maskable icons).netlify.tomlconfigures SPA redirects and manifest headers so the PWA works when deployed to Netlify’s static hosting.- Online/offline indicators rely on
navigator.onLineandwindowevents inuseAuth; reconnect triggerssyncFromCloud, which first flushes local writes then refetches Supabase tables (src/hooks/useAuth.js). - Service worker registration is delegated to VitePWA (
vite.config.jswithregisterType: 'autoUpdate'), so there is no custom background sync or push logic insrc/main.jsx. - Asset caching beyond fonts uses the default Workbox precache glob (
**/*.{js,css,html,ico,png,svg,woff2}), meaning note images remain device-local until uploaded to Supabase (and downloaded again on other devices). - Anthropic API calls are performed client-side via
fetch, so the PWA works offline for capture+queueing but requires connectivity for transcription/tagging.
5. Risks and refactor opportunities
- Single monolithic shell:
src/App.jsxmixes layout, navigation, modal orchestration, and lightbox logic; failures ripple across every screen. - Hook bloat:
src/hooks/useNoteForm.jsandsrc/hooks/useSettings.jscombine UX state with Dexie, Supabase, and Anthropic calls, making the coupling between local state, sync, and AI logic harder to reason about. - Prop drilling: Without React context providers for collections or UI state, leaf components receive long prop lists; adding context stores (e.g., notes/books provider) would shrink the surface area.
- PWA opacity: Reliance on
vite-plugin-pwadefaults hides service-worker lifecycle events; for a sync-first tool it would help to expose update prompts or background sync status. - Security exposure: Direct Anthropic calls (
src/api.js) require users to paste an API key; the UI never warns that the key lives in IndexedDB (db.meta). - Action sheets vs. accessibility: Long-press interactions implemented via
useLongPress(src/hooks/useLongPress.js) lack keyboard fallbacks, so desktop accessibility is limited.