Reflow tablet portrait layouts: Plan week 4 + 3, Settings one column
CI / ci (push) Successful in 8m7s
CI / ci (pull_request) Successful in 8m8s

At 768-1199 px held upright the shell marks itself portrait (new
useOrientation hook over the existing tablet breakpoint) and trims its side
padding; the Plan week lays out four days over three instead of scrolling
sideways, and Settings (mock 2e) stacks its two columns into one. Vitest
covers every primary route at 820x1180 and 1180x820.

Task: 529c743e-4464-479b-b750-7ec41a0c9772

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-10 23:10:16 -04:00
co-authored by Claude Opus 5.5
parent 25edb6fb26
commit b2a4e66675
9 changed files with 297 additions and 13 deletions
+8 -1
View File
@@ -1,4 +1,5 @@
import { useId, useRef, useState, type KeyboardEvent, type ReactNode } from 'react'
import { useBreakpoint, useOrientation } from '../shell/useBreakpoint.ts'
import { Card } from '../ui/Card.tsx'
import { AIAssistantCard } from './AISettingsPage.tsx'
import { HouseholdSettingsSections } from './HouseholdSettingsPage.tsx'
@@ -21,7 +22,10 @@ const step: Record<string, number> = { ArrowRight: 1, ArrowLeft: -1 }
// sub-tabs instead of the mobile list. Every tab stays mounted while hidden,
// so a draft survives switching tabs, and one leave guard covers them all.
// hidden hides the page but keeps it mounted, drafts and leave guard included.
// On an upright tablet the two columns stack into one.
export function SettingsTabs({ hidden = false }: { hidden?: boolean }) {
const layout = useBreakpoint()
const orientation = useOrientation()
const [tab, setTab] = useState<Tab>('notifications-ai')
const [householdDirty, setHouseholdDirty] = useState(false)
const [aiDirty, setAIDirty] = useState(false)
@@ -64,7 +68,10 @@ export function SettingsTabs({ hidden = false }: { hidden?: boolean }) {
}
return (
<div className={styles.page} hidden={hidden}>
<div
className={[styles.page, layout === 'tablet' && orientation === 'portrait' && styles.portrait].filter(Boolean).join(' ')}
hidden={hidden}
>
<header className={styles.header}>
<div className={styles.heading}>
<h1 className={styles.title}>Settings</h1>