feat: add edit mode toggle to dashboard page

- Edit/Done toggle button in header (pencil icon)
- Widget delete buttons only visible in edit mode
- Add widget button only visible in edit mode
- Empty state prompts to enter edit mode instead of adding directly
- Default is view mode — clean, no accidental deletes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Gjermund Høsøien Wiggen
2026-06-09 13:38:28 +02:00
parent 9938c7a7ad
commit 6ca8974eb9

View File

@@ -4,6 +4,7 @@ import { useState, useEffect, use, useCallback } from "react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import Link from "next/link"; import Link from "next/link";
import { import {
PencilIcon,
PlusIcon, PlusIcon,
Trash2Icon, Trash2Icon,
RefreshCwIcon, RefreshCwIcon,
@@ -58,6 +59,7 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [autoRefresh, setAutoRefresh] = useState(false); const [autoRefresh, setAutoRefresh] = useState(false);
const [editMode, setEditMode] = useState(false);
const [teams, setTeams] = useState<Team[]>([]); const [teams, setTeams] = useState<Team[]>([]);
// Add widget dialog // Add widget dialog
@@ -231,6 +233,15 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
</div> </div>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button
variant="outline"
size="sm"
onClick={() => setEditMode((v) => !v)}
className={cn("h-8 border-border/80", editMode ? "bg-primary/20 text-primary border-primary/40" : "bg-card/70")}
>
<PencilIcon className="h-4 w-4" />
{editMode ? "Done" : "Edit"}
</Button>
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
@@ -249,10 +260,12 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
<RefreshCwIcon className="h-4 w-4" /> <RefreshCwIcon className="h-4 w-4" />
Refresh Refresh
</Button> </Button>
<Button size="sm" onClick={() => setAddOpen(true)} className="h-8 bg-primary shadow-sm"> {editMode && (
<PlusIcon className="h-4 w-4" /> <Button size="sm" onClick={() => setAddOpen(true)} className="h-8 bg-primary shadow-sm">
Add widget <PlusIcon className="h-4 w-4" />
</Button> Add widget
</Button>
)}
</div> </div>
</div> </div>
</header> </header>
@@ -262,10 +275,17 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
<div className="flex h-full flex-col items-center justify-center gap-3"> <div className="flex h-full flex-col items-center justify-center gap-3">
<LayoutGridIcon className="h-10 w-10 text-muted-foreground/40" /> <LayoutGridIcon className="h-10 w-10 text-muted-foreground/40" />
<p className="text-sm text-muted-foreground">No widgets yet</p> <p className="text-sm text-muted-foreground">No widgets yet</p>
<Button variant="outline" size="sm" onClick={() => setAddOpen(true)}> {editMode ? (
<PlusIcon className="h-4 w-4" /> <Button variant="outline" size="sm" onClick={() => setAddOpen(true)}>
Add your first widget <PlusIcon className="h-4 w-4" />
</Button> Add your first widget
</Button>
) : (
<Button variant="outline" size="sm" onClick={() => setEditMode(true)}>
<PencilIcon className="h-4 w-4" />
Enter edit mode
</Button>
)}
</div> </div>
) : ( ) : (
<div className="grid auto-rows-[minmax(100px,auto)] grid-cols-6 gap-3 md:grid-cols-12 md:gap-4"> <div className="grid auto-rows-[minmax(100px,auto)] grid-cols-6 gap-3 md:grid-cols-12 md:gap-4">
@@ -276,14 +296,16 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
style={widgetGridStyle(widget.position)} style={widgetGridStyle(widget.position)}
> >
{renderWidget(widget)} {renderWidget(widget)}
<button {editMode && (
type="button" <button
onClick={() => handleDeleteWidget(widget.id)} type="button"
className="absolute right-2 top-2 hidden h-6 w-6 items-center justify-center rounded bg-destructive/90 text-destructive-foreground transition-opacity hover:bg-destructive group-hover:flex" onClick={() => handleDeleteWidget(widget.id)}
title="Remove widget" className="absolute right-2 top-2 hidden h-6 w-6 items-center justify-center rounded bg-destructive/90 text-destructive-foreground transition-opacity hover:bg-destructive group-hover:flex"
> title="Remove widget"
<Trash2Icon className="h-3.5 w-3.5" /> >
</button> <Trash2Icon className="h-3.5 w-3.5" />
</button>
)}
</div> </div>
))} ))}
</div> </div>