Wire ShareButton into list/note/calendar pages; fix nav and calendar select labels
- Add ShareButton to list detail, note editor, and calendar event panel - Add Settings gear icon to AppNav (core page not in module registry) - Fix calendar event dialog showing raw UUID: pass explicit children to SelectValue so labels display before SelectContent mounts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
39aa5704f9
commit
734268cb75
@@ -1,4 +1,5 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { Settings } from "lucide-react";
|
||||||
import { getRegistry } from "@/modules/_core/registry";
|
import { getRegistry } from "@/modules/_core/registry";
|
||||||
|
|
||||||
export function AppNav() {
|
export function AppNav() {
|
||||||
@@ -19,6 +20,13 @@ export function AppNav() {
|
|||||||
{item.label}
|
{item.label}
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
|
<Link
|
||||||
|
href="/settings"
|
||||||
|
className="ml-auto text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
aria-label="Settings"
|
||||||
|
>
|
||||||
|
<Settings className="size-4" />
|
||||||
|
</Link>
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { useMemo, useState, useTransition } from "react";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { ShareButton } from "@/components/share-button";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
@@ -307,7 +308,9 @@ export function CalendarShell({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SelectTrigger aria-label={`${calendar.name} visibility`}>
|
<SelectTrigger aria-label={`${calendar.name} visibility`}>
|
||||||
<SelectValue />
|
<SelectValue>
|
||||||
|
{calendar.visibility === "household" ? "Household" : "Private"}
|
||||||
|
</SelectValue>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="household">Household</SelectItem>
|
<SelectItem value="household">Household</SelectItem>
|
||||||
@@ -353,7 +356,9 @@ export function CalendarShell({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SelectTrigger aria-label="Calendar visibility">
|
<SelectTrigger aria-label="Calendar visibility">
|
||||||
<SelectValue />
|
<SelectValue>
|
||||||
|
{calendarVisibility === "household" ? "Household" : "Private"}
|
||||||
|
</SelectValue>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="household">Household</SelectItem>
|
<SelectItem value="household">Household</SelectItem>
|
||||||
@@ -431,7 +436,9 @@ export function CalendarShell({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SelectTrigger id="event-calendar">
|
<SelectTrigger id="event-calendar">
|
||||||
<SelectValue />
|
<SelectValue>
|
||||||
|
{calendarRows.find((c) => c.id === selectedEvent.calendarId)?.name ?? "Select a calendar"}
|
||||||
|
</SelectValue>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{calendarRows.map((calendar) => (
|
{calendarRows.map((calendar) => (
|
||||||
@@ -483,16 +490,21 @@ export function CalendarShell({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center justify-between gap-2 pt-2">
|
<div className="flex items-center justify-between gap-2 pt-2">
|
||||||
<div>
|
<div className="flex gap-2">
|
||||||
{selectedEvent.id && (
|
{selectedEvent.id && (
|
||||||
<Button variant="destructive" onClick={removeSelectedEvent}>
|
<Button variant="destructive" onClick={removeSelectedEvent}>
|
||||||
Delete event
|
Delete event
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Button onClick={saveSelectedEvent} disabled={!selectedEvent.title || isPending}>
|
<div className="flex gap-2">
|
||||||
Save event
|
{selectedEvent.id && (
|
||||||
</Button>
|
<ShareButton entityType="calendar.event" entityId={selectedEvent.id} />
|
||||||
|
)}
|
||||||
|
<Button onClick={saveSelectedEvent} disabled={!selectedEvent.title || isPending}>
|
||||||
|
Save event
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Archive, GripVertical, Plus, Trash2 } from "lucide-react";
|
|||||||
import { useEffect, useRef, useState, useTransition } from "react";
|
import { useEffect, useRef, useState, useTransition } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { ShareButton } from "@/components/share-button";
|
||||||
import type { ListDetailDto, ListItemDto } from "../server/queries";
|
import type { ListDetailDto, ListItemDto } from "../server/queries";
|
||||||
import { getList } from "../server/queries";
|
import { getList } from "../server/queries";
|
||||||
import {
|
import {
|
||||||
@@ -109,6 +110,7 @@ export function ListDetail({ initialList }: { initialList: ListDetailDto }) {
|
|||||||
{list.type} / {list.openCount} open / {list.doneCount} done
|
{list.type} / {list.openCount} open / {list.doneCount} done
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ShareButton entityType="lists.list" entityId={list.id} canWrite={true} />
|
||||||
<Button variant="outline" onClick={archiveCurrentList} disabled={isPending}>
|
<Button variant="outline" onClick={archiveCurrentList} disabled={isPending}>
|
||||||
<Archive />
|
<Archive />
|
||||||
Archive list
|
Archive list
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useState, useTransition } from "react";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { ShareButton } from "@/components/share-button";
|
||||||
import type { NoteDto } from "../server/queries";
|
import type { NoteDto } from "../server/queries";
|
||||||
import { createNote, deleteNote, setNotePinned, updateNote } from "../server/actions";
|
import { createNote, deleteNote, setNotePinned, updateNote } from "../server/actions";
|
||||||
import { MarkdownPreview } from "./markdown-preview";
|
import { MarkdownPreview } from "./markdown-preview";
|
||||||
@@ -76,6 +77,9 @@ export function NoteEditor({ note }: { note?: NoteDto }) {
|
|||||||
{pinned ? "Unpin note" : "Pin note"}
|
{pinned ? "Unpin note" : "Pin note"}
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
|
{currentNote ? (
|
||||||
|
<ShareButton entityType="notes.note" entityId={currentNote.id} />
|
||||||
|
) : null}
|
||||||
{currentNote ? (
|
{currentNote ? (
|
||||||
<Button variant="destructive" onClick={removeNote} disabled={isPending}>
|
<Button variant="destructive" onClick={removeNote} disabled={isPending}>
|
||||||
<Trash2 />
|
<Trash2 />
|
||||||
|
|||||||
Reference in New Issue
Block a user