From 9d181f36767d9b0f2307005c9c56ad8d3f02f8f2 Mon Sep 17 00:00:00 2001 From: Blomios Date: Wed, 22 Apr 2026 13:03:25 +0200 Subject: [PATCH] design: the window can now resize to l=380px --- src-tauri/tauri.conf.json | 4 +- src/components/GuideView.tsx | 251 ++++++++++++++++++++++------------- src/components/HomeView.tsx | 107 ++++++++------- src/components/Sidebar.tsx | 188 +++++++++++++++----------- 4 files changed, 331 insertions(+), 219 deletions(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 866c926..99a9b81 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -15,8 +15,8 @@ "title": "TougliGui", "width": 1100, "height": 720, - "minWidth": 800, - "minHeight": 500, + "minWidth": 380, + "minHeight": 400, "decorations": false, "transparent": false, "backgroundColor": "#0d1117", diff --git a/src/components/GuideView.tsx b/src/components/GuideView.tsx index db464fd..026fdd1 100644 --- a/src/components/GuideView.tsx +++ b/src/components/GuideView.tsx @@ -1,63 +1,84 @@ +import { useState } from "react"; import { openUrl } from "@tauri-apps/plugin-opener"; import { useStore } from "../store"; -import { SectionItem, QuestItem } from "../types"; +import { SectionItem, QuestItem, CombatType } from "../types"; + +function combatIcon(name: string): string { + const l = name.toLowerCase(); + if (l.includes("solo")) return "⚔️"; + if (l.includes("group") || l.includes("groupe")) return "👥"; + if (l.includes("boss")) return "💀"; + if (l.includes("arène") || l.includes("arene")) return "🏟️"; + return "⚔️"; +} export default function GuideView() { const { activeGuideData, completedQuests, toggleQuest } = useStore(); + const [resourcesCollapsed, setResourcesCollapsed] = useState(false); if (!activeGuideData) return null; - const { name, effect, recommended_level, resources, sections } = activeGuideData; + const { name, effect, recommended_level, resources, sections, combat_legend } = activeGuideData; const allQuests = collectAllQuests(sections); const completedCount = allQuests.filter(q => completedQuests.has(q)).length; const pct = allQuests.length > 0 ? Math.round((completedCount / allQuests.length) * 100) : 0; + const isDone = pct === 100; return (
- {/* Main quest list */}
- {/* Guide header */} + + {/* Header */}
-

- {name} -

-
- {recommended_level && ( - - Niveau recommandé : {recommended_level} - - )} - - {completedCount}/{allQuests.length} quêtes · {pct}% - +
+
+

{name}

+ {recommended_level && ( +
+ Niv. recommandé : {recommended_level} +
+ )} +
+
+
+ {completedCount} / {allQuests.length} +
+
{pct}%
+
- {/* Progress bar */} -
+ +
+ {effect && (
- Effet : + + ✨ Effet + {effect}
)}
+ {/* Légende */} + {combat_legend.length > 0 && ( + + )} + {/* Sections */} {sections.map((section, si) => ( -
+

0 && (
-

- Ressources -

- {resources.map((r, i) => ( -
setResourcesCollapsed(c => !c)} + title={resourcesCollapsed ? "Afficher les ressources" : "Masquer les ressources"} + style={{ + width: "100%", height: "36px", flexShrink: 0, + background: "transparent", border: "none", + borderBottom: "1px solid #2d3748", + color: "#4a5568", cursor: "pointer", + display: "flex", alignItems: "center", + justifyContent: resourcesCollapsed ? "center" : "flex-start", + padding: "0 10px", gap: "6px", + transition: "all 0.15s", + }} + onMouseEnter={e => (e.currentTarget.style.color = "#f0c040")} + onMouseLeave={e => (e.currentTarget.style.color = "#4a5568")} + > + - {r.name} - ×{r.quantity} + › + + {!resourcesCollapsed && ( + + Ressources + + )} + + + {/* List */} + {!resourcesCollapsed && ( +
+ {resources.map((r, i) => ( +
+ {r.name} + ×{r.quantity} +
+ ))}
- ))} + )}
)}
); } +function Legend({ legend }: { legend: CombatType[] }) { + return ( +
+
+ Légende +
+
+ {legend.map((ct, i) => ( +
+ {combatIcon(ct.name)} + {ct.name} +
+ ))} +
+
+ ); +} + function SectionItemView({ item, completedQuests, onToggle }: { item: SectionItem; completedQuests: Set; @@ -121,11 +200,16 @@ function SectionItemView({ item, completedQuests, onToggle }: { } return (
- ℹ️ {item.text} + + Rappel + + {item.text}
); } @@ -137,10 +221,7 @@ function SectionItemView({ item, completedQuests, onToggle }: { borderRadius: "6px", padding: "8px 10px", marginBottom: "6px", }}> {item.note && ( -
+
🔗 {item.note}
)} @@ -169,18 +250,14 @@ function QuestRow({ quest, completed, onToggle, indent }: { onClick={() => onToggle(quest.name)} style={{ display: "flex", alignItems: "flex-start", gap: "8px", - padding: indent ? "4px 0" : "5px 6px", + padding: indent ? "3px 0" : "4px 6px", borderRadius: "5px", cursor: "pointer", - marginBottom: indent ? "2px" : "3px", - opacity: completed ? 0.6 : 1, + marginBottom: indent ? "1px" : "2px", + opacity: completed ? 0.5 : 1, transition: "all 0.12s", }} - onMouseEnter={e => { - (e.currentTarget as HTMLElement).style.background = "rgba(255,255,255,0.04)"; - }} - onMouseLeave={e => { - (e.currentTarget as HTMLElement).style.background = "transparent"; - }} + onMouseEnter={e => { (e.currentTarget as HTMLElement).style.background = "rgba(255,255,255,0.04)"; }} + onMouseLeave={e => { (e.currentTarget as HTMLElement).style.background = "transparent"; }} >
-
+
+ fontSize: "12px", lineHeight: 1.4, + color: completed ? "#4a5568" : quest.url ? "#93c5fd" : "#e2e8f0", + textDecoration: completed ? "line-through" : quest.url ? "underline" : "none", + textDecorationColor: "rgba(147,197,253,0.4)", + cursor: quest.url ? "pointer" : "default", + wordBreak: "break-word", + }} + onClick={e => { + if (quest.url) { e.stopPropagation(); openUrl(quest.url); } + }} + > {quest.name} - {quest.url && ( - { e.stopPropagation(); openUrl(quest.url!); }} - style={{ - fontSize: "10px", color: "#4a9eff", cursor: "pointer", - opacity: 0.7, flexShrink: 0, lineHeight: 1, - }} - onMouseEnter={e => (e.currentTarget as HTMLElement).style.opacity = "1"} - onMouseLeave={e => (e.currentTarget as HTMLElement).style.opacity = "0.7"} - > - 🔗 + {quest.combat_indicators.map((ci, i) => ( + + {combatIcon(ci.combat_type)} x{ci.count} - )} + ))}
- {quest.combat_indicators.length > 0 && ( -
- {quest.combat_indicators.map((ci, i) => ( - - {ci.combat_type} {ci.count} - - ))} -
- )} {quest.note && ( -
+
→ {quest.note}
)} @@ -236,13 +298,12 @@ function QuestRow({ quest, completed, onToggle, indent }: { ); } -function collectAllQuests(sections: import("../types").Section[] | undefined): string[] { - if (!sections) return []; +function collectAllQuests(sections: import("../types").Section[]): string[] { const names: string[] = []; for (const section of sections) { for (const item of section.items) { if (item.type === "Quest") names.push(item.name); - else if (item.type === "Group") item.quests.forEach((q: import("../types").QuestItem) => names.push(q.name)); + else if (item.type === "Group") item.quests.forEach((q: QuestItem) => names.push(q.name)); } } return names; diff --git a/src/components/HomeView.tsx b/src/components/HomeView.tsx index 985c9c6..beabde5 100644 --- a/src/components/HomeView.tsx +++ b/src/components/HomeView.tsx @@ -4,19 +4,17 @@ export default function HomeView() { const { guides, openGuide, profiles, activeProfileId } = useStore(); const activeProfile = profiles.find(p => p.id === activeProfileId); - const totalQuests = guides.reduce((s, g) => s + g.total_quests, 0); const totalCompleted = guides.reduce((s, g) => s + g.completed_quests, 0); const globalPct = totalQuests > 0 ? Math.round((totalCompleted / totalQuests) * 100) : 0; - const completedGuides = guides.filter(g => g.total_quests > 0 && g.completed_quests === g.total_quests); const inProgressGuides = guides.filter(g => g.completed_quests > 0 && g.completed_quests < g.total_quests); return (
{/* Header */} -
-

+
+

Tougli — Guide Dofus

{activeProfile && ( @@ -32,7 +30,7 @@ export default function HomeView() { background: "#161b22", border: "1px solid #2d3748", borderRadius: "10px", padding: "16px 20px", marginBottom: "24px", }}> -
+
Progression globale {totalCompleted} / {totalQuests} quêtes ({globalPct}%) @@ -45,7 +43,7 @@ export default function HomeView() { borderRadius: "3px", transition: "width 0.4s ease", }} />
-
+
@@ -53,12 +51,12 @@ export default function HomeView() {
)} - {/* In progress first */} + {/* En cours */} {inProgressGuides.length > 0 && (
)} - {/* All guides grid */} + {/* Tous les guides */}
); @@ -66,9 +64,9 @@ export default function HomeView() { function Stat({ label, value, color }: { label: string; value: number; color: string }) { return ( -
+
{value} - {label} + {label}
); } @@ -80,13 +78,15 @@ function Section({ title, guides, onOpen }: { }) { return (
-

+

{title}

-
- {guides.map(guide => )} +
+ {guides.map(g => )}
); @@ -96,52 +96,63 @@ function GuideCard({ guide, onOpen }: { guide: import("../types").GuideListItem; onOpen: (gid: string) => void; }) { - const pct = guide.total_quests > 0 - ? Math.round((guide.completed_quests / guide.total_quests) * 100) - : 0; + const pct = guide.total_quests > 0 ? Math.round((guide.completed_quests / guide.total_quests) * 100) : 0; const isDone = pct === 100 && guide.total_quests > 0; + const inProgress = guide.completed_quests > 0 && !isDone; + + const accentColor = isDone ? "#4ade80" : inProgress ? "#f0c040" : "#4a9eff"; return ( ); diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 5a240af..d63f980 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -4,6 +4,7 @@ import { useStore } from "../store"; export default function Sidebar() { const { guides, openGuide, activeGuideGid, view } = useStore(); const [search, setSearch] = useState(""); + const [collapsed, setCollapsed] = useState(false); const filtered = guides.filter(g => g.name.toLowerCase().includes(search.toLowerCase()) @@ -11,84 +12,123 @@ export default function Sidebar() { return ( ); }