Implemented Toast and cleanup for project, remove nuxt module

pull/7398/head
Cagatay Civici 2025-03-10 14:33:08 +03:00
parent 4960abeb44
commit e2c3a120f2
23 changed files with 1482 additions and 624 deletions

View File

@ -114,6 +114,10 @@
"name": "Timeline", "name": "Timeline",
"to": "/timeline" "to": "/timeline"
}, },
{
"name": "Toast",
"to": "/toast"
},
{ {
"name": "ToggleButton", "name": "ToggleButton",
"to": "/togglebutton" "to": "/togglebutton"

View File

@ -26,8 +26,10 @@
@custom-variant p-right (&[data-p~="right"]); @custom-variant p-right (&[data-p~="right"]);
@custom-variant p-top (&[data-p~="top"]); @custom-variant p-top (&[data-p~="top"]);
@custom-variant p-bottom (&[data-p~="bottom"]); @custom-variant p-bottom (&[data-p~="bottom"]);
@custom-variant p-center (&[data-p~="center"]);
@custom-variant p-alternate (&[data-p~="alternate"]); @custom-variant p-alternate (&[data-p~="alternate"]);
@custom-variant p-center (&[data-p~="center"]);
@custom-variant p-top-center (&[data-p~="top-center"]);
@custom-variant p-bottom-center (&[data-p~="bottom-center"]);
@custom-variant p-active (&[data-p~="active"]); @custom-variant p-active (&[data-p~="active"]);
@custom-variant p-focus-visible (&[data-p~="focus-visible"]); @custom-variant p-focus-visible (&[data-p~="focus-visible"]);
@custom-variant p-readonly (&[data-p~="readonly"]); @custom-variant p-readonly (&[data-p~="readonly"]);
@ -50,6 +52,7 @@
@custom-variant p-warn (&[data-p~="warn"]); @custom-variant p-warn (&[data-p~="warn"]);
@custom-variant p-danger (&[data-p~="danger"]); @custom-variant p-danger (&[data-p~="danger"]);
@custom-variant p-error (&[data-p~="error"]); @custom-variant p-error (&[data-p~="error"]);
@custom-variant p-custom (&[data-p~="custom"]);
@custom-variant p-outlined (&[data-p~="outlined"]); @custom-variant p-outlined (&[data-p~="outlined"]);
@custom-variant p-text (&[data-p~="text"]); @custom-variant p-text (&[data-p~="text"]);
@custom-variant p-simple (&[data-p~="simple"]); @custom-variant p-simple (&[data-p~="simple"]);

View File

@ -34,6 +34,8 @@
</template> </template>
<script> <script>
import Tag from '@/volt/tag';
export default { export default {
props: { props: {
root: { root: {
@ -52,6 +54,9 @@ export default {
!menuitem.children.some((item) => item.to === `/${this.$router.currentRoute.value?.name?.replaceAll('-', '/')}` || (item.children && item.children.some((it) => it.to === `/${this.$router.currentRoute.value.name}`))) !menuitem.children.some((item) => item.to === `/${this.$router.currentRoute.value?.name?.replaceAll('-', '/')}` || (item.children && item.children.some((it) => it.to === `/${this.$router.currentRoute.value.name}`)))
); );
} }
},
components: {
Tag
} }
}; };
</script> </script>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="doc-section-code"> <div class="doc-section-code">
<div class="doc-section-code-buttons"> <div class="doc-section-code-buttons">
<button v-tooltip.bottom="{ value: 'Copy Code', class: 'doc-section-code-tooltip' }" type="button" @click="copyCode" class="h-8 w-8 p-0 inline-flex items-center justify-center"> <button type="button" @click="copyCode" class="h-8 w-8 p-0 inline-flex items-center justify-center">
<i class="pi pi-copy"></i> <i class="pi pi-copy"></i>
</button> </button>
</div> </div>

View File

@ -0,0 +1,42 @@
<template>
<DocSectionText v-bind="$attrs">
<p>A single message is represented by the Message interface that defines properties such as severity, summary and detail.</p>
</DocSectionText>
<div class="card flex justify-center">
<Button label="Show" @click="show()" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Button from '@/volt/button';
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
const toast = useToast();
const show = () => {
toast.add({ severity: 'info', summary: 'Info', detail: 'Message Content', life: 3000 });
};
const code = ref(`
<template>
<Toast />
<div class="card flex justify-center">
<Button label="Show" @click="show()" />
</div>
</template>
<script setup>
import Toast from '@/volt/toast';
import Button from '@/volt/button';
import { useToast } from 'primevue/usetoast';
const toast = useToast();
const show = () => {
toast.add({ severity: 'info', summary: 'Info', detail: 'Message Content', life: 3000 });
};
<\/script>
`);
</script>

View File

@ -0,0 +1,136 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Headless mode is enabled by defining a <i>container</i> slot along with the <i>custom</i> severity that lets you implement entire toast UI instead of the default elements.</p>
</DocSectionText>
<div class="card flex justify-center">
<Toast position="top-center" group="headless" @close="visible = false">
<template #container="{ message, closeCallback }">
<section class="flex flex-col p-4 gap-4 w-full bg-primary/70 rounded-xl">
<div class="flex items-center gap-5">
<i class="pi pi-cloud-upload text-white dark:text-black text-2xl"></i>
<span class="font-bold text-base text-white dark:text-black">{{ message.summary }}</span>
</div>
<div class="flex flex-col gap-2">
<ProgressBar :value="progress" :showValue="false" :style="{ height: '4px' }" pt:value:class="!bg-primary-50 dark:!bg-primary-900" class="!bg-primary/80"></ProgressBar>
<label class="text-sm font-bold text-white dark:text-black">{{ progress }}% uploaded</label>
</div>
<div class="flex gap-4 mb-4 justify-end">
<Button label="Another Upload?" size="small" @click="closeCallback"></Button>
<Button label="Cancel" size="small" @click="closeCallback"></Button>
</div>
</section>
</template>
</Toast>
<Button @click="show" label="View" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Button from '@/volt/button';
import ProgressBar from '@/volt/progressbar';
import Toast from '@/volt/toast';
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
const toast = useToast();
const visible = ref(false);
const progress = ref(0);
const interval = ref();
onUnmounted(() => {
if (interval.value) {
clearInterval(interval.value);
}
});
const show = () => {
if (!visible.value) {
toast.add({ severity: 'custom', summary: 'Uploading your files.', group: 'headless', styleClass: 'backdrop-blur-lg rounded-2xl' });
visible.value = true;
progress.value = 0;
if (interval.value) {
clearInterval(interval.value);
}
interval.value = setInterval(() => {
if (progress.value <= 100) {
progress.value = progress.value + 20;
}
if (progress.value >= 100) {
progress.value = 100;
clearInterval(interval.value);
}
}, 1000);
}
};
const code = ref(`
<template>
<Toast position="top-center" group="headless" @close="visible = false">
<template #container="{ message, closeCallback }">
<section class="flex flex-col p-4 gap-4 w-full bg-primary/70 rounded-xl">
<div class="flex items-center gap-5">
<i class="pi pi-cloud-upload text-white dark:text-black text-2xl"></i>
<span class="font-bold text-base text-white dark:text-black">{{ message.summary }}</span>
</div>
<div class="flex flex-col gap-2">
<ProgressBar :value="progress" :showValue="false" :style="{ height: '4px' }" pt:value:class="!bg-primary-50 dark:!bg-primary-900" class="!bg-primary/80"></ProgressBar>
<label class="text-sm font-bold text-white dark:text-black">{{ progress }}% uploaded</label>
</div>
<div class="flex gap-4 mb-4 justify-end">
<Button label="Another Upload?" size="small" @click="closeCallback"></Button>
<Button label="Cancel" size="small" @click="closeCallback"></Button>
</div>
</section>
</template>
</Toast>
<div class="card flex justify-center">
<Button @click="show" label="View" />
</div>
</template>
<script setup>
import Toast from '@/volt/toast';
import Button from '@/volt/button';
import ProgressBar from '@/volt/progressbar';
import { useToast } from 'primevue/usetoast';
const toast = useToast();
const visible = ref(false);
const progress = ref(0);
const interval = ref();
onUnmounted(() => {
if (interval.value) {
clearInterval(interval.value);
}
})
const show = () => {
if (!visible.value) {
toast.add({ severity: 'custom', summary: 'Uploading your files.', group: 'headless', styleClass: 'backdrop-blur-lg rounded-2xl' });
visible.value = true;
progress.value = 0;
if (interval.value) {
clearInterval(interval.value);
}
interval.value = setInterval(() => {
if (progress.value <= 100) {
progress.value = progress.value + 20;
}
if (progress.value >= 100) {
progress.value = 100;
clearInterval(interval.value);
}
}, 1000);
}
};
<\/script>
`);
</script>

View File

@ -0,0 +1,11 @@
<template>
<DocSectionText v-bind="$attrs" />
<DocSectionCode :code="code" lang="script" />
</template>
<script setup>
import { ref } from 'vue';
const code = ref(`import Toast from '@/volt/toast';
`);
</script>

View File

@ -0,0 +1,48 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Multiple messages are displayed by passing an array to the <i>show</i> method.</p>
</DocSectionText>
<div class="card flex justify-center">
<Button label="Multiple" @click="showMultiple()" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Button from '@/volt/button';
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
const toast = useToast();
const showMultiple = () => {
toast.add({ severity: 'success', summary: 'Success', detail: 'Message Content', life: 3000 });
toast.add({ severity: 'info', summary: 'Info', detail: 'Message Content', life: 3050 });
toast.add({ severity: 'warn', summary: 'Warn', detail: 'Message Content', life: 3100 });
toast.add({ severity: 'error', summary: 'Error', detail: 'Message Content', life: 3150 });
};
const code = ref(`
<template>
<Toast />
<div class="card flex justify-center">
<Button label="Multiple" @click="showMultiple()" />
</div>
</template>
<script setup>
import Toast from '@/volt/toast';
import Button from '@/volt/button';
import { useToast } from 'primevue/usetoast';
const toast = useToast();
const showMultiple = () => {
toast.add({ severity: 'success', summary: 'Success', detail: 'Message Content', life: 3000 });
toast.add({ severity: 'info', summary: 'Info', detail: 'Message Content', life: 3050 });
toast.add({ severity: 'warn', summary: 'Warn', detail: 'Message Content', life: 3100 });
toast.add({ severity: 'error', summary: 'Error', detail: 'Message Content', life: 3150 });
};
<\/script>
`);
</script>

View File

@ -0,0 +1,64 @@
<template>
<DocSectionText v-bind="$attrs">
<p>A message can be targeted to a certain Toast component by matching the <i>group</i> keys whereas location is customized with the <i>position</i>.</p>
</DocSectionText>
<div class="card flex flex-wrap gap-2 justify-center">
<Button label="Top Left" @click="showTopLeft" />
<Button label="Bottom Left" @click="showBottomLeft" />
<Button label="Bottom Right" @click="showBottomRight" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Button from '@/volt/button';
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
const toast = useToast();
const showTopLeft = () => {
toast.add({ severity: 'info', summary: 'Info Message', detail: 'Message Content', group: 'tl', life: 3000 });
};
const showBottomLeft = () => {
toast.add({ severity: 'warn', summary: 'Warn Message', detail: 'Message Content', group: 'bl', life: 3000 });
};
const showBottomRight = () => {
toast.add({ severity: 'success', summary: 'Success Message', detail: 'Message Content', group: 'br', life: 3000 });
};
const code = ref(`
<template>
<Toast position="top-left" group="tl" />
<Toast position="bottom-left" group="bl" />
<Toast position="bottom-right" group="br" />
<div class="card flex flex-wrap gap-2 justify-center">
<Button label="Top Left" @click="showTopLeft" />
<Button label="Bottom Left" @click="showBottomLeft" />
<Button label="Bottom Right" @click="showBottomRight" />
</div>
</template>
<script setup>
import Toast from '@/volt/toast';
import Button from '@/volt/button';
import { useToast } from 'primevue/usetoast';
const toast = useToast();
const showTopLeft = () => {
toast.add({ severity: 'info', summary: 'Info Message', detail: 'Message Content', group: 'tl', life: 3000 });
};
const showBottomLeft = () => {
toast.add({ severity: 'warn', summary: 'Warn Message', detail: 'Message Content', group: 'bl', life: 3000 });
};
const showBottomRight = () => {
toast.add({ severity: 'success', summary: 'Success Message', detail: 'Message Content', group: 'br', life: 3000 });
};
<\/script>
`);
</script>

View File

@ -0,0 +1,92 @@
<template>
<DocSectionText v-bind="$attrs">
<p>The <i>severity</i> option specifies the type of the message.</p>
</DocSectionText>
<div class="card flex flex-wrap gap-2 justify-center">
<SecondaryButton label="Success" @click="showSuccess" />
<SecondaryButton label="Info" @click="showInfo" />
<SecondaryButton label="Warn" @click="showWarn" />
<SecondaryButton label="Error" @click="showError" />
<SecondaryButton label="Secondary" @click="showSecondary" />
<SecondaryButton label="Contrast" @click="showContrast" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import SecondaryButton from '@/volt/button/secondary';
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
const toast = useToast();
const showSuccess = () => {
toast.add({ severity: 'success', summary: 'Success Message', detail: 'Message Content', life: 3000 });
};
const showInfo = () => {
toast.add({ severity: 'info', summary: 'Info Message', detail: 'Message Content', life: 3000 });
};
const showWarn = () => {
toast.add({ severity: 'warn', summary: 'Warn Message', detail: 'Message Content', life: 3000 });
};
const showError = () => {
toast.add({ severity: 'error', summary: 'Error Message', detail: 'Message Content', life: 3000 });
};
const showSecondary = () => {
toast.add({ severity: 'secondary', summary: 'Secondary Message', detail: 'Message Content', life: 3000 });
};
const showContrast = () => {
toast.add({ severity: 'contrast', summary: 'Contrast Message', detail: 'Message Content', life: 3000 });
};
const code = ref(`
<template>
<Toast />
<div class="card flex flex-wrap gap-2 justify-center">
<SecondaryButton label="Success" @click="showSuccess" />
<SecondaryButton label="Info" @click="showInfo" />
<SecondaryButton label="Warn" @click="showWarn" />
<SecondaryButton label="Error" @click="showError" />
<SecondaryButton label="Secondary" @click="showSecondary" />
<SecondaryButton label="Contrast" @click="showContrast" />
</div>
</template>
<script setup>
import Toast from '@/volt/toast';
import SecondaryButton from '@/volt/button';
import { useToast } from "primevue/usetoast";
const toast = useToast();
const showSuccess = () => {
toast.add({ severity: 'success', summary: 'Success Message', detail: 'Message Content', life: 3000 });
};
const showInfo = () => {
toast.add({ severity: 'info', summary: 'Info Message', detail: 'Message Content', life: 3000 });
};
const showWarn = () => {
toast.add({ severity: 'warn', summary: 'Warn Message', detail: 'Message Content', life: 3000 });
};
const showError = () => {
toast.add({ severity: 'error', summary: 'Error Message', detail: 'Message Content', life: 3000 });
};
const showSecondary = () => {
toast.add({ severity: 'secondary', summary: 'Secondary Message', detail: 'Message Content', life: 3000 });
};
const showContrast = () => {
toast.add({ severity: 'contrast', summary: 'Contrast Message', detail: 'Message Content', life: 3000 });
};
<\/script>
`);
</script>

View File

@ -0,0 +1,54 @@
<template>
<DocSectionText v-bind="$attrs">
<p>A message disappears after the number of milliseconds defined in the <i>life</i> option. Omit the <i>life</i> option to make the message sticky.</p>
</DocSectionText>
<div class="card flex flex-wrap gap-2 justify-center">
<Button @click="showSticky" label="Sticky" />
<SecondaryButton label="Clear" @click="clear()" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Button from '@/volt/button';
import SecondaryButton from '@/volt/button/secondary';
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
const toast = useToast();
const showSticky = () => {
toast.add({ severity: 'info', summary: 'Sticky Message', detail: 'Message Content' });
};
const clear = () => {
toast.removeAllGroups();
};
const code = ref(`
<template>
<Toast />
<div class="card flex flex-wrap gap-2 justify-center">
<Button @click="showSticky" label="Sticky" />
<SecondaryButton label="Clear" @click="clear()" />
</div>
</template>
<script setup>
import Toast from '@/volt/toast';
import Button from '@/volt/button';
import SecondaryButton from '@/volt/button/secondary';
import { useToast } from 'primevue/usetoast';
const toast = useToast();
const showSticky = () => {
toast.add({ severity: 'info', summary: 'Sticky Message', detail: 'Message Content'});
}
const clear = () => {
toast.removeAllGroups();
}
<\/script>
`);
</script>

View File

@ -0,0 +1,95 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Custom content inside a message is defined with the <i>message</i> template.</p>
</DocSectionText>
<div class="card flex justify-center">
<Toast position="bottom-center" group="bc" @close="onClose">
<template #message="slotProps">
<div class="flex flex-col items-start flex-auto">
<div class="flex items-center gap-2">
<Avatar image="https://primefaces.org/cdn/primevue/images/avatar/amyelsner.png" shape="circle" />
<span class="font-bold">Amy Elsner</span>
</div>
<div class="font-medium text-lg my-4">{{ slotProps.message.summary }}</div>
<Button size="small" label="Reply" severity="success" @click="onReply()"></Button>
</div>
</template>
</Toast>
<Button @click="showTemplate" label="View" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Avatar from '@/volt/avatar';
import Button from '@/volt/button';
import Toast from '@/volt/toast';
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
const toast = useToast();
const visible = ref(false);
const showTemplate = () => {
if (!visible.value) {
toast.add({ severity: 'success', summary: 'Can you send me the report?', group: 'bc' });
visible.value = true;
}
};
const onReply = () => {
toast.removeGroup('bc');
visible.value = false;
};
const onClose = () => {
visible.value = false;
};
const code = ref(`
<template>
<Toast position="bottom-center" group="bc" @close="onClose">
<template #message="slotProps">
<div class="flex flex-col items-start flex-auto">
<div class="flex items-center gap-2">
<Avatar image="https://primefaces.org/cdn/primevue/images/avatar/amyelsner.png" shape="circle" />
<span class="font-bold">Amy Elsner</span>
</div>
<div class="font-medium text-lg my-4">{{ slotProps.message.summary }}</div>
<Button size="small" label="Reply" severity="success" @click="onReply()"></Button>
</div>
</template>
</Toast>
<div class="card flex justify-center">
<Button @click="showTemplate" label="View" />
</div>
</template>
<script setup>
import Toast from '@/volt/toast';
import Avatar from '@/volt/avatar';
import Button from '@/volt/button';
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
const toast = useToast();
const visible = ref(false);
const showTemplate = () => {
if (!visible.value) {
toast.add({ severity: 'success', summary: 'Can you send me the report?', group: 'bc' });
visible.value = true;
}
};
const onReply = () => {
toast.removeGroup('bc');
visible.value = false;
};
const onClose = () => {
visible.value = false;
};
<\/script>
`);
</script>

View File

@ -0,0 +1,33 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Toast component is controlled via the <i>ToastService</i> that needs to be installed as an application plugin.</p>
<DocSectionCode :code="code1" lang="script" />
<p>Recommended location of a Toast is the main application template.</p>
<DocSectionCode :code="code2" />
<p>The <i>useToast</i> composable can be accessed anywhere within your application to interact with the component.</p>
<DocSectionCode :code="code3" />
</DocSectionText>
</template>
<script setup>
const code1 = ref(`import {createApp} from 'vue';
import ToastService from 'primevue/toastservice';
const app = createApp(App);
app.use(ToastService);
`);
const code2 = ref(`
<template>
<Toast />
</template>
`);
const code3 = ref(`
<script setup>
import { useToast } from 'primevue/usetoast';
const toast = useToast(); // instance to create messages
<\/script>
`);
</script>

View File

@ -9,7 +9,7 @@
<span class="font-bold text-9xl"> 4 </span> <span class="font-bold text-9xl"> 4 </span>
</div> </div>
<div class="font-bold text-center text-4xl border-t border-surface pt-8">Page Not Found</div> <div class="font-bold text-center text-4xl border-t border-surface pt-8">Page Not Found</div>
<NuxtLink to="/"><Button label="GO TO HOMEPAGE" /></NuxtLink> <NuxtLink to="/">GO TO HOMEPAGE</NuxtLink>
</div> </div>
</div> </div>
</template> </template>

View File

@ -18,6 +18,7 @@
</template> </template>
<script> <script>
import Toast from '@/volt/toast';
import { blockBodyScroll, unblockBodyScroll } from '@primeuix/utils/dom'; import { blockBodyScroll, unblockBodyScroll } from '@primeuix/utils/dom';
export default { export default {
@ -26,7 +27,7 @@ export default {
sidebarActive: false sidebarActive: false
}; };
}, },
watch: { /*watch: {
$route: { $route: {
immediate: true, immediate: true,
handler() { handler() {
@ -39,7 +40,7 @@ export default {
this.$toast.removeAllGroups(); this.$toast.removeAllGroups();
} }
} }
}, },*/
methods: { methods: {
onMenuButtonClick() { onMenuButtonClick() {
if (this.sidebarActive) { if (this.sidebarActive) {
@ -64,6 +65,9 @@ export default {
} }
]; ];
} }
},
components: {
Toast
} }
}; };
</script> </script>

