Skip to content

Commit 610a061

Browse files
committed
add alerts
1 parent 9fe446c commit 610a061

File tree

11 files changed

+222
-5
lines changed

11 files changed

+222
-5
lines changed

.prettierignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__build__
2+
dist
3+
coverage

.prettierrc.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
semi: true,
3+
trailingComma: 'es5',
4+
singleQuote: false,
5+
}

components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ declare module '@vue/runtime-core' {
1111
BoardCard: typeof import('./src/components/BoardCard.vue')['default']
1212
RouterLink: typeof import('vue-router')['RouterLink']
1313
RouterView: typeof import('vue-router')['RouterView']
14+
TheAlerts: typeof import('./src/components/TheAlerts.vue')['default']
1415
TheDrawer: typeof import('./src/components/TheDrawer.vue')['default']
1516
TheNavbar: typeof import('./src/components/TheNavbar.vue')['default']
1617
}

package-lock.json

Lines changed: 81 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@vueuse/core": "^8.9.2",
1818
"graphql-tag": "^2.12.6",
1919
"lodash-es": "^4.17.21",
20+
"pinia": "^2.0.16",
2021
"unplugin-vue-components": "^0.20.1",
2122
"uuid": "^8.3.2",
2223
"vite-plugin-pages": "^0.24.3",
@@ -40,6 +41,7 @@
4041
"@types/jsdom": "^16.2.14",
4142
"@types/lodash-es": "^4.17.6",
4243
"@types/node": "^16.11.41",
44+
"@types/uuid": "^8.3.4",
4345
"@vitejs/plugin-vue": "^2.3.3",
4446
"@vue/eslint-config-prettier": "^7.0.0",
4547
"@vue/eslint-config-typescript": "^11.0.0",

src/App.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
<script setup lang="ts">
2-
import TheNavbar from "./components/TheNavbar.vue";
3-
import TheDrawer from "./components/TheDrawer.vue";</script>
2+
// import TheNavbar from "./components/TheNavbar.vue";
3+
// import TheAlerts from "./components/TheAlerts.vue";
4+
// import TheDrawer from "./components/TheDrawer.vue";
5+
</script>
46

57
<template>
68
<TheNavbar />
79
<TheDrawer />
10+
<TheAlerts />
811
</template>

src/components/TheAlerts.vue

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<script lang="ts" setup>
2+
import { useAlerts } from "@/stores/alerts";
3+
import { Fade } from "@progress/kendo-vue-animation";
4+
import {
5+
Notification,
6+
NotificationGroup,
7+
} from "@progress/kendo-vue-notification";
8+
import { storeToRefs } from "pinia";
9+
import { reactive } from "vue";
10+
11+
const store = useAlerts();
12+
const { notify, remove } = store;
13+
14+
const { items } = storeToRefs(store);
15+
</script>
16+
17+
<template>
18+
<div class="z-10">
19+
<NotificationGroup
20+
:style="{
21+
right: '10px',
22+
bottom: '10px',
23+
alignItems: 'flex-start',
24+
flexWrap: 'wrap-reverse',
25+
}"
26+
>
27+
<Fade v-for="alert in items" :key="alert.id" appear>
28+
<Notification
29+
:type="{
30+
style: alert.style,
31+
icon: true,
32+
}"
33+
:closable="alert.closable"
34+
@close="remove(alert.id)"
35+
>
36+
<div v-if="alert.html" v-html="alert.message"></div>
37+
<span v-else>{{ alert.message }}</span>
38+
</Notification>
39+
</Fade>
40+
</NotificationGroup>
41+
</div>
42+
</template>

src/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { createApp } from "vue";
2+
import { createPinia } from "pinia";
23
import App from "./App.vue";
34
import router from "./router";
45
import "@/assets/base.css";
56
import "@progress/kendo-theme-default/dist/all.css";
67

78
const app = createApp(App);
89

9-
app.use(router);
10+
app.use(router).use(createPinia());
1011

1112
app.mount("#app");

src/pages/boards/index.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup lang="ts">
2+
import { useAlerts } from "@/stores/alerts";
23
import type { Board } from "@/types";
34
import { ref } from "vue";
45
const boards = ref<Partial<Board>[]>([
@@ -25,13 +26,15 @@ const boards = ref<Partial<Board>[]>([
2526
},
2627
]);
2728
29+
const alerts = useAlerts();
30+
2831
function createBoard() {
29-
console.log("board created");
32+
alerts.success("Board created!");
3033
}
3134
</script>
3235

3336
<template>
34-
<h1 class="text-3xl mb-5">Boards</h1>
37+
<h1 class="mb-5 text-3xl">Boards</h1>
3538
<div class="flex">
3639
<BoardCard v-for="board in boards" :key="board.id" :board="board" />
3740
<button class="text-gray-500" @click="createBoard()">

src/stores/alerts.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { acceptHMRUpdate, defineStore } from "pinia";
2+
import { v4 as uuid } from "uuid";
3+
4+
export type AlertStyle = "error" | "success" | "warning" | "info" | "none";
5+
6+
export interface AlertOptions {
7+
html?: boolean;
8+
closable?: boolean;
9+
timeout?: number | false;
10+
style?: AlertStyle;
11+
}
12+
13+
const defaultOptions: Required<AlertOptions> = {
14+
closable: true,
15+
html: false,
16+
timeout: 3000,
17+
style: "info",
18+
};
19+
20+
export interface Alert extends AlertOptions {
21+
id: string;
22+
message: string;
23+
}
24+
25+
export const useAlerts = defineStore("alerts", {
26+
state: () => ({
27+
items: [] as Alert[],
28+
}),
29+
30+
actions: {
31+
notify(message: string, style: AlertStyle, options?: AlertOptions) {
32+
options = { ...defaultOptions, style, ...options };
33+
34+
const id = uuid();
35+
this.items.push({
36+
message,
37+
id,
38+
...options,
39+
});
40+
41+
if (options.timeout !== false) {
42+
setTimeout(() => {
43+
this.remove(id);
44+
}, options.timeout);
45+
}
46+
},
47+
48+
success(message: string, options?: AlertOptions) {
49+
this.notify(message, "success", options);
50+
},
51+
52+
error(message: string, options?: AlertOptions) {
53+
this.notify(message, "error", options);
54+
},
55+
56+
warning(message: string, options?: AlertOptions) {
57+
this.notify(message, "warning", options);
58+
},
59+
60+
info(message: string, options?: AlertOptions) {
61+
this.notify(message, "info", options);
62+
},
63+
64+
remove(id: string) {
65+
const index = this.items.findIndex((item) => item.id === id);
66+
if (index > -1) {
67+
this.items.splice(index, 1);
68+
}
69+
},
70+
},
71+
});
72+
73+
if (import.meta.hot) {
74+
import.meta.hot.accept(acceptHMRUpdate(useAlerts, import.meta.hot));
75+
}

0 commit comments

Comments
 (0)