fix: Choose Avatar responsive on mobile (Fixes #35)#44
Conversation
- Use 4 columns on mobile, 5 on larger screens - Touch-friendly min 48px tap targets, responsive emoji size - Scale selected avatar 105% on mobile to avoid overflow - Add touch-manipulation and active state for mobile - Prevent horizontal overflow with min-w-0 - Graceful handling when Supabase env missing (no blank page) - Add mobile screenshot in docs/screenshots/ Made-with: Cursor
There was a problem hiding this comment.
Pull request overview
Improves the mobile responsiveness of the onboarding “Choose Avatar” UI and introduces a frontend-side fallback to avoid blank-page failures when Supabase env vars are missing.
Changes:
- Adjusts onboarding layout/avatar grid to prevent horizontal overflow and improve tap targets on small screens.
- Adds defensive handling around session lookup on the Home page to ensure loading state resolves even if session retrieval fails.
- Changes Supabase client initialization and helper functions to tolerate missing
VITE_SUPABASE_URL/VITE_SUPABASE_ANON_KEY.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| frontend/src/pages/Onboarding.tsx | Makes the avatar picker responsive (grid columns, sizing, overflow containment, touch behavior). |
| frontend/src/pages/Home.tsx | Ensures the home screen exits loading state even if session check throws. |
| frontend/src/lib/supabase.ts | Adds “Supabase not configured” fallback behavior in helpers and changes client initialization. |
| docs/screenshots/issue-35-mobile-onboarding.png | Adds a mobile screenshot documenting the updated onboarding layout. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (!supabase) { | ||
| return { data: null, error: { message: 'Supabase not configured. Add VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY to .env' } as any }; | ||
| } |
There was a problem hiding this comment.
When Supabase isn’t configured, signInAnonymously returns { data: null, error: { message } } with as any. This forces consumers to rely on runtime checks and any, and makes it easy to accidentally dereference data assuming the normal Supabase response shape. Consider returning a typed object matching Supabase’s auth response shape (e.g., data: { user: null, session: null }) and a properly typed AuthError/Error, or throw a dedicated configuration error that callers can catch and surface.
| try { | ||
| const session = await getSession(); | ||
| if (session) { | ||
| navigate('/dashboard'); | ||
| } | ||
| } catch { | ||
| // ignore | ||
| } finally { | ||
| setLoading(false); | ||
| } |
There was a problem hiding this comment.
getSession already handles the unconfigured Supabase case and catches errors internally (returns null). The extra try/catch { /* ignore */ } here is redundant and can hide unexpected errors during local debugging. Consider removing the try/catch and relying on getSession’s behavior (or at least logging the caught error in development).
| try { | |
| const session = await getSession(); | |
| if (session) { | |
| navigate('/dashboard'); | |
| } | |
| } catch { | |
| // ignore | |
| } finally { | |
| setLoading(false); | |
| } | |
| const session = await getSession(); | |
| if (session) { | |
| navigate('/dashboard'); | |
| } | |
| setLoading(false); |
| export const supabase: SupabaseClient = | ||
| supabaseUrl && supabaseAnonKey | ||
| ? createClient(supabaseUrl, supabaseAnonKey) | ||
| : (null as unknown as SupabaseClient); |
There was a problem hiding this comment.
supabase is exported as SupabaseClient but can be null at runtime via (null as unknown as SupabaseClient). This defeats strict null-safety and can lead to runtime crashes in code that uses supabase directly (e.g., frontend/src/lib/api.ts calls supabase.auth.getSession() without a guard). Prefer exporting supabase as SupabaseClient | null (or undefined) and updating call sites/helpers to handle the unconfigured case explicitly (or provide a safe stub implementation).
| export const supabase: SupabaseClient = | |
| supabaseUrl && supabaseAnonKey | |
| ? createClient(supabaseUrl, supabaseAnonKey) | |
| : (null as unknown as SupabaseClient); | |
| export const supabase: SupabaseClient | null = | |
| supabaseUrl && supabaseAnonKey | |
| ? createClient(supabaseUrl, supabaseAnonKey) | |
| : null; |
Summary
Makes the "Choose Avatar" section on the onboarding screen fully responsive on mobile devices. Fixes layout overflow, alignment, and cramped interaction on small viewports.
Changes
sm+to prevent overflowtext-2xl→text-4xlby breakpoint)scale-105on mobile,scale-110on larger screens to avoid overflowtouch-manipulationto reduce tap delay;active:border-primary-400for tap feedbackmin-w-0and overflow handling so content doesn't spill horizontallyAlso: app no longer shows a blank page when Supabase env vars are missing (graceful fallback so the UI always loads).
Screenshot (mobile)
How to test
cd frontend && npm run devFixes #35