diff --git a/.storybook/preview.ts b/.storybook/preview.ts index b01d9de..6cc8715 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,6 +1,7 @@ import { setup } from "@storybook/vue3"; import PrimeVue from "primevue/config"; import { RisUiTheme } from "../src/primevue"; +import ToastService from "primevue/toastservice"; import "../public/fonts.css"; setup((app) => { @@ -8,4 +9,5 @@ setup((app) => { pt: RisUiTheme, unstyled: true, }); + app.use(ToastService); }); diff --git a/src/primevue/index.ts b/src/primevue/index.ts index 5aad540..9fb6d6f 100644 --- a/src/primevue/index.ts +++ b/src/primevue/index.ts @@ -5,6 +5,7 @@ import inputGroup from "./inputGroup/inputGroup"; import inputGroupAddon from "./inputGroup/inputGroupAddon"; import inputText from "./inputText/inputText"; import password from "./password/password"; +import toast from "./toast/toast"; export const RisUiTheme = { button, @@ -12,4 +13,5 @@ export const RisUiTheme = { inputGroup, inputGroupAddon, password, + toast }; diff --git a/src/primevue/toast/toast.stories.ts b/src/primevue/toast/toast.stories.ts new file mode 100644 index 0000000..d2f3697 --- /dev/null +++ b/src/primevue/toast/toast.stories.ts @@ -0,0 +1,139 @@ +import { Meta, StoryObj } from "@storybook/vue3"; +import Toast from "primevue/toast"; +import { useToast } from "primevue/usetoast"; +import { html } from "@/lib/tags.ts"; +import Btn from "primevue/button"; +import IconCheck from "~icons/ic/baseline-check-circle-outline"; + + +const meta: Meta = { + component: Toast, + tags: ["autodocs"], + args: { + position: 'top-right', + }, + + argTypes: { + position: { + control: { type: 'select' }, + options: [ + 'top-right', 'top-left', + 'bottom-right', 'bottom-left', + ], + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Success: Story = { + render: (args) => ({ + components: { Toast, Btn, IconCheck }, + setup() { + const toast = useToast(); + + const showSuccess = () => { + toast.add({ + severity: 'success', + summary: 'Verkündung erfolgreich hochgeladen', + detail: 'Sie können mit der Arbeit an der neuen Verkündung beginnen.', + life: 3000 + }); + }; + + return { args, showSuccess }; + }, + template: html` +
+ + + + +
+ `, + }), +}; + +export const Warning: Story = { + render: (args) => ({ + components: { Toast, Btn }, + setup() { + const toast = useToast(); + + const showWarn = () => { + toast.add({ + severity: 'warn', + summary: 'This is a warning', + detail: 'This is a warning message.', + life: 3000 + }); + }; + + return { args, showWarn }; + }, + template: html` +
+ + +
+ `, + }), +}; + +export const Error: Story = { + render: (args) => ({ + components: { Toast, Btn }, + setup() { + const toast = useToast(); + + const showError = () => { + toast.add({ + severity: 'error', + summary: 'Error', + detail: 'An error occurred.', + life: 3000 + }); + }; + + return { args, showError }; + }, + template: html` +
+ + +
+ `, + }), +}; + +export const SuccessSticky: Story = { + render: (args) => ({ + components: { Toast, Btn, IconCheck }, + setup() { + const toast = useToast(); + + const showSuccess = () => { + toast.add({ + severity: 'success', + summary: 'Verkündung erfolgreich hochgeladen', + detail: 'Sie können mit der Arbeit an der neuen Verkündung beginnen.', + }); + }; + + return { args, showSuccess }; + }, + template: html` +
+ + + + +
+ `, + }), +}; \ No newline at end of file diff --git a/src/primevue/toast/toast.ts b/src/primevue/toast/toast.ts new file mode 100644 index 0000000..1d15426 --- /dev/null +++ b/src/primevue/toast/toast.ts @@ -0,0 +1,62 @@ +import { ToastPassThroughOptions } from "primevue/toast"; +import { tw } from "@/lib/tags.ts"; + +const toast: ToastPassThroughOptions = { + message: ({ props }) => { + const base = tw`flex flex-row items-center gap-8 border-l-8 p-16`; + + const severity = props.message?.severity; + + const success = tw`border-l-green-900 bg-green-200`; + const error = tw`border-l-red-900 bg-red-200 text-red-900`; + const warn = tw`border-l-yellow-900 bg-yellow-200 text-yellow-900`; + + return { + class: { + [base]: true, + [success]: severity === "success", + [error]: severity === "error", + [warn]: severity === "warn", + }, + }; + }, + + messageContent: () => ({ + class: tw`flex flex-row items-start gap-8`, + }), + + messageIcon: ({ props }) => { + const baseIcon = tw`p-2 w-20 h-20`; + + const severity = props.message?.severity ?? "info"; + + const successIcon = tw`text-green-900`; + const errorIcon = tw`text-red-800`; + const warnIcon = tw`text-yellow-800`; + const infoIcon = tw`text-blue-800`; + + return { + class: { + [baseIcon]: true, + [successIcon]: severity === "success", + [errorIcon]: severity === "error", + [warnIcon]: severity === "warn", + [infoIcon]: severity === "info", + }, + }; + }, + + messageText: () => ({ + class: tw`text-black`, + }), + + summary: () => ({ + class: tw`font-bold`, + }), + + closeIcon: () => ({ + class: tw`text-blue-800`, + }), +}; + +export default toast; \ No newline at end of file