feat: Improve mobile UI/UX with larger touch targets and better layouts
Some checks are pending
CI / build (18.x) (push) Waiting to run
CI / build (20.x) (push) Waiting to run

This commit is contained in:
Khoa Vo 2026-01-07 21:05:59 +07:00
parent 8fd791df68
commit a5bc7ddb39
3 changed files with 12 additions and 12 deletions

View file

@ -442,7 +442,7 @@ export function Gallery() {
)} )}
{/* Gallery Grid */} {/* Gallery Grid */}
<div className="columns-1 sm:columns-2 md:columns-3 lg:columns-4 gap-4 space-y-4"> <div className="columns-2 sm:columns-2 md:columns-3 lg:columns-4 gap-3 md:gap-4 space-y-3 md:space-y-4">
{/* Skeleton Loading State */} {/* Skeleton Loading State */}
{isGenerating && ( {isGenerating && (
<> <>
@ -490,14 +490,14 @@ export function Gallery() {
<button <button
onClick={(e) => { e.stopPropagation(); if (img.id) removeFromGallery(img.id); }} onClick={(e) => { e.stopPropagation(); if (img.id) removeFromGallery(img.id); }}
className="absolute top-2 right-2 p-1.5 bg-black/50 hover:bg-destructive/80 rounded-full text-white opacity-0 group-hover:opacity-100 transition-all" className="absolute top-2 right-2 p-2 md:p-1.5 bg-black/60 hover:bg-destructive/80 rounded-full text-white opacity-100 md:opacity-0 md:group-hover:opacity-100 transition-all min-w-[36px] min-h-[36px] md:min-w-0 md:min-h-0 flex items-center justify-center"
title="Delete" title="Delete"
> >
<X className="h-4 w-4" /> <X className="h-4 w-4" />
</button> </button>
{/* Hover Overlay - Simplified: just show prompt */} {/* Hover Overlay - Simplified: just show prompt */}
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity flex flex-col justify-end p-3 pointer-events-none"> <div className="absolute inset-0 bg-gradient-to-t from-black/70 via-transparent to-transparent opacity-100 md:opacity-0 md:group-hover:opacity-100 transition-opacity flex flex-col justify-end p-2 md:p-3 pointer-events-none">
<p className="text-white text-xs line-clamp-2">{img.prompt}</p> <p className="text-white text-xs line-clamp-2">{img.prompt}</p>
</div> </div>
</motion.div> </motion.div>

View file

@ -434,7 +434,7 @@ export function PromptHero() {
); );
return ( return (
<div className="w-full max-w-3xl mx-auto my-4 md:my-6 px-4"> <div className="w-full max-w-3xl mx-auto my-4 md:my-6 px-3 md:px-4 pb-20 md:pb-4">
{/* Error/Warning Notification Toast */} {/* Error/Warning Notification Toast */}
{errorNotification && ( {errorNotification && (
<div className={cn( <div className={cn(
@ -543,7 +543,7 @@ export function PromptHero() {
{/* Left Controls: References */} {/* Left Controls: References */}
{/* For Meta AI: Only Subject is enabled (for video generation), Scene/Style disabled */} {/* For Meta AI: Only Subject is enabled (for video generation), Scene/Style disabled */}
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2 w-full md:w-auto">
{((settings.provider === 'meta' {((settings.provider === 'meta'
? ['subject'] ? ['subject']
: ['subject', 'scene', 'style']) as ReferenceCategory[]).map((cat) => { : ['subject', 'scene', 'style']) as ReferenceCategory[]).map((cat) => {
@ -561,7 +561,7 @@ export function PromptHero() {
? "Upload image to animate into video" ? "Upload image to animate into video"
: undefined} : undefined}
className={cn( className={cn(
"flex items-center gap-1.5 rounded-md px-3 py-1.5 text-[10px] font-medium transition-all border relative overflow-hidden", "flex items-center gap-1.5 rounded-lg px-3 py-2 md:px-3 md:py-1.5 text-xs md:text-[10px] font-medium transition-all border relative overflow-hidden min-h-[44px] md:min-h-0",
hasRefs hasRefs
? "bg-purple-500/10 text-purple-200 border-purple-500/30 hover:bg-purple-500/20" ? "bg-purple-500/10 text-purple-200 border-purple-500/30 hover:bg-purple-500/20"
: "bg-white/5 text-white/40 border-white/5 hover:bg-white/10 hover:text-white/70 hover:border-white/10", : "bg-white/5 text-white/40 border-white/5 hover:bg-white/10 hover:text-white/70 hover:border-white/10",
@ -688,7 +688,7 @@ export function PromptHero() {
onClick={handleGenerate} onClick={handleGenerate}
disabled={isGenerating || !prompt.trim()} disabled={isGenerating || !prompt.trim()}
className={cn( className={cn(
"relative overflow-hidden px-4 py-1.5 rounded-lg font-bold text-sm text-white shadow-lg transition-all active:scale-95 group border border-white/10", "relative overflow-hidden px-5 py-2.5 md:px-4 md:py-1.5 rounded-xl md:rounded-lg font-bold text-base md:text-sm text-white shadow-lg transition-all active:scale-95 group border border-white/10 min-h-[44px] md:min-h-0",
"bg-gradient-to-r from-purple-600 to-indigo-600 hover:from-purple-500 hover:to-indigo-500 hover:shadow-indigo-500/25" "bg-gradient-to-r from-purple-600 to-indigo-600 hover:from-purple-500 hover:to-indigo-500 hover:shadow-indigo-500/25"
)} )}
> >
@ -730,7 +730,7 @@ export function PromptHero() {
<img <img
src={ref.thumbnail} src={ref.thumbnail}
alt="" alt=""
className="h-10 w-10 rounded object-cover ring-1 ring-white/10 group-hover/thumb:ring-purple-500/50 transition-all" className="h-12 w-12 md:h-10 md:w-10 rounded object-cover ring-1 ring-white/10 group-hover/thumb:ring-purple-500/50 transition-all"
/> />
<button <button
onClick={() => removeReference(cat, ref.id)} onClick={() => removeReference(cat, ref.id)}

View file

@ -47,27 +47,27 @@ export function Settings() {
{/* Provider Selection */} {/* Provider Selection */}
<div className="space-y-3"> <div className="space-y-3">
<label className="text-sm font-medium">Image Generation Provider</label> <label className="text-sm font-medium">Image Generation Provider</label>
<div className="grid grid-cols-3 gap-3"> <div className="grid grid-cols-2 md:grid-cols-3 gap-3">
{providers.map((p) => ( {providers.map((p) => (
<button <button
key={p.id} key={p.id}
onClick={() => setProvider(p.id)} onClick={() => setProvider(p.id)}
className={cn( className={cn(
"flex flex-col items-center gap-2 p-4 rounded-xl border-2 transition-all", "flex flex-col items-center gap-2 p-4 md:p-4 rounded-xl border-2 transition-all min-h-[100px] active:scale-95",
provider === p.id provider === p.id
? "border-primary bg-primary/10" ? "border-primary bg-primary/10"
: "border-border hover:border-primary/50 bg-card" : "border-border hover:border-primary/50 bg-card"
)} )}
> >
<p.icon className={cn( <p.icon className={cn(
"h-6 w-6", "h-7 w-7 md:h-6 md:w-6",
provider === p.id ? "text-primary" : "text-muted-foreground" provider === p.id ? "text-primary" : "text-muted-foreground"
)} /> )} />
<span className={cn( <span className={cn(
"font-medium text-sm", "font-medium text-sm",
provider === p.id ? "text-primary" : "" provider === p.id ? "text-primary" : ""
)}>{p.name}</span> )}>{p.name}</span>
<span className="text-xs text-muted-foreground">{p.description}</span> <span className="text-xs text-muted-foreground text-center">{p.description}</span>
</button> </button>
))} ))}
</div> </div>