feat(studio): localize catalog studio UI and polish responsive layout
Route all Catalog Studio strings through the admin.studio namespace (workspace, filters, review, inspector, quality, sync, scale32, organize imports and page titles/subtitles) with English fallback, and add shared StudioPage chrome plus a loading skeleton. Tighten mobile padding on the header and sub-bars.
This commit is contained in:
1 parent
d7d6382b60
commit
56676effc3
28 files changed
+1293
-634
No files matched your search
@@ -1,4 +1,5 @@
|
||||
"use client";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { adminFetch } from "@/lib/admin-fetch";
|
||||
@@ -11,6 +12,7 @@ export function NitroScale32Generator({
|
||||
disabled: boolean;
|
||||
onChanged: (metadata: Record<string, unknown>) => void;
|
||||
}) {
|
||||
const t = useTranslations("admin.studio.scale32");
|
||||
const [preview, setPreview] = useState<{
|
||||
hash: string;
|
||||
before: string;
|
||||
@@ -38,7 +40,7 @@ export function NitroScale32Generator({
|
||||
}),
|
||||
});
|
||||
const data = await response.json();
|
||||
if (!response.ok) throw Error(data.error || "Generation failed");
|
||||
if (!response.ok) throw Error(data.error || t("generationFailed"));
|
||||
if (action === "preview") setPreview(data);
|
||||
else {
|
||||
setPreview(null);
|
||||
@@ -50,45 +52,37 @@ export function NitroScale32Generator({
|
||||
onChanged(data.metadata);
|
||||
}
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Generation failed");
|
||||
setError(e instanceof Error ? e.message : t("generationFailed"));
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<section className="space-y-3 rounded-lg border p-3">
|
||||
<h3 className="font-semibold">Generate scale 32 from 64</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Adds derived artwork using nearest-neighbor reduction. Existing scale 32
|
||||
is preserved. Preview uses the saved bundle and shows one sprite at its
|
||||
original pixel size.
|
||||
</p>
|
||||
{disabled && (
|
||||
<p className="text-sm">Save or reset your pending edits first.</p>
|
||||
)}
|
||||
<h3 className="font-semibold">{t("title")}</h3>
|
||||
<p className="text-sm text-muted-foreground">{t("intro")}</p>
|
||||
{disabled && <p className="text-sm">{t("saveFirst")}</p>}
|
||||
<Button
|
||||
variant="outline"
|
||||
disabled={busy || disabled}
|
||||
onClick={() => run("preview")}
|
||||
>
|
||||
{busy ? "Working…" : "Preview generation"}
|
||||
{busy ? t("working") : t("preview")}
|
||||
</Button>
|
||||
{preview && (
|
||||
<>
|
||||
<p className="text-sm">
|
||||
{preview.count} sprite entries will be added. Check positioning and
|
||||
animations in the client after saving.
|
||||
{t("previewCount", { count: preview.count })}
|
||||
</p>
|
||||
{preview.skipped ? (
|
||||
<p className="text-sm text-destructive" role="alert">
|
||||
{preview.skipped} sprite(s) were skipped because the source bundle
|
||||
has no usable artwork for them.
|
||||
{t("skipped", { count: preview.skipped })}
|
||||
</p>
|
||||
) : null}
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{[
|
||||
["Original 64", preview.before],
|
||||
["Derived 32", preview.after],
|
||||
[t("original64"), preview.before],
|
||||
[t("derived32"), preview.after],
|
||||
].map(([label, src]) => (
|
||||
<figure key={label} className="min-w-0">
|
||||
<figcaption>{label}</figcaption>
|
||||
@@ -103,28 +97,26 @@ export function NitroScale32Generator({
|
||||
))}
|
||||
</div>
|
||||
<Button disabled={busy || disabled} onClick={() => run("apply")}>
|
||||
Save with backup
|
||||
{t("saveWithBackup")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled={busy}
|
||||
onClick={() => setPreview(null)}
|
||||
>
|
||||
Discard preview
|
||||
{t("discard")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{undo && (
|
||||
<div>
|
||||
<p className="text-sm">
|
||||
Saved. A copy of the original bundle is preserved.
|
||||
</p>
|
||||
<p className="text-sm">{t("saved")}</p>
|
||||
<Button
|
||||
variant="outline"
|
||||
disabled={busy || disabled}
|
||||
onClick={() => run("restore")}
|
||||
>
|
||||
Restore original bundle
|
||||
{t("restore")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in new issue
Block a user