feat(ui): equal-width Yes/Close buttons in confirm dialogs; trim dashboard activity to 3
DialogFooter with showCloseButton now lays out the auto-rendered Close
and the caller's primary action (typically a <form>-wrapped Submit) in
a 2-column grid that's identical at every viewport. Both buttons are
sized "sm" with w-full so they fill their column and match in height.
The trick to making this transparent for callers: \`[&>form]:contents\`
collapses the form box so its <Button> child becomes a real grid item
sibling of the Close button, not a single grid cell containing the
button. \`[&>form>button]:w-full\` then sizes the submit button to
match the Close button's column width.
Five existing call sites pick this up automatically — no changes
needed at the call site:
- reminder pause/restart/delete (actions-bar)
- account unpair / delete
- dashboard "Clear history"
- activity tab "Clear history"
Also: dashboard "Recent activity" now shows the 3 most recent runs
instead of 10. The "Recent runs" stat card description updates to
match ("3 most recent runs"), points to /activity, and a "View all"
ghost link sits beside the section heading so you can jump to the
full history without hunting.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
48cae84919
commit
7b991a565d
@ -177,8 +177,8 @@ export default async function DashboardPage() {
|
|||||||
title="Recent runs"
|
title="Recent runs"
|
||||||
value={stats.recentRuns.length}
|
value={stats.recentRuns.length}
|
||||||
icon={ActivityIcon}
|
icon={ActivityIcon}
|
||||||
description="Last 10 reminder runs"
|
description="3 most recent runs"
|
||||||
href="/reminders"
|
href="/activity"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -186,7 +186,14 @@ export default async function DashboardPage() {
|
|||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<h2 className="text-lg font-medium tracking-tight">Recent activity</h2>
|
<h2 className="text-lg font-medium tracking-tight">Recent activity</h2>
|
||||||
{hasRuns && (
|
<div className="flex items-center gap-1">
|
||||||
|
{hasRuns && (
|
||||||
|
<Button asChild variant="ghost" size="sm" className="text-muted-foreground">
|
||||||
|
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
|
||||||
|
<Link href={"/activity" as any}>View all</Link>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{hasRuns && (
|
||||||
<Dialog>
|
<Dialog>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button variant="ghost" size="sm" className="text-muted-foreground hover:text-destructive">
|
<Button variant="ghost" size="sm" className="text-muted-foreground hover:text-destructive">
|
||||||
@ -213,7 +220,8 @@ export default async function DashboardPage() {
|
|||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{hasRuns ? (
|
{hasRuns ? (
|
||||||
|
|||||||
@ -107,7 +107,16 @@ function DialogFooter({
|
|||||||
<div
|
<div
|
||||||
data-slot="dialog-footer"
|
data-slot="dialog-footer"
|
||||||
className={cn(
|
className={cn(
|
||||||
"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end",
|
"-mx-4 -mb-4 rounded-b-xl border-t bg-muted/50 p-4",
|
||||||
|
showCloseButton
|
||||||
|
// 2-col grid so the auto-rendered Close and the caller's primary
|
||||||
|
// button (typically wrapped in a <form>) get equal width on the
|
||||||
|
// same row at every viewport. `[&>form]:contents` makes the form
|
||||||
|
// a transparent grid parent so its <Button> child becomes a real
|
||||||
|
// grid item; `[&>form>button]:w-full` matches the Close button
|
||||||
|
// width so both fill their column.
|
||||||
|
? "grid grid-cols-2 gap-2 [&>form]:contents [&>form>button]:w-full"
|
||||||
|
: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@ -115,7 +124,9 @@ function DialogFooter({
|
|||||||
{children}
|
{children}
|
||||||
{showCloseButton && (
|
{showCloseButton && (
|
||||||
<DialogPrimitive.Close asChild>
|
<DialogPrimitive.Close asChild>
|
||||||
<Button variant="outline">Close</Button>
|
<Button variant="outline" size="sm" className="w-full">
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
</DialogPrimitive.Close>
|
</DialogPrimitive.Close>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -26,7 +26,7 @@ export async function getDashboardStats(operatorId: string) {
|
|||||||
LEFT JOIN whatsapp_accounts wa ON wa.id = r.account_id
|
LEFT JOIN whatsapp_accounts wa ON wa.id = r.account_id
|
||||||
WHERE wa.operator_id = ${operatorId} OR r.id IS NULL
|
WHERE wa.operator_id = ${operatorId} OR r.id IS NULL
|
||||||
ORDER BY rr.fired_at DESC
|
ORDER BY rr.fired_at DESC
|
||||||
LIMIT 10
|
LIMIT 3
|
||||||
`);
|
`);
|
||||||
return {
|
return {
|
||||||
connectedAccounts: accounts.filter((a) => a.status === "connected").length,
|
connectedAccounts: accounts.filter((a) => a.status === "connected").length,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user