bt-core-app 1.4.2 → 1.4.3

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.
Files changed (68) hide show
  1. package/package.json +8 -2
  2. package/dist/useApi.d.ts +0 -0
  3. package/src/assets/vue.svg +0 -1
  4. package/src/components/BT-Btn.vue +0 -41
  5. package/src/components/BT-Col.vue +0 -36
  6. package/src/components/BT-Field-Checkbox.vue +0 -70
  7. package/src/components/BT-Field-Date.vue +0 -108
  8. package/src/components/BT-Field-Entity.vue +0 -48
  9. package/src/components/BT-Field-Select.vue +0 -67
  10. package/src/components/BT-Field-String.vue +0 -78
  11. package/src/components/BT-Field-Switch.vue +0 -68
  12. package/src/components/BT-Field-Tags.vue +0 -66
  13. package/src/components/BT-Field-Textarea.vue +0 -67
  14. package/src/components/BT-Field-Trigger.vue +0 -315
  15. package/src/components/BT-Header-Option.vue +0 -39
  16. package/src/components/BT-Json.vue +0 -67
  17. package/src/components/BT-Nav-Menu-Item.vue +0 -60
  18. package/src/components/BT-Nav-Sidebar.vue +0 -78
  19. package/src/components/BT-Select-List-Box.vue +0 -258
  20. package/src/components/BT-Select.vue +0 -46
  21. package/src/components/BT-Snack.vue +0 -31
  22. package/src/components/BT-Span.vue +0 -21
  23. package/src/components/Dialog-Confirm.vue +0 -47
  24. package/src/components/Dialog-Select-Date.vue +0 -89
  25. package/src/components/Dialog-Select.vue +0 -140
  26. package/src/components/Dialog-Text.vue +0 -59
  27. package/src/composables/actions-tracker.ts +0 -99
  28. package/src/composables/actions.ts +0 -354
  29. package/src/composables/api.ts +0 -479
  30. package/src/composables/auth.ts +0 -452
  31. package/src/composables/cosmetics.ts +0 -177
  32. package/src/composables/csv.ts +0 -198
  33. package/src/composables/dates.ts +0 -86
  34. package/src/composables/demo.ts +0 -33
  35. package/src/composables/dialogs.ts +0 -114
  36. package/src/composables/document-meta.ts +0 -44
  37. package/src/composables/draggable.ts +0 -189
  38. package/src/composables/filters.ts +0 -264
  39. package/src/composables/forage.ts +0 -49
  40. package/src/composables/helpers.ts +0 -647
  41. package/src/composables/id.ts +0 -20
  42. package/src/composables/list.ts +0 -604
  43. package/src/composables/navigation.ts +0 -222
  44. package/src/composables/presets.ts +0 -28
  45. package/src/composables/pwa.ts +0 -97
  46. package/src/composables/resizable.ts +0 -382
  47. package/src/composables/rules.ts +0 -40
  48. package/src/composables/stores.ts +0 -818
  49. package/src/composables/track.ts +0 -55
  50. package/src/composables/urls.ts +0 -66
  51. package/src/core.ts +0 -113
  52. package/src/index.ts +0 -48
  53. package/src/types.ts +0 -17
  54. package/src/useApi.ts +0 -68
  55. package/src/vite-env.d.ts +0 -1
  56. package/test/api.test.ts +0 -84
  57. package/test/auth.test.ts +0 -74
  58. package/test/forage.test.ts +0 -31
  59. package/test/helpers.test.ts +0 -231
  60. package/test/navigation.test.ts +0 -99
  61. package/test/stores-last-update.test.ts +0 -138
  62. package/test/stores-session.test.ts +0 -118
  63. package/test/track.test.ts +0 -29
  64. package/test/urls.test.ts +0 -42
  65. package/test/utils.ts +0 -15
  66. package/tsconfig.json +0 -28
  67. package/tsconfig.node.json +0 -11
  68. package/vite.config.ts +0 -45
