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:
chihlasm
2026-02-06 01:58:39 -05:00
parent cf6d8bd57b
commit 90ff25003d
14 changed files with 395 additions and 129 deletions

View File

@@ -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'
)}
>