This commit is contained in:
2025-11-16 18:46:22 +08:00
parent 9d9a2545f9
commit 46a19c12fa
12 changed files with 101 additions and 101 deletions

View File

@@ -5,9 +5,9 @@ import showToast from "./toast";
import { useTranslation } from "../utils/i18n";
import Button from "./button";
export default function CharacterEditer({charactor, setCharactor, onDelete}: {
charactor: CharacterParams;
setCharactor: (charactor: CharacterParams) => void;
export default function CharacterEditer({character, setCharacter, onDelete}: {
character: CharacterParams;
setCharacter: (character: CharacterParams) => void;
onDelete: () => void;
}) {
const { t } = useTranslation();
@@ -26,8 +26,8 @@ export default function CharacterEditer({charactor, setCharactor, onDelete}: {
const result = await network.uploadImage(file);
setUploading(false);
if (result.success) {
setCharactor({
...charactor,
setCharacter({
...character,
image: result.data!,
});
} else {
@@ -51,7 +51,7 @@ export default function CharacterEditer({charactor, setCharactor, onDelete}: {
}
<img
className="w-full h-full object-cover bg-base-200/80 hover:bg-base-200 transition-colors"
src={charactor.image === 0 ? "/cp.webp" : network.getImageUrl(charactor.image)} alt={charactor.name}
src={character.image === 0 ? "/cp.webp" : network.getImageUrl(character.image)} alt={character.name}
/>
</div>
@@ -61,8 +61,8 @@ export default function CharacterEditer({charactor, setCharactor, onDelete}: {
type="text"
className="input input-sm input-bordered flex-1"
placeholder={t("Name")}
value={charactor.name}
onChange={(e) => setCharactor({ ...charactor, name: e.target.value })}
value={character.name}
onChange={(e) => setCharacter({ ...character, name: e.target.value })}
/>
<button
className="btn btn-sm btn-error btn-square"
@@ -78,14 +78,14 @@ export default function CharacterEditer({charactor, setCharactor, onDelete}: {
type="text"
className="input input-sm input-bordered"
placeholder="CV"
value={charactor.cv}
onChange={(e) => setCharactor({ ...charactor, cv: e.target.value })}
value={character.cv}
onChange={(e) => setCharacter({ ...character, cv: e.target.value })}
/>
<select
className="select select-sm select-bordered"
value={charactor.role}
onChange={(e) => setCharactor({ ...charactor, role: e.target.value as CharacterRole })}
value={character.role}
onChange={(e) => setCharacter({ ...character, role: e.target.value as CharacterRole })}
>
<option value="primary">{t("Primary Role")}</option>
<option value="side">{t("Side Role")}</option>
@@ -95,9 +95,9 @@ export default function CharacterEditer({charactor, setCharactor, onDelete}: {
<textarea
className="textarea textarea-bordered w-full h-full resize-none text-xs"
placeholder={t("Aliases (one per line)")}
value={charactor.alias.join('\n')}
onChange={(e) => setCharactor({
...charactor,
value={character.alias.join('\n')}
onChange={(e) => setCharacter({
...character,
alias: e.target.value.split('\n').filter(line => line.trim() !== '')
})}
/>

View File

@@ -99,7 +99,7 @@ export interface ResourceDetails {
related: Resource[];
gallery: number[];
galleryNsfw: number[];
charactors: CharacterParams[];
characters: CharacterParams[];
}
export interface Storage {

View File

@@ -31,7 +31,7 @@ export default function EditResourcePage() {
const [links, setLinks] = useState<{ label: string; url: string }[]>([]);
const [galleryImages, setGalleryImages] = useState<number[]>([]);
const [galleryNsfw, setGalleryNsfw] = useState<number[]>([]);
const [charactors, setCharactors] = useState<CharacterParams[]>([]);
const [characters, setCharacters] = useState<CharacterParams[]>([]);
const [error, setError] = useState<string | null>(null);
const [isSubmitting, setSubmitting] = useState(false);
const [isLoading, setLoading] = useState(true);
@@ -61,7 +61,7 @@ export default function EditResourcePage() {
setLinks(data.links ?? []);
setGalleryImages(data.gallery ?? []);
setGalleryNsfw(data.galleryNsfw ?? []);
setCharactors(data.charactors ?? []);
setCharacters(data.characters ?? []);
setLoading(false);
} else {
showToast({ message: t("Failed to load resource"), type: "error" });
@@ -107,7 +107,7 @@ export default function EditResourcePage() {
links: links,
gallery: galleryImages,
gallery_nsfw: galleryNsfw,
characters: charactors,
characters: characters,
});
if (res.success) {
setSubmitting(false);
@@ -428,18 +428,18 @@ export default function EditResourcePage() {
<p className={"my-1"}>{t("Characters")}</p>
<div className="grid grid-cols-1 md:grid-cols-2 my-2 gap-4">
{
charactors.map((charactor, index) => {
characters.map((character, index) => {
return <CharacterEditer
charactor={charactor}
setCharactor={(newCharactor) => {
const newCharactors = [...charactors];
newCharactors[index] = newCharactor;
setCharactors(newCharactors);
character={character}
setCharacter={(newCharacter) => {
const newCharacters = [...characters];
newCharacters[index] = newCharacter;
setCharacters(newCharacters);
}}
onDelete={() => {
const newCharactors = [...charactors];
newCharactors.splice(index, 1);
setCharactors(newCharactors);
const newCharacters = [...characters];
newCharacters.splice(index, 1);
setCharacters(newCharacters);
}} />;
})
}
@@ -449,7 +449,7 @@ export default function EditResourcePage() {
className={"btn h-9"}
type={"button"}
onClick={() => {
setCharactors([...charactors, { name: "", alias: [], cv: "", image: 0 }]);
setCharacters([...characters, { name: "", alias: [], cv: "", image: 0 }]);
}}
>
<MdAdd />
@@ -461,7 +461,7 @@ export default function EditResourcePage() {
<FetchVndbCharactersButton
vnID={links.find(link => link.label.toLowerCase() === "vndb")?.url.split("/").pop() ?? ""}
onFetch={(fetchedCharacters) => {
setCharactors(fetchedCharacters);
setCharacters(fetchedCharacters);
}}
/>
</div>

View File

@@ -32,7 +32,7 @@ export default function PublishPage() {
const [galleryNsfw, setGalleryNsfw] = useState<number[]>([]);
const [error, setError] = useState<string | null>(null);
const [isSubmitting, setSubmitting] = useState(false);
const [charactors, setCharactors] = useState<CharacterParams[]>([]);
const [characters, setCharacters] = useState<CharacterParams[]>([]);
const isFirstLoad = useRef(true);
useEffect(() => {
@@ -111,7 +111,7 @@ export default function PublishPage() {
links: links,
gallery: galleryImages,
gallery_nsfw: galleryNsfw,
characters: charactors,
characters: characters,
});
if (res.success) {
localStorage.removeItem("publish_data");
@@ -435,18 +435,18 @@ export default function PublishPage() {
<p className={"my-1"}>{t("Characters")}</p>
<div className="grid grid-cols-1 md:grid-cols-2 my-2 gap-4">
{
charactors.map((charactor, index) => {
characters.map((character, index) => {
return <CharacterEditer
charactor={charactor}
setCharactor={(newCharactor) => {
const newCharactors = [...charactors];
newCharactors[index] = newCharactor;
setCharactors(newCharactors);
character={character}
setCharacter={(newCharacter) => {
const newCharacters = [...characters];
newCharacters[index] = newCharacter;
setCharacters(newCharacters);
}}
onDelete={() => {
const newCharactors = [...charactors];
newCharactors.splice(index, 1);
setCharactors(newCharactors);
const newCharacters = [...characters];
newCharacters.splice(index, 1);
setCharacters(newCharacters);
}} />;
})
}
@@ -456,7 +456,7 @@ export default function PublishPage() {
className={"btn my-2"}
type={"button"}
onClick={() => {
setCharactors([...charactors, { name: "", alias: [], cv: "", image: 0 }]);
setCharacters([...characters, { name: "", alias: [], cv: "", image: 0 }]);
}}
>
<MdAdd />

View File

@@ -600,7 +600,7 @@ function Article({ resource }: { resource: ResourceDetails }) {
</Markdown>
</article>
<div className="border-b border-base-300 h-8"></div>
<Characters charactors={resource.charactors} />
<Characters characters={resource.characters} />
</>
);
}
@@ -2078,10 +2078,10 @@ function GalleryImage({src, nfsw}: {src: string, nfsw: boolean}) {
);
}
function Characters({ charactors }: { charactors: CharacterParams[] }) {
function Characters({ characters }: { characters: CharacterParams[] }) {
const { t } = useTranslation();
if (!charactors || charactors.length === 0) {
if (!characters || characters.length === 0) {
return <></>;
}
@@ -2089,43 +2089,43 @@ function Characters({ charactors }: { charactors: CharacterParams[] }) {
<div className="mt-8">
<h3 className="text-xl font-bold mb-4">{t("Characters")}</h3>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4">
{charactors.map((charactor, index) => (
<CharacterCard key={index} charactor={charactor} />
{characters.map((character, index) => (
<CharacterCard key={index} character={character} />
))}
</div>
</div>
);
}
function CharacterCard({ charactor }: { charactor: CharacterParams }) {
function CharacterCard({ character }: { character: CharacterParams }) {
const navigate = useNavigate();
const handleCVClick = (e: React.MouseEvent) => {
e.stopPropagation();
if (charactor.cv) {
navigate(`/search?keyword=${encodeURIComponent(charactor.cv)}`);
if (character.cv) {
navigate(`/search?keyword=${encodeURIComponent(character.cv)}`);
}
};
return (
<div className="group relative aspect-[3/4] overflow-hidden rounded-lg bg-base-200 shadow-sm">
<img
src={network.getImageUrl(charactor.image)}
alt={charactor.name}
src={network.getImageUrl(character.image)}
alt={character.name}
className="w-full h-full object-cover"
/>
<div className="absolute bottom-1 left-1 right-1 px-2 py-2 border border-base-100/40 rounded-lg bg-base-100/60">
<h4 className="font-semibold text-sm leading-tight line-clamp border border-transparent px-1">
{charactor.name}
{character.name}
</h4>
{charactor.cv && (
{character.cv && (
<button
onClick={handleCVClick}
className="hover:bg-base-200/80 px-1 border border-transparent hover:border-base-300/50 rounded-sm text-xs transition-colors cursor-pointer"
>
CV: {charactor.cv}
CV: {character.cv}
</button>
)}
</div>