build mobile fix

This commit is contained in:
2026-03-28 13:32:50 -05:00
parent 53a6219e1e
commit d1bfba89a8

View File

@@ -1,5 +1,5 @@
import { useState } from 'react';
import { X, Minimize2, Trash2, Edit2, Check, Layers, FolderOpen, Inbox, ScanText, ChevronDown, ChevronUp } from 'lucide-react';
import { X, Minimize2, Trash2, Edit2, Check, Layers, FolderOpen, Inbox, ScanText, ChevronDown, ChevronUp, ExternalLink, Image, Info } from 'lucide-react';
import { useMeme, useDeleteMeme, useUpdateMeme, useMoveMeme, useCollections } from '../hooks/useMemes';
import { useAuth } from '../hooks/useAuth';
import { SharePanel } from './SharePanel';
@@ -39,6 +39,7 @@ export function MemeDetail({ memeId, onClose }: Props) {
const [editTags, setEditTags] = useState('');
const [showRescale, setShowRescale] = useState(false);
const [activeChild, setActiveChild] = useState<Meme | null>(null);
const [mobileTab, setMobileTab] = useState<'image' | 'details'>('image');
const meme = data;
const displayMeme = activeChild ?? meme;
@@ -79,16 +80,18 @@ export function MemeDetail({ memeId, onClose }: Props) {
if (!meme) return null;
const isVideo = meme.mime_type.startsWith('video/');
const fullSizeUrl = displayMeme ? api.imageUrl(displayMeme.file_path) : null;
return (
<>
<div
className="fixed inset-0 z-40 bg-black/80 animate-fade-in"
onClick={onClose}
/>
<div className="fixed inset-0 z-40 bg-black/80 animate-fade-in" onClick={onClose} />
{/* Modal — full screen on mobile, inset on desktop */}
<div className="fixed inset-0 md:inset-4 lg:inset-8 z-50 flex flex-col bg-zinc-900 md:rounded-2xl shadow-2xl border-0 md:border border-zinc-800 overflow-hidden animate-scale-in">
<div className="fixed inset-4 md:inset-8 z-50 flex flex-col bg-zinc-900 rounded-2xl shadow-2xl border border-zinc-800 overflow-hidden animate-scale-in">
{/* Header */}
<div className="flex items-center justify-between px-5 py-4 border-b border-zinc-800 flex-shrink-0">
<div className="flex items-center justify-between px-4 py-3 md:px-5 md:py-4 border-b border-zinc-800 flex-shrink-0">
{editing ? (
<input
autoFocus
@@ -97,9 +100,9 @@ export function MemeDetail({ memeId, onClose }: Props) {
className="flex-1 bg-zinc-800 border border-zinc-700 rounded-lg px-3 py-1.5 text-sm font-semibold focus:outline-none focus:border-accent mr-3"
/>
) : (
<h2 className="text-lg font-semibold truncate flex-1 mr-3">{meme.title}</h2>
<h2 className="text-base md:text-lg font-semibold truncate flex-1 mr-3">{meme.title}</h2>
)}
<div className="flex items-center gap-2 flex-shrink-0">
<div className="flex items-center gap-1.5 flex-shrink-0">
{isAdmin && (
editing ? (
<button
@@ -110,47 +113,84 @@ export function MemeDetail({ memeId, onClose }: Props) {
<Check size={14} /> Save
</button>
) : (
<button
onClick={startEdit}
className="text-zinc-500 hover:text-zinc-300 transition-colors p-1"
title="Edit"
>
<button onClick={startEdit} className="text-zinc-500 hover:text-zinc-300 transition-colors p-1.5" title="Edit">
<Edit2 size={16} />
</button>
)
)}
{isAdmin && !meme.parent_id && !meme.mime_type.startsWith('video/') && (
{isAdmin && !meme.parent_id && !isVideo && (
<button
onClick={() => setShowRescale(true)}
className="flex items-center gap-1 text-sm px-3 py-1.5 rounded-lg bg-zinc-800 hover:bg-zinc-700 text-zinc-300 transition-colors"
className="flex items-center gap-1 text-sm px-2.5 py-1.5 rounded-lg bg-zinc-800 hover:bg-zinc-700 text-zinc-300 transition-colors"
title="Create rescaled copy"
>
<Minimize2 size={14} />
<span className="hidden sm:inline">Rescale</span>
</button>
)}
{/* Full size link — always visible */}
{fullSizeUrl && (
<a
href={fullSizeUrl}
target="_blank"
rel="noopener noreferrer"
onClick={(e) => e.stopPropagation()}
className="flex items-center gap-1 text-sm px-2.5 py-1.5 rounded-lg bg-zinc-800 hover:bg-zinc-700 text-zinc-300 transition-colors"
title="Open full size"
>
<ExternalLink size={14} />
<span className="hidden sm:inline">Full size</span>
</a>
)}
{isAdmin && (
<button
onClick={handleDelete}
disabled={deleteMeme.isPending}
className="text-zinc-500 hover:text-red-400 transition-colors p-1"
className="text-zinc-500 hover:text-red-400 transition-colors p-1.5"
title="Delete"
>
<Trash2 size={16} />
</button>
)}
<button onClick={onClose} className="text-zinc-500 hover:text-zinc-300 transition-colors p-1">
<button onClick={onClose} className="text-zinc-500 hover:text-zinc-300 transition-colors p-1.5">
<X size={20} />
</button>
</div>
</div>
{/* Mobile tab bar */}
<div className="flex md:hidden border-b border-zinc-800 flex-shrink-0">
<button
onClick={() => setMobileTab('image')}
className={`flex-1 flex items-center justify-center gap-1.5 py-2.5 text-sm font-medium transition-colors border-b-2 ${
mobileTab === 'image'
? 'border-accent text-accent'
: 'border-transparent text-zinc-500 hover:text-zinc-300'
}`}
>
<Image size={14} /> Media
</button>
<button
onClick={() => setMobileTab('details')}
className={`flex-1 flex items-center justify-center gap-1.5 py-2.5 text-sm font-medium transition-colors border-b-2 ${
mobileTab === 'details'
? 'border-accent text-accent'
: 'border-transparent text-zinc-500 hover:text-zinc-300'
}`}
>
<Info size={14} /> Details
</button>
</div>
{/* Body */}
<div className="flex flex-col md:flex-row flex-1 overflow-hidden">
{/* Image / video panel */}
<div className="flex-1 flex items-center justify-center bg-zinc-950 p-4 overflow-hidden">
<div className="flex flex-col md:flex-row flex-1 min-h-0 overflow-hidden">
{/* Image / video panel — full height on mobile when image tab active */}
<div className={`flex-1 flex items-center justify-center bg-zinc-950 p-4 min-h-0 overflow-hidden ${
mobileTab === 'details' ? 'hidden md:flex' : 'flex'
}`}>
{displayMeme && (
displayMeme.mime_type.startsWith('video/') ? (
isVideo ? (
<video
key={displayMeme.id}
src={api.imageUrl(displayMeme.file_path)}
@@ -172,7 +212,9 @@ export function MemeDetail({ memeId, onClose }: Props) {
</div>
{/* Sidebar */}
<div className="md:w-80 border-t md:border-t-0 md:border-l border-zinc-800 flex flex-col overflow-y-auto">
<div className={`md:w-80 md:border-l border-zinc-800 flex flex-col overflow-y-auto ${
mobileTab === 'image' ? 'hidden md:flex' : 'flex'
}`}>
<div className="p-5 space-y-5 flex-1">
{/* Share */}
@@ -289,7 +331,7 @@ export function MemeDetail({ memeId, onClose }: Props) {
</div>
<div className="flex justify-between">
<dt className="text-zinc-500">Type</dt>
<dd className="text-zinc-300">{meme.mime_type.replace('image/', '')}</dd>
<dd className="text-zinc-300">{meme.mime_type.replace('image/', '').replace('video/', '')}</dd>
</div>
<div className="flex justify-between">
<dt className="text-zinc-500">Uploaded</dt>