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,6 +1,6 @@
|
||||
import { useEffect, useState, useCallback } from 'react'
|
||||
import { useNavigate, Link } from 'react-router-dom'
|
||||
import { Plus, Pencil, Globe, Lock, X, Trash2 } from 'lucide-react'
|
||||
import { Plus, Pencil, Globe, Lock, X, Trash2, FolderOpen } from 'lucide-react'
|
||||
import { treesApi, categoriesApi, foldersApi } from '@/api'
|
||||
import type { TreeListItem, CategoryListItem, FolderListItem } from '@/types'
|
||||
import { TagBadges } from '@/components/common/TagBadges'
|
||||
@@ -29,6 +29,9 @@ export function TreeLibraryPage() {
|
||||
const [editingFolder, setEditingFolder] = useState<FolderListItem | null>(null)
|
||||
const [newFolderParentId, setNewFolderParentId] = useState<string | null>(null)
|
||||
|
||||
// Mobile folder sidebar state
|
||||
const [mobileFolderOpen, setMobileFolderOpen] = useState(false)
|
||||
|
||||
// Delete confirmation state
|
||||
const [treeToDelete, setTreeToDelete] = useState<TreeListItem | null>(null)
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
|
||||
@@ -152,17 +155,22 @@ export function TreeLibraryPage() {
|
||||
{/* Folder Sidebar */}
|
||||
<FolderSidebar
|
||||
selectedFolderId={selectedFolderId}
|
||||
onFolderSelect={setSelectedFolderId}
|
||||
onFolderSelect={(id) => {
|
||||
setSelectedFolderId(id)
|
||||
setMobileFolderOpen(false)
|
||||
}}
|
||||
onCreateFolder={handleCreateFolder}
|
||||
onEditFolder={handleEditFolder}
|
||||
mobileOpen={mobileFolderOpen}
|
||||
onMobileClose={() => setMobileFolderOpen(false)}
|
||||
/>
|
||||
|
||||
{/* Main Content */}
|
||||
<div className="flex-1 overflow-auto">
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="mb-8 flex items-start justify-between">
|
||||
<div className="container mx-auto px-4 py-6 sm:px-6 sm:py-8">
|
||||
<div className="mb-6 flex flex-col gap-4 sm:mb-8 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-foreground">Decision Trees</h1>
|
||||
<h1 className="text-2xl font-bold text-foreground sm:text-3xl">Decision Trees</h1>
|
||||
<p className="mt-2 text-muted-foreground">
|
||||
Select a troubleshooting tree to start a new session
|
||||
</p>
|
||||
@@ -183,6 +191,18 @@ export function TreeLibraryPage() {
|
||||
|
||||
{/* Search and Filter */}
|
||||
<div className="mb-4 flex flex-col gap-4 sm:flex-row">
|
||||
{/* Mobile folder button */}
|
||||
<button
|
||||
onClick={() => setMobileFolderOpen(true)}
|
||||
className={cn(
|
||||
'flex items-center gap-2 rounded-md border border-input px-3 py-2 text-sm font-medium md:hidden',
|
||||
'text-muted-foreground hover:bg-accent hover:text-accent-foreground',
|
||||
selectedFolderId && 'border-primary text-primary'
|
||||
)}
|
||||
>
|
||||
<FolderOpen className="h-4 w-4" />
|
||||
Folders
|
||||
</button>
|
||||
<div className="flex flex-1 gap-2">
|
||||
<input
|
||||
type="text"
|
||||
@@ -294,7 +314,7 @@ export function TreeLibraryPage() {
|
||||
{trees.map((tree) => (
|
||||
<div
|
||||
key={tree.id}
|
||||
className="rounded-lg border border-border bg-card p-6 shadow-sm transition-shadow hover:shadow-md"
|
||||
className="rounded-lg border border-border bg-card p-4 shadow-sm transition-all hover:-translate-y-0.5 hover:border-primary/30 hover:shadow-md sm:p-6"
|
||||
>
|
||||
<div className="mb-2 flex items-start justify-between gap-2">
|
||||
<h3 className="font-semibold text-card-foreground">{tree.name}</h3>
|
||||
@@ -336,7 +356,7 @@ export function TreeLibraryPage() {
|
||||
<Link
|
||||
to={`/trees/${tree.id}/edit`}
|
||||
className={cn(
|
||||
'rounded-md border border-input p-1.5 text-muted-foreground',
|
||||
'rounded-md border border-input p-2 text-muted-foreground',
|
||||
'hover:bg-accent hover:text-accent-foreground'
|
||||
)}
|
||||
title="Edit tree"
|
||||
@@ -364,7 +384,7 @@ export function TreeLibraryPage() {
|
||||
type="button"
|
||||
onClick={() => handleStartSession(tree.id)}
|
||||
className={cn(
|
||||
'rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground',
|
||||
'rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground',
|
||||
'hover:bg-primary/90'
|
||||
)}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user