Files
tehran_taj/apps/user-app-v2/src/composables/useToast.ts
T
s.esmaeiliandClaude Sonnet 5 c05352d6fd refactor(ui): replace modal dialogs with toast/sheet components
Remove DialogVant/NotifyVant and add Toast and Sheet components with
useToast, useReveal, and usePageTransition composables. Rework
Navigation, RegisterView, and styles across both apps; rebuild dist assets.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-04 13:57:25 +03:30

73 lines
2.0 KiB
TypeScript

import { reactive } from 'vue'
/**
* App-wide toasts. One shared queue, rendered by <ToastHost> (mounted once in
* App.vue), so any view or store can call `toast.success(...)` without placing
* a component in its own template.
*/
export type ToastType = 'success' | 'error' | 'info' | 'warning'
export interface ToastOptions {
title?: string
/** ms before it closes by itself; 0 keeps it until the user dismisses it. */
duration?: number
/** Custom icon name; defaults to one per type. */
icon?: string
}
export interface ToastItem {
id: number
type: ToastType
message: string
title?: string
icon: string
duration: number
}
const DEFAULT_DURATION = 3200
// Older toasts beyond this are dropped so the stack never covers the screen.
const MAX_VISIBLE = 3
const ICONS: Record<ToastType, string> = {
success: 'vuesax-linear:tick-circle',
error: 'vuesax-linear:close-circle',
info: 'vuesax-linear:info-circle',
warning: 'vuesax-linear:warning-2',
}
const state = reactive<{ items: ToastItem[] }>({ items: [] })
let nextId = 1
function show(type: ToastType, message: string, options: ToastOptions = {}): number {
const id = nextId++
state.items.push({
id,
type,
message,
title: options.title,
icon: options.icon ?? ICONS[type],
duration: options.duration ?? DEFAULT_DURATION,
})
if (state.items.length > MAX_VISIBLE) state.items.splice(0, state.items.length - MAX_VISIBLE)
return id
}
function dismiss(id: number) {
const i = state.items.findIndex((t) => t.id === id)
if (i !== -1) state.items.splice(i, 1)
}
export const toast = {
show,
dismiss,
success: (message: string, options?: ToastOptions) => show('success', message, options),
error: (message: string, options?: ToastOptions) => show('error', message, options),
info: (message: string, options?: ToastOptions) => show('info', message, options),
warning: (message: string, options?: ToastOptions) => show('warning', message, options),
}
export function useToast() {
return { toasts: state.items, ...toast }
}