feat: upgrade needed ressources and fight for each quest

This commit is contained in:
2026-04-25 14:39:16 +02:00
parent de6550cee4
commit 0e577b8efd
13 changed files with 560 additions and 2 deletions

View File

@ -16,6 +16,19 @@ function useWindowWidth() {
function combatIcon(name: string): string {
const l = name.toLowerCase();
if (l === "solo") return "🗡️";
if (l === "groupe") return "⚔️";
if (l === "donjon") return "💀";
if (
l === "combat_vagues" ||
l === "combat_tactique" ||
l === "combat_aleatoire" ||
l === "combat_zone" ||
l === "combat"
) return "🗡️";
if (l === "deplacement") return "🗺️";
if (l === "item") return "📦";
// Fallback — conserve l'ancienne logique pour les données CSV existantes
if (l.includes("solo") || l.includes("seul")) return "🗡️";
if (l.includes("group") || l.includes("groupe")) return "⚔️";
if (l.includes("donjon") || l.includes("boss")) return "💀";
@ -324,6 +337,15 @@ function QuestRow({ quest, completed, onToggle, onSelect, indent }: {
onSelect: (quest: { name: string; url: string | null }) => void;
indent?: boolean;
}) {
const questPreviews = useStore(s => s.questPreviews);
const previewsLoading = useStore(s => s.previewsLoading);
const [previewsOpen, setPreviewsOpen] = useState(false);
const previews = quest.url ? questPreviews[quest.url] : undefined;
const showLoadingPlaceholder = previewsLoading && quest.url !== null && previews === undefined;
const hasPreviewSection = showLoadingPlaceholder || (previews && previews.length > 0);
return (
<div
style={{
@ -364,6 +386,72 @@ function QuestRow({ quest, completed, onToggle, onSelect, indent }: {
</span>
))}
</div>
{hasPreviewSection && (
<span
onClick={() => setPreviewsOpen(o => !o)}
style={{
display: "inline-block",
marginTop: "2px",
fontSize: "10px",
color: "#4a5568",
cursor: "pointer",
userSelect: "none",
}}
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.color = "#94a3b8"; }}
onMouseLeave={e => { (e.currentTarget as HTMLElement).style.color = "#4a5568"; }}
>
{previewsOpen
? `▾ À prévoir`
: `▸ À prévoir${previews && previews.length > 0 ? ` (${previews.length})` : ""}`
}
</span>
)}
{previewsOpen && (
<>
{showLoadingPlaceholder && (
<div style={{
marginTop: "3px",
width: "60px", height: "14px",
borderRadius: "4px",
background: "linear-gradient(90deg, #1f2937 25%, #2d3748 50%, #1f2937 75%)",
backgroundSize: "200% 100%",
animation: "shimmer 1.4s infinite",
}} />
)}
{!showLoadingPlaceholder && previews && previews.length > 0 && (
<div style={{ display: "flex", flexWrap: "wrap", gap: "4px", marginTop: "3px" }}>
{previews.map((ci, i) => (
<span key={i} style={{
display: "inline-flex", alignItems: "center", gap: "3px",
fontSize: "10px", padding: "1px 6px", borderRadius: "4px",
background: "rgba(255,255,255,0.05)", border: "1px solid #2d3748",
color: "#4a5568",
}}>
<span>{combatIcon(ci.combat_type)}</span>
<span>×{ci.count}{ci.combat_type !== "item" ? ` ${ci.combat_type}` : ""}</span>
{ci.evitable && (
<span style={{ color: "#4ade80" }}>(évit.)</span>
)}
{ci.label && (
<span style={{
fontStyle: "italic",
maxWidth: "80px", overflow: "hidden",
textOverflow: "ellipsis", whiteSpace: "nowrap",
display: "inline-block",
}}>
{ci.label}
</span>
)}
</span>
))}
</div>
)}
</>
)}
{quest.note && (
<div style={{ fontSize: "11px", color: "#4a5568", marginTop: "2px", fontStyle: "italic" }}>
<TextWithCoords text={quest.note} />