├── .editorconfig ├── .github ├── FUNDING.yml ├── renovate.json └── workflows │ └── ci.yml ├── .gitignore ├── .husky └── commit-msg ├── .npmrc ├── .vscode └── settings.json ├── CHANGELOG.md ├── README.md ├── assets └── cover.png ├── bun.lock ├── commitlint.config.ts ├── eslint.config.mjs ├── package.json ├── playground ├── app.vue ├── nuxt.config.ts ├── package.json ├── server │ └── tsconfig.json └── tsconfig.json ├── src ├── module.ts └── runtime │ ├── composables │ └── useToast.ts │ ├── plugin.ts │ ├── server │ └── tsconfig.json │ └── types │ └── IziToast.ts ├── test ├── basic.test.ts └── fixtures │ └── basic │ ├── app.vue │ ├── nuxt.config.ts │ └── package.json ├── tsconfig.json └── vitest.config.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_size = 2 5 | indent_style = space 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: stephenjason89 2 | custom: https://paypal.me/stephenjason 3 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "timezone": "Asia/Manila", 3 | "configMigration": true, 4 | "extends": [ 5 | "config:recommended", 6 | "docker:pinDigests", 7 | "helpers:pinGitHubActionDigests", 8 | ":pinDevDependencies" 9 | ], 10 | "prHourlyLimit": 5, 11 | "schedule": ["before 3am on Monday"], 12 | "enabledManagers": ["npm", "bun"], 13 | "rangeStrategy": "bump", 14 | "updatePinnedDependencies": false, 15 | "packageRules": [ 16 | { 17 | "matchUpdateTypes": ["major", "pin"], 18 | "enabled": false 19 | }, 20 | { 21 | "groupName": "Bumped minor version of packages", 22 | "prHeader": "Bumped minor version of packages, check if builds are still passing.", 23 | "matchUpdateTypes": ["minor", "patch"], 24 | "matchDepTypes": ["dependencies", "devDependencies"] 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | lint: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Setup Bun 19 | uses: oven-sh/setup-bun@v1 20 | with: 21 | bun-version: latest 22 | 23 | - name: Install dependencies 24 | run: bun install 25 | 26 | - name: Lint 27 | run: bun run lint 28 | 29 | test: 30 | runs-on: ubuntu-latest 31 | 32 | steps: 33 | - uses: actions/checkout@v4 34 | 35 | - name: Setup Bun 36 | uses: oven-sh/setup-bun@v1 37 | with: 38 | bun-version: latest 39 | 40 | - name: Install dependencies 41 | run: bun install 42 | 43 | - name: Install Playwright Browsers (exact version) 44 | run: node_modules/.bin/playwright install chromium --with-deps 45 | 46 | - name: Playground prepare 47 | run: bun run dev:prepare 48 | 49 | - name: Test 50 | run: bun run test 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules 3 | 4 | # Logs 5 | *.log* 6 | 7 | # Temp directories 8 | .temp 9 | .tmp 10 | .cache 11 | 12 | # Yarn 13 | **/.yarn/cache 14 | **/.yarn/*state* 15 | 16 | # Generated dirs 17 | dist 18 | 19 | # Nuxt 20 | .nuxt 21 | .output 22 | .data 23 | .vercel_build_output 24 | .build-* 25 | .netlify 26 | 27 | # Env 28 | .env 29 | 30 | # Testing 31 | reports 32 | coverage 33 | *.lcov 34 | .nyc_output 35 | 36 | # VSCode 37 | .vscode/* 38 | !.vscode/settings.json 39 | !.vscode/tasks.json 40 | !.vscode/launch.json 41 | !.vscode/extensions.json 42 | !.vscode/*.code-snippets 43 | 44 | # Intellij idea 45 | *.iml 46 | .idea 47 | 48 | # OSX 49 | .DS_Store 50 | .AppleDouble 51 | .LSOverride 52 | .AppleDB 53 | .AppleDesktop 54 | Network Trash Folder 55 | Temporary Items 56 | .apdisk 57 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npm run commitlint "${1}" 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.experimental.useFlatConfig": true 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | ## v1.1.4 5 | 6 | [compare changes](https://github.com/stephenjason89/nuxt-toast/compare/v1.1.3...v1.1.4) 7 | 8 | ### 🩹 Fixes 9 | 10 | - Add iziToast to vite optimizeDeps for proper module resolution ([149384c](https://github.com/stephenjason89/nuxt-toast/commit/149384c)) 11 | 12 | ### ❤️ Contributors 13 | 14 | - Stephen Jason Wang 15 | 16 | ## v1.1.3 17 | 18 | [compare changes](https://github.com/stephenjason89/nuxt-izi-toast/compare/v1.1.2...v1.1.3) 19 | 20 | ### 🩹 Fixes 21 | 22 | - Move iziToast to peerDependencies for better module resolution ([1d65a17](https://github.com/stephenjason89/nuxt-izi-toast/commit/1d65a17)) 23 | 24 | ### ❤️ Contributors 25 | 26 | - Stephen Jason Wang 27 | 28 | ## v1.1.2 29 | 30 | [compare changes](https://github.com/stephenjason89/nuxt-izi-toast/compare/v1.1.1...v1.1.2) 31 | 32 | ### 🩹 Fixes 33 | 34 | - Ensure compatibility with CommonJS module for izitoast ([73bef5b](https://github.com/stephenjason89/nuxt-izi-toast/commit/73bef5b)) 35 | 36 | ### 📖 Documentation 37 | 38 | - Clarify usage of custom composable name in Nuxt config ([03ddeeb](https://github.com/stephenjason89/nuxt-izi-toast/commit/03ddeeb)) 39 | - Enhance README with cover image and additional info ([fd6bf88](https://github.com/stephenjason89/nuxt-izi-toast/commit/fd6bf88)) 40 | 41 | ### 🎨 Styles 42 | 43 | - Ensure #app imports are properly included ([0833fc5](https://github.com/stephenjason89/nuxt-izi-toast/commit/0833fc5)) 44 | 45 | ### 🤖 CI 46 | 47 | - Switch to Bun for improved performance ([a732434](https://github.com/stephenjason89/nuxt-izi-toast/commit/a732434)) 48 | 49 | ### ❤️ Contributors 50 | 51 | - Stephen Jason Wang 52 | 53 | ## v1.1.1 54 | 55 | [compare changes](https://github.com/stephenjason89/nuxt-izi-toast/compare/v1.1.0...v1.1.1) 56 | 57 | ### 💅 Refactors 58 | 59 | - Rename configKey from iziToast to toast ([68e47ee](https://github.com/stephenjason89/nuxt-izi-toast/commit/68e47ee)) 60 | 61 | ### 📖 Documentation 62 | 63 | - Refine README with better installation guide ([5db254d](https://github.com/stephenjason89/nuxt-izi-toast/commit/5db254d)) 64 | 65 | ### 🏡 Chore 66 | 67 | - Clean up code and add tests for page rendering ([eaf4a8c](https://github.com/stephenjason89/nuxt-izi-toast/commit/eaf4a8c)) 68 | 69 | ### ❤️ Contributors 70 | 71 | - Stephen Jason Wang 72 | 73 | ## v1.1.0 74 | 75 | 76 | ### 🚀 Enhancements 77 | 78 | - Add iziToast integration with auto-imported composable ([b8cf45b](https://github.com/stephenjason89/nuxt-izi-toast/commit/b8cf45b)) 79 | 80 | ### ❤️ Contributors 81 | 82 | - Stephen Jason Wang 83 | 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | Project Logo 3 |
4 |

