@nside/wefa 0.3.0 → 0.4.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.
Files changed (156) hide show
  1. package/README.md +46 -3
  2. package/dist/LegalConsent-9nOroDoA.cjs +1 -0
  3. package/dist/LegalConsent-CrPVZOxx.js +151 -0
  4. package/dist/LegalDocument-CVJiGmPJ.cjs +109 -0
  5. package/dist/{LegalDocument-BhoEpJ2O.js → LegalDocument-DwVhwjIf.js} +236 -215
  6. package/dist/{LoginView-kH440cCh.js → LoginView-DUPa_PsC.js} +3 -3
  7. package/dist/{LoginView-IIkXXw3R.cjs → LoginView-Dihs8n_X.cjs} +1 -1
  8. package/dist/{LogoutView-DGqh4bP7.js → LogoutView-DAh7MrFi.js} +3 -3
  9. package/dist/{LogoutView-B90MA-_Q.cjs → LogoutView-Fl3nfeJ0.cjs} +1 -1
  10. package/dist/{apiClient-DJdAL3tN.cjs → apiClient-BUS5ZclN.cjs} +1 -1
  11. package/dist/{apiClient-D-kcx_S1.js → apiClient-BbJl566D.js} +1 -1
  12. package/dist/axios-CZvsFspN.js +1887 -0
  13. package/dist/axios-DMqeKDaq.cjs +6 -0
  14. package/dist/containers.cjs +590 -5
  15. package/dist/containers.d.ts +39 -0
  16. package/dist/containers.js +3803 -977
  17. package/dist/{index-Coos428-.js → index--_rUTrqU.js} +308 -282
  18. package/dist/{index-B4vneBZh.cjs → index-B4oFnh1T.cjs} +6 -6
  19. package/dist/index-BHSxFTgZ.js +49 -0
  20. package/dist/{index-BSfhC_wu.cjs → index-BaA_oL1s.cjs} +1 -1
  21. package/dist/{index-CJmnkrIs.cjs → index-Becfy0pF.cjs} +1 -1
  22. package/dist/{index-Dj5oTSEE.js → index-C09d0pI4.js} +15 -15
  23. package/dist/{index-BXrnPbjr.cjs → index-CbQWytWd.cjs} +4 -4
  24. package/dist/{index-DmVIgb18.js → index-CgAb-gZi.js} +11 -11
  25. package/dist/{index-B53YL3vD.cjs → index-DFOQKDki.cjs} +2 -2
  26. package/dist/index-DFSkcsx-.cjs +943 -0
  27. package/dist/{index-CEz0St1t.js → index-DQFN7qxo.js} +7 -7
  28. package/dist/index-DRozw3P8.js +167 -0
  29. package/dist/index-DfCQoHSf.cjs +146 -0
  30. package/dist/index-DkuJMEY1.js +6731 -0
  31. package/dist/{index-bRjoenrr.js → index-Dv6jyKbT.js} +12 -12
  32. package/dist/{index-Bl3JVLei.cjs → index-EDm9-cRY.cjs} +1 -1
  33. package/dist/index-IGN7_cyg.cjs +2 -0
  34. package/dist/{index-DGvdYnh3.js → index-lFl6UsTa.js} +7 -7
  35. package/dist/index-lQmq7gxp.cjs +54 -0
  36. package/dist/{index-FS8xE7Mo.js → index-xUb0UC07.js} +5 -5
  37. package/dist/lib-C3DWunRS.js +26376 -0
  38. package/dist/lib-COvHzA2Y.cjs +2104 -0
  39. package/dist/lib.cjs +1 -1
  40. package/dist/lib.d.ts +160 -7
  41. package/dist/lib.js +33 -30
  42. package/dist/libRoutes-B-H3e9wZ.js +22 -0
  43. package/dist/libRoutes-Cl3TklhN.cjs +1 -0
  44. package/dist/network.cjs +1 -1
  45. package/dist/network.d.ts +19 -0
  46. package/dist/network.js +3 -3
  47. package/dist/router.cjs +1 -1
  48. package/dist/router.d.ts +26 -4
  49. package/dist/router.js +10 -10
  50. package/package.json +55 -48
  51. package/src/assets/main.css +2 -2
  52. package/src/components/AutoroutedBreadcrumb/AutoroutedBreadcrumb.mdx +8 -8
  53. package/src/components/AutoroutedBreadcrumb/AutoroutedBreadcrumb.spec.ts +86 -45
  54. package/src/components/AutoroutedBreadcrumb/AutoroutedBreadcrumb.vue +29 -21
  55. package/src/components/AvatarComponent/AvatarComponent.mdx +63 -0
  56. package/src/components/AvatarComponent/AvatarComponent.stories.ts +98 -0
  57. package/src/components/AvatarComponent/AvatarComponent.vue +115 -0
  58. package/src/components/GanttChartComponent/GanttChartComponent.mdx +143 -0
  59. package/src/components/GanttChartComponent/GanttChartComponent.spec.ts +257 -0
  60. package/src/components/GanttChartComponent/GanttChartComponent.stories.ts +253 -0
  61. package/src/components/GanttChartComponent/GanttChartComponent.vue +220 -0
  62. package/src/components/GanttChartComponent/GanttChartGrid.vue +66 -0
  63. package/src/components/GanttChartComponent/GanttChartHeaderGrid.vue +167 -0
  64. package/src/components/GanttChartComponent/GanttChartHeaderLabel.vue +23 -0
  65. package/src/components/GanttChartComponent/GanttChartLinksOverlay.vue +105 -0
  66. package/src/components/GanttChartComponent/GanttChartRowGrid.vue +288 -0
  67. package/src/components/GanttChartComponent/GanttChartRowLabel.vue +32 -0
  68. package/src/components/GanttChartComponent/composables/useGanttLinks.ts +212 -0
  69. package/src/components/GanttChartComponent/composables/useGanttSizing.ts +42 -0
  70. package/src/components/GanttChartComponent/ganttChartLayout.ts +211 -0
  71. package/src/components/GanttChartComponent/ganttChartTypes.ts +24 -0
  72. package/src/components/GanttChartComponent/index.ts +1 -0
  73. package/src/components/NetworkButton/ApiMutationButton.vue +7 -5
  74. package/src/components/NetworkButton/ApiQueryButton.vue +6 -4
  75. package/src/components/PlotlyComponent/PlotlyComponent.stories.ts +74 -45
  76. package/src/containers/BareContainer/BareContainer.mdx +1 -1
  77. package/src/containers/LayoutContainer/LayoutContainer.mdx +128 -0
  78. package/src/containers/LayoutContainer/LayoutContainer.spec.ts +151 -0
  79. package/src/containers/LayoutContainer/LayoutContainer.stories.ts +292 -0
  80. package/src/containers/LayoutContainer/LayoutContainer.vue +53 -0
  81. package/src/containers/LayoutContainer/MobileNavigationComponent/MobileNavigationComponent.spec.ts +139 -0
  82. package/src/containers/LayoutContainer/MobileNavigationComponent/MobileNavigationComponent.vue +63 -0
  83. package/src/containers/LayoutContainer/SideNavigationComponent/BottomComponent/BottomComponent.spec.ts +39 -0
  84. package/src/containers/LayoutContainer/SideNavigationComponent/BottomComponent/BottomComponent.vue +9 -0
  85. package/src/containers/LayoutContainer/SideNavigationComponent/MainComponent/MainComponent.spec.ts +175 -0
  86. package/src/containers/LayoutContainer/SideNavigationComponent/MainComponent/MainComponent.vue +163 -0
  87. package/src/containers/LayoutContainer/SideNavigationComponent/MainComponent/NavigationLinkComponent.spec.ts +105 -0
  88. package/src/containers/LayoutContainer/SideNavigationComponent/MainComponent/NavigationLinkComponent.vue +45 -0
  89. package/src/containers/LayoutContainer/SideNavigationComponent/SideNavigationComponent.spec.ts +78 -0
  90. package/src/containers/LayoutContainer/SideNavigationComponent/SideNavigationComponent.vue +29 -0
  91. package/src/containers/LayoutContainer/SideNavigationComponent/TopComponent/TopComponent.spec.ts +60 -0
  92. package/src/containers/LayoutContainer/SideNavigationComponent/TopComponent/TopComponent.vue +56 -0
  93. package/src/containers/LayoutContainer/UserMenuTriggerComponent/UserMenuTriggerComponent.spec.ts +96 -0
  94. package/src/containers/LayoutContainer/UserMenuTriggerComponent/UserMenuTriggerComponent.vue +80 -0
  95. package/src/containers/LayoutContainer/index.ts +1 -0
  96. package/src/containers/NavbarContainer/NavbarContainer.mdx +1 -1
  97. package/src/containers/RoutedTabsComponent/RoutedTabsComponent.mdx +3 -3
  98. package/src/containers/SideMenuContainer/SideMenuContainer.mdx +1 -1
  99. package/src/containers/helpers.ts +6 -3
  100. package/src/containers/index.ts +2 -0
  101. package/src/containers/storybook/PlaceholderView.vue +1 -1
  102. package/src/containers/storybook/PrimeComponents.stories.ts +17 -0
  103. package/src/containers/storybook/PrimeComponentsShowcase.vue +587 -0
  104. package/src/containers/storybook/overview.mdx +36 -36
  105. package/src/demo/App.vue +7 -0
  106. package/src/{demo.ts → demo/main.ts} +8 -9
  107. package/src/demo/router.ts +65 -19
  108. package/src/demo/views/PlaygroundView.vue +86 -0
  109. package/src/demo/views/ShowcaseView.vue +41 -0
  110. package/src/lib.ts +3 -1
  111. package/src/locales/Translation.mdx +2 -2
  112. package/src/locales/en/avatar.json +3 -0
  113. package/src/locales/en/gantt_chart.json +6 -0
  114. package/src/locales/en/navigation.json +3 -1
  115. package/src/locales/index.ts +0 -4
  116. package/src/plugins/legalConsent/views/__tests__/LegalConsent.test.ts +12 -7
  117. package/src/router/guards.ts +4 -4
  118. package/src/router/libRoutes.ts +6 -2
  119. package/src/router/router.mdx +107 -66
  120. package/src/router/types.ts +24 -3
  121. package/src/stores/__tests__/backend/jwt.test.ts +4 -4
  122. package/src/stores/__tests__/backend/oauth.test.ts +104 -0
  123. package/src/stores/__tests__/backend/token.test.ts +4 -4
  124. package/src/stores/authentication.mdx +138 -0
  125. package/src/stores/backend/common.ts +89 -0
  126. package/src/stores/backend/constants.ts +22 -0
  127. package/src/stores/backend/schemes/jwt.ts +208 -0
  128. package/src/stores/backend/schemes/oauth.ts +142 -0
  129. package/src/stores/backend/schemes/token.ts +122 -0
  130. package/src/stores/backend/types.ts +96 -0
  131. package/src/stores/backend.ts +21 -427
  132. package/src/stores/index.ts +6 -0
  133. package/src/theme/index.ts +2 -0
  134. package/src/theme/nside.ts +157 -0
  135. package/src/utils/color.spec.ts +24 -0
  136. package/src/utils/color.ts +100 -0
  137. package/src/utils/translations.ts +0 -4
  138. package/dist/LegalConsent-CEcXZml6.cjs +0 -1
  139. package/dist/LegalConsent-Dzq3fdnt.js +0 -277
  140. package/dist/LegalDocument-CS3MnOcV.cjs +0 -109
  141. package/dist/axios-ClRPr3Xn.js +0 -1777
  142. package/dist/axios-Dcidtc2l.cjs +0 -6
  143. package/dist/index-Bc699sOR.js +0 -4997
  144. package/dist/index-CL_OJMNr.cjs +0 -55
  145. package/dist/index-CTNsucOq.cjs +0 -147
  146. package/dist/index-CwLAV8WF.js +0 -210
  147. package/dist/index-FrfvunRp.cjs +0 -146
  148. package/dist/lib-BBJH9d11.cjs +0 -2792
  149. package/dist/lib-Y8FPgwH4.js +0 -20886
  150. package/dist/libRoutes-BsneoQ4G.js +0 -18
  151. package/dist/libRoutes-BzeZrIaK.cjs +0 -1
  152. package/src/demo/DemoApp.vue +0 -13
  153. package/src/demo/ShowcaseView.vue +0 -39
  154. package/src/demo/demo.css +0 -15
  155. /package/src/demo/{DemoContent.vue → views/DemoContent.vue} +0 -0
  156. /package/src/demo/{DemoView.vue → views/DemoView.vue} +0 -0
