Polish toast actions and extend delete confirm timeout

- Toast: snooze/dismiss buttons side-by-side on the right, dismiss
  uses X icon, snooze shows clock icon + 'Snooze' label
- SnoozeDropdown trigger now shows text label alongside icon
- Delete confirm 'Sure?' lingers 4 seconds instead of 2

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kyle 2026-02-24 03:24:40 +08:00
parent c609e374e7
commit 38bce21ac3
4 changed files with 20 additions and 19 deletions

View File

@ -70,7 +70,7 @@ export default function ReminderItem({ reminder, onEdit }: ReminderItemProps) {
const handleDelete = () => { const handleDelete = () => {
if (!confirmingDelete) { if (!confirmingDelete) {
setConfirmingDelete(true); setConfirmingDelete(true);
setTimeout(() => setConfirmingDelete(false), 2000); setTimeout(() => setConfirmingDelete(false), 4000);
return; return;
} }
deleteMutation.mutate(); deleteMutation.mutate();

View File

@ -32,9 +32,10 @@ export default function SnoozeDropdown({ onSnooze, label }: SnoozeDropdownProps)
<button <button
onClick={() => setOpen(!open)} onClick={() => setOpen(!open)}
aria-label={`Snooze "${label}"`} aria-label={`Snooze "${label}"`}
className="p-1 rounded hover:bg-accent/10 hover:text-accent text-muted-foreground transition-colors" className="flex items-center gap-1 px-1.5 py-1 rounded hover:bg-accent/10 hover:text-accent text-muted-foreground transition-colors"
> >
<Clock className="h-3.5 w-3.5" /> <Clock className="h-3.5 w-3.5" />
<span className="text-[11px] font-medium">Snooze</span>
</button> </button>
{open && ( {open && (
<div className="absolute right-0 bottom-full mb-1 w-32 rounded-md border bg-popover shadow-lg z-50 py-1 animate-fade-in"> <div className="absolute right-0 bottom-full mb-1 w-32 rounded-md border bg-popover shadow-lg z-50 py-1 animate-fade-in">

View File

@ -77,7 +77,7 @@ export default function TodoItem({ todo, onEdit }: TodoItemProps) {
if (!confirmingDelete) { if (!confirmingDelete) {
setConfirmingDelete(true); setConfirmingDelete(true);
// Auto-reset after 2 seconds if not confirmed // Auto-reset after 2 seconds if not confirmed
setTimeout(() => setConfirmingDelete(false), 2000); setTimeout(() => setConfirmingDelete(false), 4000);
return; return;
} }
deleteMutation.mutate(); deleteMutation.mutate();

View File

@ -2,7 +2,7 @@ import { createContext, useContext, useRef, useEffect, useCallback, type ReactNo
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { Bell } from 'lucide-react'; import { Bell, X } from 'lucide-react';
import api from '@/lib/api'; import api from '@/lib/api';
import { getRelativeTime, toLocalDatetime } from '@/lib/date-utils'; import { getRelativeTime, toLocalDatetime } from '@/lib/date-utils';
import SnoozeDropdown from '@/components/reminders/SnoozeDropdown'; import SnoozeDropdown from '@/components/reminders/SnoozeDropdown';
@ -98,14 +98,15 @@ export function AlertsProvider({ children }: { children: ReactNode }) {
function renderToast(_t: string | number, reminder: Reminder) { function renderToast(_t: string | number, reminder: Reminder) {
const timeAgo = reminder.remind_at ? getRelativeTime(reminder.remind_at) : ''; const timeAgo = reminder.remind_at ? getRelativeTime(reminder.remind_at) : '';
return ( return (
<div className="flex items-start gap-3 bg-card border border-border rounded-lg p-3 shadow-lg w-[356px]"> <div className="flex items-center gap-3 bg-card border border-border rounded-lg p-3 shadow-lg w-[356px]">
<div className="p-1.5 rounded-md bg-orange-500/10 shrink-0 mt-0.5"> <div className="p-1.5 rounded-md bg-orange-500/10 shrink-0">
<Bell className="h-4 w-4 text-orange-400" /> <Bell className="h-4 w-4 text-orange-400" />
</div> </div>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="text-sm font-medium text-foreground truncate">{reminder.title}</p> <p className="text-sm font-medium text-foreground truncate">{reminder.title}</p>
<p className="text-xs text-muted-foreground mt-0.5">{timeAgo}</p> <p className="text-xs text-muted-foreground mt-0.5">{timeAgo}</p>
<div className="flex items-center gap-1 mt-2"> </div>
<div className="flex items-center gap-1 shrink-0">
<SnoozeDropdown <SnoozeDropdown
onSnooze={(m) => snoozeRef.current(reminder.id, m)} onSnooze={(m) => snoozeRef.current(reminder.id, m)}
label={reminder.title} label={reminder.title}
@ -113,13 +114,12 @@ export function AlertsProvider({ children }: { children: ReactNode }) {
<button <button
onClick={() => dismissRef.current(reminder.id)} onClick={() => dismissRef.current(reminder.id)}
aria-label={`Dismiss "${reminder.title}"`} aria-label={`Dismiss "${reminder.title}"`}
className="ml-auto px-2 py-0.5 rounded text-[11px] bg-secondary hover:bg-card-elevated text-muted-foreground hover:text-foreground transition-colors" className="p-1 rounded hover:bg-accent/10 hover:text-accent text-muted-foreground transition-colors"
> >
Dismiss <X className="h-3.5 w-3.5" />
</button> </button>
</div> </div>
</div> </div>
</div>
); );
} }