→
diff --git a/src/index.css b/src/index.css
index 1f764ce..1c7f5b8 100644
--- a/src/index.css
+++ b/src/index.css
@@ -110,6 +110,11 @@ input[type="checkbox"] {
to { transform: rotate(360deg); }
}
+@keyframes shimmer {
+ 0% { background-position: 200% 0; }
+ 100% { background-position: -200% 0; }
+}
+
.animate-fade-in {
animation: fadeIn 0.2s ease-out;
}
diff --git a/src/store.ts b/src/store.ts
index 2a38db4..c1d8a22 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -1,6 +1,6 @@
import { create } from "zustand";
import { invoke } from "@tauri-apps/api/core";
-import { Profile, GuideListItem, GuideData, SyncResult } from "./types";
+import { Profile, GuideListItem, GuideData, SyncResult, CombatIndicator, Section } from "./types";
interface AppState {
profiles: Profile[];
@@ -15,6 +15,8 @@ interface AppState {
sidebarCollapsed: boolean;
resourcesPanelCollapsed: boolean;
resourceInventory: Record
;
+ questPreviews: Record;
+ previewsLoading: boolean;
setResourcesPanelCollapsed: (v: boolean) => void;
loadResourceInventory: () => Promise;
@@ -28,6 +30,7 @@ interface AppState {
openGuide: (gid: string) => Promise;
setSidebarCollapsed: (collapsed: boolean) => void;
closeGuide: () => void;
+ loadQuestPreviews: (gid: string) => Promise;
toggleQuest: (questName: string) => Promise;
@@ -48,6 +51,8 @@ export const useStore = create((set, get) => ({
sidebarCollapsed: false,
resourcesPanelCollapsed: false,
resourceInventory: {},
+ questPreviews: {},
+ previewsLoading: false,
setResourcesPanelCollapsed: (v) => set({ resourcesPanelCollapsed: v }),
@@ -112,13 +117,32 @@ export const useStore = create((set, get) => ({
const data = await invoke("get_guide", { gid });
await invoke("set_setting", { key: "active_guide", value: gid });
set({ activeGuideGid: gid, activeGuideData: data, view: "guide" });
+ await get().loadQuestPreviews(gid);
},
setSidebarCollapsed: (collapsed) => set({ sidebarCollapsed: collapsed }),
closeGuide: () => {
invoke("set_setting", { key: "active_guide", value: "" });
- set({ activeGuideGid: null, activeGuideData: null, view: "home" });
+ set({ activeGuideGid: null, activeGuideData: null, view: "home", questPreviews: {}, previewsLoading: false });
+ },
+
+ loadQuestPreviews: async (gid) => {
+ const { activeGuideData } = get();
+ if (!activeGuideData) return;
+
+ const urls = collectQuestUrls(activeGuideData.sections);
+ if (urls.length === 0) return;
+
+ // Hydratation immédiate depuis le cache DB
+ const cached = await invoke>("get_cached_previews", { questUrls: urls });
+ set({ questPreviews: cached });
+
+ // Fetch réseau en tâche de fond (fire & forget)
+ set({ previewsLoading: true });
+ invoke>("fetch_guide_previews", { gid })
+ .then(result => set({ questPreviews: result, previewsLoading: false }))
+ .catch(() => set({ previewsLoading: false }));
},
toggleQuest: async (questName) => {
@@ -164,3 +188,18 @@ export const useStore = create((set, get) => ({
await invoke("sync_single_guide", { gid, name });
},
}));
+
+function collectQuestUrls(sections: Section[]): string[] {
+ const urls: string[] = [];
+ for (const section of sections) {
+ for (const item of section.items) {
+ if (item.type === "Quest" && item.url) urls.push(item.url);
+ else if (item.type === "Group") {
+ for (const q of item.quests) {
+ if (q.url) urls.push(q.url);
+ }
+ }
+ }
+ }
+ return urls;
+}
diff --git a/src/types.ts b/src/types.ts
index 5f50a07..cfd542c 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -25,6 +25,8 @@ export interface Resource {
export interface CombatIndicator {
combat_type: string;
count: string;
+ label?: string;
+ evitable?: boolean;
}
export interface QuestItem {