appsalutely 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +21 -0
- package/README.md +3 -0
- package/dist/components/AppBase.vue.d.ts +23 -0
- package/dist/components/DashboardPage.vue.d.ts +20 -0
- package/dist/components/FooterSection.vue.d.ts +12 -0
- package/dist/components/LoginForm.vue.d.ts +24 -0
- package/dist/components/NavDrawerLink.vue.d.ts +8 -0
- package/dist/components/OTPForm.vue.d.ts +27 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +381 -0
- package/dist/index.umd.cjs +1 -0
- package/dist/stores/colorMode.d.ts +11 -0
- package/dist/stores/footer.d.ts +98 -0
- package/dist/stores/notify.d.ts +62 -0
- package/package.json +2 -1
- package/vite.config.d.ts +3 -0
- package/vite.config.js +25 -0
- package/src/components/AppBase.vue +0 -139
- package/src/components/DashboardPage.vue +0 -22
- package/src/components/FooterSection.vue +0 -6
- package/src/components/LoginForm.vue +0 -56
- package/src/components/NavDrawerLink.vue +0 -18
- package/src/components/OTPForm.vue +0 -54
- package/src/index.ts +0 -22
- package/src/stores/colorMode.ts +0 -16
- package/src/stores/footer.ts +0 -41
- package/src/stores/notify.ts +0 -51
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Merlin Zimmerman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type __VLS_PublicProps = {
|
|
2
|
+
'drawerOpen'?: boolean;
|
|
3
|
+
};
|
|
4
|
+
declare var __VLS_14: {}, __VLS_40: {}, __VLS_50: {};
|
|
5
|
+
type __VLS_Slots = {} & {
|
|
6
|
+
header?: (props: typeof __VLS_14) => any;
|
|
7
|
+
} & {
|
|
8
|
+
footer?: (props: typeof __VLS_40) => any;
|
|
9
|
+
} & {
|
|
10
|
+
drawer?: (props: typeof __VLS_50) => any;
|
|
11
|
+
};
|
|
12
|
+
declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
13
|
+
"update:drawerOpen": (value: boolean) => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
15
|
+
"onUpdate:drawerOpen"?: ((value: boolean) => any) | undefined;
|
|
16
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
18
|
+
export default _default;
|
|
19
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
20
|
+
new (): {
|
|
21
|
+
$slots: S;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { VBreadcrumbs } from 'vuetify/components';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
breadcrumbs?: VBreadcrumbs['$props']['items'];
|
|
4
|
+
fluid?: boolean;
|
|
5
|
+
title?: string;
|
|
6
|
+
};
|
|
7
|
+
declare var __VLS_10: {};
|
|
8
|
+
type __VLS_Slots = {} & {
|
|
9
|
+
default?: (props: typeof __VLS_10) => any;
|
|
10
|
+
};
|
|
11
|
+
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
12
|
+
fluid: boolean;
|
|
13
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
15
|
+
export default _default;
|
|
16
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
17
|
+
new (): {
|
|
18
|
+
$slots: S;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare var __VLS_1: {};
|
|
2
|
+
type __VLS_Slots = {} & {
|
|
3
|
+
default?: (props: typeof __VLS_1) => any;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
6
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
7
|
+
export default _default;
|
|
8
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
9
|
+
new (): {
|
|
10
|
+
$slots: S;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
title?: string;
|
|
3
|
+
submitButtonText?: string;
|
|
4
|
+
minWidth?: string | number;
|
|
5
|
+
maxWidth?: string | number;
|
|
6
|
+
loading?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type __VLS_PublicProps = __VLS_Props & {
|
|
9
|
+
'username'?: string;
|
|
10
|
+
'password'?: string;
|
|
11
|
+
};
|
|
12
|
+
declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
13
|
+
submit: (args_0: string, args_1: string) => any;
|
|
14
|
+
"update:username": (value: string) => any;
|
|
15
|
+
"update:password": (value: string) => any;
|
|
16
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
17
|
+
onSubmit?: ((args_0: string, args_1: string) => any) | undefined;
|
|
18
|
+
"onUpdate:username"?: ((value: string) => any) | undefined;
|
|
19
|
+
"onUpdate:password"?: ((value: string) => any) | undefined;
|
|
20
|
+
}>, {
|
|
21
|
+
title: string;
|
|
22
|
+
submitButtonText: string;
|
|
23
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
24
|
+
export default _default;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RouteLocationRaw } from 'vue-router';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
to: RouteLocationRaw;
|
|
4
|
+
icon: string;
|
|
5
|
+
text: string;
|
|
6
|
+
};
|
|
7
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
8
|
+
export default _default;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
title?: string;
|
|
3
|
+
subtitle?: string;
|
|
4
|
+
submitButtonText?: string;
|
|
5
|
+
minWidth?: string | number;
|
|
6
|
+
maxWidth?: string | number;
|
|
7
|
+
loading?: boolean;
|
|
8
|
+
length?: number;
|
|
9
|
+
autosubmit?: boolean;
|
|
10
|
+
};
|
|
11
|
+
type __VLS_PublicProps = __VLS_Props & {
|
|
12
|
+
'otp'?: string;
|
|
13
|
+
};
|
|
14
|
+
declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
15
|
+
submit: (args_0: string) => any;
|
|
16
|
+
"update:otp": (value: string) => any;
|
|
17
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
18
|
+
onSubmit?: ((args_0: string) => any) | undefined;
|
|
19
|
+
"onUpdate:otp"?: ((value: string) => any) | undefined;
|
|
20
|
+
}>, {
|
|
21
|
+
length: number;
|
|
22
|
+
title: string;
|
|
23
|
+
subtitle: string;
|
|
24
|
+
submitButtonText: string;
|
|
25
|
+
autosubmit: boolean;
|
|
26
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
27
|
+
export default _default;
|
package/dist/index.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
html{overflow:auto}html[data-theme=dark]{color-scheme:dark}html[data-theme=light]{color-scheme:light}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import AppBase from './components/AppBase.vue';
|
|
2
|
+
import DashboardPage from './components/DashboardPage.vue';
|
|
3
|
+
import FooterSection from './components/FooterSection.vue';
|
|
4
|
+
import LoginForm from './components/LoginForm.vue';
|
|
5
|
+
import NavDrawerLink from './components/NavDrawerLink.vue';
|
|
6
|
+
import OTPForm from './components/OTPForm.vue';
|
|
7
|
+
import useColorMode from './stores/colorMode';
|
|
8
|
+
import useFooter from './stores/footer';
|
|
9
|
+
import useNotify from './stores/notify';
|
|
10
|
+
export { AppBase, DashboardPage, FooterSection, LoginForm, NavDrawerLink, OTPForm, useColorMode, useFooter, useNotify, };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import { ref as v, watch as S, computed as P, defineComponent as k, useModel as B, useSlots as A, onBeforeMount as E, createBlock as f, openBlock as m, unref as t, withCtx as s, createCommentVNode as h, createVNode as d, createElementBlock as w, renderSlot as V, createElementVNode as b, normalizeClass as j, toDisplayString as M, Fragment as T, renderList as F, normalizeStyle as z, mergeModels as C, withModifiers as U } from "vue";
|
|
2
|
+
import { useRouter as q, RouterView as R } from "vue-router";
|
|
3
|
+
import { VApp as G, VProgressLinear as H, VAppBar as O, VMain as J, VFooter as K, VBtn as x, VNavigationDrawer as Q, VList as X, VSnackbar as Y, VContainer as Z, VBreadcrumbs as ee, VCard as W, VForm as I, VCardText as N, VTextField as L, VListItem as te, VIcon as oe, VOtpInput as le } from "vuetify/components";
|
|
4
|
+
import { defineStore as D } from "pinia";
|
|
5
|
+
const ne = D("colorMode", () => {
|
|
6
|
+
const o = v(localStorage.getItem("colorMode") == "dark" ? "dark" : "light");
|
|
7
|
+
function n() {
|
|
8
|
+
o.value = o.value === "dark" ? "light" : "dark";
|
|
9
|
+
}
|
|
10
|
+
function l(r) {
|
|
11
|
+
localStorage.setItem("colorMode", r), document.documentElement.setAttribute("data-theme", r);
|
|
12
|
+
}
|
|
13
|
+
return S(o, (r) => l(r)), l(o.value), { mode: o, toggle: n };
|
|
14
|
+
}), re = D("footer", () => {
|
|
15
|
+
const o = v([]), n = P(() => o.value.length > 0 ? o.value[o.value.length - 1] : null);
|
|
16
|
+
function l(a) {
|
|
17
|
+
return a.id || (a.id = (/* @__PURE__ */ new Date()).getTime().toString()), a.timeout === void 0 && (a.timeout = 5e3), o.value.push(a), a.timeout && setTimeout(() => {
|
|
18
|
+
r(a.id);
|
|
19
|
+
}, a.timeout), a.id;
|
|
20
|
+
}
|
|
21
|
+
function r(a) {
|
|
22
|
+
o.value = o.value.filter((c) => c.id !== a);
|
|
23
|
+
}
|
|
24
|
+
return { messages: o, current: n, addMessage: l, removeMessage: r };
|
|
25
|
+
}), ae = D("notify", () => {
|
|
26
|
+
const o = v([]), n = v({});
|
|
27
|
+
function l(e) {
|
|
28
|
+
return e.id ? r(e.id) : e.id = (/* @__PURE__ */ new Date()).getTime().toString(), e.timeout === void 0 && (e.timeout = 5e3), o.value.push(e), e.timeout && (n.value[e.id] = setTimeout(() => {
|
|
29
|
+
r(e.id);
|
|
30
|
+
}, e.timeout)), e.id;
|
|
31
|
+
}
|
|
32
|
+
function r(e) {
|
|
33
|
+
o.value = o.value.filter((_) => _.id !== e), n.value[e] && (clearTimeout(n.value[e]), delete n.value[e]);
|
|
34
|
+
}
|
|
35
|
+
function a(e) {
|
|
36
|
+
return l({ text: e, type: "info" });
|
|
37
|
+
}
|
|
38
|
+
function c(e) {
|
|
39
|
+
return l({ text: e, type: "success" });
|
|
40
|
+
}
|
|
41
|
+
function u(e) {
|
|
42
|
+
return l({ text: e, type: "warning" });
|
|
43
|
+
}
|
|
44
|
+
function i(e) {
|
|
45
|
+
return l({ text: e, type: "error" });
|
|
46
|
+
}
|
|
47
|
+
return { messages: o, add: l, remove: r, info: a, success: c, warning: u, error: i };
|
|
48
|
+
}), ue = { class: "d-flex flex-column pa-4 h-100" }, ie = ["textContent"], xe = /* @__PURE__ */ k({
|
|
49
|
+
__name: "AppBase",
|
|
50
|
+
props: {
|
|
51
|
+
drawerOpen: { type: Boolean, default: !1 },
|
|
52
|
+
drawerOpenModifiers: {}
|
|
53
|
+
},
|
|
54
|
+
emits: ["update:drawerOpen"],
|
|
55
|
+
setup(o) {
|
|
56
|
+
const n = ne(), l = B(o, "drawerOpen"), r = v(!1), a = re(), c = v(!1), u = v(null), i = ae(), e = q(), _ = A();
|
|
57
|
+
return S(r, (g) => {
|
|
58
|
+
localStorage.setItem("drawerDocked", String(g));
|
|
59
|
+
}), E(() => {
|
|
60
|
+
e.beforeEach(() => {
|
|
61
|
+
u.value = setTimeout(() => {
|
|
62
|
+
c.value = !0;
|
|
63
|
+
}, 300);
|
|
64
|
+
}), e.afterEach(() => {
|
|
65
|
+
u.value && (clearTimeout(u.value), u.value = null), c.value = !1;
|
|
66
|
+
}), r.value = localStorage.getItem("drawerDocked") === "true", l.value = r.value;
|
|
67
|
+
}), (g, y) => (m(), f(t(G), {
|
|
68
|
+
theme: t(n).mode
|
|
69
|
+
}, {
|
|
70
|
+
default: s(() => [
|
|
71
|
+
c.value ? (m(), f(t(H), {
|
|
72
|
+
key: 0,
|
|
73
|
+
indeterminate: "",
|
|
74
|
+
class: "mb-n1",
|
|
75
|
+
style: { "z-index": "100000", opacity: "0.5" },
|
|
76
|
+
height: "1"
|
|
77
|
+
})) : h("", !0),
|
|
78
|
+
d(t(O), { height: "64" }, {
|
|
79
|
+
default: s(() => [
|
|
80
|
+
V(g.$slots, "header")
|
|
81
|
+
]),
|
|
82
|
+
_: 3
|
|
83
|
+
}),
|
|
84
|
+
d(t(J), { class: "bg-surface-light" }, {
|
|
85
|
+
default: s(() => [
|
|
86
|
+
b("div", ue, [
|
|
87
|
+
d(t(R))
|
|
88
|
+
])
|
|
89
|
+
]),
|
|
90
|
+
_: 1
|
|
91
|
+
}),
|
|
92
|
+
t(_).footer ? (m(), f(t(O), {
|
|
93
|
+
key: 1,
|
|
94
|
+
height: "40",
|
|
95
|
+
location: "bottom"
|
|
96
|
+
}, {
|
|
97
|
+
default: s(() => [
|
|
98
|
+
d(t(K), { class: "py-0 w-100 d-flex align-center" }, {
|
|
99
|
+
default: s(() => [
|
|
100
|
+
t(a).current ? (m(), w("span", {
|
|
101
|
+
key: 0,
|
|
102
|
+
textContent: M(t(a).current.text),
|
|
103
|
+
class: j([t(a).current.type ? {} : { ["text-" + t(a).current.type]: !0 }, "overflow-hidden text-no-wrap"]),
|
|
104
|
+
style: { "text-overflow": "ellipsis" }
|
|
105
|
+
}, null, 10, ie)) : h("", !0),
|
|
106
|
+
t(a).current && t(a).current.actions ? (m(!0), w(T, { key: 1 }, F(Object.entries(t(a).current.actions), (p, $) => (m(), f(t(x), {
|
|
107
|
+
text: p[0],
|
|
108
|
+
onClick: p[1],
|
|
109
|
+
key: $,
|
|
110
|
+
density: "comfortable",
|
|
111
|
+
variant: "tonal",
|
|
112
|
+
class: "mx-2 px-2 text-none",
|
|
113
|
+
color: t(a).current.type
|
|
114
|
+
}, null, 8, ["text", "onClick", "color"]))), 128)) : h("", !0),
|
|
115
|
+
y[2] || (y[2] = b("div", { class: "me-auto" }, null, -1)),
|
|
116
|
+
V(g.$slots, "footer")
|
|
117
|
+
]),
|
|
118
|
+
_: 3,
|
|
119
|
+
__: [2]
|
|
120
|
+
})
|
|
121
|
+
]),
|
|
122
|
+
_: 3
|
|
123
|
+
})) : h("", !0),
|
|
124
|
+
t(_).drawer ? (m(), f(t(Q), {
|
|
125
|
+
key: 2,
|
|
126
|
+
modelValue: l.value,
|
|
127
|
+
"onUpdate:modelValue": y[1] || (y[1] = (p) => l.value = p),
|
|
128
|
+
width: "250",
|
|
129
|
+
"rail-width": "58",
|
|
130
|
+
rail: r.value,
|
|
131
|
+
mobile: r.value ? !1 : void 0
|
|
132
|
+
}, {
|
|
133
|
+
default: s(() => [
|
|
134
|
+
d(t(X), { class: "h-100 d-flex flex-column" }, {
|
|
135
|
+
default: s(() => [
|
|
136
|
+
V(g.$slots, "drawer"),
|
|
137
|
+
d(t(x), {
|
|
138
|
+
onClick: y[0] || (y[0] = (p) => r.value = !r.value),
|
|
139
|
+
icon: "mdi-pin-outline",
|
|
140
|
+
rounded: "rounded",
|
|
141
|
+
density: "comfortable",
|
|
142
|
+
title: r.value ? "Undock sidebar" : "Dock sidebar",
|
|
143
|
+
class: "my-1 mx-3 ms-auto",
|
|
144
|
+
variant: r.value ? "tonal" : "text"
|
|
145
|
+
}, null, 8, ["title", "variant"])
|
|
146
|
+
]),
|
|
147
|
+
_: 3
|
|
148
|
+
})
|
|
149
|
+
]),
|
|
150
|
+
_: 3
|
|
151
|
+
}, 8, ["modelValue", "rail", "mobile"])) : h("", !0),
|
|
152
|
+
(m(!0), w(T, null, F(t(i).messages, (p, $) => (m(), f(t(Y), {
|
|
153
|
+
key: $,
|
|
154
|
+
"model-value": !0,
|
|
155
|
+
text: p.text,
|
|
156
|
+
color: p.type,
|
|
157
|
+
location: "bottom end",
|
|
158
|
+
style: z({ bottom: `${$ * 56}px` }),
|
|
159
|
+
timeout: -1
|
|
160
|
+
}, {
|
|
161
|
+
actions: s(() => [
|
|
162
|
+
d(t(x), {
|
|
163
|
+
icon: "mdi-close",
|
|
164
|
+
onClick: (be) => t(i).remove(p.id)
|
|
165
|
+
}, null, 8, ["onClick"])
|
|
166
|
+
]),
|
|
167
|
+
_: 2
|
|
168
|
+
}, 1032, ["text", "color", "style"]))), 128))
|
|
169
|
+
]),
|
|
170
|
+
_: 3
|
|
171
|
+
}, 8, ["theme"]));
|
|
172
|
+
}
|
|
173
|
+
}), se = ["textContent"], ke = /* @__PURE__ */ k({
|
|
174
|
+
__name: "DashboardPage",
|
|
175
|
+
props: {
|
|
176
|
+
breadcrumbs: {},
|
|
177
|
+
fluid: { type: Boolean, default: !0 },
|
|
178
|
+
title: {}
|
|
179
|
+
},
|
|
180
|
+
setup(o) {
|
|
181
|
+
return (n, l) => (m(), f(t(Z), {
|
|
182
|
+
fluid: n.fluid,
|
|
183
|
+
class: "h-100 d-flex flex-column py-0 h-100"
|
|
184
|
+
}, {
|
|
185
|
+
default: s(() => [
|
|
186
|
+
n.breadcrumbs ? (m(), f(t(ee), {
|
|
187
|
+
key: 0,
|
|
188
|
+
items: n.breadcrumbs,
|
|
189
|
+
density: "comfortable",
|
|
190
|
+
class: "pa-0"
|
|
191
|
+
}, null, 8, ["items"])) : h("", !0),
|
|
192
|
+
n.title ? (m(), w("h1", {
|
|
193
|
+
key: 1,
|
|
194
|
+
textContent: M(n.title),
|
|
195
|
+
class: "text-h5 font-bold ma-1"
|
|
196
|
+
}, null, 8, se)) : h("", !0),
|
|
197
|
+
V(n.$slots, "default")
|
|
198
|
+
]),
|
|
199
|
+
_: 3
|
|
200
|
+
}, 8, ["fluid"]));
|
|
201
|
+
}
|
|
202
|
+
}), de = (o, n) => {
|
|
203
|
+
const l = o.__vccOpts || o;
|
|
204
|
+
for (const [r, a] of n)
|
|
205
|
+
l[r] = a;
|
|
206
|
+
return l;
|
|
207
|
+
}, me = {}, ce = { class: "h-100 d-flex align-center" };
|
|
208
|
+
function fe(o, n) {
|
|
209
|
+
return m(), w(T, null, [
|
|
210
|
+
n[0] || (n[0] = b("span", {
|
|
211
|
+
class: "border-s mx-3",
|
|
212
|
+
style: { height: "32px" }
|
|
213
|
+
}, null, -1)),
|
|
214
|
+
b("span", ce, [
|
|
215
|
+
V(o.$slots, "default")
|
|
216
|
+
])
|
|
217
|
+
], 64);
|
|
218
|
+
}
|
|
219
|
+
const _e = /* @__PURE__ */ de(me, [["render", fe]]), pe = { class: "d-flex justify-center" }, $e = /* @__PURE__ */ k({
|
|
220
|
+
__name: "LoginForm",
|
|
221
|
+
props: /* @__PURE__ */ C({
|
|
222
|
+
title: { default: "Login" },
|
|
223
|
+
submitButtonText: { default: "Login" },
|
|
224
|
+
minWidth: {},
|
|
225
|
+
maxWidth: {},
|
|
226
|
+
loading: { type: Boolean }
|
|
227
|
+
}, {
|
|
228
|
+
username: { default: "" },
|
|
229
|
+
usernameModifiers: {},
|
|
230
|
+
password: { default: "" },
|
|
231
|
+
passwordModifiers: {}
|
|
232
|
+
}),
|
|
233
|
+
emits: /* @__PURE__ */ C(["submit"], ["update:username", "update:password"]),
|
|
234
|
+
setup(o, { emit: n }) {
|
|
235
|
+
const l = B(o, "username"), r = B(o, "password"), a = n, c = v(!1);
|
|
236
|
+
return (u, i) => (m(), f(t(W), {
|
|
237
|
+
title: u.title,
|
|
238
|
+
"min-width": u.minWidth,
|
|
239
|
+
"max-width": u.maxWidth
|
|
240
|
+
}, {
|
|
241
|
+
default: s(() => [
|
|
242
|
+
d(t(I), {
|
|
243
|
+
onSubmit: i[2] || (i[2] = U((e) => a("submit", l.value, r.value), ["prevent"])),
|
|
244
|
+
modelValue: c.value,
|
|
245
|
+
"onUpdate:modelValue": i[3] || (i[3] = (e) => c.value = e)
|
|
246
|
+
}, {
|
|
247
|
+
default: s(() => [
|
|
248
|
+
d(t(N), null, {
|
|
249
|
+
default: s(() => [
|
|
250
|
+
d(t(L), {
|
|
251
|
+
modelValue: l.value,
|
|
252
|
+
"onUpdate:modelValue": i[0] || (i[0] = (e) => l.value = e),
|
|
253
|
+
label: "Username",
|
|
254
|
+
rules: [(e) => !!e || "Username is required"],
|
|
255
|
+
"persistent-placeholder": "",
|
|
256
|
+
autofocus: ""
|
|
257
|
+
}, null, 8, ["modelValue", "rules"]),
|
|
258
|
+
d(t(L), {
|
|
259
|
+
modelValue: r.value,
|
|
260
|
+
"onUpdate:modelValue": i[1] || (i[1] = (e) => r.value = e),
|
|
261
|
+
label: "Password",
|
|
262
|
+
type: "password",
|
|
263
|
+
rules: [(e) => !!e || "Password is required"],
|
|
264
|
+
"persistent-placeholder": ""
|
|
265
|
+
}, null, 8, ["modelValue", "rules"]),
|
|
266
|
+
b("div", pe, [
|
|
267
|
+
d(t(x), {
|
|
268
|
+
disabled: !c.value,
|
|
269
|
+
type: "submit",
|
|
270
|
+
color: "primary",
|
|
271
|
+
variant: "flat",
|
|
272
|
+
text: u.submitButtonText,
|
|
273
|
+
loading: u.loading
|
|
274
|
+
}, null, 8, ["disabled", "text", "loading"])
|
|
275
|
+
])
|
|
276
|
+
]),
|
|
277
|
+
_: 1
|
|
278
|
+
})
|
|
279
|
+
]),
|
|
280
|
+
_: 1
|
|
281
|
+
}, 8, ["modelValue"])
|
|
282
|
+
]),
|
|
283
|
+
_: 1
|
|
284
|
+
}, 8, ["title", "min-width", "max-width"]));
|
|
285
|
+
}
|
|
286
|
+
}), ve = { class: "text-no-wrap overflow-hidden" }, Be = /* @__PURE__ */ k({
|
|
287
|
+
__name: "NavDrawerLink",
|
|
288
|
+
props: {
|
|
289
|
+
to: {},
|
|
290
|
+
icon: {},
|
|
291
|
+
text: {}
|
|
292
|
+
},
|
|
293
|
+
setup(o) {
|
|
294
|
+
return (n, l) => (m(), f(t(te), {
|
|
295
|
+
role: "option",
|
|
296
|
+
to: n.to,
|
|
297
|
+
slim: ""
|
|
298
|
+
}, {
|
|
299
|
+
prepend: s(() => [
|
|
300
|
+
d(t(oe), { icon: n.icon }, null, 8, ["icon"])
|
|
301
|
+
]),
|
|
302
|
+
default: s(() => [
|
|
303
|
+
b("span", ve, M(n.text), 1)
|
|
304
|
+
]),
|
|
305
|
+
_: 1
|
|
306
|
+
}, 8, ["to"]));
|
|
307
|
+
}
|
|
308
|
+
}), he = { class: "d-flex justify-center" }, Ce = /* @__PURE__ */ k({
|
|
309
|
+
__name: "OTPForm",
|
|
310
|
+
props: /* @__PURE__ */ C({
|
|
311
|
+
title: { default: "2FA Verification" },
|
|
312
|
+
subtitle: { default: "Enter the code from your authenticator app" },
|
|
313
|
+
submitButtonText: { default: "Verify" },
|
|
314
|
+
minWidth: {},
|
|
315
|
+
maxWidth: {},
|
|
316
|
+
loading: { type: Boolean },
|
|
317
|
+
length: { default: 6 },
|
|
318
|
+
autosubmit: { type: Boolean, default: !0 }
|
|
319
|
+
}, {
|
|
320
|
+
otp: { default: "" },
|
|
321
|
+
otpModifiers: {}
|
|
322
|
+
}),
|
|
323
|
+
emits: /* @__PURE__ */ C(["submit"], ["update:otp"]),
|
|
324
|
+
setup(o, { emit: n }) {
|
|
325
|
+
const l = B(o, "otp"), r = n, a = o, c = P(() => l.value.length === a.length);
|
|
326
|
+
return S(l, () => {
|
|
327
|
+
a.autosubmit && l.value.length === a.length && r("submit", l.value);
|
|
328
|
+
}), (u, i) => (m(), f(t(W), {
|
|
329
|
+
title: u.title,
|
|
330
|
+
subtitle: u.subtitle,
|
|
331
|
+
"min-width": u.minWidth,
|
|
332
|
+
"max-width": u.maxWidth
|
|
333
|
+
}, {
|
|
334
|
+
default: s(() => [
|
|
335
|
+
d(t(I), {
|
|
336
|
+
onSubmit: i[1] || (i[1] = U((e) => r("submit", l.value), ["prevent"])),
|
|
337
|
+
"model-value": c.value
|
|
338
|
+
}, {
|
|
339
|
+
default: s(() => [
|
|
340
|
+
d(t(N), null, {
|
|
341
|
+
default: s(() => [
|
|
342
|
+
d(t(le), {
|
|
343
|
+
modelValue: l.value,
|
|
344
|
+
"onUpdate:modelValue": i[0] || (i[0] = (e) => l.value = e),
|
|
345
|
+
label: "OTP",
|
|
346
|
+
"persistent-placeholder": "",
|
|
347
|
+
autofocus: "",
|
|
348
|
+
length: u.length
|
|
349
|
+
}, null, 8, ["modelValue", "length"]),
|
|
350
|
+
b("div", he, [
|
|
351
|
+
d(t(x), {
|
|
352
|
+
disabled: !c.value,
|
|
353
|
+
type: "submit",
|
|
354
|
+
color: "primary",
|
|
355
|
+
variant: "flat",
|
|
356
|
+
text: u.submitButtonText,
|
|
357
|
+
loading: u.loading
|
|
358
|
+
}, null, 8, ["disabled", "text", "loading"])
|
|
359
|
+
])
|
|
360
|
+
]),
|
|
361
|
+
_: 1
|
|
362
|
+
})
|
|
363
|
+
]),
|
|
364
|
+
_: 1
|
|
365
|
+
}, 8, ["model-value"])
|
|
366
|
+
]),
|
|
367
|
+
_: 1
|
|
368
|
+
}, 8, ["title", "subtitle", "min-width", "max-width"]));
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
export {
|
|
372
|
+
xe as AppBase,
|
|
373
|
+
ke as DashboardPage,
|
|
374
|
+
_e as FooterSection,
|
|
375
|
+
$e as LoginForm,
|
|
376
|
+
Be as NavDrawerLink,
|
|
377
|
+
Ce as OTPForm,
|
|
378
|
+
ne as useColorMode,
|
|
379
|
+
re as useFooter,
|
|
380
|
+
ae as useNotify
|
|
381
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(s,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue"),require("vue-router"),require("vuetify/components"),require("pinia")):typeof define=="function"&&define.amd?define(["exports","vue","vue-router","vuetify/components","pinia"],e):(s=typeof globalThis<"u"?globalThis:s||self,e(s.appsalutely={},s.Vue,s.VueRouter,s.VuetifyComponents,s.Pinia))})(this,function(s,e,y,i,w){"use strict";const k=w.defineStore("colorMode",()=>{const o=e.ref(localStorage.getItem("colorMode")=="dark"?"dark":"light");function l(){o.value=o.value==="dark"?"light":"dark"}function r(n){localStorage.setItem("colorMode",n),document.documentElement.setAttribute("data-theme",n)}return e.watch(o,n=>r(n)),r(o.value),{mode:o,toggle:l}}),b=w.defineStore("footer",()=>{const o=e.ref([]),l=e.computed(()=>o.value.length>0?o.value[o.value.length-1]:null);function r(a){return a.id||(a.id=new Date().getTime().toString()),a.timeout===void 0&&(a.timeout=5e3),o.value.push(a),a.timeout&&setTimeout(()=>{n(a.id)},a.timeout),a.id}function n(a){o.value=o.value.filter(f=>f.id!==a)}return{messages:o,current:l,addMessage:r,removeMessage:n}}),B=w.defineStore("notify",()=>{const o=e.ref([]),l=e.ref({});function r(t){return t.id?n(t.id):t.id=new Date().getTime().toString(),t.timeout===void 0&&(t.timeout=5e3),o.value.push(t),t.timeout&&(l.value[t.id]=setTimeout(()=>{n(t.id)},t.timeout)),t.id}function n(t){o.value=o.value.filter(h=>h.id!==t),l.value[t]&&(clearTimeout(l.value[t]),delete l.value[t])}function a(t){return r({text:t,type:"info"})}function f(t){return r({text:t,type:"success"})}function d(t){return r({text:t,type:"warning"})}function u(t){return r({text:t,type:"error"})}return{messages:o,add:r,remove:n,info:a,success:f,warning:d,error:u}}),g={class:"d-flex flex-column pa-4 h-100"},x=["textContent"],C=e.defineComponent({__name:"AppBase",props:{drawerOpen:{type:Boolean,default:!1},drawerOpenModifiers:{}},emits:["update:drawerOpen"],setup(o){const l=k(),r=e.useModel(o,"drawerOpen"),n=e.ref(!1),a=b(),f=e.ref(!1),d=e.ref(null),u=B(),t=y.useRouter(),h=e.useSlots();return e.watch(n,p=>{localStorage.setItem("drawerDocked",String(p))}),e.onBeforeMount(()=>{t.beforeEach(()=>{d.value=setTimeout(()=>{f.value=!0},300)}),t.afterEach(()=>{d.value&&(clearTimeout(d.value),d.value=null),f.value=!1}),n.value=localStorage.getItem("drawerDocked")==="true",r.value=n.value}),(p,m)=>(e.openBlock(),e.createBlock(e.unref(i.VApp),{theme:e.unref(l).mode},{default:e.withCtx(()=>[f.value?(e.openBlock(),e.createBlock(e.unref(i.VProgressLinear),{key:0,indeterminate:"",class:"mb-n1",style:{"z-index":"100000",opacity:"0.5"},height:"1"})):e.createCommentVNode("",!0),e.createVNode(e.unref(i.VAppBar),{height:"64"},{default:e.withCtx(()=>[e.renderSlot(p.$slots,"header")]),_:3}),e.createVNode(e.unref(i.VMain),{class:"bg-surface-light"},{default:e.withCtx(()=>[e.createElementVNode("div",g,[e.createVNode(e.unref(y.RouterView))])]),_:1}),e.unref(h).footer?(e.openBlock(),e.createBlock(e.unref(i.VAppBar),{key:1,height:"40",location:"bottom"},{default:e.withCtx(()=>[e.createVNode(e.unref(i.VFooter),{class:"py-0 w-100 d-flex align-center"},{default:e.withCtx(()=>[e.unref(a).current?(e.openBlock(),e.createElementBlock("span",{key:0,textContent:e.toDisplayString(e.unref(a).current.text),class:e.normalizeClass([e.unref(a).current.type?{}:{["text-"+e.unref(a).current.type]:!0},"overflow-hidden text-no-wrap"]),style:{"text-overflow":"ellipsis"}},null,10,x)):e.createCommentVNode("",!0),e.unref(a).current&&e.unref(a).current.actions?(e.openBlock(!0),e.createElementBlock(e.Fragment,{key:1},e.renderList(Object.entries(e.unref(a).current.actions),(c,V)=>(e.openBlock(),e.createBlock(e.unref(i.VBtn),{text:c[0],onClick:c[1],key:V,density:"comfortable",variant:"tonal",class:"mx-2 px-2 text-none",color:e.unref(a).current.type},null,8,["text","onClick","color"]))),128)):e.createCommentVNode("",!0),m[2]||(m[2]=e.createElementVNode("div",{class:"me-auto"},null,-1)),e.renderSlot(p.$slots,"footer")]),_:3,__:[2]})]),_:3})):e.createCommentVNode("",!0),e.unref(h).drawer?(e.openBlock(),e.createBlock(e.unref(i.VNavigationDrawer),{key:2,modelValue:r.value,"onUpdate:modelValue":m[1]||(m[1]=c=>r.value=c),width:"250","rail-width":"58",rail:n.value,mobile:n.value?!1:void 0},{default:e.withCtx(()=>[e.createVNode(e.unref(i.VList),{class:"h-100 d-flex flex-column"},{default:e.withCtx(()=>[e.renderSlot(p.$slots,"drawer"),e.createVNode(e.unref(i.VBtn),{onClick:m[0]||(m[0]=c=>n.value=!n.value),icon:"mdi-pin-outline",rounded:"rounded",density:"comfortable",title:n.value?"Undock sidebar":"Dock sidebar",class:"my-1 mx-3 ms-auto",variant:n.value?"tonal":"text"},null,8,["title","variant"])]),_:3})]),_:3},8,["modelValue","rail","mobile"])):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(u).messages,(c,V)=>(e.openBlock(),e.createBlock(e.unref(i.VSnackbar),{key:V,"model-value":!0,text:c.text,color:c.type,location:"bottom end",style:e.normalizeStyle({bottom:`${V*56}px`}),timeout:-1},{actions:e.withCtx(()=>[e.createVNode(e.unref(i.VBtn),{icon:"mdi-close",onClick:W=>e.unref(u).remove(c.id)},null,8,["onClick"])]),_:2},1032,["text","color","style"]))),128))]),_:3},8,["theme"]))}}),N=["textContent"],S=e.defineComponent({__name:"DashboardPage",props:{breadcrumbs:{},fluid:{type:Boolean,default:!0},title:{}},setup(o){return(l,r)=>(e.openBlock(),e.createBlock(e.unref(i.VContainer),{fluid:l.fluid,class:"h-100 d-flex flex-column py-0 h-100"},{default:e.withCtx(()=>[l.breadcrumbs?(e.openBlock(),e.createBlock(e.unref(i.VBreadcrumbs),{key:0,items:l.breadcrumbs,density:"comfortable",class:"pa-0"},null,8,["items"])):e.createCommentVNode("",!0),l.title?(e.openBlock(),e.createElementBlock("h1",{key:1,textContent:e.toDisplayString(l.title),class:"text-h5 font-bold ma-1"},null,8,N)):e.createCommentVNode("",!0),e.renderSlot(l.$slots,"default")]),_:3},8,["fluid"]))}}),_=(o,l)=>{const r=o.__vccOpts||o;for(const[n,a]of l)r[n]=a;return r},M={},T={class:"h-100 d-flex align-center"};function $(o,l){return e.openBlock(),e.createElementBlock(e.Fragment,null,[l[0]||(l[0]=e.createElementVNode("span",{class:"border-s mx-3",style:{height:"32px"}},null,-1)),e.createElementVNode("span",T,[e.renderSlot(o.$slots,"default")])],64)}const F=_(M,[["render",$]]),E={class:"d-flex justify-center"},D=e.defineComponent({__name:"LoginForm",props:e.mergeModels({title:{default:"Login"},submitButtonText:{default:"Login"},minWidth:{},maxWidth:{},loading:{type:Boolean}},{username:{default:""},usernameModifiers:{},password:{default:""},passwordModifiers:{}}),emits:e.mergeModels(["submit"],["update:username","update:password"]),setup(o,{emit:l}){const r=e.useModel(o,"username"),n=e.useModel(o,"password"),a=l,f=e.ref(!1);return(d,u)=>(e.openBlock(),e.createBlock(e.unref(i.VCard),{title:d.title,"min-width":d.minWidth,"max-width":d.maxWidth},{default:e.withCtx(()=>[e.createVNode(e.unref(i.VForm),{onSubmit:u[2]||(u[2]=e.withModifiers(t=>a("submit",r.value,n.value),["prevent"])),modelValue:f.value,"onUpdate:modelValue":u[3]||(u[3]=t=>f.value=t)},{default:e.withCtx(()=>[e.createVNode(e.unref(i.VCardText),null,{default:e.withCtx(()=>[e.createVNode(e.unref(i.VTextField),{modelValue:r.value,"onUpdate:modelValue":u[0]||(u[0]=t=>r.value=t),label:"Username",rules:[t=>!!t||"Username is required"],"persistent-placeholder":"",autofocus:""},null,8,["modelValue","rules"]),e.createVNode(e.unref(i.VTextField),{modelValue:n.value,"onUpdate:modelValue":u[1]||(u[1]=t=>n.value=t),label:"Password",type:"password",rules:[t=>!!t||"Password is required"],"persistent-placeholder":""},null,8,["modelValue","rules"]),e.createElementVNode("div",E,[e.createVNode(e.unref(i.VBtn),{disabled:!f.value,type:"submit",color:"primary",variant:"flat",text:d.submitButtonText,loading:d.loading},null,8,["disabled","text","loading"])])]),_:1})]),_:1},8,["modelValue"])]),_:1},8,["title","min-width","max-width"]))}}),O={class:"text-no-wrap overflow-hidden"},L=e.defineComponent({__name:"NavDrawerLink",props:{to:{},icon:{},text:{}},setup(o){return(l,r)=>(e.openBlock(),e.createBlock(e.unref(i.VListItem),{role:"option",to:l.to,slim:""},{prepend:e.withCtx(()=>[e.createVNode(e.unref(i.VIcon),{icon:l.icon},null,8,["icon"])]),default:e.withCtx(()=>[e.createElementVNode("span",O,e.toDisplayString(l.text),1)]),_:1},8,["to"]))}}),P={class:"d-flex justify-center"},U=e.defineComponent({__name:"OTPForm",props:e.mergeModels({title:{default:"2FA Verification"},subtitle:{default:"Enter the code from your authenticator app"},submitButtonText:{default:"Verify"},minWidth:{},maxWidth:{},loading:{type:Boolean},length:{default:6},autosubmit:{type:Boolean,default:!0}},{otp:{default:""},otpModifiers:{}}),emits:e.mergeModels(["submit"],["update:otp"]),setup(o,{emit:l}){const r=e.useModel(o,"otp"),n=l,a=o,f=e.computed(()=>r.value.length===a.length);return e.watch(r,()=>{a.autosubmit&&r.value.length===a.length&&n("submit",r.value)}),(d,u)=>(e.openBlock(),e.createBlock(e.unref(i.VCard),{title:d.title,subtitle:d.subtitle,"min-width":d.minWidth,"max-width":d.maxWidth},{default:e.withCtx(()=>[e.createVNode(e.unref(i.VForm),{onSubmit:u[1]||(u[1]=e.withModifiers(t=>n("submit",r.value),["prevent"])),"model-value":f.value},{default:e.withCtx(()=>[e.createVNode(e.unref(i.VCardText),null,{default:e.withCtx(()=>[e.createVNode(e.unref(i.VOtpInput),{modelValue:r.value,"onUpdate:modelValue":u[0]||(u[0]=t=>r.value=t),label:"OTP","persistent-placeholder":"",autofocus:"",length:d.length},null,8,["modelValue","length"]),e.createElementVNode("div",P,[e.createVNode(e.unref(i.VBtn),{disabled:!f.value,type:"submit",color:"primary",variant:"flat",text:d.submitButtonText,loading:d.loading},null,8,["disabled","text","loading"])])]),_:1})]),_:1},8,["model-value"])]),_:1},8,["title","subtitle","min-width","max-width"]))}});s.AppBase=C,s.DashboardPage=S,s.FooterSection=F,s.LoginForm=D,s.NavDrawerLink=L,s.OTPForm=U,s.useColorMode=k,s.useFooter=b,s.useNotify=B,Object.defineProperty(s,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare const _default: import("pinia").StoreDefinition<"colorMode", Pick<{
|
|
2
|
+
mode: import("vue").Ref<"light" | "dark", "light" | "dark">;
|
|
3
|
+
toggle: () => void;
|
|
4
|
+
}, "mode">, Pick<{
|
|
5
|
+
mode: import("vue").Ref<"light" | "dark", "light" | "dark">;
|
|
6
|
+
toggle: () => void;
|
|
7
|
+
}, never>, Pick<{
|
|
8
|
+
mode: import("vue").Ref<"light" | "dark", "light" | "dark">;
|
|
9
|
+
toggle: () => void;
|
|
10
|
+
}, "toggle">>;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export interface FooterMessage {
|
|
2
|
+
id?: string;
|
|
3
|
+
text: string;
|
|
4
|
+
type?: 'info' | 'success' | 'warning' | 'error';
|
|
5
|
+
timeout?: number;
|
|
6
|
+
actions?: {
|
|
7
|
+
[key: string]: () => void;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
declare const _default: import("pinia").StoreDefinition<"footer", Pick<{
|
|
11
|
+
messages: import("vue").Ref<{
|
|
12
|
+
id?: string | undefined;
|
|
13
|
+
text: string;
|
|
14
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
15
|
+
timeout?: number | undefined;
|
|
16
|
+
actions?: {
|
|
17
|
+
[key: string]: () => void;
|
|
18
|
+
} | undefined;
|
|
19
|
+
}[], FooterMessage[] | {
|
|
20
|
+
id?: string | undefined;
|
|
21
|
+
text: string;
|
|
22
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
23
|
+
timeout?: number | undefined;
|
|
24
|
+
actions?: {
|
|
25
|
+
[key: string]: () => void;
|
|
26
|
+
} | undefined;
|
|
27
|
+
}[]>;
|
|
28
|
+
current: import("vue").ComputedRef<{
|
|
29
|
+
id?: string | undefined;
|
|
30
|
+
text: string;
|
|
31
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
32
|
+
timeout?: number | undefined;
|
|
33
|
+
actions?: {
|
|
34
|
+
[key: string]: () => void;
|
|
35
|
+
} | undefined;
|
|
36
|
+
} | null>;
|
|
37
|
+
addMessage: (message: FooterMessage) => string;
|
|
38
|
+
removeMessage: (id: string) => void;
|
|
39
|
+
}, "messages">, Pick<{
|
|
40
|
+
messages: import("vue").Ref<{
|
|
41
|
+
id?: string | undefined;
|
|
42
|
+
text: string;
|
|
43
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
44
|
+
timeout?: number | undefined;
|
|
45
|
+
actions?: {
|
|
46
|
+
[key: string]: () => void;
|
|
47
|
+
} | undefined;
|
|
48
|
+
}[], FooterMessage[] | {
|
|
49
|
+
id?: string | undefined;
|
|
50
|
+
text: string;
|
|
51
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
52
|
+
timeout?: number | undefined;
|
|
53
|
+
actions?: {
|
|
54
|
+
[key: string]: () => void;
|
|
55
|
+
} | undefined;
|
|
56
|
+
}[]>;
|
|
57
|
+
current: import("vue").ComputedRef<{
|
|
58
|
+
id?: string | undefined;
|
|
59
|
+
text: string;
|
|
60
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
61
|
+
timeout?: number | undefined;
|
|
62
|
+
actions?: {
|
|
63
|
+
[key: string]: () => void;
|
|
64
|
+
} | undefined;
|
|
65
|
+
} | null>;
|
|
66
|
+
addMessage: (message: FooterMessage) => string;
|
|
67
|
+
removeMessage: (id: string) => void;
|
|
68
|
+
}, "current">, Pick<{
|
|
69
|
+
messages: import("vue").Ref<{
|
|
70
|
+
id?: string | undefined;
|
|
71
|
+
text: string;
|
|
72
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
73
|
+
timeout?: number | undefined;
|
|
74
|
+
actions?: {
|
|
75
|
+
[key: string]: () => void;
|
|
76
|
+
} | undefined;
|
|
77
|
+
}[], FooterMessage[] | {
|
|
78
|
+
id?: string | undefined;
|
|
79
|
+
text: string;
|
|
80
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
81
|
+
timeout?: number | undefined;
|
|
82
|
+
actions?: {
|
|
83
|
+
[key: string]: () => void;
|
|
84
|
+
} | undefined;
|
|
85
|
+
}[]>;
|
|
86
|
+
current: import("vue").ComputedRef<{
|
|
87
|
+
id?: string | undefined;
|
|
88
|
+
text: string;
|
|
89
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
90
|
+
timeout?: number | undefined;
|
|
91
|
+
actions?: {
|
|
92
|
+
[key: string]: () => void;
|
|
93
|
+
} | undefined;
|
|
94
|
+
} | null>;
|
|
95
|
+
addMessage: (message: FooterMessage) => string;
|
|
96
|
+
removeMessage: (id: string) => void;
|
|
97
|
+
}, "addMessage" | "removeMessage">>;
|
|
98
|
+
export default _default;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface NotifyMessage {
|
|
2
|
+
id?: string;
|
|
3
|
+
text: string;
|
|
4
|
+
type?: 'info' | 'success' | 'warning' | 'error';
|
|
5
|
+
timeout?: number;
|
|
6
|
+
}
|
|
7
|
+
declare const _default: import("pinia").StoreDefinition<"notify", Pick<{
|
|
8
|
+
messages: import("vue").Ref<{
|
|
9
|
+
id?: string | undefined;
|
|
10
|
+
text: string;
|
|
11
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
12
|
+
timeout?: number | undefined;
|
|
13
|
+
}[], NotifyMessage[] | {
|
|
14
|
+
id?: string | undefined;
|
|
15
|
+
text: string;
|
|
16
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
17
|
+
timeout?: number | undefined;
|
|
18
|
+
}[]>;
|
|
19
|
+
add: (message: NotifyMessage) => string;
|
|
20
|
+
remove: (id: string) => void;
|
|
21
|
+
info: (text: string) => string;
|
|
22
|
+
success: (text: string) => string;
|
|
23
|
+
warning: (text: string) => string;
|
|
24
|
+
error: (text: string) => string;
|
|
25
|
+
}, "messages">, Pick<{
|
|
26
|
+
messages: import("vue").Ref<{
|
|
27
|
+
id?: string | undefined;
|
|
28
|
+
text: string;
|
|
29
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
30
|
+
timeout?: number | undefined;
|
|
31
|
+
}[], NotifyMessage[] | {
|
|
32
|
+
id?: string | undefined;
|
|
33
|
+
text: string;
|
|
34
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
35
|
+
timeout?: number | undefined;
|
|
36
|
+
}[]>;
|
|
37
|
+
add: (message: NotifyMessage) => string;
|
|
38
|
+
remove: (id: string) => void;
|
|
39
|
+
info: (text: string) => string;
|
|
40
|
+
success: (text: string) => string;
|
|
41
|
+
warning: (text: string) => string;
|
|
42
|
+
error: (text: string) => string;
|
|
43
|
+
}, never>, Pick<{
|
|
44
|
+
messages: import("vue").Ref<{
|
|
45
|
+
id?: string | undefined;
|
|
46
|
+
text: string;
|
|
47
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
48
|
+
timeout?: number | undefined;
|
|
49
|
+
}[], NotifyMessage[] | {
|
|
50
|
+
id?: string | undefined;
|
|
51
|
+
text: string;
|
|
52
|
+
type?: "info" | "success" | "warning" | "error" | undefined;
|
|
53
|
+
timeout?: number | undefined;
|
|
54
|
+
}[]>;
|
|
55
|
+
add: (message: NotifyMessage) => string;
|
|
56
|
+
remove: (id: string) => void;
|
|
57
|
+
info: (text: string) => string;
|
|
58
|
+
success: (text: string) => string;
|
|
59
|
+
warning: (text: string) => string;
|
|
60
|
+
error: (text: string) => string;
|
|
61
|
+
}, "info" | "success" | "warning" | "error" | "add" | "remove">>;
|
|
62
|
+
export default _default;
|
package/package.json
CHANGED
package/vite.config.d.ts
ADDED
package/vite.config.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import Vue from '@vitejs/plugin-vue';
|
|
3
|
+
var config = {
|
|
4
|
+
build: {
|
|
5
|
+
lib: {
|
|
6
|
+
entry: 'src/index.ts',
|
|
7
|
+
name: 'appsalutely',
|
|
8
|
+
fileName: 'index',
|
|
9
|
+
},
|
|
10
|
+
rollupOptions: {
|
|
11
|
+
external: ['vue', 'vue-router', 'pinia', 'vuetify', 'vuetify/components'],
|
|
12
|
+
output: {
|
|
13
|
+
globals: {
|
|
14
|
+
vue: 'Vue',
|
|
15
|
+
'vue-router': 'VueRouter',
|
|
16
|
+
pinia: 'Pinia',
|
|
17
|
+
vuetify: 'Vuetify',
|
|
18
|
+
'vuetify/components': 'VuetifyComponents',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
plugins: [Vue()],
|
|
24
|
+
};
|
|
25
|
+
export default defineConfig(config);
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref, onBeforeMount, watch, useSlots } from 'vue'
|
|
3
|
-
import { useRouter, RouterView } from 'vue-router'
|
|
4
|
-
import {
|
|
5
|
-
VApp,
|
|
6
|
-
VProgressLinear,
|
|
7
|
-
VAppBar,
|
|
8
|
-
VNavigationDrawer,
|
|
9
|
-
VList,
|
|
10
|
-
VMain,
|
|
11
|
-
VFooter,
|
|
12
|
-
VBtn,
|
|
13
|
-
VSnackbar,
|
|
14
|
-
} from 'vuetify/components'
|
|
15
|
-
import useColorMode from '../stores/colorMode'
|
|
16
|
-
import useFooter from '../stores/footer'
|
|
17
|
-
import useNotify from '../stores/notify'
|
|
18
|
-
|
|
19
|
-
const colorMode = useColorMode()
|
|
20
|
-
const drawerOpen = defineModel<boolean>('drawerOpen', { default: false })
|
|
21
|
-
const drawerDocked = ref(false)
|
|
22
|
-
const footer = useFooter()
|
|
23
|
-
const navigating = ref(false)
|
|
24
|
-
const navigatingTimeout = ref<number | null>(null)
|
|
25
|
-
const notify = useNotify()
|
|
26
|
-
const router = useRouter()
|
|
27
|
-
const slots = useSlots()
|
|
28
|
-
|
|
29
|
-
watch(drawerDocked, (newValue) => {
|
|
30
|
-
localStorage.setItem('drawerDocked', String(newValue))
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
onBeforeMount(() => {
|
|
34
|
-
router.beforeEach(() => {
|
|
35
|
-
navigatingTimeout.value = setTimeout(() => {
|
|
36
|
-
navigating.value = true
|
|
37
|
-
}, 300)
|
|
38
|
-
})
|
|
39
|
-
router.afterEach(() => {
|
|
40
|
-
if (navigatingTimeout.value) {
|
|
41
|
-
clearTimeout(navigatingTimeout.value)
|
|
42
|
-
navigatingTimeout.value = null
|
|
43
|
-
}
|
|
44
|
-
navigating.value = false
|
|
45
|
-
})
|
|
46
|
-
drawerDocked.value = localStorage.getItem('drawerDocked') === 'true'
|
|
47
|
-
drawerOpen.value = drawerDocked.value
|
|
48
|
-
})
|
|
49
|
-
</script>
|
|
50
|
-
<template>
|
|
51
|
-
<VApp :theme="colorMode.mode">
|
|
52
|
-
<VProgressLinear
|
|
53
|
-
indeterminate
|
|
54
|
-
v-if="navigating"
|
|
55
|
-
class="mb-n1"
|
|
56
|
-
style="z-index: 100000; opacity: 0.5"
|
|
57
|
-
height="1"
|
|
58
|
-
/>
|
|
59
|
-
<VAppBar height="64">
|
|
60
|
-
<slot name="header" />
|
|
61
|
-
</VAppBar>
|
|
62
|
-
<VMain class="bg-surface-light">
|
|
63
|
-
<div class="d-flex flex-column pa-4 h-100">
|
|
64
|
-
<RouterView />
|
|
65
|
-
</div>
|
|
66
|
-
</VMain>
|
|
67
|
-
<VAppBar v-if="slots.footer" height="40" location="bottom">
|
|
68
|
-
<VFooter class="py-0 w-100 d-flex align-center">
|
|
69
|
-
<span
|
|
70
|
-
v-if="footer.current"
|
|
71
|
-
v-text="footer.current.text"
|
|
72
|
-
:class="footer.current.type ? {} : { ['text-' + footer.current.type]: true }"
|
|
73
|
-
style="text-overflow: ellipsis"
|
|
74
|
-
class="overflow-hidden text-no-wrap"
|
|
75
|
-
/>
|
|
76
|
-
<template v-if="footer.current && footer.current.actions">
|
|
77
|
-
<VBtn
|
|
78
|
-
v-for="(action, index) of Object.entries(footer.current.actions)"
|
|
79
|
-
:text="action[0]"
|
|
80
|
-
@click="action[1]"
|
|
81
|
-
:key="index"
|
|
82
|
-
density="comfortable"
|
|
83
|
-
variant="tonal"
|
|
84
|
-
class="mx-2 px-2 text-none"
|
|
85
|
-
:color="footer.current.type"
|
|
86
|
-
/>
|
|
87
|
-
</template>
|
|
88
|
-
<div class="me-auto" />
|
|
89
|
-
<slot name="footer" />
|
|
90
|
-
</VFooter>
|
|
91
|
-
</VAppBar>
|
|
92
|
-
<VNavigationDrawer
|
|
93
|
-
v-if="slots.drawer"
|
|
94
|
-
v-model="drawerOpen"
|
|
95
|
-
width="250"
|
|
96
|
-
rail-width="58"
|
|
97
|
-
:rail="drawerDocked"
|
|
98
|
-
:mobile="drawerDocked ? false : undefined"
|
|
99
|
-
>
|
|
100
|
-
<VList class="h-100 d-flex flex-column">
|
|
101
|
-
<slot name="drawer" />
|
|
102
|
-
<VBtn
|
|
103
|
-
@click="drawerDocked = !drawerDocked"
|
|
104
|
-
icon="mdi-pin-outline"
|
|
105
|
-
rounded="rounded"
|
|
106
|
-
density="comfortable"
|
|
107
|
-
:title="drawerDocked ? 'Undock sidebar' : 'Dock sidebar'"
|
|
108
|
-
class="my-1 mx-3 ms-auto"
|
|
109
|
-
:variant="drawerDocked ? 'tonal' : 'text'"
|
|
110
|
-
/>
|
|
111
|
-
</VList>
|
|
112
|
-
</VNavigationDrawer>
|
|
113
|
-
<VSnackbar
|
|
114
|
-
v-for="(message, index) of notify.messages"
|
|
115
|
-
:key="index"
|
|
116
|
-
:model-value="true"
|
|
117
|
-
:text="message.text"
|
|
118
|
-
:color="message.type"
|
|
119
|
-
location="bottom end"
|
|
120
|
-
:style="{ bottom: `${index * 56}px` }"
|
|
121
|
-
:timeout="-1"
|
|
122
|
-
>
|
|
123
|
-
<template #actions>
|
|
124
|
-
<VBtn icon="mdi-close" @click="notify.remove(message.id!)" />
|
|
125
|
-
</template>
|
|
126
|
-
</VSnackbar>
|
|
127
|
-
</VApp>
|
|
128
|
-
</template>
|
|
129
|
-
<style>
|
|
130
|
-
html {
|
|
131
|
-
overflow: auto;
|
|
132
|
-
}
|
|
133
|
-
html[data-theme='dark'] {
|
|
134
|
-
color-scheme: dark;
|
|
135
|
-
}
|
|
136
|
-
html[data-theme='light'] {
|
|
137
|
-
color-scheme: light;
|
|
138
|
-
}
|
|
139
|
-
</style>
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { VBreadcrumbs, VContainer } from 'vuetify/components'
|
|
3
|
-
import { defineProps, withDefaults } from 'vue'
|
|
4
|
-
|
|
5
|
-
withDefaults(
|
|
6
|
-
defineProps<{
|
|
7
|
-
breadcrumbs?: VBreadcrumbs['$props']['items']
|
|
8
|
-
fluid?: boolean
|
|
9
|
-
title?: string
|
|
10
|
-
}>(),
|
|
11
|
-
{
|
|
12
|
-
fluid: true,
|
|
13
|
-
},
|
|
14
|
-
)
|
|
15
|
-
</script>
|
|
16
|
-
<template>
|
|
17
|
-
<VContainer :fluid="fluid" class="h-100 d-flex flex-column py-0 h-100">
|
|
18
|
-
<VBreadcrumbs :items="breadcrumbs" density="comfortable" class="pa-0" v-if="breadcrumbs" />
|
|
19
|
-
<h1 v-if="title" v-text="title" class="text-h5 font-bold ma-1" />
|
|
20
|
-
<slot />
|
|
21
|
-
</VContainer>
|
|
22
|
-
</template>
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { defineProps, withDefaults, defineModel, defineEmits, ref } from 'vue'
|
|
3
|
-
import { VBtn, VCard, VCardText, VForm, VTextField } from 'vuetify/components'
|
|
4
|
-
|
|
5
|
-
const username = defineModel<string>('username', { default: '' })
|
|
6
|
-
const password = defineModel<string>('password', { default: '' })
|
|
7
|
-
const emit = defineEmits<{
|
|
8
|
-
submit: [string, string]
|
|
9
|
-
}>()
|
|
10
|
-
withDefaults(
|
|
11
|
-
defineProps<{
|
|
12
|
-
title?: string
|
|
13
|
-
submitButtonText?: string
|
|
14
|
-
minWidth?: string | number
|
|
15
|
-
maxWidth?: string | number
|
|
16
|
-
loading?: boolean
|
|
17
|
-
}>(),
|
|
18
|
-
{
|
|
19
|
-
title: 'Login',
|
|
20
|
-
submitButtonText: 'Login',
|
|
21
|
-
},
|
|
22
|
-
)
|
|
23
|
-
const valid = ref(false)
|
|
24
|
-
</script>
|
|
25
|
-
<template>
|
|
26
|
-
<VCard :title="title" :min-width="minWidth" :max-width="maxWidth">
|
|
27
|
-
<VForm @submit.prevent="emit('submit', username, password)" v-model="valid">
|
|
28
|
-
<VCardText>
|
|
29
|
-
<VTextField
|
|
30
|
-
v-model="username"
|
|
31
|
-
label="Username"
|
|
32
|
-
:rules="[(v) => !!v || 'Username is required']"
|
|
33
|
-
persistent-placeholder
|
|
34
|
-
autofocus
|
|
35
|
-
/>
|
|
36
|
-
<VTextField
|
|
37
|
-
v-model="password"
|
|
38
|
-
label="Password"
|
|
39
|
-
type="password"
|
|
40
|
-
:rules="[(v) => !!v || 'Password is required']"
|
|
41
|
-
persistent-placeholder
|
|
42
|
-
/>
|
|
43
|
-
<div class="d-flex justify-center">
|
|
44
|
-
<VBtn
|
|
45
|
-
:disabled="!valid"
|
|
46
|
-
type="submit"
|
|
47
|
-
color="primary"
|
|
48
|
-
variant="flat"
|
|
49
|
-
:text="submitButtonText"
|
|
50
|
-
:loading="loading"
|
|
51
|
-
/>
|
|
52
|
-
</div>
|
|
53
|
-
</VCardText>
|
|
54
|
-
</VForm>
|
|
55
|
-
</VCard>
|
|
56
|
-
</template>
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import type { RouteLocationRaw } from 'vue-router'
|
|
3
|
-
import { VListItem, VIcon } from 'vuetify/components'
|
|
4
|
-
|
|
5
|
-
defineProps<{
|
|
6
|
-
to: RouteLocationRaw
|
|
7
|
-
icon: string
|
|
8
|
-
text: string
|
|
9
|
-
}>()
|
|
10
|
-
</script>
|
|
11
|
-
<template>
|
|
12
|
-
<VListItem role="option" :to="to" slim>
|
|
13
|
-
<template #prepend>
|
|
14
|
-
<VIcon :icon="icon" />
|
|
15
|
-
</template>
|
|
16
|
-
<span class="text-no-wrap overflow-hidden">{{ text }}</span>
|
|
17
|
-
</VListItem>
|
|
18
|
-
</template>
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { defineProps, withDefaults, defineModel, defineEmits, computed, watch } from 'vue'
|
|
3
|
-
import { VBtn, VCard, VCardText, VForm, VOtpInput } from 'vuetify/components'
|
|
4
|
-
|
|
5
|
-
const otp = defineModel<string>('otp', { default: '' })
|
|
6
|
-
const emit = defineEmits<{
|
|
7
|
-
submit: [string]
|
|
8
|
-
}>()
|
|
9
|
-
const props = withDefaults(
|
|
10
|
-
defineProps<{
|
|
11
|
-
title?: string
|
|
12
|
-
subtitle?: string
|
|
13
|
-
submitButtonText?: string
|
|
14
|
-
minWidth?: string | number
|
|
15
|
-
maxWidth?: string | number
|
|
16
|
-
loading?: boolean
|
|
17
|
-
length?: number
|
|
18
|
-
autosubmit?: boolean
|
|
19
|
-
}>(),
|
|
20
|
-
{
|
|
21
|
-
title: '2FA Verification',
|
|
22
|
-
subtitle: 'Enter the code from your authenticator app',
|
|
23
|
-
submitButtonText: 'Verify',
|
|
24
|
-
length: 6,
|
|
25
|
-
autosubmit: true,
|
|
26
|
-
},
|
|
27
|
-
)
|
|
28
|
-
const valid = computed(() => otp.value.length === props.length)
|
|
29
|
-
|
|
30
|
-
watch(otp, () => {
|
|
31
|
-
if (props.autosubmit && otp.value.length === props.length) {
|
|
32
|
-
emit('submit', otp.value)
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
|
-
</script>
|
|
36
|
-
<template>
|
|
37
|
-
<VCard :title="title" :subtitle="subtitle" :min-width="minWidth" :max-width="maxWidth">
|
|
38
|
-
<VForm @submit.prevent="emit('submit', otp)" :model-value="valid">
|
|
39
|
-
<VCardText>
|
|
40
|
-
<VOtpInput v-model="otp" label="OTP" persistent-placeholder autofocus :length="length" />
|
|
41
|
-
<div class="d-flex justify-center">
|
|
42
|
-
<VBtn
|
|
43
|
-
:disabled="!valid"
|
|
44
|
-
type="submit"
|
|
45
|
-
color="primary"
|
|
46
|
-
variant="flat"
|
|
47
|
-
:text="submitButtonText"
|
|
48
|
-
:loading="loading"
|
|
49
|
-
/>
|
|
50
|
-
</div>
|
|
51
|
-
</VCardText>
|
|
52
|
-
</VForm>
|
|
53
|
-
</VCard>
|
|
54
|
-
</template>
|
package/src/index.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import AppBase from './components/AppBase.vue'
|
|
2
|
-
import DashboardPage from './components/DashboardPage.vue'
|
|
3
|
-
import FooterSection from './components/FooterSection.vue'
|
|
4
|
-
import LoginForm from './components/LoginForm.vue'
|
|
5
|
-
import NavDrawerLink from './components/NavDrawerLink.vue'
|
|
6
|
-
import OTPForm from './components/OTPForm.vue'
|
|
7
|
-
|
|
8
|
-
import useColorMode from './stores/colorMode'
|
|
9
|
-
import useFooter from './stores/footer'
|
|
10
|
-
import useNotify from './stores/notify'
|
|
11
|
-
|
|
12
|
-
export {
|
|
13
|
-
AppBase,
|
|
14
|
-
DashboardPage,
|
|
15
|
-
FooterSection,
|
|
16
|
-
LoginForm,
|
|
17
|
-
NavDrawerLink,
|
|
18
|
-
OTPForm,
|
|
19
|
-
useColorMode,
|
|
20
|
-
useFooter,
|
|
21
|
-
useNotify,
|
|
22
|
-
}
|
package/src/stores/colorMode.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { ref, watch } from 'vue'
|
|
2
|
-
import { defineStore } from 'pinia'
|
|
3
|
-
|
|
4
|
-
export default defineStore('colorMode', () => {
|
|
5
|
-
const mode = ref<'light' | 'dark'>(localStorage.getItem('colorMode') == 'dark' ? 'dark' : 'light')
|
|
6
|
-
function toggle() {
|
|
7
|
-
mode.value = mode.value === 'dark' ? 'light' : 'dark'
|
|
8
|
-
}
|
|
9
|
-
function update(newMode: 'light' | 'dark') {
|
|
10
|
-
localStorage.setItem('colorMode', newMode)
|
|
11
|
-
document.documentElement.setAttribute('data-theme', newMode)
|
|
12
|
-
}
|
|
13
|
-
watch(mode, (newMode) => update(newMode))
|
|
14
|
-
update(mode.value)
|
|
15
|
-
return { mode, toggle }
|
|
16
|
-
})
|
package/src/stores/footer.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { ref, computed } from 'vue'
|
|
2
|
-
import { defineStore } from 'pinia'
|
|
3
|
-
|
|
4
|
-
export interface FooterMessage {
|
|
5
|
-
id?: string
|
|
6
|
-
text: string
|
|
7
|
-
type?: 'info' | 'success' | 'warning' | 'error'
|
|
8
|
-
timeout?: number
|
|
9
|
-
actions?: {
|
|
10
|
-
[key: string]: () => void
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default defineStore('footer', () => {
|
|
15
|
-
const messages = ref<FooterMessage[]>([])
|
|
16
|
-
const current = computed(() => {
|
|
17
|
-
if (messages.value.length > 0) {
|
|
18
|
-
return messages.value[messages.value.length - 1]
|
|
19
|
-
}
|
|
20
|
-
return null
|
|
21
|
-
})
|
|
22
|
-
function addMessage(message: FooterMessage) {
|
|
23
|
-
if (!message.id) {
|
|
24
|
-
message.id = new Date().getTime().toString()
|
|
25
|
-
}
|
|
26
|
-
if (message.timeout === undefined) {
|
|
27
|
-
message.timeout = 5000
|
|
28
|
-
}
|
|
29
|
-
messages.value.push(message)
|
|
30
|
-
if (message.timeout) {
|
|
31
|
-
setTimeout(() => {
|
|
32
|
-
removeMessage(message.id!)
|
|
33
|
-
}, message.timeout)
|
|
34
|
-
}
|
|
35
|
-
return message.id!
|
|
36
|
-
}
|
|
37
|
-
function removeMessage(id: string) {
|
|
38
|
-
messages.value = messages.value.filter((message) => message.id !== id)
|
|
39
|
-
}
|
|
40
|
-
return { messages, current, addMessage, removeMessage }
|
|
41
|
-
})
|
package/src/stores/notify.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { ref } from 'vue'
|
|
2
|
-
import { defineStore } from 'pinia'
|
|
3
|
-
|
|
4
|
-
export interface NotifyMessage {
|
|
5
|
-
id?: string
|
|
6
|
-
text: string
|
|
7
|
-
type?: 'info' | 'success' | 'warning' | 'error'
|
|
8
|
-
timeout?: number
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default defineStore('notify', () => {
|
|
12
|
-
const messages = ref<NotifyMessage[]>([])
|
|
13
|
-
const timeouts = ref<Record<string, number>>({})
|
|
14
|
-
function add(message: NotifyMessage) {
|
|
15
|
-
if (!message.id) {
|
|
16
|
-
message.id = new Date().getTime().toString()
|
|
17
|
-
} else {
|
|
18
|
-
remove(message.id)
|
|
19
|
-
}
|
|
20
|
-
if (message.timeout === undefined) {
|
|
21
|
-
message.timeout = 5000
|
|
22
|
-
}
|
|
23
|
-
messages.value.push(message)
|
|
24
|
-
if (message.timeout) {
|
|
25
|
-
timeouts.value[message.id] = setTimeout(() => {
|
|
26
|
-
remove(message.id!)
|
|
27
|
-
}, message.timeout)
|
|
28
|
-
}
|
|
29
|
-
return message.id!
|
|
30
|
-
}
|
|
31
|
-
function remove(id: string) {
|
|
32
|
-
messages.value = messages.value.filter((message) => message.id !== id)
|
|
33
|
-
if (timeouts.value[id]) {
|
|
34
|
-
clearTimeout(timeouts.value[id])
|
|
35
|
-
delete timeouts.value[id]
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function info(text: string) {
|
|
39
|
-
return add({ text, type: 'info' })
|
|
40
|
-
}
|
|
41
|
-
function success(text: string) {
|
|
42
|
-
return add({ text, type: 'success' })
|
|
43
|
-
}
|
|
44
|
-
function warning(text: string) {
|
|
45
|
-
return add({ text, type: 'warning' })
|
|
46
|
-
}
|
|
47
|
-
function error(text: string) {
|
|
48
|
-
return add({ text, type: 'error' })
|
|
49
|
-
}
|
|
50
|
-
return { messages, add, remove, info, success, warning, error }
|
|
51
|
-
})
|