Remove hover scale effects and optimize mobile UI transitions

This commit is contained in:
Riccardo Giorato
2025-12-27 11:42:54 +01:00
parent 5a1d0e3849
commit d17d360d0e
5 changed files with 106 additions and 98 deletions
+1 -1
View File
@@ -115,7 +115,7 @@ export default function Home() {
</div> </div>
<div className="relative"> <div className="relative">
<div className="bg-white w-80 aspect-3/4 p-2 shadow-2xl rounded-sm hover:shadow-indigo/20 hover:shadow-3xl transition-all duration-300 hover:scale-[1.02]"> <div className="bg-white w-80 aspect-3/4 p-2 shadow-2xl rounded-sm hover:shadow-indigo/20 hover:shadow-3xl transition-all duration-300">
<div className="w-full h-full bg-neutral-900 border-4 border-black overflow-hidden relative"> <div className="w-full h-full bg-neutral-900 border-4 border-black overflow-hidden relative">
{/* Page transition container */} {/* Page transition container */}
<div className="relative w-full h-full"> <div className="relative w-full h-full">
+87 -92
View File
@@ -92,103 +92,98 @@ export default function StoriesPage() {
<Navbar /> <Navbar />
<main className="flex-1 flex flex-col min-h-[calc(100vh-4rem)]"> <main className="flex-1 flex flex-col min-h-[calc(100vh-4rem)]">
<div className="w-full px-4 sm:px-6 lg:px-12 xl:px-20 py-4 sm:py-6 relative"> <div className="w-full px-4 sm:px-6 lg:px-12 xl:px-20 py-4 sm:py-6 relative">
<div className="max-w-7xl mx-auto w-full z-10 py-8"> <div className="max-w-7xl mx-auto w-full z-10 py-8">
{stories.length === 0 ? ( {stories.length === 0 ? (
<div className="opacity-0 animate-fade-in-up animation-delay-100 text-center py-20"> <div className="opacity-0 animate-fade-in-up animation-delay-100 text-center py-20">
<div className="relative mb-8"> <div className="relative mb-8">
<div className="inline-flex items-center justify-center w-40 h-52 glass-panel border-2 border-dashed border-border rounded-lg hover:border-indigo/30 hover:shadow-indigo/10 hover:shadow-lg transition-all duration-300 group"> <div className="inline-flex items-center justify-center w-40 h-52 glass-panel border-2 border-dashed border-border rounded-lg hover:border-indigo/30 hover:shadow-indigo/10 hover:shadow-lg transition-all duration-300 group">
<Plus className="w-20 h-20 text-muted-foreground/50 group-hover:text-indigo/40 transition-colors duration-300" /> <Plus className="w-20 h-20 text-muted-foreground/50 group-hover:text-indigo/40 transition-colors duration-300" />
</div> </div>
<div className="absolute -inset-1 bg-gradient-to-r from-indigo/20 to-emerald/20 rounded-lg blur opacity-0 group-hover:opacity-100 transition-opacity duration-300 -z-10" /> <div className="absolute -inset-1 bg-linear-to-r from-indigo/20 to-emerald/20 rounded-lg blur opacity-0 group-hover:opacity-100 transition-opacity duration-300 -z-10" />
</div> </div>
<h2 className="text-4xl font-heading font-semibold mb-4 text-foreground tracking-tight"> <h2 className="text-4xl font-heading font-semibold mb-4 text-foreground tracking-tight">
Your Comic Library Awaits Your Comic Library Awaits
</h2> </h2>
<p className="text-muted-foreground mb-10 max-w-lg mx-auto leading-relaxed text-lg"> <p className="text-muted-foreground mb-10 max-w-lg mx-auto leading-relaxed text-lg">
Start crafting your first visual story. Every great comic begins with a single panel. Start crafting your first visual story. Every great comic
</p> begins with a single panel.
<Button </p>
onClick={() => router.push('/')} <Button
className="glass-panel glass-panel-hover px-8 py-4 text-base font-medium hover:scale-105 transition-all duration-300 hover:shadow-indigo/20 hover:shadow-lg" onClick={() => router.push("/")}
> className="glass-panel glass-panel-hover px-8 py-4 text-base font-medium transition-all duration-300 hover:shadow-indigo/20 hover:shadow-lg"
<Plus className="w-5 h-5 mr-3" /> >
Create Your First Comic <Plus className="w-5 h-5 mr-3" />
</Button> Create Your First Comic
</div> </Button>
) : ( </div>
<> ) : (
<div className="opacity-0 animate-fade-in-up animation-delay-100 mb-12"> <>
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-heading font-semibold text-foreground mb-4 tracking-tight"> <div className="opacity-0 animate-fade-in-up animation-delay-100 mb-12">
Your Comic Library <h1 className="text-4xl sm:text-5xl lg:text-6xl font-heading font-semibold text-foreground mb-4 tracking-tight">
</h1> Your Comic Library
<p className="text-muted-foreground text-base sm:text-lg max-w-3xl leading-relaxed"> </h1>
Browse and continue your comic creations. Each story is a unique visual narrative waiting to unfold. <p className="text-muted-foreground text-base sm:text-lg max-w-3xl leading-relaxed">
</p> Browse and continue your comic creations. Each story is a
</div> unique visual narrative waiting to unfold.
</p>
</div>
<div className="opacity-0 animate-fade-in-up animation-delay-200 grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-4 sm:gap-6"> <div className="opacity-0 animate-fade-in-up animation-delay-200 grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-4 sm:gap-6">
{stories.map((story, index) => ( {stories.map((story, index) => (
<button <button
key={story.id} key={story.id}
onClick={() => router.push(`/story/${story.slug}`)} onClick={() => router.push(`/story/${story.slug}`)}
className={`opacity-0 animate-fade-in-up group relative glass-panel p-3 rounded-lg hover:shadow-indigo/20 hover:shadow-2xl transition-all duration-500 hover:scale-[1.05] hover:-translate-y-2 border border-border/50 hover:border-indigo/30 hover:bg-white/[0.02] backdrop-blur-sm focus:outline-none`} className={`opacity-0 animate-fade-in-up group relative glass-panel p-3 rounded-lg hover:shadow-indigo/20 hover:shadow-2xl transition-all duration-500 border border-border/50 backdrop-blur-sm focus:outline-none`}
style={{ animationDelay: `${200 + index * 100}ms` }} style={{ animationDelay: `${200 + index * 100}ms` }}
> >
<div className="w-full h-full bg-neutral-900 border-4 border-black overflow-hidden relative group-hover:border-indigo/30 transition-colors duration-300"> <div className="w-full h-full bg-neutral-900 border-4 border-black overflow-hidden relative transition-colors duration-300">
{story.coverImage ? ( {story.coverImage ? (
<> <>
<img <img
src={story.coverImage} src={story.coverImage}
alt={story.title} alt={story.title}
className="w-full h-full object-cover transition-all duration-500 group-hover:scale-105 group-hover:brightness-110 opacity-90" className="w-full h-full object-cover transition-all duration-500 group-hover:brightness-110 opacity-90"
/> />
{story.pageCount > 1 && ( <div className="absolute inset-0 bg-linear-to-t from-black/95 via-black/30 to-transparent group-hover:from-black/90 transition-all duration-300" />
<div className="absolute inset-0 pointer-events-none">
<div className="absolute top-0 left-0 right-0 bottom-0 translate-x-1 translate-y-1 bg-black/20 group-hover:bg-indigo/10 transition-colors duration-300" />
{story.pageCount > 2 && (
<div className="absolute top-0 left-0 right-0 bottom-0 translate-x-2 translate-y-2 bg-black/10 group-hover:bg-indigo/5 transition-colors duration-300" />
)}
</div>
)}
<div className="absolute inset-0 bg-gradient-to-t from-black/95 via-black/30 to-transparent group-hover:from-black/90 transition-all duration-300" /> <div className="absolute top-2 right-2 px-1.5 py-0.5 bg-black/80 text-white text-[9px] font-mono uppercase tracking-widest border border-white/20 group-hover:bg-indigo/80 group-hover:border-indigo/40 transition-colors duration-300">
{COMIC_STYLES.find(
(s) => s.id === story.style
)?.name.toUpperCase() ||
story.style.toUpperCase()}
</div>
{/* Subtle glow effect on hover */} <div className="absolute bottom-0 left-0 right-0 p-3 text-left">
<div className="absolute inset-0 opacity-0 group-hover:opacity-20 bg-gradient-to-r from-indigo/20 via-transparent to-emerald/20 transition-opacity duration-500" /> <h3 className="font-display text-sm text-white leading-tight line-clamp-1 mb-1 group-hover:text-indigo-100 transition-colors duration-300">
{story.title}
<div className="absolute top-2 right-2 px-1.5 py-0.5 bg-black/80 text-white text-[9px] font-mono uppercase tracking-widest border border-white/20 group-hover:bg-indigo/80 group-hover:border-indigo/40 transition-colors duration-300"> </h3>
{COMIC_STYLES.find(s => s.id === story.style)?.name.toUpperCase() || story.style.toUpperCase()} <p className="text-[10px] text-white/60 font-mono uppercase tracking-wider group-hover:text-white/80 transition-colors duration-300">
</div> {new Date(story.createdAt).toLocaleDateString()}
</p>
<div className="absolute bottom-0 left-0 right-0 p-3 text-left"> </div>
<h3 className="font-display text-sm text-white leading-tight line-clamp-1 mb-1 group-hover:text-indigo-100 transition-colors duration-300"> </>
{story.title} ) : (
</h3> <div className="w-full h-full flex items-center justify-center bg-linear-to-br from-neutral-800 to-neutral-900">
<p className="text-[10px] text-white/60 font-mono uppercase tracking-wider group-hover:text-white/80 transition-colors duration-300"> <div className="text-center">
{new Date(story.createdAt).toLocaleDateString()} <Loader2 className="w-8 h-8 animate-spin text-indigo/60 mx-auto mb-3" />
</p> <p className="text-xs text-white/70 font-mono uppercase tracking-wider">
</div> Generating...
</> </p>
) : ( </div>
<div className="w-full h-full flex items-center justify-center bg-gradient-to-br from-neutral-800 to-neutral-900"> </div>
<div className="text-center"> )}
<Loader2 className="w-8 h-8 animate-spin text-indigo/60 mx-auto mb-3" /> </div>
<p className="text-xs text-white/70 font-mono uppercase tracking-wider">Generating...</p> </button>
</div> ))}
</div> </div>
)} </>
</div> )}
</button> </div>
))}
</div>
</>
)}
</div>
</div> </div>
</main> </main>
</div> </div>
); );
} }
+15 -2
View File
@@ -82,7 +82,7 @@ export function ComicCanvas({
</div> </div>
{/* Action buttons below the page image */} {/* Action buttons below the page image */}
<div className="flex items-center justify-center gap-2 mt-4"> <div className="hidden md:flex items-center justify-center gap-2 mt-4">
{onInfoClick && ( {onInfoClick && (
<Button <Button
variant="ghost" variant="ghost"
@@ -123,10 +123,23 @@ export function ComicCanvas({
</div> </div>
<div className="flex flex-col items-center gap-3 mt-4"> <div className="flex flex-col items-center gap-3 mt-4">
{/* <div className="text-xs text-muted-foreground">Page {page.id}</div> */} <div className="text-xs text-muted-foreground md:hidden">
Page {pageIndex + 1} of {totalPages}
</div>
{/* Mobile action buttons */} {/* Mobile action buttons */}
<div className="flex items-center gap-2 md:hidden"> <div className="flex items-center gap-2 md:hidden">
{onInfoClick && (
<Button
variant="ghost"
size="icon"
className="hover:bg-secondary text-muted-foreground hover:text-white h-9 w-9"
onClick={onInfoClick}
>
<Info className="w-4 h-4" />
</Button>
)}
{isOwner && ( {isOwner && (
<Button <Button
variant="ghost" variant="ghost"
+2 -2
View File
@@ -33,7 +33,7 @@ export function PageSidebar({
isOwner = true, isOwner = true,
}: PageSidebarProps) { }: PageSidebarProps) {
return ( return (
<aside className="w-20 md:w-24 border-r border-border/50 bg-background/50 flex flex-col items-center py-4 gap-2 justify-between"> <aside className="hidden md:flex md:flex-col md:items-center w-24 border-r border-border/50 bg-background/50 py-4 gap-2 justify-between">
{/* Top section: page thumbnails */} {/* Top section: page thumbnails */}
<div className="flex flex-col items-center gap-3"> <div className="flex flex-col items-center gap-3">
{pages.map((page, index) => ( {pages.map((page, index) => (
@@ -84,7 +84,7 @@ export function PageSidebar({
onClick={onAddPage} onClick={onAddPage}
className="w-16 h-16 rounded-lg border-2 border-dashed border-border/50 hover:border-indigo/50 bg-background/50 hover:bg-background/80 transition-all group flex items-center justify-center" className="w-16 h-16 rounded-lg border-2 border-dashed border-border/50 hover:border-indigo/50 bg-background/50 hover:bg-background/80 transition-all group flex items-center justify-center"
> >
<Plus className="w-6 h-6 text-muted-foreground group-hover:text-indigo transition-transform group-hover:scale-110" /> <Plus className="w-6 h-6 text-muted-foreground group-hover:text-indigo transition-transform" />
</button> </button>
)} )}
</div> </div>
+1 -1
View File
@@ -26,7 +26,7 @@ export function StoryLoader({ text = "Loading story..." }: StoryLoaderProps) {
key={currentSvgIndex} // Force re-render for smooth transition key={currentSvgIndex} // Force re-render for smooth transition
src={`/loader/${loaderSvgs[currentSvgIndex]}`} src={`/loader/${loaderSvgs[currentSvgIndex]}`}
alt="Loading..." alt="Loading..."
className="w-full h-full object-contain animate-pulse transition-all duration-700 ease-in-out transform scale-90 hover:scale-110" className="w-full h-full object-contain animate-pulse transition-all duration-700 ease-in-out transform"
style={{ filter: 'invert(1)' }} style={{ filter: 'invert(1)' }}
/> />
</div> </div>