feat : overhual [no ci]

This commit is contained in:
2026-09-14 18:02:18 +07:00 Unverified
parent 316a1eecfa
commit 648b5fdb18
11 changed files with 46 additions and 26 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ export function AdminHeader() {
className="mr-auto flex min-h-11 items-center gap-3 rounded-lg font-heading font-semibold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
>
<Image src="/icon.png" alt="" width={36} height={36} className="size-9 object-contain" />
<span className="hidden sm:inline">{exportText("watermark")}</span>
<span className="hidden sm:inline">Buzz Guide</span>
</Link>
<LanguageDropdown />
<nav aria-label="Admin navigation" className="flex items-center gap-1">
+3 -3
View File
@@ -121,15 +121,15 @@ function SortableBleedingLayer({ layer, onChange, onRemove }: { layer: BleedingL
items={blendModeItems}
value={selectedMode}
onValueChange={(value) => value && onChange({ blendMode: value.value })}
itemToStringLabel={(item) => t(item.label)}
itemToStringLabel={(item) => item.label}
itemToStringValue={(item) => item.value}
filter={(item, query) => `${t(item.label)} ${item.label} ${item.value}`.toLowerCase().includes(query.trim().toLowerCase())}
filter={(item, query) => `${item.label} ${item.value}`.toLowerCase().includes(query.trim().toLowerCase())}
>
<ComboboxInput className="w-full" placeholder={t("เลือก Blend mode…")} />
<ComboboxContent>
<ComboboxEmpty>{t("ไม่พบ Blend mode")}</ComboboxEmpty>
<ComboboxList>
{(item) => <ComboboxItem key={item.value} value={item}>{t(item.label)}</ComboboxItem>}
{(item) => <ComboboxItem key={item.value} value={item}>{item.label}</ComboboxItem>}
</ComboboxList>
</ComboboxContent>
</Combobox>
+5 -15
View File
@@ -100,7 +100,6 @@ import {
weaponTypeIconPath,
type OverviewRole,
} from "@/lib/overview-image";
import { withoutNotesFileName } from "@/lib/guides/export-text";
import { cn } from "@/lib/utils";
type Character = {
@@ -649,10 +648,10 @@ function SortableBlendLayerRow({
onValueChange={(value) => {
if (value) onUpdate({ mode: value.value });
}}
itemToStringLabel={(item) => t(item.label)}
itemToStringLabel={(item) => item.label}
itemToStringValue={(item) => item.value}
filter={(item, query) =>
`${t(item.label)} ${item.label} ${item.value}`
`${item.label} ${item.value}`
.toLocaleLowerCase("en")
.includes(query.trim().toLocaleLowerCase("en"))
}
@@ -663,7 +662,7 @@ function SortableBlendLayerRow({
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{t(item.label)}
{item.label}
</ComboboxItem>
)}
</ComboboxList>
@@ -1006,7 +1005,7 @@ export function OverviewImageGenerator({
}
}
async function download(includeNotes = true) {
async function download() {
const node = captureRef.current;
if (
!node ||
@@ -1038,7 +1037,7 @@ export function OverviewImageGenerator({
const link = document.createElement("a");
link.href = url;
const fileName = overviewFileName(character.key, displayRole);
link.download = includeNotes ? fileName : withoutNotesFileName(fileName);
link.download = fileName;
document.body.append(link);
link.click();
link.remove();
@@ -1343,15 +1342,6 @@ export function OverviewImageGenerator({
)}
{exporting ? e("exporting") : e("downloadPng", { width: 3000, height: 3000 })}
</Button>
<Button
variant="outline"
className="w-full"
disabled={!ready || exporting}
onClick={() => void download(false)}
>
<DownloadIcon data-icon="inline-start" />
{e("withoutNote")}
</Button>
</CardFooter>
</Card>
</div>
+4 -2
View File
@@ -1,6 +1,6 @@
"use client";
import { cloneElement, type ReactElement } from "react";
import { Children, cloneElement, type ReactElement } from "react";
import { useTranslation } from "./locale-provider";
import { exportStatLabel, type ExportMessageKey } from "@/lib/guides/export-text";
import type { MessageParams } from "@/lib/i18n/messages";
@@ -28,7 +28,9 @@ export function Localized({ children, attributes }: {
const props = Object.fromEntries(Object.entries(attributes).map(([key, value]) => [
key, typeof value === "string" ? t(value) : t(value.message, value.params),
]));
return cloneElement(children, props);
// Children.toArray resolves lazy children streamed across the server/client boundary.
const child = Children.only(Children.toArray(children)[0]) as ReactElement;
return cloneElement(child, props);
}
export function MetricText({ value }: { value: string }) {
@@ -173,6 +173,7 @@ export function ArtifactImageExport({
</div>
) : null}
<GuideImageExport
allowWithoutNote
fileName={fileName}
width={exportWidth}
height={exportHeight}
+3 -1
View File
@@ -27,6 +27,7 @@ export function GuideImageExport({
disabled = false,
captureClassName,
buttonLabel,
allowWithoutNote = false,
}: {
children: ReactNode;
fileName: string;
@@ -36,6 +37,7 @@ export function GuideImageExport({
disabled?: boolean;
captureClassName?: string;
buttonLabel?: string;
allowWithoutNote?: boolean;
}) {
const { e, locale } = useTranslation();
const captureRef = useRef<HTMLDivElement>(null);
@@ -111,7 +113,7 @@ export function GuideImageExport({
return (
<>
<div className="flex flex-wrap gap-2">
{(["with-notes", "without-notes"] as const).map((mode) => (
{(["with-notes", ...(allowWithoutNote ? ["without-notes"] as const : [])] as const).map((mode) => (
<Button
key={mode}
type="button"
+1 -1
View File
@@ -31,7 +31,7 @@ export function SiteHeader({ editHref = "/admin", guideId }: { editHref?: string
className="mr-auto flex min-h-11 items-center gap-3 rounded-lg font-heading font-semibold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
>
<Image src="/icon.png" alt="" width={36} height={36} className="size-9 object-contain" />
<span className="hidden sm:inline">{exportText("watermark")}</span>
<span className="hidden sm:inline">Buzz Guide</span>
</Link>
<LanguageDropdown />
<nav aria-label="Public navigation" className="flex items-center gap-1">
+1
View File
@@ -1102,6 +1102,7 @@ function ConstellationSection({ guide }: { guide: PublicGuide }) {
<div key={group.id} className="flex flex-col gap-4">
<div>
<GuideImageExport
allowWithoutNote
fileName={`${guide.name}-Constellations${groups.length > 1 ? `-${group.name || `Condition-${groupIndex + 1}`}` : ""}.png`}
width={1500}
height={1500}
@@ -140,6 +140,7 @@ export function WeaponImageExport({
<div className="grid gap-2 sm:grid-cols-2">
{metricOptions.map(([metric, label]) => (
<GuideImageExport
allowWithoutNote
key={metric}
fileName={`${baseName}-${label}.png`}
width={1200}