Enhance mobile responsiveness across all components
Comprehensive mobile improvements: - Toolbar: Added hamburger menu for mobile, larger touch targets - FileTabs: Taller tabs with always-visible close buttons on mobile - FileTree: Larger touch targets, bigger icons and buttons - ConsolePanel: Collapsed by default on mobile with toggle - Added touch-manipulation CSS for better tap performance - Responsive typography and spacing throughout
This commit is contained in:
parent
024ec42c5e
commit
68c881374d
4 changed files with 146 additions and 84 deletions
|
|
@ -38,6 +38,7 @@ function App() {
|
|||
const isMobile = useIsMobile();
|
||||
|
||||
const [showPassportLogin, setShowPassportLogin] = useState(false);
|
||||
const [consoleCollapsed, setConsoleCollapsed] = useState(isMobile);
|
||||
const [user, setUser] = useState<{ login: string; avatarUrl: string; email: string } | null>(() => {
|
||||
const stored = typeof window !== 'undefined' ? localStorage.getItem('aethex-user') : null;
|
||||
return stored ? JSON.parse(stored) : null;
|
||||
|
|
@ -446,7 +447,10 @@ end)`,
|
|||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</div>
|
||||
<ConsolePanel />
|
||||
<ConsolePanel
|
||||
collapsed={consoleCollapsed}
|
||||
onToggle={() => setConsoleCollapsed(!consoleCollapsed)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{/* Unified feature tabs for all major panels */}
|
||||
|
|
|
|||
|
|
@ -19,12 +19,12 @@ export function FileTabs({
|
|||
if (openFiles.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div className="flex items-center bg-card/70 border-b border-border h-8 min-h-8">
|
||||
<div className="flex overflow-x-auto flex-1">
|
||||
<div className="flex items-center bg-card/70 border-b border-border h-9 md:h-8 min-h-[36px] md:min-h-8">
|
||||
<div className="flex overflow-x-auto flex-1 scrollbar-thin scrollbar-thumb-muted scrollbar-track-transparent">
|
||||
{openFiles.map((file) => (
|
||||
<div
|
||||
key={file.id}
|
||||
className={`flex items-center gap-1 px-3 h-8 border-r border-border cursor-pointer group min-w-0 transition-colors select-none ${
|
||||
className={`flex items-center gap-1 px-3 md:px-3 py-1 md:py-0 h-9 md:h-8 border-r border-border cursor-pointer group min-w-0 transition-colors select-none ${
|
||||
activeFileId === file.id
|
||||
? 'bg-background border-b-2 border-b-accent font-semibold text-accent'
|
||||
: 'hover:bg-muted/60 text-muted-foreground'
|
||||
|
|
@ -32,18 +32,19 @@ export function FileTabs({
|
|||
onClick={() => onFileSelect(file)}
|
||||
title={file.name}
|
||||
>
|
||||
<span className="text-xs truncate max-w-[100px]">{file.name}</span>
|
||||
<span className="text-xs md:text-xs truncate max-w-[100px] md:max-w-[120px]">{file.name}</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-4 w-4 p-0 ml-1 opacity-0 group-hover:opacity-100 hover:text-destructive flex-shrink-0"
|
||||
className="h-5 w-5 md:h-4 md:w-4 p-0 ml-1 opacity-70 md:opacity-0 group-hover:opacity-100 hover:text-destructive flex-shrink-0 touch-manipulation"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onFileClose(file.id);
|
||||
}}
|
||||
tabIndex={-1}
|
||||
>
|
||||
<X size={12} />
|
||||
<X size={14} className="md:hidden" />
|
||||
<X size={12} className="hidden md:block" />
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ export function FileTree({
|
|||
onDragLeave={handleDragLeave}
|
||||
onDrop={(e) => handleDrop(e, node)}
|
||||
onDragEnd={handleDragEnd}
|
||||
className={`flex items-center gap-1 px-2 py-1 hover:bg-muted/60 cursor-pointer group rounded-sm transition-colors ${
|
||||
className={`flex items-center gap-1 px-2 py-1.5 md:py-1 hover:bg-muted/60 cursor-pointer group rounded-sm transition-colors touch-manipulation ${
|
||||
isSelected ? 'bg-accent/30 text-accent font-semibold' : 'text-foreground'
|
||||
} ${isDragging ? 'opacity-50' : ''} ${isDropTarget && node.type === 'folder' ? 'bg-blue-500/20 border-2 border-blue-500 border-dashed' : ''}`}
|
||||
style={{ paddingLeft: `${depth * 10 + 8}px` }}
|
||||
|
|
@ -167,12 +167,12 @@ export function FileTree({
|
|||
>
|
||||
{node.type === 'folder' ? (
|
||||
isExpanded ? (
|
||||
<FolderOpen size={15} className="flex-shrink-0 opacity-80" />
|
||||
<FolderOpen size={16} className="flex-shrink-0 opacity-80 md:w-[15px] md:h-[15px]" />
|
||||
) : (
|
||||
<Folder size={15} className="flex-shrink-0 opacity-80" />
|
||||
<Folder size={16} className="flex-shrink-0 opacity-80 md:w-[15px] md:h-[15px]" />
|
||||
)
|
||||
) : (
|
||||
<File size={15} className="flex-shrink-0 opacity-80" />
|
||||
<File size={16} className="flex-shrink-0 opacity-80 md:w-[15px] md:h-[15px]" />
|
||||
)}
|
||||
|
||||
{isEditing ? (
|
||||
|
|
@ -197,9 +197,9 @@ export function FileTree({
|
|||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-5 w-5 opacity-0 group-hover:opacity-100"
|
||||
className="h-6 w-6 md:h-5 md:w-5 opacity-50 md:opacity-0 group-hover:opacity-100 touch-manipulation"
|
||||
>
|
||||
<DotsThree size={13} />
|
||||
<DotsThree size={16} className="md:w-[13px] md:h-[13px]" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { Copy, FileCode, Download, Info, Play, FolderPlus, User, SignOut } from '@phosphor-icons/react';
|
||||
import { Copy, FileCode, Download, Info, Play, FolderPlus, User, SignOut, List } from '@phosphor-icons/react';
|
||||
import { toast } from 'sonner';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
|
|
@ -56,92 +56,149 @@ export function Toolbar({ code, onTemplatesClick, onPreviewClick, onNewProjectCl
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center gap-1 px-2 py-1.5 bg-card border-b border-border min-h-[38px]">
|
||||
<h1 className="text-lg font-bold tracking-tight leading-none">
|
||||
<div className="flex items-center gap-1 px-2 py-1.5 bg-card border-b border-border min-h-[38px] md:min-h-[42px]">
|
||||
<h1 className="text-base md:text-lg font-bold tracking-tight leading-none">
|
||||
Ae<span className="text-accent">Thex</span>
|
||||
</h1>
|
||||
<span className="text-xs text-muted-foreground ml-1 leading-none">Studio</span>
|
||||
|
||||
<div className="flex-1" />
|
||||
|
||||
{/* Desktop: Show all buttons */}
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={onNewProjectClick}
|
||||
className="p-1.5 rounded hover:bg-accent/10"
|
||||
aria-label="New Project"
|
||||
>
|
||||
<FolderPlus size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>New Project</TooltipContent>
|
||||
</Tooltip>
|
||||
<div className="hidden md:flex items-center gap-1">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={onNewProjectClick}
|
||||
className="p-1.5 rounded hover:bg-accent/10"
|
||||
aria-label="New Project"
|
||||
>
|
||||
<FolderPlus size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>New Project</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={onPreviewClick}
|
||||
className="p-1.5 rounded hover:bg-accent/10"
|
||||
aria-label="Preview"
|
||||
>
|
||||
<Play size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Preview</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={onPreviewClick}
|
||||
className="p-1.5 rounded hover:bg-accent/10"
|
||||
aria-label="Preview"
|
||||
>
|
||||
<Play size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Preview</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="ghost" size="icon" onClick={onTemplatesClick} className="p-1.5 rounded hover:bg-accent/10" aria-label="Templates">
|
||||
<FileCode size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Templates</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="ghost" size="icon" onClick={onTemplatesClick} className="p-1.5 rounded hover:bg-accent/10" aria-label="Templates">
|
||||
<FileCode size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Templates</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="ghost" size="icon" onClick={handleCopy} className="p-1.5 rounded hover:bg-accent/10" aria-label="Copy">
|
||||
<Copy size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Copy</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="ghost" size="icon" onClick={handleCopy} className="p-1.5 rounded hover:bg-accent/10" aria-label="Copy">
|
||||
<Copy size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Copy</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={handleExport}
|
||||
className="p-1.5 rounded hover:bg-accent/10 hidden sm:flex"
|
||||
aria-label="Export"
|
||||
>
|
||||
<Download size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Export</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={handleExport}
|
||||
className="p-1.5 rounded hover:bg-accent/10"
|
||||
aria-label="Export"
|
||||
>
|
||||
<Download size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Export</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="ghost" size="icon" onClick={() => setShowInfo(true)} className="p-1.5 rounded hover:bg-accent/10" aria-label="About">
|
||||
<Info size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>About</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="ghost" size="icon" onClick={() => setShowInfo(true)} className="p-1.5 rounded hover:bg-accent/10" aria-label="About">
|
||||
<Info size={18} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>About</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
{/* Mobile: Hamburger menu with essential actions */}
|
||||
<div className="flex md:hidden items-center gap-1">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={onPreviewClick}
|
||||
className="p-2 rounded hover:bg-accent/10"
|
||||
aria-label="Preview"
|
||||
>
|
||||
<Play size={20} weight="bold" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Preview</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="p-2 rounded hover:bg-accent/10"
|
||||
aria-label="Menu"
|
||||
>
|
||||
<List size={20} weight="bold" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-48">
|
||||
<DropdownMenuItem onClick={onNewProjectClick}>
|
||||
<FolderPlus className="mr-2" size={16} />
|
||||
<span>New Project</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={onTemplatesClick}>
|
||||
<FileCode className="mr-2" size={16} />
|
||||
<span>Templates</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={handleCopy}>
|
||||
<Copy className="mr-2" size={16} />
|
||||
<span>Copy Code</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={handleExport}>
|
||||
<Download className="mr-2" size={16} />
|
||||
<span>Export</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => setShowInfo(true)}>
|
||||
<Info className="mr-2" size={16} />
|
||||
<span>About</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="rounded-full p-0">
|
||||
<Avatar className="h-7 w-7">
|
||||
<Button variant="ghost" size="icon" className="rounded-full p-0 ml-1">
|
||||
<Avatar className="h-7 w-7 md:h-8 md:w-8">
|
||||
<AvatarImage src={user?.avatarUrl} alt={user?.login || 'User'} />
|
||||
<AvatarFallback>
|
||||
<User size={16} />
|
||||
|
|
|
|||
Loading…
Reference in a new issue