reworked the guest pwa, modernized start and gallery page. added share link functionality.
This commit is contained in:
@@ -3,6 +3,7 @@ import { Link } from 'react-router-dom';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { getDeviceId } from '../lib/device';
|
||||
import { usePollGalleryDelta } from '../polling/usePollGalleryDelta';
|
||||
import { Heart } from 'lucide-react';
|
||||
|
||||
type Props = { token: string };
|
||||
|
||||
@@ -50,56 +51,45 @@ export default function GalleryPreview({ token }: Props) {
|
||||
return 'Abendstimmung';
|
||||
}
|
||||
|
||||
const filters: { value: PreviewFilter; label: string }[] = [
|
||||
{ value: 'latest', label: 'Newest' },
|
||||
{ value: 'popular', label: 'Popular' },
|
||||
{ value: 'mine', label: 'My Photos' },
|
||||
{ value: 'photobooth', label: 'Fotobox' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<div className="inline-flex rounded-full bg-white/80 backdrop-blur-sm border border-pink-200 p-1 shadow-sm">
|
||||
<button
|
||||
onClick={() => setMode('latest')}
|
||||
className={`px-4 py-2 text-sm font-medium rounded-full transition-all duration-200 ${
|
||||
mode === 'latest'
|
||||
? 'bg-gradient-to-r from-pink-500 to-pink-600 text-white shadow-lg scale-105'
|
||||
: 'text-gray-600 hover:bg-pink-50 hover:text-pink-700'
|
||||
}`}
|
||||
>
|
||||
Newest
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setMode('popular')}
|
||||
className={`px-4 py-2 text-sm font-medium rounded-full transition-all duration-200 ${
|
||||
mode === 'popular'
|
||||
? 'bg-gradient-to-r from-pink-500 to-pink-600 text-white shadow-lg scale-105'
|
||||
: 'text-gray-600 hover:bg-pink-50 hover:text-pink-700'
|
||||
}`}
|
||||
>
|
||||
Popular
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setMode('mine')}
|
||||
className={`px-4 py-2 text-sm font-medium rounded-full transition-all duration-200 ${
|
||||
mode === 'mine'
|
||||
? 'bg-gradient-to-r from-pink-500 to-pink-600 text-white shadow-lg scale-105'
|
||||
: 'text-gray-600 hover:bg-pink-50 hover:text-pink-700'
|
||||
}`}
|
||||
>
|
||||
My Photos
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setMode('photobooth')}
|
||||
className={`px-4 py-2 text-sm font-medium rounded-full transition-all duration-200 ${
|
||||
mode === 'photobooth'
|
||||
? 'bg-gradient-to-r from-pink-500 to-pink-600 text-white shadow-lg scale-105'
|
||||
: 'text-gray-600 hover:bg-pink-50 hover:text-pink-700'
|
||||
}`}
|
||||
>
|
||||
Fotobox
|
||||
</button>
|
||||
<section className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-xs uppercase tracking-wide text-muted-foreground">Live-Galerie</p>
|
||||
<h3 className="text-lg font-semibold text-foreground">Alle Uploads auf einen Blick</h3>
|
||||
</div>
|
||||
<Link to={`/e/${encodeURIComponent(token)}/gallery?mode=${mode}`} className="text-sm text-pink-600 hover:text-pink-700 font-medium">
|
||||
<Link
|
||||
to={`/e/${encodeURIComponent(token)}/gallery?mode=${mode}`}
|
||||
className="text-sm font-semibold text-pink-600 hover:text-pink-700"
|
||||
>
|
||||
Alle ansehen →
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 overflow-x-auto pb-1 text-sm font-medium [-ms-overflow-style:none] [scrollbar-width:none]">
|
||||
{filters.map((filter) => (
|
||||
<button
|
||||
key={filter.value}
|
||||
type="button"
|
||||
onClick={() => setMode(filter.value)}
|
||||
className={`rounded-full border px-4 py-1 transition ${
|
||||
mode === filter.value
|
||||
? 'border-pink-500 bg-pink-500 text-white shadow'
|
||||
: 'border-transparent bg-white/70 text-muted-foreground hover:border-pink-200'
|
||||
}`}
|
||||
>
|
||||
{filter.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{loading && <p className="text-sm text-muted-foreground">Lädt…</p>}
|
||||
{!loading && items.length === 0 && (
|
||||
<Card>
|
||||
@@ -108,31 +98,31 @@ export default function GalleryPreview({ token }: Props) {
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
{items.map((p: any) => (
|
||||
<Link key={p.id} to={`/e/${encodeURIComponent(token)}/gallery?photoId=${p.id}`} className="block">
|
||||
<div className="relative">
|
||||
<img
|
||||
src={p.thumbnail_path || p.file_path}
|
||||
alt={p.title || 'Foto'}
|
||||
className="aspect-square w-full rounded-xl object-cover shadow-lg hover:shadow-xl transition-shadow duration-200"
|
||||
loading="lazy"
|
||||
/>
|
||||
{/* Photo Title */}
|
||||
<div className="mt-2">
|
||||
<div className="text-xs font-medium text-gray-900 line-clamp-2 bg-white/80 px-2 py-1 rounded-md">
|
||||
{p.title || getPhotoTitle(p)}
|
||||
</div>
|
||||
{p.likes_count > 0 && (
|
||||
<div className="mt-1 flex items-center gap-1 text-xs text-pink-600">
|
||||
❤️ {p.likes_count}
|
||||
</div>
|
||||
)}
|
||||
<Link
|
||||
key={p.id}
|
||||
to={`/e/${encodeURIComponent(token)}/gallery?photoId=${p.id}`}
|
||||
className="group relative block overflow-hidden rounded-3xl border border-white/30 bg-gray-900 text-white shadow-lg"
|
||||
>
|
||||
<img
|
||||
src={p.thumbnail_path || p.file_path}
|
||||
alt={p.title || 'Foto'}
|
||||
className="h-48 w-full object-cover transition duration-300 group-hover:scale-105"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/10 to-transparent" aria-hidden />
|
||||
<div className="absolute bottom-0 left-0 right-0 p-4">
|
||||
<p className="text-sm font-semibold leading-tight line-clamp-2">{p.title || getPhotoTitle(p)}</p>
|
||||
<div className="mt-2 flex items-center gap-1 text-xs text-white/80">
|
||||
<Heart className="h-4 w-4 fill-current" aria-hidden />
|
||||
{p.likes_count ?? 0}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user