@fy-/fws-vue 2.1.6 → 2.1.8
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 +23 -20
- package/components/fws/CmsArticleSingle.vue +74 -68
- package/components/fws/DataTable.vue +132 -125
- package/components/fws/FilterData.vue +99 -101
- package/components/fws/UserData.vue +33 -32
- package/components/fws/UserFlow.vue +163 -155
- package/components/fws/UserOAuth2.vue +73 -72
- package/components/fws/UserProfile.vue +98 -101
- package/components/fws/UserProfileStrict.vue +65 -64
- package/components/ssr/ClientOnly.ts +7 -7
- package/components/ui/DefaultBreadcrumb.vue +13 -13
- package/components/ui/DefaultConfirm.vue +35 -34
- package/components/ui/DefaultDateSelection.vue +19 -17
- package/components/ui/DefaultDropdown.vue +25 -25
- package/components/ui/DefaultDropdownLink.vue +15 -14
- package/components/ui/DefaultGallery.vue +179 -168
- package/components/ui/DefaultInput.vue +121 -126
- package/components/ui/DefaultLoader.vue +17 -17
- package/components/ui/DefaultModal.vue +35 -33
- package/components/ui/DefaultNotif.vue +50 -52
- package/components/ui/DefaultPaging.vue +92 -95
- package/components/ui/DefaultSidebar.vue +29 -25
- package/components/ui/DefaultTagInput.vue +121 -119
- package/components/ui/transitions/CollapseTransition.vue +1 -1
- package/components/ui/transitions/ExpandTransition.vue +1 -1
- package/components/ui/transitions/FadeTransition.vue +1 -1
- package/components/ui/transitions/ScaleTransition.vue +1 -1
- package/components/ui/transitions/SlideTransition.vue +3 -3
- package/composables/event-bus.ts +10 -8
- package/composables/rest.ts +59 -56
- package/composables/seo.ts +111 -95
- package/composables/ssr.ts +64 -62
- package/composables/templating.ts +57 -57
- package/composables/translations.ts +13 -13
- package/env.d.ts +6 -4
- package/index.ts +101 -98
- package/package.json +7 -7
- package/stores/serverRouter.ts +25 -25
- package/stores/user.ts +79 -72
- package/types.d.ts +65 -65
package/composables/seo.ts
CHANGED
|
@@ -1,116 +1,125 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import { useHead, useSeoMeta } from
|
|
4
|
-
import {
|
|
5
|
-
import { useRoute } from "vue-router";
|
|
1
|
+
import type { Ref } from 'vue'
|
|
2
|
+
import { getLocale, getPrefix, getURL } from '@fy-/fws-js'
|
|
3
|
+
import { useHead, useSeoMeta } from '@unhead/vue'
|
|
4
|
+
import { useRoute } from 'vue-router'
|
|
6
5
|
|
|
7
6
|
export interface LazyHead {
|
|
8
|
-
name?: string
|
|
9
|
-
title?: string
|
|
10
|
-
image?: string
|
|
11
|
-
imageType?: string
|
|
12
|
-
imageWidth?: string
|
|
13
|
-
imageHeight?: string
|
|
14
|
-
description?: string
|
|
15
|
-
published?: string
|
|
16
|
-
modified?: string
|
|
17
|
-
keywords?: string
|
|
18
|
-
type?:
|
|
19
|
-
searchAction?: string
|
|
20
|
-
next?: string
|
|
21
|
-
prev?: string
|
|
22
|
-
locale?: string
|
|
23
|
-
robots?: string
|
|
24
|
-
url?: string
|
|
25
|
-
canonical?: string
|
|
26
|
-
isAdult?: boolean
|
|
27
|
-
alternateLocales?: string[]
|
|
28
|
-
twitterCreator?: string
|
|
7
|
+
name?: string
|
|
8
|
+
title?: string
|
|
9
|
+
image?: string
|
|
10
|
+
imageType?: string
|
|
11
|
+
imageWidth?: string
|
|
12
|
+
imageHeight?: string
|
|
13
|
+
description?: string
|
|
14
|
+
published?: string
|
|
15
|
+
modified?: string
|
|
16
|
+
keywords?: string
|
|
17
|
+
type?: 'blog' | 'search' | 'article' | 'website'
|
|
18
|
+
searchAction?: string
|
|
19
|
+
next?: string
|
|
20
|
+
prev?: string
|
|
21
|
+
locale?: string
|
|
22
|
+
robots?: string
|
|
23
|
+
url?: string
|
|
24
|
+
canonical?: string
|
|
25
|
+
isAdult?: boolean
|
|
26
|
+
alternateLocales?: string[]
|
|
27
|
+
twitterCreator?: string
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const
|
|
30
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
31
|
+
export function useSeo(seoData: Ref<LazyHead>, initial: boolean = false) {
|
|
32
|
+
const route = useRoute()
|
|
33
|
+
const currentLocale = getLocale()
|
|
34
|
+
// const url = getURL()
|
|
35
35
|
|
|
36
36
|
useHead({
|
|
37
37
|
meta: () => {
|
|
38
|
-
const metas: any[] = []
|
|
38
|
+
const metas: any[] = []
|
|
39
39
|
if (seoData.value.isAdult) {
|
|
40
40
|
metas.push({
|
|
41
|
-
name:
|
|
42
|
-
content:
|
|
43
|
-
key:
|
|
44
|
-
})
|
|
41
|
+
name: 'rating',
|
|
42
|
+
content: 'RTA-5042-1996-1400-1577-RTA',
|
|
43
|
+
key: 'rating',
|
|
44
|
+
})
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
return metas
|
|
47
|
+
return metas
|
|
48
48
|
},
|
|
49
49
|
link: () => {
|
|
50
|
-
const links: any[] = []
|
|
50
|
+
const links: any[] = []
|
|
51
|
+
|
|
52
|
+
/*
|
|
53
|
+
const page
|
|
54
|
+
= route.query.page && Number.parseInt(route.query.page.toString()) > 1
|
|
55
|
+
? `?page=${route.query.page}`
|
|
56
|
+
: ''
|
|
51
57
|
|
|
52
58
|
links.push({
|
|
53
|
-
rel:
|
|
54
|
-
href: `${url.Scheme}://${url.Host}${
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
rel: 'canonical',
|
|
60
|
+
href: `${url.Scheme}://${url.Host}${getURL().Path}${page}`,
|
|
61
|
+
})
|
|
62
|
+
*/
|
|
57
63
|
|
|
58
64
|
seoData.value.alternateLocales?.forEach((locale) => {
|
|
59
65
|
if (locale !== currentLocale) {
|
|
60
66
|
links.push({
|
|
61
|
-
rel:
|
|
67
|
+
rel: 'alternate',
|
|
62
68
|
hreflang: locale,
|
|
63
69
|
href: `${getURL().Scheme}://${
|
|
64
70
|
getURL().Host
|
|
65
|
-
}/l/${locale}${getURL().Path.replace(getPrefix(),
|
|
71
|
+
}/l/${locale}${getURL().Path.replace(getPrefix(), '')}`,
|
|
66
72
|
key: `alternate-${locale}`,
|
|
67
|
-
})
|
|
73
|
+
})
|
|
68
74
|
}
|
|
69
|
-
})
|
|
75
|
+
})
|
|
70
76
|
|
|
77
|
+
/*
|
|
71
78
|
if (seoData.value.image) {
|
|
72
79
|
links.push({
|
|
73
|
-
rel:
|
|
80
|
+
rel: 'preload',
|
|
74
81
|
href: seoData.value.image,
|
|
75
|
-
as:
|
|
76
|
-
fetchpriority:
|
|
77
|
-
})
|
|
82
|
+
as: 'image',
|
|
83
|
+
fetchpriority: 'high',
|
|
84
|
+
})
|
|
78
85
|
}
|
|
86
|
+
*/
|
|
79
87
|
|
|
80
|
-
return links
|
|
88
|
+
return links
|
|
81
89
|
},
|
|
82
|
-
})
|
|
90
|
+
})
|
|
83
91
|
|
|
84
92
|
useSeoMeta({
|
|
85
93
|
ogUrl: () => `${getURL().Scheme}://${getURL().Host}${route.fullPath}`,
|
|
86
94
|
ogLocale: () => {
|
|
87
95
|
if (currentLocale) {
|
|
88
|
-
return currentLocale.replace(
|
|
96
|
+
return currentLocale.replace('-', '_')
|
|
89
97
|
}
|
|
90
98
|
},
|
|
91
99
|
robots:
|
|
92
|
-
|
|
93
|
-
title: () => seoData.value.title,
|
|
100
|
+
'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1',
|
|
101
|
+
title: () => seoData.value.title || '',
|
|
94
102
|
ogTitle: () => seoData.value.title,
|
|
95
103
|
ogDescription: () => seoData.value.description,
|
|
96
|
-
twitterCard:
|
|
104
|
+
twitterCard: 'summary_large_image',
|
|
97
105
|
ogSiteName: () => seoData.value.name,
|
|
98
106
|
twitterTitle: () => seoData.value.title,
|
|
99
107
|
twitterDescription: () => seoData.value.description,
|
|
100
108
|
ogImageAlt: () => {
|
|
101
109
|
if (seoData.value.image) {
|
|
102
|
-
return seoData.value.title
|
|
110
|
+
return seoData.value.title
|
|
103
111
|
}
|
|
104
|
-
return undefined
|
|
112
|
+
return undefined
|
|
105
113
|
},
|
|
106
|
-
|
|
114
|
+
// @ts-expect-error: Type 'string' is not assignable to type 'undefined'.
|
|
115
|
+
ogType: () => (seoData.value.type ? seoData.value.type : 'website'),
|
|
107
116
|
twitterCreator: () => seoData.value.twitterCreator,
|
|
108
117
|
twitterSite: () => seoData.value.twitterCreator,
|
|
109
118
|
twitterImageAlt: () => {
|
|
110
119
|
if (seoData.value.image) {
|
|
111
|
-
return seoData.value.title
|
|
120
|
+
return seoData.value.title
|
|
112
121
|
}
|
|
113
|
-
return undefined
|
|
122
|
+
return undefined
|
|
114
123
|
},
|
|
115
124
|
description: () => seoData.value.description,
|
|
116
125
|
keywords: () => seoData.value.keywords,
|
|
@@ -118,68 +127,75 @@ export const useSeo = (seoData: Ref<LazyHead>, initial: boolean = false) => {
|
|
|
118
127
|
articleModifiedTime: () => seoData.value.modified,
|
|
119
128
|
ogImageSecureUrl: () => {
|
|
120
129
|
if (seoData.value.image) {
|
|
121
|
-
if (seoData.value.image.includes(
|
|
130
|
+
if (seoData.value.image.includes('?vars=')) {
|
|
122
131
|
if (seoData.value.imageType) {
|
|
123
132
|
return seoData.value.image.replace(
|
|
124
|
-
|
|
125
|
-
`.${seoData.value.imageType.replace(
|
|
126
|
-
)
|
|
127
|
-
}
|
|
128
|
-
|
|
133
|
+
'?vars=',
|
|
134
|
+
`.${seoData.value.imageType.replace('image/', '')}?vars=`,
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
return seoData.value.image.replace('?vars=', '.png?vars=')
|
|
129
139
|
}
|
|
130
140
|
}
|
|
131
|
-
return seoData.value.image
|
|
141
|
+
return seoData.value.image
|
|
132
142
|
}
|
|
133
143
|
},
|
|
134
144
|
ogImageUrl: () => {
|
|
135
145
|
if (seoData.value.image) {
|
|
136
|
-
if (seoData.value.image.includes(
|
|
146
|
+
if (seoData.value.image.includes('?vars=')) {
|
|
137
147
|
if (seoData.value.imageType) {
|
|
138
148
|
return seoData.value.image.replace(
|
|
139
|
-
|
|
140
|
-
`.${seoData.value.imageType.replace(
|
|
141
|
-
)
|
|
142
|
-
}
|
|
143
|
-
|
|
149
|
+
'?vars=',
|
|
150
|
+
`.${seoData.value.imageType.replace('image/', '')}?vars=`,
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
return seoData.value.image.replace('?vars=', '.png?vars=')
|
|
144
155
|
}
|
|
145
156
|
}
|
|
146
|
-
return seoData.value.image
|
|
157
|
+
return seoData.value.image
|
|
147
158
|
}
|
|
148
159
|
},
|
|
149
160
|
ogImageType: () => {
|
|
150
161
|
if (seoData.value.imageType) {
|
|
151
|
-
|
|
152
|
-
? seoData.value.imageType
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
162
|
+
const type = seoData.value.imageType.includes('image/')
|
|
163
|
+
? seoData.value.imageType
|
|
164
|
+
: `image/${seoData.value.imageType}`
|
|
165
|
+
if (type === 'image/jpeg' || type === 'image/gif' || type === 'image/png') {
|
|
166
|
+
return type
|
|
167
|
+
}
|
|
168
|
+
return 'image/png'
|
|
156
169
|
}
|
|
157
|
-
return undefined
|
|
170
|
+
return undefined
|
|
158
171
|
},
|
|
159
172
|
twitterImageUrl: () => {
|
|
160
173
|
if (seoData.value.image) {
|
|
161
|
-
if (seoData.value.image.includes(
|
|
174
|
+
if (seoData.value.image.includes('?vars=')) {
|
|
162
175
|
if (seoData.value.imageType) {
|
|
163
176
|
return seoData.value.image.replace(
|
|
164
|
-
|
|
165
|
-
`.${seoData.value.imageType.replace(
|
|
166
|
-
)
|
|
167
|
-
}
|
|
168
|
-
|
|
177
|
+
'?vars=',
|
|
178
|
+
`.${seoData.value.imageType.replace('image/', '')}?vars=`,
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
return seoData.value.image.replace('?vars=', '.png?vars=')
|
|
169
183
|
}
|
|
170
184
|
}
|
|
171
|
-
return seoData.value.image
|
|
185
|
+
return seoData.value.image
|
|
172
186
|
}
|
|
173
187
|
},
|
|
174
188
|
twitterImageType() {
|
|
175
189
|
if (seoData.value.imageType) {
|
|
176
|
-
|
|
177
|
-
? seoData.value.imageType
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
190
|
+
const type = seoData.value.imageType.includes('image/')
|
|
191
|
+
? seoData.value.imageType
|
|
192
|
+
: `image/${seoData.value.imageType}`
|
|
193
|
+
if (type === 'image/jpeg' || type === 'image/gif' || type === 'image/png') {
|
|
194
|
+
return type
|
|
195
|
+
}
|
|
196
|
+
return 'image/png'
|
|
181
197
|
}
|
|
182
|
-
return undefined
|
|
198
|
+
return undefined
|
|
183
199
|
},
|
|
184
|
-
})
|
|
185
|
-
}
|
|
200
|
+
})
|
|
201
|
+
}
|
package/composables/ssr.ts
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import type { Pinia } from 'pinia'
|
|
2
|
+
import type { Router } from 'vue-router'
|
|
3
|
+
import { getInitialState, getPath, getURL, getUUID } from '@fy-/fws-js'
|
|
4
|
+
import { renderSSRHead } from '@unhead/ssr'
|
|
5
|
+
import { renderToString } from '@vue/server-renderer'
|
|
6
|
+
import { useServerRouter } from '../stores/serverRouter'
|
|
7
7
|
|
|
8
8
|
export interface SSRResult {
|
|
9
9
|
initial: {
|
|
10
|
-
isSSR: boolean
|
|
11
|
-
pinia?: string
|
|
12
|
-
}
|
|
13
|
-
uuid?: string
|
|
14
|
-
meta?: string
|
|
15
|
-
link?: string
|
|
16
|
-
bodyAttributes?: string
|
|
17
|
-
bodyTagsOpen?: string
|
|
18
|
-
htmlAttributes?: string
|
|
19
|
-
bodyTags?: string
|
|
20
|
-
app?: string
|
|
21
|
-
statusCode?: number
|
|
22
|
-
redirect?: string
|
|
10
|
+
isSSR: boolean
|
|
11
|
+
pinia?: string
|
|
12
|
+
}
|
|
13
|
+
uuid?: string
|
|
14
|
+
meta?: string
|
|
15
|
+
link?: string
|
|
16
|
+
bodyAttributes?: string
|
|
17
|
+
bodyTagsOpen?: string
|
|
18
|
+
htmlAttributes?: string
|
|
19
|
+
bodyTags?: string
|
|
20
|
+
app?: string
|
|
21
|
+
statusCode?: number
|
|
22
|
+
redirect?: string
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export function isServerRendered() {
|
|
26
|
-
const state = getInitialState()
|
|
27
|
-
if (state && state.isSSR) return true
|
|
28
|
-
return false
|
|
26
|
+
const state = getInitialState()
|
|
27
|
+
if (state && state.isSSR) return true
|
|
28
|
+
return false
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export function initVueClient(router: Router, pinia: Pinia) {
|
|
32
|
-
const state = getInitialState()
|
|
32
|
+
const state = getInitialState()
|
|
33
33
|
if (state.isSSR && state && state.pinia) {
|
|
34
|
-
pinia.state.value = state.pinia
|
|
34
|
+
pinia.state.value = state.pinia
|
|
35
35
|
}
|
|
36
|
-
useServerRouter(pinia)._setRouter(router)
|
|
36
|
+
useServerRouter(pinia)._setRouter(router)
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export async function initVueServer(
|
|
@@ -41,13 +41,13 @@ export async function initVueServer(
|
|
|
41
41
|
callback: Function,
|
|
42
42
|
options: { url?: string } = {},
|
|
43
43
|
) {
|
|
44
|
-
const url
|
|
45
|
-
options.url || `${getPath()}${getURL().Query ? `?${getURL().Query}` :
|
|
46
|
-
const { app, router, head, pinia } = await createApp(true)
|
|
47
|
-
const serverRouter = useServerRouter(pinia)
|
|
48
|
-
serverRouter._setRouter(router)
|
|
49
|
-
await router.push(url)
|
|
50
|
-
await router.isReady()
|
|
44
|
+
const url
|
|
45
|
+
= options.url || `${getPath()}${getURL().Query ? `?${getURL().Query}` : ''}`
|
|
46
|
+
const { app, router, head, pinia } = await createApp(true)
|
|
47
|
+
const serverRouter = useServerRouter(pinia)
|
|
48
|
+
serverRouter._setRouter(router)
|
|
49
|
+
await router.push(url)
|
|
50
|
+
await router.isReady()
|
|
51
51
|
|
|
52
52
|
const result: SSRResult = {
|
|
53
53
|
uuid: getUUID(),
|
|
@@ -55,47 +55,49 @@ export async function initVueServer(
|
|
|
55
55
|
isSSR: true,
|
|
56
56
|
pinia: undefined,
|
|
57
57
|
},
|
|
58
|
-
}
|
|
58
|
+
}
|
|
59
59
|
|
|
60
60
|
if (url !== serverRouter.route.fullPath) {
|
|
61
|
-
result.redirect = serverRouter.route.value.fullPath
|
|
62
|
-
result.statusCode = 307
|
|
63
|
-
callback(result)
|
|
64
|
-
return result
|
|
61
|
+
result.redirect = serverRouter.route.value.fullPath
|
|
62
|
+
result.statusCode = 307
|
|
63
|
+
callback(result)
|
|
64
|
+
return result
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
try {
|
|
68
|
-
const html = await renderToString(app)
|
|
69
|
-
const payload = await renderSSRHead(head)
|
|
68
|
+
const html = await renderToString(app)
|
|
69
|
+
const payload = await renderSSRHead(head)
|
|
70
70
|
|
|
71
|
-
result.meta = payload.headTags
|
|
72
|
-
result.bodyAttributes = payload.bodyAttrs
|
|
73
|
-
result.htmlAttributes = payload.htmlAttrs
|
|
74
|
-
result.bodyTags = payload.bodyTags
|
|
75
|
-
result.bodyTagsOpen = payload.bodyTagsOpen
|
|
76
|
-
result.app = html
|
|
77
|
-
if (serverRouter.status
|
|
71
|
+
result.meta = payload.headTags
|
|
72
|
+
result.bodyAttributes = payload.bodyAttrs
|
|
73
|
+
result.htmlAttributes = payload.htmlAttrs
|
|
74
|
+
result.bodyTags = payload.bodyTags
|
|
75
|
+
result.bodyTagsOpen = payload.bodyTagsOpen
|
|
76
|
+
result.app = html
|
|
77
|
+
if (serverRouter.status !== 200) {
|
|
78
78
|
if ([301, 302, 303, 307].includes(serverRouter.status)) {
|
|
79
79
|
if (serverRouter.redirect) {
|
|
80
|
-
result.statusCode = serverRouter.status
|
|
81
|
-
result.redirect = serverRouter.redirect
|
|
80
|
+
result.statusCode = serverRouter.status
|
|
81
|
+
result.redirect = serverRouter.redirect
|
|
82
82
|
}
|
|
83
|
-
}
|
|
84
|
-
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
result.statusCode = serverRouter.status
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
serverRouter._router = null
|
|
89
|
-
result.initial.pinia = pinia.state.value
|
|
90
|
-
callback(result)
|
|
91
|
-
return result
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
89
|
+
serverRouter._router = null
|
|
90
|
+
result.initial.pinia = pinia.state.value
|
|
91
|
+
callback(result)
|
|
92
|
+
return result
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
// console.error(error);
|
|
96
|
+
result.statusCode = 500
|
|
97
|
+
const err
|
|
98
|
+
= error instanceof Error ? `${error.message}\n${error.stack}` : error
|
|
99
|
+
result.app = `<pre>${err}</pre>`
|
|
100
|
+
callback(result)
|
|
101
|
+
return result
|
|
100
102
|
}
|
|
101
103
|
}
|
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { getLocale } from '@fy-/fws-js'
|
|
2
|
+
import { format as formatDateTimeago } from 'timeago.js'
|
|
3
|
+
import { useTranslation } from './translations'
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
function cropText(str: string, ml = 100, end = '...') {
|
|
6
6
|
if (str.length > ml) {
|
|
7
|
-
return `${str.slice(0, ml)}${end}
|
|
7
|
+
return `${str.slice(0, ml)}${end}`
|
|
8
8
|
}
|
|
9
|
-
return str
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const r = parseInt(backgroundColor.substring(1, 3), 16)
|
|
13
|
-
const g = parseInt(backgroundColor.substring(3, 5), 16)
|
|
14
|
-
const b = parseInt(backgroundColor.substring(5, 7), 16)
|
|
9
|
+
return str
|
|
10
|
+
}
|
|
11
|
+
function getContrastingTextColor(backgroundColor: string) {
|
|
12
|
+
const r = Number.parseInt(backgroundColor.substring(1, 3), 16)
|
|
13
|
+
const g = Number.parseInt(backgroundColor.substring(3, 5), 16)
|
|
14
|
+
const b = Number.parseInt(backgroundColor.substring(5, 7), 16)
|
|
15
15
|
|
|
16
|
-
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255
|
|
16
|
+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255
|
|
17
17
|
|
|
18
|
-
return luminance > 0.5 ?
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (!+bytes) return
|
|
18
|
+
return luminance > 0.5 ? '#000000' : '#FFFFFF'
|
|
19
|
+
}
|
|
20
|
+
function formatBytes(bytes: number, decimals = 2) {
|
|
21
|
+
if (!+bytes) return '0 Bytes'
|
|
22
22
|
|
|
23
|
-
const k = 1024
|
|
24
|
-
const dm = decimals < 0 ? 0 : decimals
|
|
25
|
-
const sizes = [
|
|
23
|
+
const k = 1024
|
|
24
|
+
const dm = decimals < 0 ? 0 : decimals
|
|
25
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
|
26
26
|
|
|
27
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
27
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
28
28
|
|
|
29
|
-
return `${parseFloat((bytes /
|
|
30
|
-
}
|
|
29
|
+
return `${Number.parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`
|
|
30
|
+
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
let _dt = dt as number
|
|
34
|
-
if (typeof dt ===
|
|
35
|
-
_dt = Date.parse(dt)
|
|
32
|
+
function formatDate(dt: Date | string | number) {
|
|
33
|
+
let _dt = dt as number
|
|
34
|
+
if (typeof dt === 'string') {
|
|
35
|
+
_dt = Date.parse(dt)
|
|
36
36
|
if (Number.isNaN(_dt)) {
|
|
37
|
-
_dt = parseInt(dt)
|
|
37
|
+
_dt = Number.parseInt(dt)
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const translate = useTranslation()
|
|
42
|
-
return translate(
|
|
41
|
+
const translate = useTranslation()
|
|
42
|
+
return translate('global_datetime', {
|
|
43
43
|
val: new Date(_dt),
|
|
44
44
|
formatParams: {
|
|
45
45
|
val: {
|
|
46
|
-
year:
|
|
47
|
-
month:
|
|
48
|
-
day:
|
|
46
|
+
year: 'numeric',
|
|
47
|
+
month: 'long',
|
|
48
|
+
day: 'numeric',
|
|
49
49
|
},
|
|
50
50
|
},
|
|
51
|
-
})
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let _dt = dt as number
|
|
55
|
-
if (typeof dt ===
|
|
56
|
-
_dt = Date.parse(dt)
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
function formatDatetime(dt: Date | string | number) {
|
|
54
|
+
let _dt = dt as number
|
|
55
|
+
if (typeof dt === 'string') {
|
|
56
|
+
_dt = Date.parse(dt)
|
|
57
57
|
if (Number.isNaN(_dt)) {
|
|
58
|
-
_dt = parseInt(dt)
|
|
58
|
+
_dt = Number.parseInt(dt)
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
const translate = useTranslation()
|
|
62
|
-
return translate(
|
|
61
|
+
const translate = useTranslation()
|
|
62
|
+
return translate('global_datetime', {
|
|
63
63
|
val: new Date(_dt),
|
|
64
64
|
formatParams: {
|
|
65
65
|
val: {
|
|
66
|
-
year:
|
|
67
|
-
month:
|
|
68
|
-
day:
|
|
69
|
-
hour:
|
|
70
|
-
minute:
|
|
71
|
-
second:
|
|
66
|
+
year: 'numeric',
|
|
67
|
+
month: 'long',
|
|
68
|
+
day: 'numeric',
|
|
69
|
+
hour: 'numeric',
|
|
70
|
+
minute: 'numeric',
|
|
71
|
+
second: 'numeric',
|
|
72
72
|
},
|
|
73
73
|
},
|
|
74
|
-
})
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
let _dt = dt as number
|
|
78
|
-
if (typeof dt ===
|
|
79
|
-
_dt = Date.parse(dt)
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
function formatTimeago(dt: Date | string | number) {
|
|
77
|
+
let _dt = dt as number
|
|
78
|
+
if (typeof dt === 'string') {
|
|
79
|
+
_dt = Date.parse(dt)
|
|
80
80
|
if (Number.isNaN(_dt)) {
|
|
81
|
-
_dt = parseInt(dt)
|
|
81
|
+
_dt = Number.parseInt(dt)
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
return formatDateTimeago(new Date(_dt), getLocale().replace(
|
|
85
|
-
}
|
|
84
|
+
return formatDateTimeago(new Date(_dt), getLocale().replace('_', '-'))
|
|
85
|
+
}
|
|
86
86
|
|
|
87
87
|
export {
|
|
88
88
|
cropText,
|
|
@@ -91,4 +91,4 @@ export {
|
|
|
91
91
|
formatDatetime,
|
|
92
92
|
formatTimeago,
|
|
93
93
|
getContrastingTextColor,
|
|
94
|
-
}
|
|
94
|
+
}
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
1
|
+
import type { I18nBackend } from '@fy-/fws-js'
|
|
2
|
+
import type { TFunction } from 'i18next'
|
|
3
|
+
import i18next from 'i18next'
|
|
4
|
+
import { inject } from 'vue'
|
|
5
5
|
|
|
6
|
-
export type I18nextTranslate = typeof i18next.t
|
|
6
|
+
export type I18nextTranslate = typeof i18next.t
|
|
7
7
|
|
|
8
8
|
export function useTranslation() {
|
|
9
|
-
const translate = inject<TFunction>(
|
|
10
|
-
if (!translate) throw new Error(
|
|
9
|
+
const translate = inject<TFunction>('fwsVueTranslate')
|
|
10
|
+
if (!translate) throw new Error('Did you apply app.use(fwsVue)?')
|
|
11
11
|
|
|
12
|
-
return translate
|
|
12
|
+
return translate
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function i18nextPromise(
|
|
16
16
|
backend: typeof I18nBackend,
|
|
17
|
-
locale: string =
|
|
17
|
+
locale: string = 'en-US',
|
|
18
18
|
debug: boolean = false,
|
|
19
|
-
ns: string =
|
|
19
|
+
ns: string = 'translation',
|
|
20
20
|
) {
|
|
21
21
|
return i18next.use(backend).init({
|
|
22
22
|
ns: [ns],
|
|
23
23
|
defaultNS: ns,
|
|
24
|
-
debug
|
|
24
|
+
debug,
|
|
25
25
|
lng: locale,
|
|
26
|
-
load:
|
|
26
|
+
load: 'currentOnly',
|
|
27
27
|
initImmediate: false,
|
|
28
|
-
})
|
|
28
|
+
})
|
|
29
29
|
}
|