Merge pull request 'Trees list: inline visibility selector (private/unlisted/public)' (#41) from tree-visibility-control into main
build-frontend / build (push) Successful in 1m30s
build-frontend / build (push) Successful in 1m30s
This commit was merged in pull request #41.
This commit is contained in:
@@ -53,6 +53,15 @@ export default function TreesPage() {
|
|||||||
await api.POST("/api/v1/trees/{tree_id}/restore", { params: { path: { tree_id: id } } });
|
await api.POST("/api/v1/trees/{tree_id}/restore", { params: { path: { tree_id: id } } });
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
|
// Optimistic visibility change so the dropdown reflects the pick immediately.
|
||||||
|
async function setVisibility(id: string, visibility: NonNullable<Tree["visibility"]>) {
|
||||||
|
setTrees((cur) => cur.map((t) => (t.id === id ? { ...t, visibility } : t)));
|
||||||
|
await api.PATCH("/api/v1/trees/{tree_id}", {
|
||||||
|
params: { path: { tree_id: id } },
|
||||||
|
body: { visibility },
|
||||||
|
});
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
if (!ready) return <p className="text-[var(--muted)]">Loading…</p>;
|
if (!ready) return <p className="text-[var(--muted)]">Loading…</p>;
|
||||||
|
|
||||||
@@ -76,16 +85,26 @@ export default function TreesPage() {
|
|||||||
{trees.map((tree) => (
|
{trees.map((tree) => (
|
||||||
<li key={tree.id}>
|
<li key={tree.id}>
|
||||||
<Card className="transition-colors hover:border-bronze/50">
|
<Card className="transition-colors hover:border-bronze/50">
|
||||||
<CardContent className="flex items-center justify-between p-4">
|
<CardContent className="flex items-center justify-between gap-3 p-4">
|
||||||
<Link href={`/trees/${tree.id}/tree`} className="min-w-0 flex-1">
|
<Link href={`/trees/${tree.id}/tree`} className="min-w-0 flex-1">
|
||||||
<div className="truncate font-medium">{tree.name}</div>
|
<div className="truncate font-medium">{tree.name}</div>
|
||||||
<div className="text-xs uppercase tracking-wide text-bronze">
|
|
||||||
{tree.visibility}
|
|
||||||
</div>
|
|
||||||
</Link>
|
</Link>
|
||||||
|
<select
|
||||||
|
value={tree.visibility ?? "private"}
|
||||||
|
onChange={(e) =>
|
||||||
|
setVisibility(tree.id, e.target.value as NonNullable<Tree["visibility"]>)
|
||||||
|
}
|
||||||
|
aria-label="Tree visibility"
|
||||||
|
title="Who can see this tree. Living people stay protected even when public."
|
||||||
|
className="rounded-md border border-[var(--border)] bg-[var(--surface)] px-2 py-1 text-xs uppercase tracking-wide text-bronze focus-visible:border-bronze focus-visible:outline-none"
|
||||||
|
>
|
||||||
|
<option value="private">Private</option>
|
||||||
|
<option value="unlisted">Unlisted</option>
|
||||||
|
<option value="public">Public</option>
|
||||||
|
</select>
|
||||||
<button
|
<button
|
||||||
onClick={() => remove(tree.id)}
|
onClick={() => remove(tree.id)}
|
||||||
className="ml-3 text-[var(--muted)] hover:text-bronze"
|
className="text-[var(--muted)] hover:text-bronze"
|
||||||
aria-label="Delete tree"
|
aria-label="Delete tree"
|
||||||
>
|
>
|
||||||
×
|
×
|
||||||
|
|||||||
Reference in New Issue
Block a user