This commit is contained in:
2025-06-29 12:08:29 +02:00
parent 44c676c62b
commit 1dba1cf093
4 changed files with 46 additions and 61 deletions

View File

@ -1,40 +1,19 @@
# Install dependencies only when needed # Base image
FROM node:20-alpine AS deps FROM node:20
WORKDIR /app
# Install global Prisma CLI # Set working directory
RUN npm install -g prisma WORKDIR /app
# Install dependencies # Install dependencies
COPY package.json package-lock.json* ./ COPY package.json package-lock.json ./
RUN npm ci RUN npm install
# Copy only prisma schema to generate client early # Copy the rest of the code
COPY prisma ./prisma/ COPY . .
RUN npx prisma generate RUN npx prisma generate
# Builder image # Expose the dev port
FROM node:20-alpine AS builder EXPOSE 3000
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Build the app # Run dev server
RUN npm run build CMD ["npm", "run", "dev"]
# Production image
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
# Copy necessary files
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/prisma ./prisma
# Run migrations if needed
# CMD npx prisma migrate deploy && node .next/standalone/server.js
CMD node .next/standalone/server.js

View File

@ -2,7 +2,6 @@ import ArtistInfoBox from "@/components/images/ArtistInfoBox";
import GlowingImageWithToggle from "@/components/images/GlowingImageWithToggle"; import GlowingImageWithToggle from "@/components/images/GlowingImageWithToggle";
import ImageMetadataBox from "@/components/images/ImageMetadataBox"; import ImageMetadataBox from "@/components/images/ImageMetadataBox";
import prisma from "@/lib/prisma"; import prisma from "@/lib/prisma";
import Link from "next/link";
export default async function ImagePage({ params }: { params: { gallerySlug: string, albumSlug: string, imageId: string } }) { export default async function ImagePage({ params }: { params: { gallerySlug: string, albumSlug: string, imageId: string } }) {
const { imageId } = await params; const { imageId } = await params;
@ -38,15 +37,15 @@ export default async function ImagePage({ params }: { params: { gallerySlug: str
</div> </div>
{resizedVariant && {resizedVariant &&
<Link href={`/raw/${image.id}`} passHref> <GlowingImageWithToggle
<GlowingImageWithToggle alt={image.imageName}
alt={image.imageName} variant={resizedVariant}
variant={resizedVariant} colors={image.colors}
colors={image.colors} src={`/api/image/${resizedVariant.s3Key}`}
src={`/api/image/${resizedVariant.s3Key}`} nsfw={image.nsfw}
nsfw={image.nsfw} imageId={image.id}
/> />
</Link>
} }
<section className="py-8 flex flex-col gap-4"> <section className="py-8 flex flex-col gap-4">
{image.artist && <ArtistInfoBox artist={image.artist} />} {image.artist && <ArtistInfoBox artist={image.artist} />}

View File

@ -5,7 +5,7 @@ import NextImage from "next/image";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
export default async function RawImagePage({ params }: { params: { imageId: string } }) { export default async function RawImagePage({ params }: { params: { imageId: string } }) {
const { imageId } = params; const { imageId } = await params;
const image = await prisma.image.findUnique({ const image = await prisma.image.findUnique({
where: { id: imageId }, where: { id: imageId },

View File

@ -1,6 +1,7 @@
"use client" "use client"
import { Color, ImageColor, ImageVariant } from "@/generated/prisma"; import { Color, ImageColor, ImageVariant } from "@/generated/prisma";
import Link from "next/link";
import { useState } from "react"; import { useState } from "react";
import { Label } from "../ui/label"; import { Label } from "../ui/label";
import { Switch } from "../ui/switch"; import { Switch } from "../ui/switch";
@ -12,22 +13,26 @@ type Props = {
alt: string; alt: string;
src: string; src: string;
nsfw: boolean; nsfw: boolean;
imageId: string;
} }
export default function GlowingImageWithToggle({ variant, colors, alt, src, nsfw }: Props) { export default function GlowingImageWithToggle({ variant, colors, alt, src, nsfw, imageId }: Props) {
const [animate, setAnimate] = useState(true); const [animate, setAnimate] = useState(true);
const [revealed, setRevealed] = useState(!nsfw) const [revealed, setRevealed] = useState(!nsfw)
return ( return (
<div className="relative w-full max-w-fit"> <div className="relative w-full max-w-fit">
<GlowingImageBorder
alt={alt} <Link href={`/raw/${imageId}`} passHref>
variant={variant} <GlowingImageBorder
colors={colors} alt={alt}
src={src} variant={variant}
animate={animate} colors={colors}
revealed={revealed} src={src}
/> animate={animate}
revealed={revealed}
/>
</Link>
<div className="flex flex-col items-center gap-4 pt-8"> <div className="flex flex-col items-center gap-4 pt-8">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@ -36,14 +41,16 @@ export default function GlowingImageWithToggle({ variant, colors, alt, src, nsfw
</div> </div>
</div> </div>
{nsfw && ( {
<div className="flex flex-col items-center gap-4 pt-8"> nsfw && (
<div className="flex items-center gap-2"> <div className="flex flex-col items-center gap-4 pt-8">
<Switch id="animate" checked={revealed} onCheckedChange={setRevealed} /> <div className="flex items-center gap-2">
<Label htmlFor="animate">Reveal NSFW</Label> <Switch id="animate" checked={revealed} onCheckedChange={setRevealed} />
<Label htmlFor="animate">Reveal NSFW</Label>
</div>
</div> </div>
</div> )
)} }
</div> </div >
); );
} }