@fy-/fws-vue 0.0.1
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/components/fws/CmsArticleBoxed.vue +113 -0
- package/components/fws/CmsArticleSingle.vue +115 -0
- package/components/fws/DataTable.vue +260 -0
- package/components/fws/FilterData.vue +179 -0
- package/components/fws/UserFlow.vue +305 -0
- package/components/ssr/ClientOnly.ts +12 -0
- package/components/ui/DefaultBreadcrumb.vue +75 -0
- package/components/ui/DefaultConfirm.vue +69 -0
- package/components/ui/DefaultDateSelection.vue +56 -0
- package/components/ui/DefaultInput.vue +243 -0
- package/components/ui/DefaultLoader.vue +49 -0
- package/components/ui/DefaultModal.vue +90 -0
- package/components/ui/DefaultPaging.vue +212 -0
- package/components/ui/transitions/CollapseTransition.vue +30 -0
- package/components/ui/transitions/ExpandTransition.vue +32 -0
- package/components/ui/transitions/FadeTransition.vue +17 -0
- package/components/ui/transitions/ScaleTransition.vue +35 -0
- package/components/ui/transitions/SlideTransition.vue +127 -0
- package/components.d.ts +22 -0
- package/env.d.ts +6 -0
- package/event-bus.ts +14 -0
- package/index.ts +121 -0
- package/package.json +43 -0
- package/rest.ts +72 -0
- package/seo.ts +114 -0
- package/ssr.ts +97 -0
- package/stores/rest.ts +24 -0
- package/stores/serverRouter.ts +49 -0
- package/stores/user.ts +81 -0
- package/style.css +42 -0
- package/templating.ts +79 -0
- package/translations.ts +29 -0
- package/types.d.ts +4 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { defineStore, Pinia } from "pinia";
|
|
2
|
+
import type { Router } from "vue-router";
|
|
3
|
+
|
|
4
|
+
export interface ServerRouterState {
|
|
5
|
+
_router: any | null;
|
|
6
|
+
status: number;
|
|
7
|
+
redirect?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const useServerRouter = defineStore({
|
|
11
|
+
id: "routerStore",
|
|
12
|
+
state: () =>
|
|
13
|
+
({
|
|
14
|
+
_router: null,
|
|
15
|
+
status: 200,
|
|
16
|
+
redirect: undefined,
|
|
17
|
+
}) as ServerRouterState,
|
|
18
|
+
getters: {
|
|
19
|
+
currentRoute: (state) => state._router!.currentRoute,
|
|
20
|
+
route: (state) => state._router!.currentRoute,
|
|
21
|
+
},
|
|
22
|
+
actions: {
|
|
23
|
+
setStatus(status: number) {
|
|
24
|
+
this.status = status;
|
|
25
|
+
},
|
|
26
|
+
_setRouter(_router: Router | null) {
|
|
27
|
+
(this._router as unknown as Router | null) = _router;
|
|
28
|
+
},
|
|
29
|
+
push(path: any, status = 302) {
|
|
30
|
+
this.status = status;
|
|
31
|
+
if (status != 302) this.redirect = path;
|
|
32
|
+
return this._router?.push(path);
|
|
33
|
+
},
|
|
34
|
+
replace(path: any, status = 302) {
|
|
35
|
+
this.status = status;
|
|
36
|
+
if (status != 302) this.redirect = path;
|
|
37
|
+
return this._router?.replace(path);
|
|
38
|
+
},
|
|
39
|
+
go(delta: number) {
|
|
40
|
+
this._router?.go(delta);
|
|
41
|
+
},
|
|
42
|
+
back() {
|
|
43
|
+
this._router?.go(-1);
|
|
44
|
+
},
|
|
45
|
+
forward() {
|
|
46
|
+
this._router?.go(1);
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
package/stores/user.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { defineStore } from "pinia";
|
|
2
|
+
import type { User } from "@fy-/fws-types";
|
|
3
|
+
import { APIResult } from "../rest";
|
|
4
|
+
import { rest } from "@fy-/fws-js";
|
|
5
|
+
import { computed } from "vue";
|
|
6
|
+
import { RouteLocation, useRouter } from "vue-router";
|
|
7
|
+
import { useServerRouter } from "./serverRouter";
|
|
8
|
+
|
|
9
|
+
export type UserStore = {
|
|
10
|
+
user: User | null;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const useUserStore = defineStore({
|
|
14
|
+
id: "userStore",
|
|
15
|
+
state: (): UserStore => ({
|
|
16
|
+
user: null,
|
|
17
|
+
}),
|
|
18
|
+
getters: {
|
|
19
|
+
isAuth: (state): boolean => {
|
|
20
|
+
return !(state.user === null);
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
actions: {
|
|
24
|
+
async refreshUser() {
|
|
25
|
+
const user: APIResult = await rest("User:get", "GET").catch((err) => {
|
|
26
|
+
console.log(err);
|
|
27
|
+
this.setUser(null);
|
|
28
|
+
});
|
|
29
|
+
if (user.result === "success") {
|
|
30
|
+
this.setUser(user.data);
|
|
31
|
+
} else {
|
|
32
|
+
this.setUser(null);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
async logout() {
|
|
36
|
+
const user: APIResult = await rest("User:logout", "POST").catch((err) => {
|
|
37
|
+
this.setUser(null);
|
|
38
|
+
});
|
|
39
|
+
if (user.result === "success") {
|
|
40
|
+
this.setUser(null);
|
|
41
|
+
} else {
|
|
42
|
+
this.setUser(null);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
setUser(user: User | null) {
|
|
46
|
+
this.user = user;
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export function useUserCheck(path = "/login", redirectLink = false) {
|
|
52
|
+
const userStore = useUserStore();
|
|
53
|
+
const isAuth = computed(() => userStore.isAuth);
|
|
54
|
+
const router = useServerRouter();
|
|
55
|
+
|
|
56
|
+
const checkUser = (route: RouteLocation) => {
|
|
57
|
+
if (route.meta.reqLogin) {
|
|
58
|
+
if (!isAuth.value) {
|
|
59
|
+
if (!redirectLink) router.push(path);
|
|
60
|
+
else {
|
|
61
|
+
router.status = 307;
|
|
62
|
+
router.push(`${path}?return_to=${route.path}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
userStore.refreshUser().then(() => {
|
|
69
|
+
if (router.currentRoute) {
|
|
70
|
+
checkUser(router.currentRoute);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
router._router.afterEach(async () => {
|
|
74
|
+
await userStore.refreshUser();
|
|
75
|
+
});
|
|
76
|
+
router._router.beforeEach((to: any) => {
|
|
77
|
+
if (to.fullPath != path) {
|
|
78
|
+
checkUser(to);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
package/style.css
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
.fws-error-text {
|
|
2
|
+
@apply text-red-700 dark:text-red-500;
|
|
3
|
+
}
|
|
4
|
+
.fws-helper-text {
|
|
5
|
+
@apply text-fv-neutral-500 dark:text-fv-neutral-400;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.fws-link {
|
|
9
|
+
@apply text-fv-primary-700 dark:text-fv-primary-300 inline-flex items-center underline hover:no-underline;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.btn {
|
|
13
|
+
@apply text-white bg-gradient-to-br hover:bg-gradient-to-bl focus:ring-4 focus:outline-none font-medium rounded-lg text-center transition-colors ease-in-out motion-reduce:transition-none;
|
|
14
|
+
&.primary {
|
|
15
|
+
@apply from-fv-primary-600 to-fv-primary-500 focus:ring-fv-primary-300 dark:focus:ring-fv-primary-800;
|
|
16
|
+
}
|
|
17
|
+
&.accent {
|
|
18
|
+
@apply from-fv-accent-600 to-fv-accent-500 focus:ring-fv-accent-300 dark:focus:ring-fv-accent-800;
|
|
19
|
+
}
|
|
20
|
+
&.success,&.valid {
|
|
21
|
+
@apply from-green-600 to-green-500 focus:ring-green-300 dark:focus:ring-green-800;
|
|
22
|
+
}
|
|
23
|
+
&.error,&.danger {
|
|
24
|
+
@apply from-red-600 to-red-500 focus:ring-red-300 dark:focus:ring-red-800;
|
|
25
|
+
}
|
|
26
|
+
&.neutral {
|
|
27
|
+
@apply from-fv-neutral-600 to-fv-neutral-500 focus:ring-fv-neutral-300 dark:focus:ring-fv-neutral-800;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
&.defaults {
|
|
31
|
+
@apply px-5 py-2.5 text-sm;
|
|
32
|
+
}
|
|
33
|
+
&.small {
|
|
34
|
+
@apply px-2.5 py-1.5 text-xs;
|
|
35
|
+
}
|
|
36
|
+
&.medium {
|
|
37
|
+
@apply px-4 py-2 text-sm;
|
|
38
|
+
}
|
|
39
|
+
&.large {
|
|
40
|
+
@apply px-6 py-3 text-base;
|
|
41
|
+
}
|
|
42
|
+
}
|
package/templating.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { format as formatDateTimeago } from "timeago.js";
|
|
2
|
+
import { useTranslation } from "./translations";
|
|
3
|
+
import { getLocale } from "@fy-/fws-js";
|
|
4
|
+
|
|
5
|
+
const cropText = (str: string, ml = 100, end = "...") => {
|
|
6
|
+
if (str.length > ml) {
|
|
7
|
+
return `${str.slice(0, ml)}${end}`;
|
|
8
|
+
}
|
|
9
|
+
return str;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const formatBytes = (bytes: number, decimals = 2) => {
|
|
13
|
+
if (!+bytes) return "0 Bytes";
|
|
14
|
+
|
|
15
|
+
const k = 1024;
|
|
16
|
+
const dm = decimals < 0 ? 0 : decimals;
|
|
17
|
+
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
18
|
+
|
|
19
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
20
|
+
|
|
21
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const formatDate = (dt: Date | string | number) => {
|
|
25
|
+
let _dt = dt as number;
|
|
26
|
+
if (typeof dt === "string") {
|
|
27
|
+
_dt = Date.parse(dt);
|
|
28
|
+
if (Number.isNaN(_dt)) {
|
|
29
|
+
_dt = parseInt(dt);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const translate = useTranslation();
|
|
34
|
+
return translate("global_datetime", {
|
|
35
|
+
val: new Date(_dt),
|
|
36
|
+
formatParams: {
|
|
37
|
+
val: {
|
|
38
|
+
year: "numeric",
|
|
39
|
+
month: "long",
|
|
40
|
+
day: "numeric",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const formatDatetime = (dt: Date | string | number) => {
|
|
46
|
+
let _dt = dt as number;
|
|
47
|
+
if (typeof dt === "string") {
|
|
48
|
+
_dt = Date.parse(dt);
|
|
49
|
+
if (Number.isNaN(_dt)) {
|
|
50
|
+
_dt = parseInt(dt);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const translate = useTranslation();
|
|
54
|
+
return translate("global_datetime", {
|
|
55
|
+
val: new Date(_dt),
|
|
56
|
+
formatParams: {
|
|
57
|
+
val: {
|
|
58
|
+
year: "numeric",
|
|
59
|
+
month: "long",
|
|
60
|
+
day: "numeric",
|
|
61
|
+
hour: "numeric",
|
|
62
|
+
minute: "numeric",
|
|
63
|
+
second: "numeric",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
const formatTimeago = (dt: Date | string | number) => {
|
|
69
|
+
let _dt = dt as number;
|
|
70
|
+
if (typeof dt === "string") {
|
|
71
|
+
_dt = Date.parse(dt);
|
|
72
|
+
if (Number.isNaN(_dt)) {
|
|
73
|
+
_dt = parseInt(dt);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return formatDateTimeago(new Date(_dt), getLocale().replace("_", "-"));
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export { cropText, formatBytes, formatDate, formatDatetime, formatTimeago };
|
package/translations.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { TFunction } from "i18next";
|
|
2
|
+
import i18next from "i18next";
|
|
3
|
+
import { inject } from "vue";
|
|
4
|
+
import { I18nBackend } from "@fy-/fws-js";
|
|
5
|
+
|
|
6
|
+
export type I18nextTranslate = typeof i18next.t;
|
|
7
|
+
|
|
8
|
+
export function useTranslation() {
|
|
9
|
+
const translate = inject<TFunction>("fwsVueTranslate");
|
|
10
|
+
if (!translate) throw new Error("Did you apply app.use(fwsVue)?");
|
|
11
|
+
|
|
12
|
+
return translate;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function i18nextPromise(
|
|
16
|
+
backend: typeof I18nBackend,
|
|
17
|
+
locale: string = "en-US",
|
|
18
|
+
debug: boolean = false,
|
|
19
|
+
ns: string = "translation",
|
|
20
|
+
) {
|
|
21
|
+
return i18next.use(backend).init({
|
|
22
|
+
ns: [ns],
|
|
23
|
+
defaultNS: ns,
|
|
24
|
+
debug: debug,
|
|
25
|
+
lng: locale,
|
|
26
|
+
load: "currentOnly",
|
|
27
|
+
initImmediate: false,
|
|
28
|
+
});
|
|
29
|
+
}
|
package/types.d.ts
ADDED