Shortcodes

This commit is contained in:
cdricms
2025-02-10 08:52:32 +01:00
parent a7ad045631
commit 8e87d834bc
20 changed files with 485 additions and 71 deletions

View File

@@ -5,19 +5,18 @@ import Link from "next/link";
import { API_URL } from "@/lib/constants";
import Image from "next/image";
const Hero = () => {
const background = `${API_URL}/media/591ab183-c72d-46ff-905c-ec04fed1bb34/file`;
const Hero: React.FC<{ background: string }> = ({ background }) => {
return (
<section className="relative flex h-[calc(100vh-68px)] items-center justify-center overflow-hidden py-32">
<div className="">
<Image
src={background}
layout="fill"
objectFit="cover"
// objectFit="cover"
priority
alt="Hero image"
unoptimized
className="grayscale"
className="grayscale object-cover "
/>
{/* Gradient and Blur Overlay */}
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-transparent to-transparent bg-opacity-30 backdrop-blur-sm"></div>
@@ -29,10 +28,12 @@ const Hero = () => {
className="h-16"
/>
<div>
<h1 className="mb-6 text-pretty text-2xl font-bold text-primary lg:text-5xl">
Trouvez votre équilibre avec
<h1 className="mb-6 text-pretty text-2xl font-bold text-primary lg:text-5xl font-times">
Trouvez votre <em>équilibre</em> avec
<br />
Latosa-Escrima
<span className="font-extrabold text-3xl lg:text-6xl">
Latosa Escrima
</span>
</h1>
<p className="text-muted-foreground lg:text-xl">
Une évolution des arts martiaux Philippins

View File

@@ -23,7 +23,7 @@ interface PhotoDialogProps {
isOpen: boolean;
onClose: () => void;
onDelete?: (id: Media["id"]) => void;
onSave: (photo: Omit<Media, "id">, file: File) => void;
onSave: (photo: Omit<Media, "id"> | Media, file: File) => void;
}
export function PhotoDialog({
@@ -34,7 +34,7 @@ export function PhotoDialog({
onSave,
}: PhotoDialogProps) {
const [file, setFile] = useState<File | null>(null);
const [newPhoto, setNewPhoto] = useState<Omit<Media, "id">>({
const [newPhoto, setNewPhoto] = useState<Omit<Media, "id"> | Media>({
url: "",
alt: "",
path: "",

View File

@@ -14,6 +14,18 @@ import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import type IShortcode from "@/interfaces/IShortcode";
import Image from "next/image";
import Media from "@/interfaces/Media";
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "./ui/pagination";
import useMedia from "@/hooks/use-media";
import { Loader2 } from "lucide-react";
interface ShortcodeDialogProps {
onSave: (shortcode: IShortcode) => void;
@@ -33,6 +45,8 @@ export default function ShortcodeDialog({
);
const handleSave = () => {
if (!(_shortcode?.code && (_shortcode.media_id || _shortcode.value)))
return;
onSave(_shortcode);
setOpen();
resetForm();
@@ -92,6 +106,7 @@ export default function ShortcodeDialog({
setShortcode((p) => ({
...p,
value: e.target.value,
media_id: undefined,
}))
}
className="col-span-3"
@@ -99,27 +114,29 @@ export default function ShortcodeDialog({
</div>
</TabsContent>
<TabsContent value="media">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="mediaId" className="text-right">
Media ID
</Label>
<Input
id="mediaId"
value={_shortcode.media_id}
onChange={(e) =>
setShortcode((p) => ({
...p,
media_id: e.target.value,
}))
}
className="col-span-3"
/>
</div>
<PhotoGrid
onSelect={(photo) => {
setShortcode((p) => ({
...p,
media_id: photo.id,
value: undefined,
}));
}}
/>
</TabsContent>
</Tabs>
</div>
<DialogFooter>
<Button type="submit" onClick={handleSave}>
<Button
disabled={
!(
_shortcode?.code &&
(_shortcode.media_id || _shortcode.value)
)
}
type="submit"
onClick={handleSave}
>
Enregistrer
</Button>
</DialogFooter>
@@ -127,3 +144,144 @@ export default function ShortcodeDialog({
</Dialog>
);
}
const LazyImage = ({
photo,
onClick,
isSelected,
}: {
photo: Media;
onClick: () => void;
isSelected: boolean;
}) => {
return (
<div
className={`aspect-square ${isSelected ? "ring-4 ring-primary" : ""}`}
>
<Image
src={photo.url || "/placeholder.svg"}
alt={photo.alt}
width={300}
height={300}
className="object-cover w-full h-full cursor-pointer transition-transform hover:scale-105"
onClick={onClick}
/>
</div>
);
};
const PhotoGrid: React.FC<{ onSelect: (photo: Media) => void }> = ({
onSelect,
}) => {
const { data, error, isLoading, success, setPage, setLimit, mutate } =
useMedia(5);
const [selectedPhoto, setSelectedPhoto] = useState<Media | null>(null);
const handlePhotoClick = (photo: Media) => {
setSelectedPhoto(photo);
onSelect(photo);
};
const handleChangeSelection = () => {
setSelectedPhoto(null);
// if (!photos) return;
// const currentIndex = photos.findIndex(
// (photo) => photo.id === selectedPhoto?.id,
// );
// const nextIndex = (currentIndex + 1) % photos.length;
// setSelectedPhoto(photos[nextIndex]);
};
if (isLoading) return <Loader2 className="animate-spin" />;
return (
<div className="container mx-auto p-4">
<h1 className="text-2xl font-bold mb-4">Gallerie Photo</h1>
{selectedPhoto ? (
<div className="flex flex-col items-center">
<Image
src={selectedPhoto.url || "/placeholder.svg"}
alt={selectedPhoto.alt}
width={600}
height={600}
className="w-full max-w-2xl h-auto mb-4 rounded-lg"
/>
<div className="flex gap-4 mt-4">
<Button onClick={handleChangeSelection}>
Changer de sélection
</Button>
</div>
</div>
) : (
<>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4">
{data?.items?.map((photo) => {
return (
<LazyImage
photo={photo}
key={photo.id}
onClick={() => handlePhotoClick(photo)}
isSelected={false}
/>
);
})}
</div>
<Pagination className="mt-8">
<PaginationContent>
<PaginationItem>
<PaginationPrevious
href="#"
onClick={(e) => {
e.preventDefault();
setPage((prev) =>
Math.max(prev - 1, 1),
);
}}
className={
data?.page === 1
? "pointer-events-none opacity-50"
: ""
}
/>
</PaginationItem>
{[...Array(data?.totalPages)].map((_, i) => (
<PaginationItem key={i + 1}>
<PaginationLink
href="#"
onClick={(e) => {
e.preventDefault();
setPage(i + 1);
}}
isActive={data?.page === i + 1}
>
{i + 1}
</PaginationLink>
</PaginationItem>
))}
<PaginationItem>
<PaginationNext
href="#"
onClick={(e) => {
e.preventDefault();
setPage((prev) =>
Math.min(
prev + 1,
data?.totalPages ?? 1,
),
);
}}
className={
data?.page === data?.totalPages
? "pointer-events-none opacity-50"
: ""
}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
</>
)}
</div>
);
};