feat : update
CI / Verify (push) Successful in 1m14s
CI / Build immutable images and deploy (push) Successful in 3m18s

This commit is contained in:
2026-09-06 15:58:11 +07:00 Unverified
parent de76a27c86
commit 5f6b8c1059
11 changed files with 3934 additions and 21 deletions
+2 -2
View File
@@ -180,7 +180,7 @@ export function GuideOverviewForm({
y: typeof (draft.posterArtOffset as Record<string, unknown>).y === "number" ? (draft.posterArtOffset as Record<string, unknown>).y as number : 0,
}
: { x: guide.posterArtOffsetX, y: guide.posterArtOffsetY },
posterArtScale: typeof draft.posterArtScale === "number" ? Math.max(50, Math.min(200, draft.posterArtScale)) : guide.posterArtScale,
posterArtScale: typeof draft.posterArtScale === "number" ? Math.max(50, Math.min(500, draft.posterArtScale)) : guide.posterArtScale,
posterTopColors: Array.isArray(draft.posterTopColors) && draft.posterTopColors.length === 2
? draft.posterTopColors as [string, string]
: guide.posterTopColors,
@@ -399,7 +399,7 @@ export function GuideOverviewForm({
</div>
<div className="rounded-lg border p-3">
<div className="flex justify-between text-sm"><span>Character image zoom</span><span>{posterArtScale}%</span></div>
<Input type="range" min={50} max={200} value={posterArtScale} onChange={(event) => setPosterArtScale(Number(event.target.value))} aria-label="Character image zoom" />
<Input type="range" min={50} max={500} value={posterArtScale} onChange={(event) => setPosterArtScale(Number(event.target.value))} aria-label="Character image zoom" />
</div>
<FieldDescription>
อัปโหลดภาพตัวละคร แล้วลากบนตัวอย่างเพื่อจัดตำแหน่ง สีด้านบนและล่างจะตรวจให้อัตโนมัติ
+7 -9
View File
@@ -23,6 +23,7 @@ type PosterCharacter = {
nameCardImageUrl: string | null;
baseStats: CatalogBaseStat[];
ascension: Array<Omit<CatalogAscensionGroup, "items"> & { items: PosterMaterial[] }>;
leveling: Array<Omit<CatalogAscensionGroup, "items"> & { items: PosterMaterial[] }>;
};
const statLabels: Record<string, string> = {
@@ -43,10 +44,6 @@ function statValue(key: string, value: number | string): string {
return key.includes("%") ? `${formatted}%` : formatted;
}
function clampOffset(value: number): number {
return Math.max(-50, Math.min(50, value));
}
export function MaterialPoster({
character,
characterArtUrl,
@@ -73,8 +70,9 @@ export function MaterialPoster({
bleeding?: Array<{ id: string; imageUrl: string | null; amount: number; scale: number; blendMode: PosterBlendMode }>;
}) {
const dragStart = useRef<{ pointerId: number; x: number; y: number; offsetX: number; offsetY: number } | null>(null);
const stats = character.baseStats.slice(0, 4);
const materials = character.ascension.flatMap((group) => group.items);
const preferredStats = ["hp", "atk", "def", "em"];
const stats = preferredStats.map((key) => character.baseStats.find((stat) => stat.key.toLowerCase() === key));
const materials = [...character.ascension, ...character.leveling].flatMap((group) => group.items);
const background = `linear-gradient(180deg, ${topColors[0]} 0%, ${topColors[1]} 22%, rgba(0,0,0,0) 42%, rgba(0,0,0,0) 62%, ${bottomColors[0]} 88%, ${bottomColors[1]} 100%)`;
function handlePointerDown(event: PointerEvent<HTMLDivElement>) {
@@ -93,8 +91,8 @@ export function MaterialPoster({
if (!dragStart.current || dragStart.current.pointerId !== event.pointerId || !onArtworkMove) return;
const rect = event.currentTarget.getBoundingClientRect();
onArtworkMove({
x: clampOffset(dragStart.current.offsetX + ((event.clientX - dragStart.current.x) / rect.width) * 100),
y: clampOffset(dragStart.current.offsetY + ((event.clientY - dragStart.current.y) / rect.height) * 100),
x: dragStart.current.offsetX + ((event.clientX - dragStart.current.x) / rect.width) * 100,
y: dragStart.current.offsetY + ((event.clientY - dragStart.current.y) / rect.height) * 100,
});
}
@@ -164,7 +162,7 @@ export function MaterialPoster({
<div className="absolute inset-x-[4%] top-[5%]" style={{ fontFamily: "Kanit Poster", fontWeight: 800, fontStyle: "italic", textShadow: "-6px 14px 0 rgba(0,0,0,0.59)" }}>
<h2 className="text-[7cqw] leading-none">BASE STATS</h2>
<div className="mt-[4%] flex w-[53%] flex-col gap-[1.5%]">
<div className="mt-[4%] flex w-[53%] flex-col gap-[2.5%]">
{Array.from({ length: 4 }, (_, index) => {
const stat = stats[index];
return (