feat: return workshop metadata with mod details

Include the Workshop title and preview image in the items response so the mod header survives a page refresh, not just navigation from search. Resolve both from the same Steam API call.
This commit is contained in:
2026-08-14 10:59:14 +08:00
parent 7163451d1f
commit 30ef76632f
7 changed files with 85 additions and 40 deletions
+4 -4
View File
@@ -1,4 +1,4 @@
import type { SearchResult, TTSMod } from '@tts/shared';
import type { ModDetails, SearchResult } from '@tts/shared';
import { traceImage } from '@tts/http';
export { traceImage };
@@ -21,13 +21,13 @@ export function searchWorkshop(q: string, page = 1): Promise<SearchResult> {
}
/**
* Fetch a full parsed TTS save.
* Fetch a full parsed TTS save plus its Workshop metadata.
*/
export function fetchMod(id: string, fileUrl?: string): Promise<TTSMod> {
export function fetchMod(id: string, fileUrl?: string): Promise<ModDetails> {
const params = new URLSearchParams();
if (fileUrl) params.set('fileUrl', fileUrl);
const qs = params.toString();
return getJson<TTSMod>(`/items/${id}${qs ? `?${qs}` : ''}`);
return getJson<ModDetails>(`/items/${id}${qs ? `?${qs}` : ''}`);
}
/** Build a URL for the raw save file download. */
+2 -2
View File
@@ -25,8 +25,8 @@ export default function ModPage() {
if (id) load(id, item?.fileUrl);
}, [id, item?.fileUrl, load]);
const tree = useMemo(() => (mod ? buildTree(mod) : []), [mod]);
const refs = useMemo(() => (mod ? collectRefs(mod) : []), [mod]);
const tree = useMemo(() => (mod ? buildTree(mod.mod) : []), [mod]);
const refs = useMemo(() => (mod ? collectRefs(mod.mod) : []), [mod]);
const selected = useMemo(
() => (mod ? findInTree(tree, selectedPath) : undefined),
+5 -5
View File
@@ -1,11 +1,11 @@
import { create } from 'zustand';
import type { TTSMod } from '@tts/shared';
import type { ModDetails } from '@tts/shared';
import { fetchMod } from '../api';
interface ModState {
id: string | null;
fileUrl?: string;
mod: TTSMod | null;
mod: ModDetails | null;
loading: boolean;
error: string | null;
load: (id: string, fileUrl?: string) => Promise<void>;
@@ -21,11 +21,11 @@ export const useModStore = create<ModState>((set) => ({
load: async (id, fileUrl) => {
set({ loading: true, error: null, id, fileUrl });
try {
const mod = await fetchMod(id, fileUrl);
set({ mod, loading: false });
const details = await fetchMod(id, fileUrl);
set({ mod: details, loading: false });
} catch (err) {
set({ loading: false, error: String(err) });
}
},
clear: () => set({ id: null, fileUrl: undefined, mod: null, error: null, loading: false }),
clear: () => set({ id: null, fileUrl: undefined, mod: null, loading: false, error: null }),
}));