@@ -1,61 +1,19 @@
1
1
  import { defineStore, type Pinia, type StoreDefinition } from 'pinia'
2
- import { type Ref, ref, watch, type WatchHandle } from 'vue'
3
- import type { AxiosResponse, AxiosError, InternalAxiosRequestConfig, AxiosInstance } from 'axios'
4
- import type { Router } from 'vue-router'
5
- import axiosInstance from '@/network/axios'
6
-
7
- /**
8
- * Represents the types of authentication mechanisms that can be used.
9
- *
10
- * This type includes the following options:
11
- * - 'TOKEN': Authentication is performed using a token-based system.
12
- * - 'JWT': Authentication is performed using JSON Web Tokens.
13
- * - 'SESSION': Authentication is managed using session-based mechanisms.
14
- *
15
- * Note: Future enhancement could include more flexible procedures registration
16
- * (postLogin, postLogout) to allow different actors to register their procedures
17
- * on some collection.
18
- */
19
- export type AuthenticationType = 'TOKEN' | 'JWT' | 'SESSION'
20
-
21
- /**
22
- * Represents a set of credentials consisting of a username and password.
23
- * Typically used for authentication purposes.
24
- */
25
- export interface Credentials {
26
- username: string
27
- password: string
28
- }
29
-
30
- export interface BackendStore {
31
- authenticated: Ref<boolean>
32
- axiosInstance: AxiosInstance
33
- login: (credentials: Credentials) => Promise<AxiosResponse>
34
- logout: () => void
35
- setPostLogin: (fn: () => void) => void
36
- setPostLogout: (fn: () => void) => void
37
- setupAuthRouteGuard: (router: Router) => void
38
- unsetAuthRouteGuard: () => void
39
- }
40
-
41
- export interface BackendStoreOptions {
42
- authenticationType: AuthenticationType
43
- }
44
-
45
- /**
46
- * A constant variable used as the key for storing and retrieving the authentication token
47
- * in the browser's localStorage. This key is utilized to maintain user session or
48
- * authentication state across browser sessions by securely saving the token locally.
49
- */
50
- const localStorageKey = 'authenticationToken'
51
-
52
- /**
53
- * Constants used as keys for storing and retrieving JWT authentication tokens
54
- * in the browser's localStorage. These keys are utilized to maintain user session or
55
- * authentication state across browser sessions by securely saving the tokens locally.
56
- */
57
- const jwtAccessTokenKey = 'jwtAccessToken'
58
- const jwtRefreshTokenKey = 'jwtRefreshToken'
2
+ import type { BackendStore, BackendStoreOptions } from './backend/types'
3
+ import { jwtAuthenticationBackendStoreSetup } from './backend/schemes/jwt.ts'
4
+ import { oauthAuthenticationBackendStoreSetup } from './backend/schemes/oauth.ts'
5
+ import { tokenAuthenticationBackendStoreSetup } from './backend/schemes/token.ts'
6
+
7
+ export type {
8
+ AuthenticationEndpoints,
9
+ AuthenticationType,
10
+ BackendStore,
11
+ BackendStoreOptions,
12
+ Credentials,
13
+ JwtEndpoints,
14
+ OAuthEndpoints,
15
+ TokenEndpoints,
16
+ } from './backend/types'
59
17
 
