feat: sidebar navigation to dedicated detail views

- Sidebar icons now navigate to full-screen views for each tool
- Dashboard bento cards have 'Expand' buttons that open the detail view
- Back arrow (←) in title bar returns to dashboard
- Detail views wrapped in a glass-card with max-w-2xl layout
- Settings page gets its own full layout with heading
- World Map, Quest Designer, Soundboard show placeholder screens with icons
- All nav items in sidebar: World, NPCs, Encounter, Dice, Session, Sound,
  Initiative, Random Tables, Calendar, Settings
This commit is contained in:
itsamejms
2026-06-28 22:43:08 +01:00
parent 4d4518aec0
commit a44de0e4bb
2 changed files with 318 additions and 87 deletions
+156 -67
View File
@@ -8,78 +8,167 @@ import {
Timer,
Volume2,
Calendar,
Maximize2,
} from "lucide-react";
import { BentoCard } from "./BentoCard";
import type { View } from "../App";
interface DashboardProps {
onNavigate: (view: View) => void;
}
export function Dashboard({ onNavigate }: DashboardProps) {
return (
<div className="grid grid-cols-4 grid-rows-4 gap-3 p-4 h-full bg-[var(--color-bg-deep)]">
{/* World Map — 2×2 */}
<BentoCard title="World Map" icon={<Map size={16} />} span="col-span-2 row-span-2">
<div className="flex flex-col items-center justify-center h-full text-[var(--color-text-dim)] text-sm gap-2">
<Map size={48} className="opacity-30" />
<p>Map canvas coming soon</p>
<button
onClick={() => onNavigate("world")}
className="text-[var(--color-gold-bright)] hover:text-[var(--color-gold-muted)] text-xs flex items-center gap-1 cursor-pointer transition-colors"
>
<Maximize2 size={12} /> Open full view
</button>
</div>
</BentoCard>
{/* NPC Sheet — 1×1 */}
<BentoCard title="NPC Sheet" icon={<User size={16} />} span="col-span-1 row-span-1">
<div className="flex flex-col h-full">
<div className="flex-1 overflow-hidden">
<NpcGenerator />
</div>
<button
onClick={() => onNavigate("npcs")}
className="text-[var(--color-gold-bright)] hover:text-[var(--color-gold-muted)] text-xs flex items-center justify-center gap-1 cursor-pointer transition-colors mt-1 pt-2 border-t border-[var(--color-border-subtle)]"
>
<Maximize2 size={12} /> Expand
</button>
</div>
</BentoCard>
{/* Dice Roller — 1×1 */}
<BentoCard title="Dice Roller" icon={<Dice5 size={16} />} span="col-span-1 row-span-1">
<div className="flex flex-col h-full">
<div className="flex-1 overflow-hidden">
<DiceRoller />
</div>
<button
onClick={() => onNavigate("dice")}
className="text-[var(--color-gold-bright)] hover:text-[var(--color-gold-muted)] text-xs flex items-center justify-center gap-1 cursor-pointer transition-colors mt-1 pt-2 border-t border-[var(--color-border-subtle)]"
>
<Maximize2 size={12} /> Expand
</button>
</div>
</BentoCard>
{/* Encounter Builder — 1×1 */}
<BentoCard title="Encounter" icon={<Swords size={16} />} span="col-span-1 row-span-1">
<div className="flex flex-col h-full">
<div className="flex-1 overflow-hidden">
<EncounterBuilder />
</div>
<button
onClick={() => onNavigate("encounter")}
className="text-[var(--color-gold-bright)] hover:text-[var(--color-gold-muted)] text-xs flex items-center justify-center gap-1 cursor-pointer transition-colors mt-1 pt-2 border-t border-[var(--color-border-subtle)]"
>
<Maximize2 size={12} /> Expand
</button>
</div>
</BentoCard>
{/* Session Log — 2×1 */}
<BentoCard title="Session Log" icon={<ScrollText size={16} />} span="col-span-2 row-span-1">
<div className="flex flex-col h-full">
<div className="flex-1 overflow-hidden">
<SessionLogger />
</div>
<button
onClick={() => onNavigate("session")}
className="text-[var(--color-gold-bright)] hover:text-[var(--color-gold-muted)] text-xs flex items-center justify-center gap-1 cursor-pointer transition-colors mt-1 pt-2 border-t border-[var(--color-border-subtle)]"
>
<Maximize2 size={12} /> Expand
</button>
</div>
</BentoCard>
{/* Quest Designer — 2×1 */}
<BentoCard title="Quest Designer" icon={<Sparkles size={16} />} span="col-span-2 row-span-1">
<div className="flex flex-col items-center justify-center h-full text-[var(--color-text-dim)] text-sm gap-2">
<Sparkles size={32} className="opacity-30" />
<p>Quest flowchart coming soon</p>
<button
onClick={() => onNavigate("quest")}
className="text-[var(--color-gold-bright)] hover:text-[var(--color-gold-muted)] text-xs flex items-center gap-1 cursor-pointer transition-colors"
>
<Maximize2 size={12} /> Open
</button>
</div>
</BentoCard>
{/* Initiative Tracker — 1×1 */}
<BentoCard title="Initiative" icon={<Timer size={16} />} span="col-span-1 row-span-1">
<div className="flex flex-col h-full">
<div className="flex-1 overflow-hidden">
<InitiativeTracker />
</div>
<button
onClick={() => onNavigate("initiative")}
className="text-[var(--color-gold-bright)] hover:text-[var(--color-gold-muted)] text-xs flex items-center justify-center gap-1 cursor-pointer transition-colors mt-1 pt-2 border-t border-[var(--color-border-subtle)]"
>
<Maximize2 size={12} /> Expand
</button>
</div>
</BentoCard>
{/* Random Tables — 1×1 */}
<BentoCard title="Random Tables" icon={<Sparkles size={16} />} span="col-span-1 row-span-1">
<div className="flex flex-col h-full">
<div className="flex-1 overflow-hidden">
<RandomTables />
</div>
<button
onClick={() => onNavigate("tables")}
className="text-[var(--color-gold-bright)] hover:text-[var(--color-gold-muted)] text-xs flex items-center justify-center gap-1 cursor-pointer transition-colors mt-1 pt-2 border-t border-[var(--color-border-subtle)]"
>
<Maximize2 size={12} /> Expand
</button>
</div>
</BentoCard>
{/* Calendar — 1×1 */}
<BentoCard title="Calendar" icon={<Calendar size={16} />} span="col-span-1 row-span-1">
<div className="flex flex-col h-full">
<div className="flex-1 overflow-hidden">
<CalendarWidget />
</div>
<button
onClick={() => onNavigate("calendar")}
className="text-[var(--color-gold-bright)] hover:text-[var(--color-gold-muted)] text-xs flex items-center justify-center gap-1 cursor-pointer transition-colors mt-1 pt-2 border-t border-[var(--color-border-subtle)]"
>
<Maximize2 size={12} /> Expand
</button>
</div>
</BentoCard>
{/* Soundboard — 1×1 */}
<BentoCard title="Soundboard" icon={<Volume2 size={16} />} span="col-span-1 row-span-1">
<div className="flex flex-col items-center justify-center h-full text-[var(--color-text-dim)] text-sm gap-2">
<Volume2 size={32} className="opacity-30" />
<p>Soundboard coming soon</p>
</div>
</BentoCard>
</div>
);
}
// Inline imports for dashboard cards (compact versions)
import { NpcGenerator } from "./NpcGenerator";
import { DiceRoller } from "./DiceRoller";
import { SessionLogger } from "./SessionLogger";
import { EncounterBuilder } from "./EncounterBuilder";
import { InitiativeTracker } from "./InitiativeTracker";
import { RandomTables } from "./RandomTables";
import { CalendarWidget } from "./CalendarWidget";
export function Dashboard() {
return (
<div className="grid grid-cols-4 grid-rows-4 gap-3 p-4 h-full bg-[var(--color-bg-deep)]">
{/* World Map — 2×2 */}
<BentoCard title="World Map" icon={<Map size={16} />} span="col-span-2 row-span-2">
<div className="flex items-center justify-center h-full text-[var(--color-text-dim)] text-sm">
<div className="text-center">
<Map size={48} className="mx-auto mb-2 opacity-30" />
<p>Map canvas coming soon</p>
<p className="text-xs mt-1">react-konva integration pending</p>
</div>
</div>
</BentoCard>
{/* NPC Sheet — 1×1 */}
<BentoCard title="NPC Sheet" icon={<User size={16} />} span="col-span-1 row-span-1">
<NpcGenerator />
</BentoCard>
{/* Dice Roller — 1×1 */}
<BentoCard title="Dice Roller" icon={<Dice5 size={16} />} span="col-span-1 row-span-1">
<DiceRoller />
</BentoCard>
{/* Encounter Builder — 1×1 */}
<BentoCard title="Encounter" icon={<Swords size={16} />} span="col-span-1 row-span-1">
<EncounterBuilder />
</BentoCard>
{/* Session Log — 2×1 */}
<BentoCard title="Session Log" icon={<ScrollText size={16} />} span="col-span-2 row-span-1">
<SessionLogger />
</BentoCard>
{/* Quest Designer — 2×1 */}
<BentoCard title="Quest Designer" icon={<Sparkles size={16} />} span="col-span-2 row-span-1">
<div className="flex items-center justify-center h-full text-[var(--color-text-dim)] text-sm">
Quest flowchart coming soon react-flow integration pending
</div>
</BentoCard>
{/* Initiative Tracker — 1×1 */}
<BentoCard title="Initiative" icon={<Timer size={16} />} span="col-span-1 row-span-1">
<InitiativeTracker />
</BentoCard>
{/* Random Tables — 1×1 */}
<BentoCard title="Random Tables" icon={<Sparkles size={16} />} span="col-span-1 row-span-1">
<RandomTables />
</BentoCard>
{/* Calendar — 1×1 */}
<BentoCard title="Calendar" icon={<Calendar size={16} />} span="col-span-1 row-span-1">
<CalendarWidget />
</BentoCard>
{/* Soundboard — 1×1 */}
<BentoCard title="Soundboard" icon={<Volume2 size={16} />} span="col-span-1 row-span-1">
<div className="flex items-center justify-center h-full text-[var(--color-text-dim)] text-sm">
Soundboard coming soon
</div>
</BentoCard>
</div>
);
}
import { CalendarWidget } from "./CalendarWidget";