feat: add mobile responsiveness, design consistency, and micro-interactions
- Add mobile hamburger menu with slide-out nav drawer (AppLayout) - Make modals responsive: full-width on mobile, slide-up animation - Scratchpad becomes full-screen overlay on mobile with backdrop - Folder sidebar hidden on mobile, opens as slide-over drawer - Tree editor shows "Desktop Required" gate on mobile - Stack action buttons vertically on mobile (sessions, detail pages) - Increase touch targets throughout (buttons, close icons) - Add CSS animations: fade-in, slide-in-left, scale-in, btn-press - Add card hover lift effect and consistent border highlights - Standardize page padding (px-4 py-6 sm:px-6 sm:py-8) - Responsive headings (text-2xl sm:text-3xl) - CustomStepModal goes full-screen on mobile - Tighten auth page spacing on mobile Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useState, useCallback } from 'react'
|
||||
import { useParams, useNavigate, useBlocker } from 'react-router-dom'
|
||||
import { useStore } from 'zustand'
|
||||
import { Undo2, Redo2, Save, CheckCircle2 } from 'lucide-react'
|
||||
import { Undo2, Redo2, Save, CheckCircle2, Monitor } from 'lucide-react'
|
||||
import { treesApi } from '@/api'
|
||||
import type { TreeCreate, TreeUpdate } from '@/types'
|
||||
import { useTreeEditorStore, useTreeEditorTemporal } from '@/store/treeEditorStore'
|
||||
@@ -42,6 +42,15 @@ export function TreeEditorPage() {
|
||||
const [showDraftPrompt, setShowDraftPrompt] = useState(false)
|
||||
const [saveError, setSaveError] = useState<string | null>(null)
|
||||
|
||||
// Mobile detection
|
||||
const [isMobile, setIsMobile] = useState(false)
|
||||
useEffect(() => {
|
||||
const check = () => setIsMobile(window.innerWidth < 768)
|
||||
check()
|
||||
window.addEventListener('resize', check)
|
||||
return () => window.removeEventListener('resize', check)
|
||||
}, [])
|
||||
|
||||
// Calculate if there are blocking errors
|
||||
const hasBlockingErrors = validationErrors.some(e => e.severity === 'error')
|
||||
|
||||
@@ -203,17 +212,30 @@ export function TreeEditorPage() {
|
||||
)
|
||||
}
|
||||
|
||||
// Mobile warning
|
||||
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
|
||||
// Mobile gate: show read-only message
|
||||
if (isMobile) {
|
||||
return (
|
||||
<div className="flex h-[calc(100vh-4rem)] flex-col items-center justify-center px-6 text-center">
|
||||
<Monitor className="mb-4 h-12 w-12 text-muted-foreground" />
|
||||
<h2 className="mb-2 text-xl font-semibold text-foreground">Desktop Required</h2>
|
||||
<p className="mb-6 max-w-sm text-sm text-muted-foreground">
|
||||
The tree editor requires a larger screen for the best experience. Please open this page on a desktop or tablet in landscape mode.
|
||||
</p>
|
||||
<button
|
||||
onClick={() => navigate('/trees')}
|
||||
className={cn(
|
||||
'rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground',
|
||||
'hover:bg-primary/90'
|
||||
)}
|
||||
>
|
||||
Back to Library
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-[calc(100vh-4rem)] flex-col">
|
||||
{/* Mobile Warning */}
|
||||
{isMobile && (
|
||||
<div className="bg-yellow-100 px-4 py-2 text-center text-sm text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-200">
|
||||
Desktop recommended for tree editing. Viewing mode only on mobile.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Draft Restore Prompt */}
|
||||
{showDraftPrompt && (
|
||||
|
||||
Reference in New Issue
Block a user