60
18
  export const useBackendStore = (
61
19
  options: BackendStoreOptions,
@@ -76,378 +34,14 @@ export const defineBackendStore = (backendStoreOptions: BackendStoreOptions): St
76
34
  function getBackendStoreSetup(backendStoreOptions: BackendStoreOptions): BackendStore {
77
35
  switch (backendStoreOptions.authenticationType) {
78
36
  case 'TOKEN':
79
- return tokenAuthenticationBackendStoreSetup()
37
+ return tokenAuthenticationBackendStoreSetup(backendStoreOptions)
80
38
  case 'JWT':
81
- return jwtAuthenticationBackendStoreSetup()
39
+ return jwtAuthenticationBackendStoreSetup(backendStoreOptions)
40
+ case 'OAUTH':
41
+ return oauthAuthenticationBackendStoreSetup(backendStoreOptions)
42
+ case 'SESSION':
43
+ throw new Error('SESSION authentication is not yet supported.')
82
44
  default:
83
45
  throw new Error(`Unknown authentication type: ${backendStoreOptions.authenticationType}`)
84
46
  }
85
47
  }
86
-
87
- /**
88
- * Creates common authentication functions that can be shared between different authentication implementations.
89
- * @param authenticated - Reactive reference to the authentication state
90
- * @param postLogin - Reactive reference to the post-login callback
91
- * @param postLogout - Reactive reference to the post-logout callback
92
- * @returns An object containing common authentication functions
93
- */
94
- function createCommonAuthFunctions(
95
- authenticated: Ref<boolean>,
96
- postLogin: Ref<() => void>,
97
- postLogout: Ref<() => void>
98
- ) {
99
- let authRouteGuardWatcher: WatchHandle | null = null
100
-
101
- /**
102
- * Sets the function to be executed after login.
103
- * @param fn - A callback function to execute post-login.
104
- */
105
- function setPostLogin(fn: () => void): void {
106
- postLogin.value = fn
107
- }
108
-
109
- /**
110
- * Sets the postLogout function to be called after a logout action.
111
- * @param fn - A function to be executed post-logout.
112
- */
113
- function setPostLogout(fn: () => void): void {
114
- postLogout.value = fn
115
- }
116
-
117
- /**
118
- * Sets up a route guard that responds to authentication status changes
119
- *
120
- * This function should be installed in the root component (App.vue) setup script to ensure
121
- * proper route reevaluation when authentication status changes. It forces the router to
122
- * reevaluate the current route, allowing navigation guards to run again and potentially
123
- * redirect the user based on the new authentication state.
124
- * @param router - Vue Router instance
125
- * @example
126
- * // In App.vue setup script, given you have a router setup
127
- * import router from '@/router'
128
- * import { useBackendStore } from '@/stores/backend'
129
- *
130
- * const backendStore = useBackendStore()
131
- *
132
- * // Set up auth route guard to respond to authentication changes
133
- * backendStore.setupAuthRouteGuard(router)
134
- */
135
- function setupAuthRouteGuard(router: Router) {
136
- authRouteGuardWatcher = watch(authenticated, (value, oldValue) => {
137
- if (value != oldValue) {
138
- // Force a reevaluation of the current route, so router guards apply
139
- router.push({ path: router.currentRoute.value.path, force: true }).then(() => {})
140
- }
141
- })
142
- }
143
-
144
- /**
145
- * Removes the authentication route guard previously set up by `setupAuthRouteGuard`.
146
- *
147
- * This function cleans up the navigation guard registered with the Vue Router instance,
148
- * preventing any authentication-related redirects. It's useful when you need to
149
- * disable authentication checks, such as during application teardown or when switching
150
- * authentication strategies.
151
- * @see setupAuthRouteGuard - The corresponding function that sets up the route guard.
152
- */
153
- function unsetAuthRouteGuard(): void {
154
- if (authRouteGuardWatcher) authRouteGuardWatcher()
155
- }
156
-
157
- return {
158
- setPostLogin,
159
- setPostLogout,
160
- setupAuthRouteGuard,
161
- unsetAuthRouteGuard,
162
- authRouteGuardWatcher,
163
- }
164
- }
165
-
166
- /**
167
- * Configures and sets up a token-based authentication backend store for managing API authentication.
168
- *
169
- * The method initializes authentication states, such as tokens, login/logout handlers, and
170
- * authentication interceptors on the axiosInstance for requests and responses.
171
- * It also provides helper functions for handling authentication processes, like login, logout,
172
- * and post-login/logout callbacks. Additionally, it enables the setting of route guards to
173
- * respond to authentication status changes in a Vue.js application.
174
- * @returns An object containing authentication state, API client instance, and helper functions:
175
- * - `axiosInstance`: Pre-configured axios instance with authentication support
176
- * - `authenticated`: Reactive flag representing the authentication status
177
- * - `login`: Function to authenticate users using credentials
178
- * - `logout`: Function to deauthenticate users and clear authentication tokens
179
- * - `setPostLogin`: Method to set a callback function invoked after successful login
180
- * - `setPostLogout`: Method to set a callback function invoked after logout
181
- * - `setupAuthRouteGuard`: Function to set up route guard for managing authentication-driven route reevaluations
182
- */
183
- function tokenAuthenticationBackendStoreSetup(): BackendStore {
184
- /**
185
- * A reactive variable that indicates whether a user is authenticated or not.
186
- *
187
- * The value is `false` by default, representing an unauthenticated state.
188
- * This variable can be updated dynamically to reflect the authentication status
189
- * of the user within the application.
190
- */
191
- const authenticated = ref(false)
192
- const _token: Ref<string | null> = ref(null)
193
- const _postLogout: Ref<() => void> = ref(() => {})
194
- const _postLogin: Ref<() => void> = ref(() => {})
195
- const _fromLocalStorage = localStorage.getItem(localStorageKey)
196
-
197
- // Create common authentication functions
198
- const commonAuth = createCommonAuthFunctions(authenticated, _postLogin, _postLogout)
199
-
200
- if (_fromLocalStorage) {
201
- _token.value = _fromLocalStorage
202
- authenticated.value = true
203
- }
204
-
205
- watch(_token, () => {
206
- localStorage.setItem(localStorageKey, _token.value ?? '')
207
- })
208
-
209
- axiosInstance.defaults.withCredentials = true
210
- axiosInstance.defaults.headers.common['Content-Type'] = 'application/json'
211
-
212
- axiosInstance.interceptors.request.use(
213
- async (config) => {
214
- if (authenticated.value && _token.value) {
215
- config.headers['Authorization'] = `Token ${_token.value}`
216
- }
217
- return config
218
- },
219
- (error) => Promise.reject(error)
220
- )
221
-
222
- axiosInstance.interceptors.response.use(
223
- (response) => response,
224
- async (error) => {
225
- if (error.response.status === 403) {
226
- const data = error.response.data
227
- if (data?.detail === 'Authentication credentials were not provided.') {
228
- logout()
229
- }
230
- return Promise.reject(error)
231
- } else {
232
- return Promise.reject(error)
233
- }
234
- }
235
- )
236
-
237
- /**
238
- * Authenticates a user by sending their credentials to the server.
239
- * @param credentials - The user's login credentials, typically including a username and password.
240
- * @returns A promise that resolves to the Axios response object returned from the authentication request.
241
- */
242
- async function login(credentials: Credentials): Promise<AxiosResponse> {
243
- const response = await axiosInstance.post('/api/token-auth/', credentials)
244
- if (response.status === 200) {
245
- authenticated.value = true
246
- _token.value = response.data.token
247
- }
248
- _postLogin.value()
249
- return response
250
- }
251
-
252
- /**
253
- * Logs the user out of the application by performing the following actions:
254
- * - Removes the user's authentication token from localStorage.
255
- * - Updates the application's authenticated state to false.
256
- * - Resets the stored authentication token to null.
257
- * - Executes any additional post-logout logic defined in the application.
258
- */
259
- function logout(): void {
260
- localStorage.removeItem(localStorageKey)
261
- authenticated.value = false
262
- _token.value = null
263
- _postLogout.value()
264
- }
265
-
266
- return {
267
- axiosInstance,
268
- authenticated,
269
- login,
270
- logout,
271
- setPostLogin: commonAuth.setPostLogin,
272
- setPostLogout: commonAuth.setPostLogout,
273
- setupAuthRouteGuard: commonAuth.setupAuthRouteGuard,
274
- unsetAuthRouteGuard: commonAuth.unsetAuthRouteGuard,
275
- }
276
- }
277
-
278
- /**
279
- * Configures and sets up a JWT-based authentication backend store for managing API authentication.
280
- *
281
- * The method initializes authentication states, such as access and refresh tokens, login/logout handlers, and
282
- * authentication interceptors on the axios instance for requests and responses.
283
- * It also provides helper functions for handling authentication processes, like login, logout,
284
- * and post-login/logout callbacks. Additionally, it enables the setting of route guards to
285
- * respond to authentication status changes in a Vue.js application.
286
- *
287
- * This implementation is designed to work with a Django backend using the "Simple JWT" library.
288
- * @returns An object containing authentication state, API client instance, and helper functions:
289
- * - `axiosInstance`: Pre-configured axios instance with authentication support
290
- * - `authenticated`: Reactive flag representing the authentication status
291
- * - `login`: Function to authenticate users using credentials
292
- * - `logout`: Function to deauthenticate users and clear authentication tokens
293
- * - `setPostLogin`: Method to set a callback function invoked after successful login
294
- * - `setPostLogout`: Method to set a callback function invoked after logout
295
- * - `setupAuthRouteGuard`: Function to set up route guard for managing authentication-driven route reevaluations
296
- */
297
- function jwtAuthenticationBackendStoreSetup(): BackendStore {
298
- /**
299
- * A reactive variable that indicates whether a user is authenticated or not.
300
- *
301
- * The value is `false` by default, representing an unauthenticated state.
302
- * This variable can be updated dynamically to reflect the authentication status
303
- * of the user within the application.
304
- */
305
- const authenticated = ref(false)
306
- const _accessToken: Ref<string | null> = ref(null)
307
- const _refreshToken: Ref<string | null> = ref(null)
308
- const _postLogout: Ref<() => void> = ref(() => {})
309
- const _postLogin: Ref<() => void> = ref(() => {})
310
- const _accessTokenFromLocalStorage = localStorage.getItem(jwtAccessTokenKey)
311
- const _refreshTokenFromLocalStorage = localStorage.getItem(jwtRefreshTokenKey)
312
- const refreshUrl = '/api/token/refresh/'
313
-
314
- // Create common authentication functions
315
- const commonAuth = createCommonAuthFunctions(authenticated, _postLogin, _postLogout)
316
-
317
- if (_accessTokenFromLocalStorage && _refreshTokenFromLocalStorage) {
318
- _accessToken.value = _accessTokenFromLocalStorage
319
- _refreshToken.value = _refreshTokenFromLocalStorage
320
- authenticated.value = true
321
- }
322
-
323
- watch(_accessToken, () => {
324
- localStorage.setItem(jwtAccessTokenKey, _accessToken.value ?? '')
325
- })
326
-
327
- watch(_refreshToken, () => {
328
- localStorage.setItem(jwtRefreshTokenKey, _refreshToken.value ?? '')
329
- })
330
-
331
- axiosInstance.defaults.withCredentials = true
332
- axiosInstance.defaults.headers.common['Content-Type'] = 'application/json'
333
-
334
- axiosInstance.interceptors.request.use(
335
- async (config) => {
336
- if (authenticated.value && _accessToken.value) {
337
- config.headers['Authorization'] = `Bearer ${_accessToken.value}`
338
- }
339
- return config
340
- },
341
- (error) => Promise.reject(error)
342
- )
343
-
344
- /**
345
- * Checks if the error is related to token authentication issues
346
- * @param error - The Axios error to check for token-related issues
347
- * @returns True if the error is related to token authentication, false otherwise
348
- */
349
- function isTokenError(error: AxiosError): boolean {
350
- return !!(
351
- error.response &&
352
- [401, 403].includes(error.response.status) &&
353
- ((error.response?.data as { code?: string })?.code === 'token_not_valid' ||
354
- !_accessToken.value ||
355
- !_refreshToken.value)
356
- )
357
- }
358
-
359
- /**
360
- * Attempts to refresh the JWT token and retry the original request
361
- * @param originalRequest - The original Axios request configuration to retry after token refresh
362
- * @returns A promise that resolves to the Axios response from the retried request
363
- */
364
- async function handleTokenRefresh(
365
- originalRequest: InternalAxiosRequestConfig
366
- ): Promise<AxiosResponse> {
367
- const response = await axiosInstance.post(refreshUrl, {
368
- refresh: _refreshToken.value,
369
- })
370
-
371
- if (response.status === 200) {
372
- // Update the tokens
373
- _accessToken.value = response.data.access
374
- if (response.data.refresh) {
375
- _refreshToken.value = response.data.refresh
376
- }
377
-
378
- // Retry the original request with the new token
379
- originalRequest.headers['Authorization'] = `Bearer ${_accessToken.value}`
380
- return axiosInstance(originalRequest)
381
- }
382
- throw new Error('Token refresh failed')
383
- }
384
-
385
- axiosInstance.interceptors.response.use(
386
- (response) => response,
387
- async (error) => {
388
- if (!isTokenError(error)) {
389
- return Promise.reject(error)
390
- }
391
-
392
- const originalRequest = error.config
393
- const isRefreshRequest = originalRequest.url === refreshUrl
394
-
395
- // Prevent infinite loops
396
- if (!isRefreshRequest && _refreshToken.value) {
397
- try {
398
- return await handleTokenRefresh(originalRequest)
399
- } catch (refreshError) {
400
- logout()
401
- return Promise.reject(refreshError)
402
- }
403
- } else {
404
- logout()
405
- }
406
-
407
- return Promise.reject(error)
408
- }
409
- )
410
-
411
- /**
412
- * Authenticates a user by sending their credentials to the server.
413
- * @param credentials - The user's login credentials, typically including a username and password.
414
- * @returns A promise that resolves to the Axios response object returned from the authentication request.
415
- */
416
- async function login(credentials: Credentials): Promise<AxiosResponse> {
417
- const response = await axiosInstance.post('/api/token/', credentials)
418
- if (response.status === 200) {
419
- authenticated.value = true
420
- _accessToken.value = response.data.access
421
- _refreshToken.value = response.data.refresh
422
- }
423
- _postLogin.value()
424
- return response
425
- }
426
-
427
- /**
428
- * Logs the user out of the application by performing the following actions:
429
- * - Removes the user's authentication tokens from localStorage.
430
- * - Updates the application's authenticated state to false.
431
- * - Resets the stored authentication tokens to null.
432
- * - Executes any additional post-logout logic defined in the application.
433
- */
434
- function logout(): void {
435
- localStorage.removeItem(jwtAccessTokenKey)
436
- localStorage.removeItem(jwtRefreshTokenKey)
437
- authenticated.value = false
438
- _accessToken.value = null
439
- _refreshToken.value = null
440
- _postLogout.value()
441
- }
442
-
443
- return {
444
- axiosInstance,
445
- authenticated,
446
- login,
447
- logout,
448
- setPostLogin: commonAuth.setPostLogin,
449
- setPostLogout: commonAuth.setPostLogout,
450
- setupAuthRouteGuard: commonAuth.setupAuthRouteGuard,
451
- unsetAuthRouteGuard: commonAuth.unsetAuthRouteGuard,
452
- }
453
- }
@@ -1,6 +1,12 @@
1
1
  export {
2
2
  useBackendStore,
3
+ type AuthenticationEndpoints,
3
4
  type BackendStore,
4
5
  type Credentials,
5
6
  type AuthenticationType,
7
+ type JwtEndpoints,
8
+ type OAuthEndpoints,
9
+ type TokenEndpoints,
6
10
  } from './backend.ts'
11
+
12
+ export { useDarkModeStore } from './darkMode.ts'
@@ -0,0 +1,2 @@
1
+ export { createNsideTheme } from './nside'
2
+ export type { NsidePrimaryColor } from './nside'
@@ -0,0 +1,157 @@
1
+ import Aura from '@primeuix/themes/aura'
2
+ import { definePreset, palette } from '@primeuix/themes'
3
+
4
+ const SCALE_KEYS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const
5
+ type ScaleKey = (typeof SCALE_KEYS)[number]
6
+
7
+ // Ensures a full Tailwind-like scale (50–950) by overlaying explicit brand steps
8
+ // on top of a generated palette while keeping every scale key present.
9
+ const mergeScale = (base: Record<ScaleKey, string>, overrides: Partial<Record<ScaleKey, string>>) =>
10
+ SCALE_KEYS.reduce<Record<ScaleKey, string>>(
11
+ (acc, key) => {
12
+ acc[key] = overrides[key] ?? base[key]
13
+ return acc
14
+ },
15
+ {} as Record<ScaleKey, string>
16
+ )
17
+
18
+ const greenPalette = mergeScale(palette('#8CBB13') as Record<ScaleKey, string>, {
19
+ 50: '#F1F6E2',
20
+ 100: '#D4E5A7',
21
+ 300: '#B7D46C',
22
+ 500: '#8CBB13',
23
+ 700: '#70A100',
24
+ 900: '#0A3B00',
25
+ })
26
+
27
+ const tealPalette = mergeScale(palette('#00ACC2') as Record<ScaleKey, string>, {
28
+ 50: '#DFF5F7',
29
+ 100: '#9FE0E8',
30
+ 300: '#40C1D1',
31
+ 500: '#00ACC2',
32
+ 700: '#0090A7',
33
+ 900: '#002A41',
34
+ })
35
+
36
+ const orangePalette = mergeScale(palette('#F4A74F') as Record<ScaleKey, string>, {
37
+ 50: '#FEF4E9',
38
+ 100: '#FBDEBD',
39
+ 300: '#F7BD7B',
40
+ 500: '#F4A74F',
41
+ 700: '#D48C37',
42
+ 900: '#752800',
43
+ })
44
+
45
+ const pinkPalette = mergeScale(palette('#D63487') as Record<ScaleKey, string>, {
46
+ 50: '#FAE6F0',
47
+ 100: '#F0B3D2',
48
+ 300: '#E067A5',
49
+ 500: '#D63487',
50
+ 700: '#B80870',
51
+ 900: '#570008',
52
+ })
53
+
54
+ const purplePalette = mergeScale(palette('#A83A8D') as Record<ScaleKey, string>, {
55
+ 50: '#F4E6F1',
56
+ 100: '#DEB5D4',
57
+ 300: '#BE6BAA',
58
+ 500: '#A83A8D',
59
+ 700: '#8A1B73',
60
+ 900: '#8A1B73',
61
+ })
62
+
63
+ const redPalette = mergeScale(palette('#C6243D') as Record<ScaleKey, string>, {
64
+ 50: '#F8E4E7',
65
+ 100: '#EAADB6',
66
+ 300: '#D45B6E',
67
+ 500: '#C6243D',
68
+ 700: '#A50027',
69
+ 900: '#600000',
70
+ })
71
+
72
+ const grayPalette = mergeScale(palette('#535F6B') as Record<ScaleKey, string>, {
73
+ 50: '#FAFCFE',
74
+ 100: '#F8F9FA',
75
+ 200: '#E9ECEF',
76
+ 300: '#DEE2E6',
77
+ 400: '#CED4DA',
78
+ 500: '#ADB5BD',
79
+ 600: '#868E96',
80
+ 700: '#495057',
81
+ 800: '#343A40',
82
+ 900: '#212529',
83
+ })
84
+
85
+ const surfaceLightBase = grayPalette
86
+
87
+ const surfaceLight = {
88
+ 0: '#FFFFFF',
89
+ ...surfaceLightBase,
90
+ }
91
+
92
+ const surfaceDark = {
93
+ 0: '#E7EBF5',
94
+ ...mergeScale(palette('#162950') as Record<ScaleKey, string>, {}),
95
+ }
96
+
97
+ export type NsidePrimaryColor = 'green' | 'orange' | 'blue'
98
+
99
+ export const createNsideTheme = (primary: NsidePrimaryColor = 'green') =>
100
+ definePreset(Aura, {
101
+ primitive: {
102
+ borderRadius: {
103
+ none: '0',
104
+ xs: '3px',
105
+ sm: '6px',
106
+ md: '8px',
107
+ lg: '10px',
108
+ xl: '14px',
109
+ },
110
+ green: greenPalette,
111
+ teal: tealPalette,
112
+ cyan: tealPalette,
113
+ blue: tealPalette,
114
+ sky: tealPalette,
115
+ yellow: orangePalette,
116
+ orange: orangePalette,
117
+ red: redPalette,
118
+ pink: pinkPalette,
119
+ purple: purplePalette,
120
+ gray: grayPalette,
121
+ },
122
+ css: `
123
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap');
124
+
125
+ :root,
126
+ :host {
127
+ font-size: 14px;
128
+ font-family: 'Poppins', sans-serif;
129
+ --nside-gradient-teal-purple: linear-gradient(135deg, #00ACC2 0%, #807FBD 100%);
130
+ --nside-gradient-orange-pink: linear-gradient(135deg, #F4A74F 0%, #EE4D9B 100%);
131
+ --nside-gradient-green-blue: linear-gradient(135deg, #8CBB13 0%, #71CFEC 100%);
132
+ }
133
+ `,
134
+ semantic: {
135
+ primary: palette(`{${primary}}`),
136
+ colorScheme: {
137
+ light: {
138
+ surface: surfaceLight,
139
+ text: {
140
+ color: '#535F6B',
141
+ hoverColor: '#162950',
142
+ mutedColor: '#66728C',
143
+ hoverMutedColor: '#535F6B',
144
+ },
145
+ },
146
+ dark: {
147
+ surface: surfaceDark,
148
+ text: {
149
+ color: '#E7EBF5',
150
+ hoverColor: '#FFFFFF',
151
+ mutedColor: '#A5BEDB',
152
+ hoverMutedColor: '#E7EBF5',
153
+ },
154
+ },
155
+ },
156
+ },
157
+ })
@@ -0,0 +1,24 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { getAccessibleTextColor, getRelativeLuminance, hashString, hslToRgb } from './color'
3
+
4
+ describe('color utilities', () => {
5
+ it('hashes strings deterministically', () => {
6
+ expect(hashString('alice')).toBe(hashString('alice'))
7
+ expect(hashString('alice')).not.toBe(hashString('bob'))
8
+ })
9
+
10
+ it('converts hsl values to rgb', () => {
11
+ expect(hslToRgb(0, 100, 50)).toEqual({ r: 255, g: 0, b: 0 })
12
+ expect(hslToRgb(120, 100, 50)).toEqual({ r: 0, g: 255, b: 0 })
13
+ })
14
+
15
+ it('computes luminance in expected bounds', () => {
16
+ expect(getRelativeLuminance(0, 0, 0)).toBe(0)
17
+ expect(getRelativeLuminance(255, 255, 255)).toBe(1)
18
+ })
19
+
20
+ it('chooses readable text color for background contrast', () => {
21
+ expect(getAccessibleTextColor({ r: 0, g: 0, b: 0 })).toBe('#FFFFFF')
22
+ expect(getAccessibleTextColor({ r: 255, g: 255, b: 255 })).toBe('#0F172A')
23
+ })
24
+ })