View File

@ -6,7 +6,6 @@ import tailwindcss from '@tailwindcss/vite';
export default defineNuxtConfig({ export default defineNuxtConfig({
compatibilityDate: '2024-11-01', compatibilityDate: '2024-11-01',
devtools: { enabled: true }, devtools: { enabled: true },
modules: ['@primevue/nuxt-module'],
components: [ components: [
{ {
path: '~/components', path: '~/components',
@ -37,12 +36,6 @@ export default defineNuxtConfig({
runtimeConfig: { runtimeConfig: {
GITHUB_TOKEN: '' GITHUB_TOKEN: ''
}, },
primevue: {
autoImport: false,
options: {
unstyled: true
}
},
app: { app: {
baseURL: baseUrl, baseURL: baseUrl,
head: { head: {

View File

@ -35,18 +35,10 @@
}, },
"dependencies": { "dependencies": {
"@docsearch/js": "catalog:app", "@docsearch/js": "catalog:app",
"@primeuix/themes": "catalog:",
"@primevue/core": "workspace:*",
"@primevue/forms": "workspace:*",
"@primevue/nuxt-module": "workspace:*",
"primeicons": "catalog:", "primeicons": "catalog:",
"primevue": "workspace:*", "primevue": "workspace:*",
"chart.js": "catalog:app", "chart.js": "catalog:app",
"quill": "catalog:app", "quill": "catalog:app"
"superstruct": "^2.0.2",
"valibot": "^0.42.1",
"yup": "1.4.0",
"zod": "3.23.8"
}, },
"devDependencies": { "devDependencies": {
"@stackblitz/sdk": "^1.8.2", "@stackblitz/sdk": "^1.8.2",

View File

@ -0,0 +1,65 @@
<template>
<DocComponent title="Vue Toast Component" header="Toast" description="Toast is used to display messages in an overlay." :componentDocs="docs" />
</template>
<script setup>
import BasicDoc from '@/doc/toast/BasicDoc.vue';
import HeadlessDoc from '@/doc/toast/HeadlessDoc.vue';
import ImportDoc from '@/doc/toast/ImportDoc.vue';
import MultipleDoc from '@/doc/toast/MultipleDoc.vue';
import PositionDoc from '@/doc/toast/PositionDoc.vue';
import SeverityDoc from '@/doc/toast/SeverityDoc.vue';
import StickyDoc from '@/doc/toast/StickyDoc.vue';
import TemplateDoc from '@/doc/toast/TemplateDoc.vue';
import ToastServiceDoc from '@/doc/toast/ToastServiceDoc.vue';
import { ref } from 'vue';
const docs = ref([
{
id: 'import',
label: 'Import',
component: ImportDoc
},
{
id: 'toast-service',
label: 'Toast Service',
component: ToastServiceDoc
},
{
id: 'basic',
label: 'Basic',
component: BasicDoc
},
{
id: 'severity',
label: 'Severity',
component: SeverityDoc
},
{
id: 'position',
label: 'Position',
component: PositionDoc
},
{
id: 'multiple',
label: 'Multiple',
component: MultipleDoc
},
{
id: 'sticky',
label: 'Sticky',
component: StickyDoc
},
{
id: 'template',
label: 'Template',
component: TemplateDoc
},
{
id: 'headless',
label: 'Headless',
component: HeadlessDoc
}
]);
</script>

View File

@ -0,0 +1,7 @@
import PrimeVue from 'primevue/config';
import StyleClass from 'primevue/styleclass';
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(PrimeVue);
nuxtApp.vueApp.directive('styleclass', StyleClass);
});

View File

@ -0,0 +1,56 @@
<template>
<Toast
unstyled
:pt="theme"
:ptOptions="{
mergeProps: ptViewMerge
}"
>
<template v-for="(_, slotName) in $slots" v-slot:[slotName]="slotProps">
<slot :name="slotName" v-bind="slotProps ?? {}" />
</template>
</Toast>
</template>
<script setup>
import Toast from 'primevue/toast';
import { ref } from 'vue';
import { ptViewMerge } from '../utils';
const theme = ref({
root: `w-96 rounded-md whitespace-pre-line break-words
p-top-center:-translate-x-1/2 p-bottom-center:-translate-x-1/2
p-center:min-w-[20vw] p-center:-translate-x-1/2 p-center:-translate-y-1/2`,
message: `mb-4 not-p-custom:border not-p-custom:backdrop-blur-sm dark:not-p-custom:backdrop-blur-md not-p-custom:rounded-md
p-info:bg-blue-50/95 p-info:border-blue-200 p-info:text-blue-600 dark:p-info:bg-blue-500/15 dark:p-info:border-blue-700/35 dark:p-info:text-blue-500
p-success:bg-green-50/95 p-success:border-green-200 p-success:text-green-600 dark:p-success:bg-green-500/15 dark:p-success:border-green-700/35 dark:p-success:text-green-500
p-warn:bg-yellow-50/95 p-warn:border-yellow-200 p-warn:text-yellow-600 dark:p-warn:bg-yellow-500/15 dark:p-warn:border-yellow-700/35 dark:p-warn:text-yellow-500
p-error:bg-red-50/95 p-error:border-red-200 p-error:text-red-600 dark:p-error:bg-red-500/15 dark:p-error:border-red-700/35 dark:p-error:text-red-500
p-secondary:bg-surface-100 p-secondary:border-surface-200 p-secondary:text-surface-600 dark:p-secondary:bg-surface-800 dark:p-secondary:border-surface-700 dark:p-secondary:text-surface-300
p-contrast:bg-surface-900 p-contrast:border-surface-950 p-contrast:text-surface-50 dark:p-contrast:bg-surface-0 dark:p-contrast:border-surface-100 dark:p-contrast:text-surface-950`,
messageContent: `flex items-start p-3 gap-2`,
messageIcon: `flex-shrink-0 text-lg w-[1.125rem] h-[1.125rem] mt-1`,
messageText: `flex-auto flex flex-col gap-2`,
summary: `font-medium text-base`,
detail: `font-medium text-sm text-surface-700 dark:text-surface-0
p-contrast:text-surface-0 dark:p-contrast:text-surface-950`,
buttonContainer: ``,
closeButton: `flex items-center justify-center overflow-hidden relative cursor-pointer bg-transparent select-none
transition-colors duration-200 text-inherit w-7 h-7 rounded-full -mt-[25%] -end-1/4 p-0 border-none
focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2
p-info:hover:bg-blue-100 p-info:focus-visible:outline-blue-600 dark:p-info:hover:bg-white/5 dark:p-info:focus-visible:outline-blue-500
p-success:hover:bg-green-100 p-success:focus-visible:outline-green-600 dark:p-success:hover:bg-white/5 dark:p-success:focus-visible:outline-green-500
p-warn:hover:bg-yellow-100 p-warn:focus-visible:outline-yellow-600 dark:p-warn:hover:bg-white/5 dark:p-warn:focus-visible:outline-yellow-500
p-error:hover:bg-red-100 p-error:focus-visible:outline-red-600 dark:p-error:hover:bg-white/5 dark:p-error:focus-visible:outline-red-500
p-secondary:hover:bg-surface-200 p-secondary:focus-visible:outline-surface-600 dark:p-secondary:hover:bg-surface-700 dark:p-secondary:focus-visible:outline-surface-300
p-contrast:hover:bg-surface-800 p-contrast:focus-visible:outline-surface-50 dark:p-contrast:hover:bg-surface-100 dark:p-contrast:focus-visible:outline-surface-950`,
closeIcon: `text-base w-4 h-4`,
transition: {
enterFromClass: 'opacity-0 translate-y-2/4',
enterActiveClass: 'transition-[transform,opacity] duration-300',
leaveFromClass: 'max-h-[1000px]',
leaveActiveClass: '!transition-[max-height_.45s_cubic-bezier(0,1,0,1),opacity_.3s,margin-bottom_.3s] overflow-hidden',
leaveToClass: 'max-h-0 opacity-0 mb-0'
}
});
</script>

View File

@ -1,6 +1,6 @@
<template> <template>
<Portal> <Portal>
<div ref="container" :class="cx('root')" :style="sx('root', true, { position })" v-bind="ptmi('root')"> <div ref="container" :class="cx('root')" :style="sx('root', true, { position })" :data-p="dataP" v-bind="ptmi('root')">
<transition-group name="p-toast-message" tag="div" @enter="onEnter" @leave="onLeave" v-bind="{ ...ptm('transition') }"> <transition-group name="p-toast-message" tag="div" @enter="onEnter" @leave="onLeave" v-bind="{ ...ptm('transition') }">
<ToastMessage <ToastMessage
v-for="msg of messages" v-for="msg of messages"
@ -23,6 +23,7 @@
</template> </template>
<script> <script>
import { cn } from '@primeuix/utils';
import { setAttribute } from '@primeuix/utils/dom'; import { setAttribute } from '@primeuix/utils/dom';
import { isEmpty } from '@primeuix/utils/object'; import { isEmpty } from '@primeuix/utils/object';
import { ZIndex } from '@primeuix/utils/zindex'; import { ZIndex } from '@primeuix/utils/zindex';
@ -96,6 +97,7 @@ export default {
} }
}, },
onRemoveAllGroups() { onRemoveAllGroups() {
this.messages.forEach((message) => this.$emit('close', { message }));
this.messages = []; this.messages = [];
}, },
onEnter() { onEnter() {
@ -145,6 +147,13 @@ export default {
} }
} }
}, },
computed: {
dataP() {
return cn({
[this.position]: this.position
});
}
},
components: { components: {
ToastMessage: ToastMessage, ToastMessage: ToastMessage,
Portal: Portal Portal: Portal

View File

@ -1,17 +1,17 @@
<template> <template>
<div :class="[cx('message'), message.styleClass]" role="alert" aria-live="assertive" aria-atomic="true" v-bind="ptm('message')" @click="onMessageClick" @mouseenter="onMouseEnter" @mouseleave="onMouseLeave"> <div :class="[cx('message'), message.styleClass]" role="alert" aria-live="assertive" aria-atomic="true" :data-p="dataP" v-bind="ptm('message')" @click="onMessageClick" @mouseenter="onMouseEnter" @mouseleave="onMouseLeave">
<component v-if="templates.container" :is="templates.container" :message="message" :closeCallback="onCloseClick" /> <component v-if="templates.container" :is="templates.container" :message="message" :closeCallback="onCloseClick" />
<div v-else :class="[cx('messageContent'), message.contentStyleClass]" v-bind="ptm('messageContent')"> <div v-else :class="[cx('messageContent'), message.contentStyleClass]" v-bind="ptm('messageContent')">
<template v-if="!templates.message"> <template v-if="!templates.message">
<component :is="templates.messageicon ? templates.messageicon : templates.icon ? templates.icon : iconComponent && iconComponent.name ? iconComponent : 'span'" :class="cx('messageIcon')" v-bind="ptm('messageIcon')" /> <component :is="templates.messageicon ? templates.messageicon : templates.icon ? templates.icon : iconComponent && iconComponent.name ? iconComponent : 'span'" :class="cx('messageIcon')" v-bind="ptm('messageIcon')" />
<div :class="cx('messageText')" v-bind="ptm('messageText')"> <div :class="cx('messageText')" :data-p="dataP" v-bind="ptm('messageText')">
<span :class="cx('summary')" v-bind="ptm('summary')">{{ message.summary }}</span> <span :class="cx('summary')" :data-p="dataP" v-bind="ptm('summary')">{{ message.summary }}</span>
<div v-if="message.detail" :class="cx('detail')" v-bind="ptm('detail')">{{ message.detail }}</div> <div v-if="message.detail" :class="cx('detail')" :data-p="dataP" v-bind="ptm('detail')">{{ message.detail }}</div>
</div> </div>
</template> </template>
<component v-else :is="templates.message" :message="message"></component> <component v-else :is="templates.message" :message="message"></component>
<div v-if="message.closable !== false" v-bind="ptm('buttonContainer')"> <div v-if="message.closable !== false" v-bind="ptm('buttonContainer')">
<button v-ripple :class="cx('closeButton')" type="button" :aria-label="closeAriaLabel" @click="onCloseClick" autofocus v-bind="{ ...closeButtonProps, ...ptm('closeButton') }"> <button v-ripple :class="cx('closeButton')" type="button" :aria-label="closeAriaLabel" @click="onCloseClick" autofocus :data-p="dataP" v-bind="{ ...closeButtonProps, ...ptm('closeButton') }">
<component :is="templates.closeicon || 'TimesIcon'" :class="[cx('closeIcon'), closeIcon]" v-bind="ptm('closeIcon')" /> <component :is="templates.closeicon || 'TimesIcon'" :class="[cx('closeIcon'), closeIcon]" v-bind="ptm('closeIcon')" />
</button> </button>
</div> </div>
@ -20,6 +20,7 @@
</template> </template>
<script> <script>
import { cn } from '@primeuix/utils';
import BaseComponent from '@primevue/core/basecomponent'; import BaseComponent from '@primevue/core/basecomponent';
import CheckIcon from '@primevue/icons/check'; import CheckIcon from '@primevue/icons/check';
import ExclamationTriangleIcon from '@primevue/icons/exclamationtriangle'; import ExclamationTriangleIcon from '@primevue/icons/exclamationtriangle';
@ -142,6 +143,11 @@ export default {
}, },
closeAriaLabel() { closeAriaLabel() {
return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.close : undefined; return this.$primevue.config.locale.aria ? this.$primevue.config.locale.aria.close : undefined;
},
dataP() {
return cn({
[this.message.severity]: this.message.severity
});
} }
}, },
components: { components: {

File diff suppressed because it is too large Load Diff