Add Dockerfile, add raw view

This commit is contained in:
2025-12-21 13:27:12 +01:00
parent 9bb649c9e2
commit b1541f8777
35 changed files with 2811 additions and 78 deletions

View File

@ -0,0 +1,34 @@
import ArtworkThumbGallery from "@/components/artworks/ArtworkThumbGallery";
import { prisma } from "@/lib/prisma";
export default async function AnimalStudiesPage() {
const artworks = await prisma.artwork.findMany({
where: {
categories: {
some: {
name: "Animal Studies"
}
},
published: true
},
include: {
file: true,
metadata: true,
tags: true,
variants: true
},
orderBy: [{ sortKey: "asc" }, { id: "asc" }]
})
// console.log(JSON.stringify(artworks, null, 4))
return (
<div className="flex flex-col gap-4 p-4">
<div>
<h1 className="text-2xl font-bold text-center">Animal studies</h1>
</div>
<ArtworkThumbGallery items={artworks} fit={{ mode: "fixedWidth", width: 300 }} />
</div>
);
}

View File

@ -0,0 +1,162 @@
import { prisma } from "@/lib/prisma";
import { cn } from "@/lib/utils";
import { LayersIcon, QuoteIcon, TagIcon } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
export default async function SingleArtworkPage({ params }: { params: { id: string } }) {
const { id } = await params;
const artwork = await prisma.artwork.findUnique({
where: {
id,
},
include: {
file: true,
gallery: true,
metadata: true,
albums: true,
categories: true,
colors: { include: { color: true } },
tags: true,
variants: true
}
})
if (!artwork) return <div>Artwork with this ID could not be found</div>
const { width, height } = artwork.variants.find((v) => v.type === "resized") ?? { width: 0, height: 0 }
const colors =
artwork.colors?.map((c) => c.color?.hex).filter((hex): hex is string => Boolean(hex)) ?? []
const gradientColors = colors.length
? colors.join(", ")
: "rgba(0,0,0,0.1), rgba(0,0,0,0.03)"
return (
<div className="px-8 py-4">
<div className="flex flex-col items-center gap-4">
<div>
<h1 className="text-2xl font-bold mb-4 pb-4">{artwork.name}</h1>
</div>
<div className="group rounded-lg border overflow-hidden hover:shadow-lg transition-shadow bg-background relative">
<div className="relative w-full bg-muted items-center justify-center"
style={{ aspectRatio: "4 / 3" }}
>
<Link href={`/raw/${artwork.id}`}>
<Image
src={`/api/image/resized/${artwork.file.fileKey}.webp`}
alt={artwork.altText || "Artwork"}
fill={!width || !height}
width={width}
height={height}
className={cn("object-cover transition duration-300")}
/>
</Link>
{/* {image.nsfw && (
<div className="absolute top-1 left-1 z-10 flex gap-1">
<TagBadge
label="NSFW"
variant="destructive"
icon={<EyeOffIcon size={12} />}
className="text-xs px-2 py-0.5 inline-flex items-center"
/>
</div>
)} */}
</div>
{/* {!isLarge && (
<div className="p-4">
<h2 className="text-lg font-semibold truncate text-center">{image.imageName}</h2>
</div>
)} */}
</div>
<div
className="rounded-lg"
style={{
background: `linear-gradient(135deg, ${gradientColors})`,
}}>
<div
className="overflow-hidden border rounded-lg m-0.5 p-4 shadow w-full max-w-xl space-y-3 bg-white dark:bg-black"
>
{artwork.altText && (
<div className="flex items-center gap-2">
<TagIcon className="shrink-0 w-4 h-4 text-muted-foreground mt-px" />
<span className="text-sm text-muted-foreground">{artwork.altText}</span>
</div>
)}
{artwork.description && (
<div className="flex items-center gap-2">
<QuoteIcon className="shrink-0 w-4 h-4 text-muted-foreground mt-px" />
<span className="text-sm text-muted-foreground">{artwork.description}</span>
</div>
)}
{/* {creationLabel && (
<div className="flex items-center gap-2">
<CalendarDaysIcon className="shrink-0 w-4 h-4 text-muted-foreground mt-[1px]" />
<span className="text-sm text-muted-foreground">{creationLabel}</span>
</div>
)}
{album && (
<div className="flex items-center gap-2 flex-wrap">
<ImagesIcon className="shrink-0 w-4 h-4 text-muted-foreground mt-[1px]" />
<Link href={`/galleries/${album.gallery?.slug}/${album.slug}`} className="text-sm underline">
{album.name}
</Link>
</div>
)} */}
{artwork.categories.length > 0 && (
<div className="flex items-center gap-2 flex-wrap">
<LayersIcon className="shrink-0 w-4 h-4 text-muted-foreground mt-1px" />
{artwork.categories.map((cat) => (
<Link
key={cat.id}
href={`/categories/${cat.id}`}
className="text-sm underline"
>
{cat.name}
</Link>
))}
</div>
)}
{artwork.tags.length > 0 && (
<div className="flex items-center gap-2 flex-wrap">
<TagIcon className="shrink-0 w-4 h-4 text-muted-foreground mt-1px" />
{artwork.tags.map((tag) => (
<Link
key={tag.id}
href={`/tags/${tag.id}`}
className="text-sm underline"
>
{tag.name}
</Link>
))}
</div>
)}
</div>
</div>
{/* <ImageCard image={image} gallerySlug={image.album?.gallery?.slug} albumSlug={image.album?.slug} size="large" />
<section className="py-8 flex flex-col gap-4">
{image.artist && <ArtistInfoBox artist={image.artist} />}
<ImageMetadataBox
album={image.album}
categories={image.categories}
tags={image.tags}
creationDate={image.creationDate}
creationYear={image.creationYear}
creationMonth={image.creationMonth}
altText={image.altText}
description={image.description}
/>
</section> */}
</div>
</div >
);
}