refactor(control-center): Quick Controls 재디자인 및 플랜/잠금 결제 동선 정리
This commit is contained in:
@@ -7,6 +7,11 @@ import { cn } from '@/shared/lib/cn';
|
||||
interface ToastPayload {
|
||||
title: string;
|
||||
description?: string;
|
||||
durationMs?: number;
|
||||
action?: {
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
interface ToastItem extends ToastPayload {
|
||||
@@ -22,15 +27,20 @@ const ToastContext = createContext<ToastContextValue | null>(null);
|
||||
export const ToastProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [toasts, setToasts] = useState<ToastItem[]>([]);
|
||||
|
||||
const removeToast = useCallback((id: number) => {
|
||||
setToasts((current) => current.filter((toast) => toast.id !== id));
|
||||
}, []);
|
||||
|
||||
const pushToast = useCallback((payload: ToastPayload) => {
|
||||
const id = Date.now() + Math.floor(Math.random() * 10000);
|
||||
const durationMs = payload.durationMs ?? 2400;
|
||||
|
||||
setToasts((current) => [...current, { id, ...payload }]);
|
||||
|
||||
window.setTimeout(() => {
|
||||
setToasts((current) => current.filter((toast) => toast.id !== id));
|
||||
}, 2400);
|
||||
}, []);
|
||||
removeToast(id);
|
||||
}, durationMs);
|
||||
}, [removeToast]);
|
||||
|
||||
const value = useMemo(() => ({ pushToast }), [pushToast]);
|
||||
|
||||
@@ -42,7 +52,7 @@ export const ToastProvider = ({ children }: { children: ReactNode }) => {
|
||||
<div
|
||||
key={toast.id}
|
||||
className={cn(
|
||||
'rounded-xl border border-white/15 bg-slate-950/92 px-4 py-3 text-sm text-white shadow-lg shadow-slate-950/60',
|
||||
'pointer-events-auto rounded-xl border border-white/15 bg-slate-950/92 px-4 py-3 text-sm text-white shadow-lg shadow-slate-950/60',
|
||||
'animate-[toast-in_180ms_ease-out] motion-reduce:animate-none',
|
||||
)}
|
||||
>
|
||||
@@ -50,6 +60,20 @@ export const ToastProvider = ({ children }: { children: ReactNode }) => {
|
||||
{toast.description ? (
|
||||
<p className="mt-1 text-xs text-white/70">{toast.description}</p>
|
||||
) : null}
|
||||
{toast.action ? (
|
||||
<div className="mt-2 flex justify-end">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
toast.action?.onClick();
|
||||
removeToast(toast.id);
|
||||
}}
|
||||
className="rounded-full border border-white/25 bg-white/[0.08] px-2.5 py-1 text-[11px] font-medium text-white/88 transition-colors hover:bg-white/[0.16]"
|
||||
>
|
||||
{toast.action.label}
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user