5 | Elegant, responsive and lightweight notification plugin with no dependencies. 6 |

7 | 8 |

9 | Documentation 10 |

11 | 12 | # Nuxt Toast 13 | 14 | [![npm version][npm-version-src]][npm-version-href] 15 | [![npm downloads][npm-downloads-src]][npm-downloads-href] 16 | [![License][license-src]][license-href] 17 | [![Nuxt][nuxt-src]][nuxt-href] 18 | 19 | A Nuxt module for easily integrating [iziToast](https://github.com/marcelodolza/iziToast) notifications into your Nuxt 3 application. 20 | 21 | ## Features 22 | 23 | - 🔔  Easily show toast notifications in your Nuxt 3 app 24 | - 🎨  Customizable styles and icons 25 | - ⚡  Supports auto-imported composable (`useToast()` by default) 26 | - 🔧  Fully configurable via `nuxt.config.ts` 27 | - 🔄  Supports changing the composable name dynamically 28 | 29 | ## Quick Setup 30 | 31 | Install the module to your Nuxt application with one command: 32 | 33 | ```bash 34 | npx nuxi module add nuxt-toast 35 | ``` 36 | 37 | ### **Manual Installation** 38 | 39 | If you prefer to install manually, run: 40 | 41 | ```bash 42 | # Using npm 43 | npm install nuxt-toast 44 | 45 | # Using yarn 46 | yarn add nuxt-toast 47 | 48 | # Using pnpm 49 | pnpm add nuxt-toast 50 | 51 | # Using bun 52 | bun add nuxt-toast 53 | ``` 54 | 55 | Then, add it to your Nuxt config: 56 | 57 | ```ts 58 | export default defineNuxtConfig({ 59 | modules: [ 60 | 'nuxt-toast' 61 | ] 62 | }) 63 | ``` 64 | ## 🚀 Usage 65 | 66 | Once installed, you can use `useToast()` anywhere in your Nuxt app: 67 | 68 | ### **Basic Example** 69 | 70 | ```vue 71 | 80 | ``` 81 | 82 | ### **Customizing Toast Appearance & Options** 83 | 84 | ```vue 85 | 95 | ``` 96 | 97 | ### **Dynamically Hiding Toasts** 98 | 99 | ```vue 100 | 115 | ``` 116 | 117 | ### **Customizing the Composable Name** 118 | 119 | If you've modified the `composableName` in `nuxt.config.ts`, for example: 120 | 121 | ```ts 122 | export default defineNuxtConfig({ 123 | toast: { composableName: 'useNotification' } 124 | }) 125 | ``` 126 | 127 | Then, use the updated composable name in your component: 128 | 129 | ```vue 130 | 136 | ``` 137 | 138 | This ensures consistency with your custom naming convention. 🚀 139 | 140 | 141 | 142 | [npm-version-src]: https://img.shields.io/npm/v/nuxt-toast/latest.svg?style=flat&colorA=020420&colorB=00DC82 143 | [npm-version-href]: https://npmjs.com/package/nuxt-toast 144 | [npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-toast.svg?style=flat&colorA=020420&colorB=00DC82 145 | [npm-downloads-href]: https://npm.chart.dev/nuxt-toast 146 | [license-src]: https://img.shields.io/npm/l/nuxt-toast.svg?style=flat&colorA=020420&colorB=00DC82 147 | [license-href]: https://npmjs.com/package/nuxt-toast 148 | [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js 149 | [nuxt-href]: https://nuxt.com 150 | 151 | -------------------------------------------------------------------------------- /assets/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephenjason89/nuxt-toast/8ffeff6230af687b54f97f09dff59de0217a6b41/assets/cover.png -------------------------------------------------------------------------------- /commitlint.config.ts: -------------------------------------------------------------------------------- 1 | export default { extends: ['@commitlint/config-conventional'] } 2 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import { createConfigForNuxt } from '@nuxt/eslint-config/flat' 3 | 4 | // Run `npx @eslint/config-inspector` to inspect the resolved config interactively 5 | export default createConfigForNuxt({ 6 | features: { 7 | // Rules for module authors 8 | tooling: true, 9 | // Rules for formatting 10 | stylistic: true, 11 | }, 12 | dirs: { 13 | src: [ 14 | './playground', 15 | ], 16 | }, 17 | }) 18 | .append( 19 | // your custom flat config here... 20 | ) 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt-toast", 3 | "version": "1.1.4", 4 | "description": "A Nuxt module for iziToast notifications", 5 | "repository": "https://github.com/stephenjason89/nuxt-toast", 6 | "author": "Stephen Jason Wang", 7 | "license": "MIT", 8 | "type": "module", 9 | "exports": { 10 | ".": { 11 | "types": "./dist/types.d.ts", 12 | "import": "./dist/module.mjs", 13 | "require": "./dist/module.cjs" 14 | } 15 | }, 16 | "main": "./dist/module.cjs", 17 | "types": "./dist/types.d.ts", 18 | "files": [ 19 | "dist" 20 | ], 21 | "scripts": { 22 | "commitlint": "commitlint --edit", 23 | "prepack": "nuxt-module-build build", 24 | "dev": "nuxi dev playground", 25 | "dev:build": "nuxi build playground", 26 | "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground", 27 | "release": "npm run lint && npm run prepack && changelogen --release && npm publish && git push --follow-tags", 28 | "lint": "eslint .", 29 | "prepare": "husky", 30 | "test": "vitest run", 31 | "test:watch": "vitest watch", 32 | "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit" 33 | }, 34 | "dependencies": { 35 | "@nuxt/kit": "^3.16.2" 36 | }, 37 | "peerDependencies": { 38 | "izitoast": "^1.4.0" 39 | }, 40 | "devDependencies": { 41 | "@commitlint/cli": "^19.8.0", 42 | "@commitlint/config-conventional": "^19.8.0", 43 | "@nuxt/devtools": "^1.7.0", 44 | "@nuxt/eslint-config": "^0.7.6", 45 | "@nuxt/module-builder": "^0.8.4", 46 | "@nuxt/schema": "^3.16.2", 47 | "@nuxt/test-utils": "^3.17.2", 48 | "@types/node": "latest", 49 | "changelogen": "^0.5.7", 50 | "eslint": "^9.24.0", 51 | "husky": "^9.1.7", 52 | "nuxt": "^3.16.2", 53 | "playwright": "^1.51.1", 54 | "typescript": "~5.7.3", 55 | "vitest": "^2.1.9", 56 | "vue-tsc": "^2.2.8" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /playground/app.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /playground/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | modules: ['../src/module'], 3 | devtools: { enabled: true }, 4 | compatibilityDate: '2025-01-20', 5 | }) 6 | -------------------------------------------------------------------------------- /playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "my-module-playground", 4 | "type": "module", 5 | "scripts": { 6 | "dev": "nuxi dev", 7 | "build": "nuxi build", 8 | "generate": "nuxi generate" 9 | }, 10 | "dependencies": { 11 | "nuxt": "^3.15.2" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /playground/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /src/module.ts: -------------------------------------------------------------------------------- 1 | import { defineNuxtModule, addPlugin, createResolver, addImports } from '@nuxt/kit' 2 | 3 | export interface ModuleOptions { 4 | composableName?: string 5 | } 6 | 7 | export default defineNuxtModule({ 8 | meta: { 9 | name: 'nuxt-toast', 10 | configKey: 'toast', 11 | compatibility: { nuxt: '>=3.0.0' }, 12 | }, 13 | 14 | setup(options, nuxt) { 15 | const resolver = createResolver(import.meta.url) 16 | 17 | nuxt.hook('vite:extend', ({ config }) => { 18 | (config.optimizeDeps ??= {}).include ??= [] 19 | config.optimizeDeps.include.push('izitoast') 20 | }) 21 | 22 | addPlugin({ 23 | src: resolver.resolve('./runtime/plugin'), 24 | mode: 'client', 25 | }) 26 | 27 | addImports({ 28 | name: 'useToast', 29 | as: options.composableName ?? 'useToast', 30 | from: resolver.resolve('./runtime/composables/useToast'), 31 | }) 32 | }, 33 | }) 34 | -------------------------------------------------------------------------------- /src/runtime/composables/useToast.ts: -------------------------------------------------------------------------------- 1 | import type Toast from '../types/IziToast' 2 | import { useNuxtApp } from '#app' 3 | 4 | export function useToast(): Toast { 5 | if (import.meta.server) { 6 | return new Proxy({} as Toast, { get: () => () => {} }) // SSR Safe 7 | } 8 | return useNuxtApp().$iziToast 9 | } 10 | -------------------------------------------------------------------------------- /src/runtime/plugin.ts: -------------------------------------------------------------------------------- 1 | import type { IziToastSettings } from 'izitoast' 2 | import iziToast from 'izitoast' 3 | import type Toast from './types/IziToast.ts' 4 | import 'izitoast/dist/css/iziToast.min.css' 5 | import { defineNuxtPlugin } from '#app' 6 | 7 | export default defineNuxtPlugin(async () => { 8 | const THEMES = { 9 | info: { color: 'blue', icon: 'ico-info' }, 10 | success: { color: 'green', icon: 'ico-success' }, 11 | warning: { color: 'orange', icon: 'ico-warning' }, 12 | error: { color: 'red', icon: 'ico-error' }, 13 | question: { color: 'yellow', icon: 'ico-question' }, 14 | } 15 | 16 | return { 17 | provide: { 18 | iziToast: { 19 | ...iziToast, 20 | hideToast(title: string, message: string, status: keyof typeof THEMES) { 21 | const color = THEMES[status].color 22 | const newId = btoa(encodeURIComponent(`${title}${message}${color}`)).replace(/=/g, '') 23 | 24 | document 25 | .querySelectorAll(`.iziToast#${newId}`) 26 | .forEach( 27 | element => 28 | element instanceof HTMLDivElement 29 | && iziToast.hide({ title, message, id: newId }, element, 'replaced'), 30 | ) 31 | }, 32 | data(data: IziToastSettings & { status: keyof typeof THEMES }) { 33 | iziToast.show({ 34 | ...data, 35 | color: THEMES[data?.status]?.color, 36 | icon: THEMES[data?.status]?.icon, 37 | timeout: data.timeout ?? 2500, 38 | }) 39 | }, 40 | } as Toast, 41 | }, 42 | } 43 | }) 44 | -------------------------------------------------------------------------------- /src/runtime/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../.nuxt/tsconfig.server.json", 3 | } 4 | -------------------------------------------------------------------------------- /src/runtime/types/IziToast.ts: -------------------------------------------------------------------------------- 1 | import type { IziToast, IziToastSettings } from 'izitoast' 2 | 3 | export default interface Toast extends IziToast { 4 | hideToast: (title: string, message: string, status: string) => void 5 | data: (data: IziToastSettings & { status: string }) => void 6 | } 7 | -------------------------------------------------------------------------------- /test/basic.test.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { describe, it, expect } from 'vitest' 3 | import { setup, createPage } from '@nuxt/test-utils/e2e' 4 | 5 | describe('Basic Page Rendering', async () => { 6 | await setup({ 7 | rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)), 8 | browser: true, 9 | }) 10 | 11 | it('renders the page and displays iziToast notification', async () => { 12 | const page = await createPage('/') 13 | 14 | await page.waitForSelector('.iziToast-message') 15 | 16 | const toastText = await page.textContent('.iziToast-message') 17 | expect(toastText).toContain('Success message') 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /test/fixtures/basic/app.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /test/fixtures/basic/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | import MyModule from '../../../src/module' 2 | 3 | export default defineNuxtConfig({ 4 | modules: [ 5 | MyModule, 6 | ], 7 | }) 8 | -------------------------------------------------------------------------------- /test/fixtures/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "basic", 4 | "type": "module" 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json", 3 | "exclude": [ 4 | "dist", 5 | "node_modules", 6 | "playground", 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | 3 | export default defineConfig({ 4 | test: { 5 | include: ['test/**/*.test.ts', 'test/**/*.spec.ts'], 6 | }, 7 | }) 8 | --------------------------------------------------------------------------------