mirror of
https://github.com/wgh136/nysoure.git
synced 2025-12-16 07:51:14 +00:00
nsfw images
This commit is contained in:
@@ -48,6 +48,7 @@ export interface CreateResourceParams {
|
||||
article: string;
|
||||
images: number[];
|
||||
gallery: number[];
|
||||
gallery_nsfw: number[];
|
||||
}
|
||||
|
||||
export interface Image {
|
||||
@@ -86,6 +87,7 @@ export interface ResourceDetails {
|
||||
comments: number;
|
||||
related: Resource[];
|
||||
gallery: number[];
|
||||
galleryNsfw: number[];
|
||||
}
|
||||
|
||||
export interface Storage {
|
||||
|
||||
@@ -29,6 +29,7 @@ export default function EditResourcePage() {
|
||||
const [images, setImages] = useState<number[]>([]);
|
||||
const [links, setLinks] = useState<{ label: string; url: string }[]>([]);
|
||||
const [galleryImages, setGalleryImages] = useState<number[]>([]);
|
||||
const [galleryNsfw, setGalleryNsfw] = useState<number[]>([]);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isSubmitting, setSubmitting] = useState(false);
|
||||
const [isLoading, setLoading] = useState(true);
|
||||
@@ -57,6 +58,7 @@ export default function EditResourcePage() {
|
||||
setImages(data.images.map((i) => i.id));
|
||||
setLinks(data.links ?? []);
|
||||
setGalleryImages(data.gallery ?? []);
|
||||
setGalleryNsfw(data.galleryNsfw ?? []);
|
||||
setLoading(false);
|
||||
} else {
|
||||
showToast({ message: t("Failed to load resource"), type: "error" });
|
||||
@@ -101,6 +103,7 @@ export default function EditResourcePage() {
|
||||
images: images,
|
||||
links: links,
|
||||
gallery: galleryImages,
|
||||
gallery_nsfw: galleryNsfw,
|
||||
});
|
||||
if (res.success) {
|
||||
setSubmitting(false);
|
||||
@@ -322,6 +325,7 @@ export default function EditResourcePage() {
|
||||
<td>{t("Preview")}</td>
|
||||
<td>{"Markdown"}</td>
|
||||
<td>{t("Gallery")}</td>
|
||||
<td>{"Nsfw"}</td>
|
||||
<td>{t("Action")}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -365,6 +369,22 @@ export default function EditResourcePage() {
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="checkbox checkbox-accent"
|
||||
checked={galleryNsfw.includes(image)}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setGalleryNsfw((prev) => [...prev, image]);
|
||||
} else {
|
||||
setGalleryNsfw((prev) =>
|
||||
prev.filter((id) => id !== image),
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
className={"btn btn-square"}
|
||||
|
||||
@@ -28,6 +28,7 @@ export default function PublishPage() {
|
||||
const [images, setImages] = useState<number[]>([]);
|
||||
const [links, setLinks] = useState<{ label: string; url: string }[]>([]);
|
||||
const [galleryImages, setGalleryImages] = useState<number[]>([]);
|
||||
const [galleryNsfw, setGalleryNsfw] = useState<number[]>([]);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isSubmitting, setSubmitting] = useState(false);
|
||||
|
||||
@@ -108,6 +109,7 @@ export default function PublishPage() {
|
||||
images: images,
|
||||
links: links,
|
||||
gallery: galleryImages,
|
||||
gallery_nsfw: galleryNsfw,
|
||||
});
|
||||
if (res.success) {
|
||||
localStorage.removeItem("publish_data");
|
||||
@@ -332,6 +334,7 @@ export default function PublishPage() {
|
||||
<td>{t("Preview")}</td>
|
||||
<td>{"Markdown"}</td>
|
||||
<td>{"Gallery"}</td>
|
||||
<td>{"Nsfw"}</td>
|
||||
<td>{t("Action")}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -375,6 +378,22 @@ export default function PublishPage() {
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="checkbox checkbox-accent"
|
||||
checked={galleryNsfw.includes(image)}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setGalleryNsfw((prev) => [...prev, image]);
|
||||
} else {
|
||||
setGalleryNsfw((prev) =>
|
||||
prev.filter((id) => id !== image),
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
className={"btn btn-square"}
|
||||
|
||||
@@ -255,12 +255,12 @@ export default function ResourcePage() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-96 md:w-md lg:w-lg xl:w-xl p-4 hidden sm:flex items-center justify-center">
|
||||
<Gallery images={resource.gallery} />
|
||||
<Gallery images={resource.gallery} nsfw={resource.galleryNsfw} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full p-4 flex sm:hidden items-center justify-center">
|
||||
<Gallery images={resource.gallery} />
|
||||
<Gallery images={resource.gallery} nsfw={resource.galleryNsfw} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -357,18 +357,20 @@ function Tags({ tags }: { tags: Tag[] }) {
|
||||
tagsMap.get(type)?.push(tag);
|
||||
}
|
||||
|
||||
const compactMode = tags.length > 10;
|
||||
|
||||
return (
|
||||
<>
|
||||
{Array.from(tagsMap.entries()).map(([type, tags]) => (
|
||||
<p key={type} className={"px-4"}>
|
||||
<Badge className="shadow-xs" key={type}>
|
||||
<Badge className="shadow-xs mr-0.5" key={type}>
|
||||
{type == "" ? t("Other") : type}
|
||||
</Badge>
|
||||
{tags.map((tag) => (
|
||||
<Badge
|
||||
key={tag.name}
|
||||
className={
|
||||
"m-1 cursor-pointer badge-soft badge-primary shadow-xs"
|
||||
`${compactMode ? "m-0.5" : "m-1"} cursor-pointer badge-soft badge-primary shadow-xs`
|
||||
}
|
||||
onClick={() => {
|
||||
navigate(`/tag/${encodeURIComponent(tag.name)}`);
|
||||
@@ -1879,7 +1881,7 @@ function CollectionSelector({
|
||||
);
|
||||
}
|
||||
|
||||
function Gallery({ images }: { images: number[] }) {
|
||||
function Gallery({ images, nsfw }: { images: number[], nsfw: number[] }) {
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
const [direction, setDirection] = useState(0); // 方向:1=向右,-1=向左
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
@@ -1919,6 +1921,10 @@ function Gallery({ images }: { images: number[] }) {
|
||||
setCurrentIndex(index);
|
||||
};
|
||||
|
||||
if (nsfw == null) {
|
||||
nsfw = [];
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative w-full overflow-hidden rounded-xl bg-base-100-tr82 shadow-sm"
|
||||
@@ -1930,10 +1936,8 @@ function Gallery({ images }: { images: number[] }) {
|
||||
<div ref={containerRef} className="w-full h-full relative">
|
||||
{width > 0 && (
|
||||
<AnimatePresence initial={false} custom={direction} mode="sync">
|
||||
<motion.img
|
||||
<motion.div
|
||||
key={currentIndex}
|
||||
src={network.getImageUrl(images[currentIndex])}
|
||||
alt={`Gallery image ${currentIndex + 1}`}
|
||||
className="absolute w-full h-full object-contain"
|
||||
variants={{
|
||||
enter: (dir: number) => ({
|
||||
@@ -1952,7 +1956,12 @@ function Gallery({ images }: { images: number[] }) {
|
||||
animate="center"
|
||||
exit="exit"
|
||||
custom={direction}
|
||||
/>
|
||||
>
|
||||
<GalleryImage
|
||||
src={network.getImageUrl(images[currentIndex])}
|
||||
nfsw={nsfw.includes(images[currentIndex])}
|
||||
/>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
)}
|
||||
</div>
|
||||
@@ -1999,3 +2008,29 @@ function Gallery({ images }: { images: number[] }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function GalleryImage({src, nfsw}: {src: string, nfsw: boolean}) {
|
||||
const [show, setShow] = useState(!nfsw);
|
||||
|
||||
return (
|
||||
<div className="relative w-full h-full">
|
||||
<img
|
||||
src={src}
|
||||
alt=""
|
||||
className={`w-full h-full object-contain transition-all duration-300 ${!show ? 'blur-xl' : ''}`}
|
||||
/>
|
||||
{!show && (
|
||||
<>
|
||||
<div className="absolute inset-0 bg-base-content/20 cursor-pointer" onClick={() => {
|
||||
setShow(true)
|
||||
}} />
|
||||
<div className="absolute top-4 left-4">
|
||||
<Badge className="badge-error shadow-lg">
|
||||
NSFW
|
||||
</Badge>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user