From b42d73587006521eefe09f937c81bbe6a8be6d49 Mon Sep 17 00:00:00 2001 From: Mohan Date: Wed, 12 Aug 2026 16:35:32 +0800 Subject: [PATCH] feat(component): add SongScrim and message toast --- src/components/SongMessageContainer.vue | 95 ++++++++++++++++++++ src/components/SongScrim.vue | 115 ++++++++++++++++++++++++ src/composables/useMessage.ts | 44 +++++++++ 3 files changed, 254 insertions(+) create mode 100644 src/components/SongMessageContainer.vue create mode 100644 src/components/SongScrim.vue create mode 100644 src/composables/useMessage.ts diff --git a/src/components/SongMessageContainer.vue b/src/components/SongMessageContainer.vue new file mode 100644 index 0000000..271dddd --- /dev/null +++ b/src/components/SongMessageContainer.vue @@ -0,0 +1,95 @@ + + + + + \ No newline at end of file diff --git a/src/components/SongScrim.vue b/src/components/SongScrim.vue new file mode 100644 index 0000000..52573f6 --- /dev/null +++ b/src/components/SongScrim.vue @@ -0,0 +1,115 @@ + + + + + \ No newline at end of file diff --git a/src/composables/useMessage.ts b/src/composables/useMessage.ts new file mode 100644 index 0000000..af37b66 --- /dev/null +++ b/src/composables/useMessage.ts @@ -0,0 +1,44 @@ +import { createVNode, reactive, render } from 'vue' +import SongMessageContainer from '@/components/SongMessageContainer.vue' + +interface ToastItem { + id: number + type: string + text: string +} + +type ToastType = 'success' | 'danger' | 'warning' | 'info' + +const list = reactive([]) +let seed = 0 +let hostEl: HTMLDivElement | null = null + +function remove(id: number) { + const i = list.findIndex((t) => t.id === id) + if (i > -1) list.splice(i, 1) +} + +function push(type: ToastType, text: string, duration = 3400) { + const id = ++seed + list.push({ id, type, text }) + setTimeout(() => remove(id), duration) +} + +function ensureHost() { + if (!hostEl) { + hostEl = document.createElement('div') + hostEl.className = 'song-message-host' + document.body.appendChild(hostEl) + render(createVNode(SongMessageContainer, { list }), hostEl) + } +} + +export function useMessage() { + ensureHost() + return { + success: (text: string) => push('success', text), + danger: (text: string) => push('danger', text), + warning: (text: string) => push('warning', text), + info: (text: string) => push('info', text) + } +} \ No newline at end of file