@@ -1,452 +0,0 @@
1
- import { appendUrl, isLengthyArray } from '../composables/helpers'
2
- import { DateTime } from 'luxon'
3
- import { type RemovableRef, useStorage } from '@vueuse/core'
4
- import { type BTDemo } from '../composables/demo'
5
- import { useRouter } from 'vue-router'
6
- import { computed, type ComputedRef, toValue } from 'vue'
7
- import { useAuthUrl } from './urls'
8
- import { useApi } from './api'
9
-
10
- export interface AuthItem {
11
- children?: AuthItem[]
12
- ignoreSuspension?: boolean
13
- permissions?: string[]
14
- requiresAuth?: boolean
15
- subscriptions?: string[]
16
- }
17
-
18
- export interface AuthSubscription {
19
- code: string
20
- value: number
21
- }
22
-
23
- export interface BaseAuthCredentials {
24
- expiresOn?: string
25
- isGlobalAdmin?: boolean
26
- isLoggedIn?: boolean
27
- isSuspended?: boolean
28
- permissions?: string
29
- subscriptionCode?: string
30
- timeZone?: string
31
- token?: string
32
- userID?: string
33
- userPermissions?: string[]
34
- }
35
-
36
- let defaultTimeZone = 'Australia/Melbourne'
37
-
38
- // export type GetAuthUrl = (redirectPath?: string, state?: string) => string
39
-
40
- export interface CreateAuthOptions {
41
- defaultTimeZone?: string,
42
- demo?: BTDemo,
43
- /**expiry token date format. Defaults to 'd/MM/yyyy h:mm:ss a' */
44
- expiryTokenFormat?: string
45
- /**OVERRIDES CORE DEFAULT. retrieve the auth item */
46
- getAuthItem?: (navName?: string | AuthItem) => AuthItem | null
47
- /**OVERRIDES DEFAULT. the url to start the OAuth 2.0 process */
48
- getAuthorizeUrl?: (redirectPath?: string, state?: string) => string
49
- /**OVERRIDES DEFAULT. use the given code and generate the url to convert to an access token */
50
- getTokenUrl?: (code: string, redirect_uri: string, grant_type: string, client_id: string) => string
51
- /**OVERRIDES DEFAULT. */
52
- getToken?: (code?: string, state?: string) => Promise<void>
53
- oauthGrantType?: string
54
- oauthClientID?: string
55
- /**sets current credentials on top of default function
56
- * for processing the token payload and applying to state
57
- */
58
- processTokenPayload?: (state: RemovableRef<any>, payload: any) => void
59
- /**suboptions */
60
- subscriptionOptions?: AuthSubscription[]
61
- }
62
-
63
- export interface BTAuth {
64
- authState: string
65
- canEdit: (navName?: string) => boolean
66
- canEditPermit: (permit: string) => boolean
67
- canView: (navName?: string) => boolean
68
- canViewPermit: (permit: string) => boolean
69
- credentials: RemovableRef<any>
70
- doShow: (subcodes?: string[], permissions?: string[], action?: 'view' | 'edit') => boolean
71
- doShowByNav: (navName?: string | AuthItem, includeChildren?: boolean) => boolean
72
- getAuthorizeUrl: (redirectPath?: string) => string
73
- getTimeZone: () => string
74
- getToken: (code?: string, state?: string) => Promise<void>
75
- isLoggedIn: ComputedRef<boolean>
76
- login: (redirectPath?: string) => void
77
- logout: (navNameRedirect?: string) => void
78
- setAuth: (jwtToken?: string) => void
79
- timeZone: ComputedRef<string>
80
- tryLogin: () => boolean | undefined
81
- }
82
-
83
- let current: BTAuth
84
-
85
- export function useAuth(): BTAuth {
86
- return current
87
- }
88
-
89
- export function createAuth(options: CreateAuthOptions): BTAuth {
90
- const expiryFormat = options.expiryTokenFormat ?? 'd/MM/yyyy h:mm:ss a'
91
- const authState = useStorage<string>('auth-credentials-state', (Math.random().toString(36).substring(4, 19) + Math.random().toString(12).substring(1, 11)))
92
- const state = useStorage<BaseAuthCredentials>('auth-credentials', {})
93
-
94
- /**can edit if navName is undefined, isGlobalAdmin, not suspended, or user permissions allow editing of this navItem */
95
- function canEdit(navName?: string): boolean {
96
- if (navName == null) return true
97
-
98
- var navItem = options.getAuthItem != null ? options.getAuthItem(navName) : null;
99
- if (navItem == null) return false
100
- if (navItem.requiresAuth === false) return true
101
-
102
- const mState = toValue(state)
103
- if (mState.isSuspended && navItem.ignoreSuspension !== true) return false
104
- if (mState.isGlobalAdmin) return true
105
-
106
- if (navItem.permissions != null) {
107
- for (var ii = 0; ii < navItem.permissions.length; ii++) {
108
- if (!canEditPermit(navItem.permissions[ii])) {
109
- return false
110
- }
111
- }
112
- }
113
-
114
- return true;
115
- }
116
-
117
- /**purely tests for whether this permit is in the user's permissions list.
118
- * Or else the user just needs the 'everything.edit' permission.
119
- */
120
- function canEditPermit(permit: string): boolean {
121
- const mState = toValue(state)
122
-
123
- if (mState.userPermissions != null) {
124
- for (var i = 0; i < mState.userPermissions.length; i++) {
125
- var parts = mState.userPermissions[i].split('.');
126
- if (mState.userPermissions[i] == 'everything.edit' ||
127
- permit == parts[0] && parts.length > 1 && parts[1] == 'edit') {
128
- return true;
129
- }
130
- }
131
- }
132
-
133
- return false
134
- }
135
-
136
- /**can view if navName is undefined, isGlobalAdmin, not susepended, or user permissions allow viewing of this navItem */
137
- function canView(navName: string | undefined): boolean {
138
- if (navName == null) return true
139
-
140
- var navItem = options.getAuthItem != null ? options.getAuthItem(navName) : null;
141
- if (navItem == null) return false
142
- if (navItem.requiresAuth === false) return true
143
-
144
- const mState = toValue(state)
145
- if (mState.isSuspended && navItem.ignoreSuspension !== true) return false
146
- if (mState.isGlobalAdmin) return true
147
-
148
- if (navItem.permissions != null) {
149
- for (var ii = 0; ii < navItem.permissions.length; ii++) {
150
- if (!canViewPermit(navItem.permissions[ii])) {
151
- return false;
152
- }
153
- }
154
- }
155
-
156
- return true;
157
- }
158
-
159
- /**purely tests for whether this permit is in the user's permissions list.
160
- * Or else the user just needs the 'everything.view' permission or '[permit].edit'.
161
- */
162
- function canViewPermit(permit: string): boolean {
163
- const mState = toValue(state)
164
-
165
- if (mState.userPermissions != null) {
166
- for (var i = 0; i < mState.userPermissions.length; i++) {
167
- var parts = mState.userPermissions[i].split('.');
168
- if (permit == parts[0] || permit == 'everything' ||
169
- mState.userPermissions[i] == 'everything.view' ||
170
- mState.userPermissions[i] == 'everything.edit') {
171
- return true;
172
- }
173
- }
174
- }
175
-
176
- return false;
177
- }
178
-
179
- /**doesn't check for suspension
180
- * if user
181
- */
182
- function doShow(subcodes?: string[], permissions?: string[], action?: 'view' | 'edit'): boolean {
183
- let doShowRes = true
184
-
185
- const mState = toValue(state)
186
- if (mState.isGlobalAdmin) return true
187
-
188
- if (permissions != null && permissions.length > 0) {
189
- permissions.forEach((permit: string) => {
190
- if (action == 'edit') {
191
- if (!canEditPermit(permit)) {
192
- doShowRes = false
193
- }
194
- }
195
- else {
196
- //otherwise it will be view
197
- if (!canViewPermit(permit)) {
198
- doShowRes = false
199
- }
200
- }
201
- })
202
- }
203
-
204
- if (subcodes != null && subcodes.length > 0) {
205
- if (!subcodes.some((subCode: string) => isWithinSubscription(subCode))) {
206
- doShowRes = false
207
- }
208
- }
209
-
210
- return doShowRes
211
- }
212
-
213
- function doShowByNav(navName?: string | AuthItem, includeChildren: boolean = false) {
214
- var navItem = options.getAuthItem != null ? options.getAuthItem(navName) : null;
215
- let doShowRes = false;
216
-
217
- if (navItem == null) return false
218
-
219
- let subcodes = navItem.subscriptions ?? []
220
- let permissions = navItem.permissions ?? []
221
- let oRes = doShow(subcodes, permissions, 'view');
222
-
223
- if (oRes || !includeChildren || !isLengthyArray(navItem.children))
224
- return oRes
225
-
226
- if (navItem?.children != null) {
227
- navItem.children.forEach(child => {
228
- if (doShowByNav(child, true)) {
229
- doShowRes = true;
230
- }
231
- })
232
- }
233
-
234
- return doShowRes;
235
- }
236
-
237
- function getAuthorizeUrl(redirectPath?: string) {
238
- options.getAuthorizeUrl ??= (redirectPath?: string, state?: string) => {
239
- const path = appendUrl(useAuthUrl(), `authorize?response_type=code&client_id=${options.oauthClientID}&redirect_uri=${window.location.origin}/authentication&state=${state}`)
240
- return redirectPath ? `${path}&redirect_path=${redirectPath}` : path
241
- }
242
-
243
- if (options.getAuthorizeUrl != null)
244
- return options.getAuthorizeUrl(redirectPath, authState.value) ?? ''
245
-
246
- return ''
247
- }
248
-
249
- /**undefined or unfound is worth 0 */
250
- function getSubscriptionCodeValue(subCode?: string) {
251
- if (subCode == null) return 0
252
- let subList = options.subscriptionOptions ?? []
253
- return subList.find(x => x.code == subCode)?.value ?? 0
254
- }
255
-
256
- /**identifies whether user's subscription level allows for this subCode */
257
- function isWithinSubscription(subCode?: string) {
258
- const mState = toValue(state)
259
-
260
- if (mState.subscriptionCode == null) return false
261
- if (mState.subscriptionCode == subCode) return true
262
-
263
- const subLevelNeeded = getSubscriptionCodeValue(subCode)
264
- const subCompanyLevel = getSubscriptionCodeValue(mState.subscriptionCode)
265
-
266
- return subLevelNeeded <= subCompanyLevel
267
- }
268
-
269
- /**decrypts jwt token */
270
- function jwtDecrypt(token: string) {
271
- const base64Url = token.split('.')[1];
272
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
273
- const jsonPayload = decodeURIComponent(
274
- atob(base64)
275
- .split("")
276
- .map(function(c) {
277
- return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
278
- })
279
- .join("")
280
- );
281
-
282
- return JSON.parse(jsonPayload);
283
- }
284
-
285
- /**clears credentials and potentially redirects */
286
- function logout(navNameRedirect?: string) {
287
- state.value = undefined
288
-
289
- //ensure time zone still exists
290
- reinstateDefaults()
291
-
292
- //clear stores
293
-
294
- //maybe redirect
295
- if (navNameRedirect != null) {
296
- const router = useRouter()
297
- if (router.currentRoute.value.name != navNameRedirect) {
298
- router.push({ name: navNameRedirect })
299
- }
300
- }
301
- }
302
-
303
- /**Redirects to OAuth 2.0 process if not yet logged in and token expired. Ends demo. */
304
- function login(redirectPath?: string) {
305
- const mState = toValue(state)
306
-
307
- if (!mState.isLoggedIn) {
308
- options.demo?.endDemo()
309
- if (tokenExpired()) {
310
- logout()
311
- window.location.href = getAuthorizeUrl(redirectPath) //}response_type=code&client_id=appClient1&redirect_path=${redirectPath}` : getAuthUrl()
312
- }
313
- }
314
- }
315
-
316
- /**defaults to find parameters from route query */
317
- async function getToken(code?: string, state?: string) {
318
- options.getToken ??= async () => {
319
- let mCode = code
320
- let mState = state
321
- let mGrantType = options.oauthGrantType ?? 'authorization_token'
322
- let mClientID = options.oauthClientID ?? ''
323
-
324
- if (mCode == null || mState == null) {
325
- throw new Error('Code and State required in OAuth token process')
326
- }
327
-
328
- if (mState != authState.value)
329
- throw new Error('state does not match')
330
-
331
- let url = ''
332
-
333
- options.getTokenUrl ??= () => {
334
- return appendUrl(useAuthUrl(), 'token')
335
- }
336
-
337
- url = options.getTokenUrl(mCode, `${window.location.origin}/authentication`, mGrantType, mClientID)
338
-
339
- const formData: any = {}
340
- formData['grant_type'] = mGrantType
341
- formData['code'] = mCode
342
- formData['redirect_uri'] = `${window.location.origin}/authentication`
343
- formData['client_id'] = mClientID
344
-
345
- const api = useApi()
346
- const res = await api.post<any>({
347
- additionalUrl: url,
348
- data: formData
349
- })
350
-
351
- // const res = await fetch(url, {
352
- // method: 'POST',
353
- // mode: 'cors',
354
- // cache: 'no-cache',
355
- // body: JSON.stringify(formData)
356
- // })
357
-
358
- // const data = await res.json()
359
-
360
- setAuth(res.access_token)
361
- }
362
-
363
- return await options.getToken(code, state)
364
- }
365
-
366
- /**if not demoing, then will decrypt the jwtToken and attempt to set credentials */
367
- function setAuth(jwtToken?: string) {
368
- if (jwtToken == null) return
369
-
370
- if (options.demo == null || !options.demo.isDemoing.value) {
371
- const d = jwtDecrypt(jwtToken)
372
-
373
- setDefaultAuth(d)
374
-
375
- if (options.processTokenPayload != null)
376
- options.processTokenPayload(state, d)
377
- }
378
- }
379
-
380
- function setDefaultAuth(d: any) {
381
- const v = state.value
382
- v.expiresOn = d.ExpiresOn
383
- v.isGlobalAdmin = d.IsGlobalAdmin == 'True'
384
- v.isLoggedIn = true
385
- v.permissions = d.Permissions
386
- v.subscriptionCode = d.Subscription
387
-
388
- // v.subscriptionsInUse = d.SubscriptionsInUse
389
- v.timeZone ??= (options.defaultTimeZone ?? defaultTimeZone)
390
-
391
- v.token = d
392
- v.userID = d.UserLoginID
393
- v.userPermissions = d.Permissions?.split(',') ?? []
394
- }
395
-
396
- function reinstateDefaults() {
397
- state.value ??= {}
398
- state.value.timeZone ??= (options.defaultTimeZone ?? defaultTimeZone)
399
- }
400
-
401
- function getTimeZone() {
402
- return state.value.timeZone ?? options.defaultTimeZone ?? defaultTimeZone
403
- }
404
-
405
- /**returns whether or not logged in. Potentially redirects to OAauth 2.0 process if logged in and expired */
406
- function tryLogin() {
407
- const mState = toValue(state)
408
-
409
- //what if no internet?
410
- if (mState.isLoggedIn && tokenExpired()) {
411
- logout()
412
- window.location.href = getAuthorizeUrl()
413
- }
414
-
415
- return mState.isLoggedIn
416
- }
417
-
418
- function tokenExpired() {
419
- const mState = toValue(state)
420
- if (mState == null || mState.expiresOn == null) return true
421
-
422
- const e1 = DateTime.fromFormat(mState.expiresOn, expiryFormat)
423
- const e2 = DateTime.utc()
424
- return e1 <= e2
425
- }
426
-
427
- reinstateDefaults()
428
-
429
- current = {
430
- authState: authState.value,
431
- canEdit,
432
- canEditPermit,
433
- canView,
434
- canViewPermit,
435
- credentials: state,
436
- doShow,
437
- doShowByNav,
438
- getAuthorizeUrl,
439
- getTimeZone,
440
- getToken,
441
- isLoggedIn: computed(() => state.value.isLoggedIn === true),
442
- login,
443
- logout,
444
- setAuth,
445
- timeZone: computed(() => {
446
- return state.value.timeZone ?? options.defaultTimeZone ?? defaultTimeZone
447
- }),
448
- tryLogin
449
- }
450
-
451
- return current
452
- }
@@ -1,177 +0,0 @@
1
- import { RemovableRef, useStorage } from '@vueuse/core'
2
- import { useTheme } from 'vuetify';
3
-
4
- interface CosmeticData {
5
- dark?: BaseCosmeticTheme,
6
- drawer?: boolean,
7
- drawerStick?: boolean,
8
- light?: BaseCosmeticTheme,
9
- theme?: string
10
- }
11
-
12
- export interface BaseCosmeticTheme {
13
- primary: string,
14
- secondary: string,
15
- accent: string,
16
- error: string,
17
- info: string,
18
- success: string,
19
- warning: string,
20
- }
21
-
22
- const defaultLight: BaseCosmeticTheme = {
23
- primary: '#192233',
24
- secondary: '#192233',
25
- accent: '#2a76a2',
26
- error: '#FF5252',
27
- info: '#2196F3',
28
- success: '#4CAF50',
29
- warning: '#FB8C00'
30
- }
31
-
32
- const defaultDark: BaseCosmeticTheme = {
33
- primary: '#1d5474',
34
- secondary: '#192233',
35
- accent: '#7fcbf7',
36
- error: '#FF5252',
37
- info: '#2196F3',
38
- success: '#4CAF50',
39
- warning: '#FB8C00'
40
- }
41
-
42
- export interface UseCosmeticsOptions<T extends BaseCosmeticTheme> {
43
- defaultDarkTheme?: T
44
- defaultLightTheme?: T
45
- defaultDrawer?: boolean
46
- defaultDrawerStick?: boolean
47
- defaultTheme?: string
48
- }
49
-
50
- export interface BTCosmetics {
51
- state: RemovableRef<CosmeticData>
52
- initiate: () => void
53
- resetCosmetics: (toDefault: boolean) => void
54
- setTemporaryColor: (color: string) => void
55
- toggleDrawer: () => void
56
- toggleDrawerStick: () => void
57
- toggleLightDark: () => void
58
- undoTemporaryColor: () => void
59
- }
60
-
61
- let defaults: any = {}
62
- let state: RemovableRef<CosmeticData>
63
-
64
- export function useCosmetics(): BTCosmetics {
65
- const themeManager = useTheme()
66
-
67
- /**used for initiating the themes and colors from storage when the web app is loaded */
68
- function loadCosmetics() {
69
- themeManager.global.name.value = state.value.theme!
70
-
71
- //load dark colors
72
- let darkColors = themeManager.themes.value.dark.colors
73
- let storedDarkTheme = state.value.dark!
74
- const darkThemeKeys = Object.keys(storedDarkTheme)
75
- darkThemeKeys.forEach(darkKey => {
76
- const k = darkKey as keyof typeof storedDarkTheme
77
- darkColors[darkKey] = storedDarkTheme[k]
78
- })
79
-
80
- let lightColors = themeManager.themes.value.light.colors
81
- let storedLightTheme = state.value.light!
82
- const lightThemeKeys = Object.keys(storedLightTheme)
83
- lightThemeKeys.forEach(lightKey => {
84
- const lKey = lightKey as keyof typeof storedLightTheme
85
- lightColors[lKey] = storedLightTheme[lKey]
86
- })
87
- }
88
-
89
- /**resets to the default colors or last saved colors of the current theme */
90
- function resetCosmetics(toDefault: boolean) {
91
- themeManager.global.name.value = state.value.theme!
92
-
93
- if (themeManager.global.name.value == 'dark') {
94
- //dark
95
- if (toDefault)
96
- state.value.dark = { ...(defaults.defaultDarkTheme ?? defaultDark) };
97
-
98
- themeManager.themes.value.dark = {
99
- ...themeManager.themes.value.dark,
100
- colors: {
101
- ...themeManager.themes.value.dark.colors,
102
- ...state.value.dark
103
- }
104
- }
105
- }
106
- else {
107
- //light
108
- if (toDefault)
109
- state.value.light = { ...(defaults.defaultLightTheme ?? defaultLight) };
110
-
111
- themeManager.themes.value.light = {
112
- ...themeManager.themes.value.light,
113
- colors: {
114
- ...themeManager.themes.value.light.colors,
115
- ...state.value.light
116
- }
117
- }
118
- }
119
- }
120
-
121
- /**sets a temporary primary color that is not saved but is applied to cosmetics */
122
- function setTemporaryColor(color: string) {
123
- const dark = themeManager.themes.value.dark
124
- const light = themeManager.themes.value.light
125
-
126
- dark.colors.primary = color
127
- light.colors.primary = color
128
-
129
- document.querySelector('meta[name="theme-color"]')?.setAttribute("content", color)
130
- }
131
-
132
- function toggleDrawer() {
133
- state.value.drawer = !state.value.drawer
134
- }
135
-
136
- function toggleDrawerStick() {
137
- state.value.drawerStick = !state.value.drawerStick
138
- }
139
-
140
- function toggleLightDark() {
141
- state.value.theme = state.value.theme == 'dark' ? 'light' : 'dark'
142
- themeManager.global.name.value = state.value.theme
143
- }
144
-
145
- function undoTemporaryColor() {
146
- const dark = themeManager.themes.value.dark
147
- const light = themeManager.themes.value.light
148
-
149
- dark.colors.primary = (state.value.dark ?? defaults.defaultDarkTheme ?? defaultDark).primary
150
- light.colors.primary = (state.value.light ?? defaults.defaultLightTheme ?? defaultLight).primary
151
-
152
- document.querySelector('meta[name="theme-color"]')?.setAttribute("content", '')
153
- }
154
-
155
- return {
156
- state: state,
157
- initiate: loadCosmetics,
158
- resetCosmetics,
159
- setTemporaryColor,
160
- toggleDrawer,
161
- toggleDrawerStick,
162
- toggleLightDark,
163
- undoTemporaryColor
164
- }
165
- }
166
-
167
- export function createCosmetics<T extends BaseCosmeticTheme>(options: UseCosmeticsOptions<T>) {
168
- state = useStorage<CosmeticData>('cosmetics', {
169
- theme: options.defaultTheme ?? 'light',
170
- light: options.defaultLightTheme ?? defaultLight,
171
- dark: options.defaultDarkTheme ?? defaultDark,
172
- drawer: options.defaultDrawer ?? true,
173
- drawerStick: options.defaultDrawerStick ?? false
174
- })
175
-
176
- defaults = options
177
- }