Add a global toast/notification component #33

Closed
opened 2026-07-14 17:52:44 +02:00 by Sirttas · 0 comments
Owner

Goal

Provide a reusable, app-wide toast/notification mechanism so any part of the app can surface transient success / error / info messages to the user.

Motivation

There is currently no way to show non-blocking feedback to the user — the only global overlay is the blocking ConfirmModal. This is a prerequisite for #13 (notify the user when a processing run completes), and will be reusable for other flows (buy/sell actions, refresh errors, etc.).

Design

Mirror the existing src/confirm/ pattern (Pinia store + a single globally-mounted component + a module-level convenience helper). New slice under src/toast/:

  • useToast.ts — Pinia store 'toast' holding a reactive toasts list. Each toast: { id, message, title?, type } where type ∈ 'success' | 'error' | 'info'.

    • push(opts: ToastOptions | string): number — appends a toast, returns its id, and auto-dismisses after duration (default ~5s; duration: 0 = sticky).
    • dismiss(id: number) — removes a toast.
    • Module-level convenience toast helper (like confirm): callable toast('msg') plus toast.success(msg), toast.error(msg), toast.info(msg).
    • ToastOptions: { message, title?, type?, duration? }.
  • ToastContainer.vue — renders the stack, mounted once. Fixed corner (top-right), TransitionGroup for enter/leave, per-type icon (@heroicons/vue/24/outline: CheckCircleIcon / XCircleIcon / InformationCircleIcon) and accent colour (success → emerald, error → rose/amber, info → sky, per style.css palette). Each toast has a manual close (XMarkIcon) button.

  • index.ts — export ToastContainer, toast, useToastStore, and the ToastOptions / ToastType types.

  • Mount <ToastContainer /> once in App.vue (alongside <ConfirmModal />).

Out of scope

  • Wiring toasts into the processing SSE stream (#13).
  • Action buttons / undo inside toasts.

Acceptance criteria

  • toast.success('...'), toast.error('...'), toast.info('...'), and toast('...') display a toast from anywhere in the app.
  • Toasts auto-dismiss after the default duration; duration: 0 keeps them until manually closed.
  • Multiple toasts stack and can be individually dismissed via a close button.
  • Success / error / info are visually distinct (icon + colour) and consistent with the style.css palette.
  • Component is mounted once globally in App.vue; styling matches the app (dark slate theme).

Affected files

  • src/toast/useToast.ts (new)
  • src/toast/ToastContainer.vue (new)
  • src/toast/index.ts (new)
  • src/App.vue

Reference

  • Existing pattern to mirror: src/confirm/ (useConfirm.ts, ConfirmModal.vue, index.ts).

Blocks #13.

## Goal Provide a reusable, app-wide toast/notification mechanism so any part of the app can surface transient success / error / info messages to the user. ## Motivation There is currently no way to show non-blocking feedback to the user — the only global overlay is the blocking `ConfirmModal`. This is a prerequisite for #13 (notify the user when a processing run completes), and will be reusable for other flows (buy/sell actions, refresh errors, etc.). ## Design Mirror the existing `src/confirm/` pattern (Pinia store + a single globally-mounted component + a module-level convenience helper). New slice under `src/toast/`: - **`useToast.ts`** — Pinia store `'toast'` holding a reactive `toasts` list. Each toast: `{ id, message, title?, type }` where `type ∈ 'success' | 'error' | 'info'`. - `push(opts: ToastOptions | string): number` — appends a toast, returns its id, and auto-dismisses after `duration` (default ~5s; `duration: 0` = sticky). - `dismiss(id: number)` — removes a toast. - Module-level convenience `toast` helper (like `confirm`): callable `toast('msg')` plus `toast.success(msg)`, `toast.error(msg)`, `toast.info(msg)`. - `ToastOptions`: `{ message, title?, type?, duration? }`. - **`ToastContainer.vue`** — renders the stack, mounted once. Fixed corner (top-right), `TransitionGroup` for enter/leave, per-type icon (`@heroicons/vue/24/outline`: `CheckCircleIcon` / `XCircleIcon` / `InformationCircleIcon`) and accent colour (success → emerald, error → rose/amber, info → sky, per `style.css` palette). Each toast has a manual close (`XMarkIcon`) button. - **`index.ts`** — export `ToastContainer`, `toast`, `useToastStore`, and the `ToastOptions` / `ToastType` types. - **Mount** `<ToastContainer />` once in `App.vue` (alongside `<ConfirmModal />`). ## Out of scope - Wiring toasts into the processing SSE stream (#13). - Action buttons / undo inside toasts. ## Acceptance criteria - [x] `toast.success('...')`, `toast.error('...')`, `toast.info('...')`, and `toast('...')` display a toast from anywhere in the app. - [x] Toasts auto-dismiss after the default duration; `duration: 0` keeps them until manually closed. - [x] Multiple toasts stack and can be individually dismissed via a close button. - [x] Success / error / info are visually distinct (icon + colour) and consistent with the `style.css` palette. - [x] Component is mounted once globally in `App.vue`; styling matches the app (dark slate theme). ## Affected files - `src/toast/useToast.ts` (new) - `src/toast/ToastContainer.vue` (new) - `src/toast/index.ts` (new) - `src/App.vue` ## Reference - Existing pattern to mirror: `src/confirm/` (`useConfirm.ts`, `ConfirmModal.vue`, `index.ts`). Blocks #13.
Sirttas added the
Priority
Medium
3
Kind/Feature
labels 2026-07-14 17:52:44 +02:00
Sirttas added a new dependency 2026-07-14 17:54:05 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: eveal/gemory#33