From 08b61b5d9187ed82ce42681cba33ab13271757e3 Mon Sep 17 00:00:00 2001 From: gunshiz Date: Mon, 5 Oct 2026 20:59:44 +0700 Subject: [PATCH] feat : update --- app/admin/[character]/[page]/page.tsx | 6 + components/admin/guide-section-editor.tsx | 166 +- components/admin/media-uploader.tsx | 4 + components/public/condition-switcher.tsx | 27 +- components/public/structured-guide.tsx | 9 +- components/public/team-search.tsx | 10 +- db/schema.ts | 8 +- drizzle/0072_sweet_joseph.sql | 8 + drizzle/meta/0072_snapshot.json | 4100 +++++++++++++++++++++ drizzle/meta/_journal.json | 7 + lib/guides/mutations.ts | 54 +- lib/guides/queries.test.ts | 27 +- lib/guides/queries.ts | 17 +- lib/guides/schemas.test.ts | 10 + lib/guides/schemas.ts | 7 + 15 files changed, 4398 insertions(+), 62 deletions(-) create mode 100644 drizzle/0072_sweet_joseph.sql create mode 100644 drizzle/meta/0072_snapshot.json diff --git a/app/admin/[character]/[page]/page.tsx b/app/admin/[character]/[page]/page.tsx index a0941ed..dffba80 100644 --- a/app/admin/[character]/[page]/page.tsx +++ b/app/admin/[character]/[page]/page.tsx @@ -111,6 +111,8 @@ export default async function StructuredEditorPage({ id: group.id, name: group.name, note: group.note, + iconMediaId: group.iconMediaId, + iconUrl: group.iconUrl, tiers: group.tiers.map((tier) => ({ id: tier.id, name: tier.name, @@ -127,6 +129,8 @@ export default async function StructuredEditorPage({ id: group.id, name: group.name, note: group.note, + iconMediaId: group.iconMediaId, + iconUrl: group.iconUrl, rows: group.rows, })), teams: content.teams.map((team) => ({ @@ -148,6 +152,8 @@ export default async function StructuredEditorPage({ id: group.id, name: group.name, note: group.note, + iconMediaId: group.iconMediaId, + iconUrl: group.iconUrl, teams: group.teams.map((team) => ({ id: team.id, title: team.title, diff --git a/components/admin/guide-section-editor.tsx b/components/admin/guide-section-editor.tsx index d8924f2..1bd8f32 100644 --- a/components/admin/guide-section-editor.tsx +++ b/components/admin/guide-section-editor.tsx @@ -14,6 +14,7 @@ import { GripVerticalIcon, HeartPulseIcon, MousePointerClickIcon, + PencilIcon, PlusIcon, RefreshCcwIcon, SearchIcon, @@ -62,6 +63,7 @@ import { } from "@/components/admin/ui/catalog-select"; import { ConstellationSelect, RefinementSelect } from "@/components/admin/ui/option-select"; import { MediaUploader } from "@/components/admin/media-uploader"; +import { ConditionTabIcon } from "@/components/public/condition-switcher"; import { ScrollableNav } from "@/components/public/scrollable-nav"; import { LunarisText } from "@/components/public/lunaris-text"; import { TeamArtifactIcon } from "@/components/public/team-search"; @@ -258,6 +260,8 @@ type WeaponGroupValue = { id: string; name: string | null; note: string | null; + iconMediaId: string | null; + iconUrl: string | null; rows: WeaponValue[]; }; type ArtifactTierValue = { @@ -274,6 +278,8 @@ type ArtifactValue = { id: string; name: string | null; note: string | null; + iconMediaId: string | null; + iconUrl: string | null; tiers: ArtifactTierValue[]; }; type ArtifactProfile = { @@ -284,6 +290,8 @@ type ArtifactProfile = { recommendedConditions: Array<{ name?: string | null; note: string | null; + iconMediaId: string | null; + iconUrl: string | null; sands: string[]; goblet: string[]; circlet: string[]; @@ -293,6 +301,8 @@ type ArtifactProfile = { targetConditions: Array<{ name?: string | null; note: string | null; + iconMediaId: string | null; + iconUrl: string | null; rows: Array<{ stat: string; value: string }>; }>; talents: TalentPriority[]; @@ -308,6 +318,8 @@ type ConstellationGroupValue = { id: string; name: string | null; note: string | null; + iconMediaId: string | null; + iconUrl: string | null; rows: ConstellationValue[]; }; type CatalogConstellation = { @@ -341,6 +353,8 @@ type TeamGroupValue = { id: string; name: string | null; note: string | null; + iconMediaId: string | null; + iconUrl: string | null; teams: TeamValue[]; }; @@ -373,20 +387,25 @@ function ConditionRenameDialog({ open, fallback, value, + iconUrl, onOpenChange, onChange, + onIconChange, }: { open: boolean; fallback: string; value: string; + iconUrl: string | null; onOpenChange: (open: boolean) => void; onChange: (value: string) => void; + onIconChange: (icon: { iconMediaId: string | null; iconUrl: string | null }) => void; }) { + const [uploading, setUploading] = useState(false); return ( - - + { if (!uploading) onOpenChange(next); }}> + - Rename condition + Edit condition Leave blank to use {fallback}. @@ -402,14 +421,29 @@ function ConditionRenameDialog({ onChange={(event) => onChange(event.target.value)} /> + - + ); } +function ConditionIconField({ iconUrl, onChange, onUploadingChange }: { + iconUrl: string | null; + onChange: (icon: { iconMediaId: string | null; iconUrl: string | null }) => void; + onUploadingChange?: (uploading: boolean) => void; +}) { + return
+ {iconUrl ?
+ + +
: null} + onChange({ iconMediaId: asset.id, iconUrl: asset.url })} onUploadingChange={onUploadingChange} /> +
; +} + function parseEditorDraft( value: unknown, arrayKeys: string[], @@ -891,6 +925,8 @@ function SortableExtraItem({ type ConditionNavItem = { clientId: string; name: string; + iconMediaId: string | null; + iconUrl: string | null; }; function SortableConditionTab({ @@ -922,13 +958,14 @@ function SortableConditionTab({ style={{ transform: CSS.Transform.toString(transform), transition }} className={cn("flex shrink-0 items-center rounded-md", isDragging && "z-10 opacity-60")} > + {index > 0 ?