Remove unnecessary files
This commit is contained in:
@ -1,41 +0,0 @@
|
||||
import { Image } from "@/generated/prisma";
|
||||
import clsx from "clsx";
|
||||
import NextImage from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function ImageList({ images, gallerySlug, albumSlug }: { images: Image[], gallerySlug: string, albumSlug: string }) {
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h1 className="text-2xl font-bold mb-4">Images</h1>
|
||||
<div className="grid gap-6 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4">
|
||||
{images ? images.map((img) => (
|
||||
<Link href={`/galleries/${gallerySlug}/${albumSlug}/${img.id}`} key={img.id}>
|
||||
<div className="group rounded-lg border overflow-hidden hover:shadow-lg transition-shadow bg-background">
|
||||
<div className="relative aspect-[4/3] w-full bg-muted items-center justify-center">
|
||||
{img.fileKey ? (
|
||||
<NextImage
|
||||
src={`/api/image/thumbnails/${img.fileKey}.webp`}
|
||||
alt={img.imageName}
|
||||
fill
|
||||
className={clsx(
|
||||
" object-cover",
|
||||
img.nsfw && "blur-md scale-105"
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full text-muted-foreground text-sm">
|
||||
No cover image
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<h2 className="text-lg font-semibold truncate text-center">{img.imageName}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)) : "There are no images here!"}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
"use client";
|
||||
|
||||
// import ImageCard from "@/components/image/ImageCard"; // You likely have this already
|
||||
// import type { Album, Gallery, Image, ImageVariant } from "@prisma/client";
|
||||
import { Album, Gallery, Image, ImageVariant } from "@/generated/prisma";
|
||||
import { useState } from "react";
|
||||
import ImageCard from "./ImageCard";
|
||||
|
||||
type Props = {
|
||||
images: (Image & {
|
||||
album: Album & { gallery: Gallery | null } | null;
|
||||
variants: ImageVariant[];
|
||||
})[];
|
||||
};
|
||||
|
||||
export default function ArtistImageGrid({ images }: Props) {
|
||||
const [showNSFW, setShowNSFW] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<button
|
||||
onClick={() => setShowNSFW(!showNSFW)}
|
||||
className="text-sm underline text-muted-foreground"
|
||||
>
|
||||
{showNSFW ? "Hide NSFW" : "Show NSFW"} content
|
||||
</button>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4">
|
||||
{images.map((img) => (
|
||||
<ImageCard key={img.id} image={img} showNSFW={showNSFW} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
import { Album, Gallery, Image, ImageVariant } from "@/generated/prisma";
|
||||
import NextImage from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
type Props = {
|
||||
image: Image & {
|
||||
variants: ImageVariant[];
|
||||
album: Album & { gallery: Gallery | null } | null;
|
||||
};
|
||||
showNSFW?: boolean;
|
||||
};
|
||||
|
||||
export default function ImageCard({ image, showNSFW = false }: Props) {
|
||||
const variant = image.variants.find(v => v.type === "thumbnail") || image.variants[0];
|
||||
if (!variant) return null;
|
||||
|
||||
const href = image.album?.gallery && image.album
|
||||
? `/galleries/${image.album.gallery.slug}/${image.album.slug}/${image.id}`
|
||||
: `/image/${image.id}`;
|
||||
|
||||
const shouldBlur = image.nsfw && !showNSFW;
|
||||
|
||||
return (
|
||||
<Link href={href} className="group relative overflow-hidden rounded-lg border bg-background shadow transition hover:shadow-lg">
|
||||
<div className="aspect-[4/5] w-full relative">
|
||||
<NextImage
|
||||
src={`/api/image/${variant.s3Key}`}
|
||||
alt={image.altText || image.imageName}
|
||||
width={variant.width}
|
||||
height={variant.height}
|
||||
className={`object-cover h-full transition duration-200 ease-in-out ${shouldBlur ? "blur-md scale-105" : ""
|
||||
}`}
|
||||
/>
|
||||
{image.nsfw && (
|
||||
<div className="absolute top-1 left-1 bg-black/60 text-white text-xs px-2 py-0.5 rounded z-10">
|
||||
NSFW
|
||||
</div>
|
||||
)}
|
||||
<div className="absolute bottom-0 left-0 w-full bg-black/50 text-white text-sm px-2 py-1 line-clamp-1 truncate">
|
||||
{image.imageName}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
import { Album, Image } from "@/generated/prisma";
|
||||
import NextImage from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
type Props = {
|
||||
album: Album & {
|
||||
coverImage: Image | null;
|
||||
};
|
||||
gallerySlug: string;
|
||||
};
|
||||
|
||||
export default function AlbumCard({ album, gallerySlug }: Props) {
|
||||
const href = `/galleries/${gallerySlug}/${album.slug}`;
|
||||
const cover = album.coverImage;
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
className="group relative overflow-hidden rounded-lg border bg-background shadow transition hover:shadow-lg"
|
||||
>
|
||||
<div className="aspect-[4/3] w-full relative">
|
||||
{cover ? (
|
||||
<NextImage
|
||||
src={`/api/image/thumbnails/${cover.fileKey}.webp`}
|
||||
alt={cover.imageName}
|
||||
fill
|
||||
className="object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full w-full bg-muted text-muted-foreground text-sm">
|
||||
No cover image
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Overlay: Album label */}
|
||||
<div className="absolute top-1 left-1 bg-black/60 text-white text-xs px-2 py-0.5 rounded z-10">
|
||||
Album
|
||||
</div>
|
||||
|
||||
{/* Bottom: Album name */}
|
||||
<div className="absolute bottom-0 left-0 w-full bg-black/50 text-white text-sm px-2 py-1 line-clamp-1 truncate">
|
||||
{album.name}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
import { Album, Gallery, Image } from "@/generated/prisma";
|
||||
import NextImage from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
type ImagesWithItems = (Pick<Image, "id" | "fileKey" | "imageName" | "altText" | "nsfw"> & {
|
||||
album?: (Pick<Album, "slug"> & {
|
||||
gallery?: Pick<Gallery, "slug"> | null
|
||||
}) | null
|
||||
})[]
|
||||
|
||||
export default function CategoryImageList({ images }: { images: ImagesWithItems }) {
|
||||
return (
|
||||
<section>
|
||||
<h1 className="text-2xl font-bold mb-4">Images</h1>
|
||||
<div className="grid gap-6 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4">
|
||||
{images ? images.map((img) => {
|
||||
const gallerySlug = img.album?.gallery?.slug;
|
||||
const albumSlug = img.album?.slug;
|
||||
if (!gallerySlug || !albumSlug || !img.id) return null;
|
||||
|
||||
return (
|
||||
<Link href={`/${gallerySlug}/${albumSlug}/${img.id}`} key={img.id}>
|
||||
<div className="group rounded-lg border overflow-hidden hover:shadow-lg transition-shadow bg-background">
|
||||
<div className="relative aspect-[4/3] w-full bg-muted items-center justify-center">
|
||||
{img.fileKey ? (
|
||||
<NextImage
|
||||
src={`/api/image/thumbnails/${img.fileKey}.webp`}
|
||||
alt={img.altText || ""}
|
||||
fill
|
||||
className="object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full text-muted-foreground text-sm">
|
||||
No cover image
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<h2 className="text-lg font-semibold truncate text-center">{img.imageName}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
}) : "There are no images here!"}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
import { Album, Image } from "@/generated/prisma";
|
||||
import NextImage from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
type AlbumsWithItems = Album & {
|
||||
coverImage: Image | null;
|
||||
}
|
||||
|
||||
export default function AlbumList({ albums, gallerySlug }: { albums: AlbumsWithItems[], gallerySlug: string }) {
|
||||
return (
|
||||
<section>
|
||||
<h1 className="text-2xl font-bold mb-4">Albums</h1>
|
||||
<div className="grid gap-6 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4">
|
||||
{albums ? albums.map((album) => (
|
||||
<Link href={`/galleries/${gallerySlug}/${album.slug}`} key={album.id}>
|
||||
<div className="group rounded-lg border overflow-hidden hover:shadow-lg transition-shadow bg-background">
|
||||
<div className="relative aspect-[4/3] w-full bg-muted items-center justify-center">
|
||||
{album.coverImage?.fileKey ? (
|
||||
<NextImage
|
||||
src={`/api/image/thumbnails/${album.coverImage.fileKey}.webp`}
|
||||
alt={album.coverImage.imageName}
|
||||
fill
|
||||
className="object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full text-muted-foreground text-sm">
|
||||
No cover image
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<h2 className="text-lg font-semibold truncate text-center">{album.name}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)) : "There are no albums here!"}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { Color, ImageColor, ImageVariant } from "@/generated/prisma"
|
||||
import clsx from "clsx"
|
||||
import { useTheme } from "next-themes"
|
||||
import NextImage from "next/image"
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
type Colors = ImageColor & {
|
||||
color: Color
|
||||
}
|
||||
|
||||
type Props = {
|
||||
alt: string,
|
||||
variant: ImageVariant,
|
||||
colors: Colors[],
|
||||
src: string,
|
||||
revealed?: boolean,
|
||||
className?: string,
|
||||
animate?: boolean
|
||||
}
|
||||
|
||||
export default function GlowingImageBorder({
|
||||
alt,
|
||||
variant,
|
||||
colors,
|
||||
src,
|
||||
className,
|
||||
revealed = true,
|
||||
animate = true,
|
||||
}: Props) {
|
||||
const { resolvedTheme } = useTheme()
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
const getColor = (type: string) =>
|
||||
colors.find((c) => c.type === type)?.color.hex
|
||||
|
||||
const vibrantLight = getColor("Vibrant") || "#ff5ec4"
|
||||
const mutedLight = getColor("Muted") || "#5ecaff"
|
||||
|
||||
const darkVibrant = getColor("DarkVibrant") || "#fc03a1"
|
||||
const darkMuted = getColor("DarkMuted") || "#035efc"
|
||||
|
||||
const vibrant = resolvedTheme === "dark" ? darkVibrant : vibrantLight
|
||||
const muted = resolvedTheme === "dark" ? darkMuted : mutedLight
|
||||
|
||||
if (!mounted) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"relative inline-block rounded-xl overflow-hidden p-[12px]",
|
||||
animate ? "glow-border" : "static-glow-border",
|
||||
className
|
||||
)}
|
||||
style={
|
||||
{
|
||||
"--vibrant": vibrant,
|
||||
"--muted": muted,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<div className="relative z-10 rounded-xl overflow-hidden group">
|
||||
<NextImage
|
||||
src={src}
|
||||
alt={alt || "Image"}
|
||||
width={variant.width}
|
||||
height={variant.height}
|
||||
className={clsx(
|
||||
"rounded-xl transition duration-300",
|
||||
!revealed && "blur-md scale-105"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { Color, ImageColor, ImageVariant } from "@/generated/prisma";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { Label } from "../ui/label";
|
||||
import { Switch } from "../ui/switch";
|
||||
import GlowingImageBorder from "./GlowingImageBorder";
|
||||
|
||||
type Props = {
|
||||
variant: ImageVariant;
|
||||
colors: (ImageColor & { color: Color })[];
|
||||
alt: string;
|
||||
src: string;
|
||||
nsfw: boolean;
|
||||
imageId: string;
|
||||
}
|
||||
|
||||
export default function GlowingImageWithToggle({ variant, colors, alt, src, nsfw, imageId }: Props) {
|
||||
const [animate, setAnimate] = useState(true);
|
||||
const [revealed, setRevealed] = useState(!nsfw)
|
||||
|
||||
return (
|
||||
<div className="relative w-full max-w-fit">
|
||||
|
||||
<Link href={`/raw/${imageId}`} passHref>
|
||||
<GlowingImageBorder
|
||||
alt={alt}
|
||||
variant={variant}
|
||||
colors={colors}
|
||||
src={src}
|
||||
animate={animate}
|
||||
revealed={revealed}
|
||||
/>
|
||||
</Link>
|
||||
|
||||
<div className="flex flex-col items-center gap-4 pt-8">
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="animate" checked={animate} onCheckedChange={setAnimate} />
|
||||
<Label htmlFor="animate">Animate glow</Label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{
|
||||
nsfw && (
|
||||
<div className="flex flex-col items-center gap-4 pt-8">
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="animate" checked={revealed} onCheckedChange={setRevealed} />
|
||||
<Label htmlFor="animate">Reveal NSFW</Label>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div >
|
||||
);
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
import { Image as ImageType } from "@/generated/prisma";
|
||||
import Link from "next/link";
|
||||
// import { SocialIcon } from "react-social-icons";
|
||||
|
||||
type Props = {
|
||||
image: ImageType & {
|
||||
artist?: {
|
||||
id: string;
|
||||
slug: string;
|
||||
displayName: string;
|
||||
socials?: { type: string; handle: string; link: string }[];
|
||||
};
|
||||
categories?: { id: string; name: string }[];
|
||||
tags?: { id: string; name: string }[];
|
||||
album?: { id: string; name: string; slug: string };
|
||||
};
|
||||
};
|
||||
|
||||
export default function ImageInfoPanel({ image }: Props) {
|
||||
return (
|
||||
<div className="w-full max-w-2xl mt-8 border border-border rounded-lg p-6 shadow-sm bg-background">
|
||||
{/* Creator */}
|
||||
{image.artist && (
|
||||
<div className="mb-4">
|
||||
<h2 className="text-lg font-semibold mb-1">Creator</h2>
|
||||
<Link
|
||||
href={`/artists/${image.artist.slug}`}
|
||||
className="text-primary hover:underline font-medium"
|
||||
>
|
||||
{image.artist.displayName}
|
||||
</Link>
|
||||
|
||||
{image.artist.socials?.length > 0 && (
|
||||
<div className="flex gap-2 mt-2">
|
||||
{image.artist.socials.map((social, i) => (
|
||||
<SocialIcon
|
||||
key={i}
|
||||
url={social.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{ height: 28, width: 28 }}
|
||||
title={social.type}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Album */}
|
||||
{image.album && (
|
||||
<div className="mb-4">
|
||||
<h2 className="text-lg font-semibold mb-1">Album</h2>
|
||||
<Link
|
||||
href={`/galleries/${image.album.slug}`}
|
||||
className="text-primary hover:underline"
|
||||
>
|
||||
{image.album.name}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Categories */}
|
||||
{image.categories?.length > 0 && (
|
||||
<div className="mb-4">
|
||||
<h2 className="text-lg font-semibold mb-1">Categories</h2>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{image.categories.map((cat) => (
|
||||
<Link
|
||||
key={cat.id}
|
||||
href={`/categories/${cat.id}`}
|
||||
className="bg-muted text-sm px-2 py-1 rounded hover:bg-accent"
|
||||
>
|
||||
{cat.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Tags */}
|
||||
{image.tags?.length > 0 && (
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold mb-1">Tags</h2>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{image.tags.map((tag) => (
|
||||
<Link
|
||||
key={tag.id}
|
||||
href={`/tags/${tag.id}`}
|
||||
className="bg-muted text-sm px-2 py-1 rounded hover:bg-accent"
|
||||
>
|
||||
#{tag.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user