@lilaquadrat/design-core 0.1.0

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 (86) hide show
  1. package/README.md +236 -0
  2. package/html/index.html +25 -0
  3. package/html/index.mail.html +15 -0
  4. package/html/index.server.html +29 -0
  5. package/package.json +148 -0
  6. package/src/client-entry.ts +28 -0
  7. package/src/components/partials/action.partial.vue +30 -0
  8. package/src/components/partials/client-only.partial.vue +11 -0
  9. package/src/components/partials/error.partial.vue +73 -0
  10. package/src/components/partials/main-components.partial.vue +167 -0
  11. package/src/components/partials/mediadetection.partial.vue +71 -0
  12. package/src/components/partials/qrcode.partial.vue +35 -0
  13. package/src/customs.ts +12 -0
  14. package/src/env.d.ts +1 -0
  15. package/src/functions/PaymenyProviderFactory.ts +27 -0
  16. package/src/functions/lila-dom.ts +100 -0
  17. package/src/functions/shopify.provider.ts +378 -0
  18. package/src/functions/stripe.provider.ts +181 -0
  19. package/src/globals.d.ts +19 -0
  20. package/src/index.ts +47 -0
  21. package/src/interfaces/AppState.interface.ts +4 -0
  22. package/src/interfaces/EditorConfiguration.interface.ts +15 -0
  23. package/src/interfaces/EventDeclaration.interface.ts +19 -0
  24. package/src/interfaces/FrontendConfig.interface.ts +42 -0
  25. package/src/interfaces/GenericEvents.interface.ts +6 -0
  26. package/src/interfaces/GenericState.interface.ts +5 -0
  27. package/src/interfaces/IconsPartial.ts +9 -0
  28. package/src/interfaces/IdTokenExtended.interface.ts +7 -0
  29. package/src/interfaces/ModuleBaseProps.interface.ts +8 -0
  30. package/src/interfaces/PaymentProvider.interface.ts +13 -0
  31. package/src/libs/ActionNotice.ts +235 -0
  32. package/src/libs/Models.class.ts +482 -0
  33. package/src/main.ts +84 -0
  34. package/src/mixins/createCookieString.ts +78 -0
  35. package/src/mixins/createModelDeclaration.ts +29 -0
  36. package/src/mixins/createRouter.ts +30 -0
  37. package/src/mixins/date.ts +23 -0
  38. package/src/mixins/formatSize.ts +12 -0
  39. package/src/mixins/getAnchor.ts +14 -0
  40. package/src/mixins/getRoutes.ts +50 -0
  41. package/src/mixins/hasSlotContent.ts +32 -0
  42. package/src/mixins/hooks.ts +104 -0
  43. package/src/mixins/loadComponents.ts +107 -0
  44. package/src/mixins/logger.ts +32 -0
  45. package/src/mixins/replaceVariables.ts +19 -0
  46. package/src/mixins/scroll.ts +83 -0
  47. package/src/models/Address.model.ts +24 -0
  48. package/src/models/Contact.model.ts +22 -0
  49. package/src/models.ts +2 -0
  50. package/src/plugins/auth.ts +121 -0
  51. package/src/plugins/currency.ts +26 -0
  52. package/src/plugins/events.ts +156 -0
  53. package/src/plugins/filters.ts +43 -0
  54. package/src/plugins/inview.ts +351 -0
  55. package/src/plugins/replacer.ts +18 -0
  56. package/src/plugins/resize.ts +128 -0
  57. package/src/plugins/signupFlow.ts +89 -0
  58. package/src/plugins/traceable.ts +53 -0
  59. package/src/plugins/translations.ts +29 -0
  60. package/src/plugins/youtube.ts +80 -0
  61. package/src/routes.ts +132 -0
  62. package/src/server-entry.ts +113 -0
  63. package/src/stores/calls.store.ts +33 -0
  64. package/src/stores/cart.store.ts +186 -0
  65. package/src/stores/content.store.ts +83 -0
  66. package/src/stores/editor.store.ts +27 -0
  67. package/src/stores/files.store.ts +166 -0
  68. package/src/stores/main.store.ts +184 -0
  69. package/src/stores/user.store.ts +124 -0
  70. package/src/translations/de.ts +138 -0
  71. package/src/views/content.view.vue +219 -0
  72. package/src/views/download.view.vue +143 -0
  73. package/src/views/editor.view.vue +243 -0
  74. package/src/views/login.view.vue +82 -0
  75. package/src/views/signup-account.view.vue +64 -0
  76. package/tooling/cypress/config.ts +80 -0
  77. package/tooling/cypress/generate-manifest.js +5 -0
  78. package/tooling/cypress/manifest-utils.mjs +40 -0
  79. package/tooling/cypress/run-parallel.mjs +77 -0
  80. package/tooling/cypress/support/commands.ts +436 -0
  81. package/tooling/cypress/support/e2e.ts +17 -0
  82. package/tooling/eslint.config.js +223 -0
  83. package/tooling/preview.plugin.ts +134 -0
  84. package/tooling/ssr-test/index.mjs +391 -0
  85. package/tooling/stylelint.config.mjs +24 -0
  86. package/tooling/vite.ts +246 -0
@@ -0,0 +1,482 @@
1
+ import { v4 as uuid } from 'uuid';
2
+ import { hardCopy } from '@lilaquadrat/studio/lib/esm/frontend';
3
+
4
+ type DeclarationTypes = 'string' | 'number' | 'boolean' | 'object';
5
+ type SingleDeclaration = { type: 'string', default?: string } |
6
+ { type: 'number', default?: number } |
7
+ { type: 'boolean', default?: boolean } |
8
+ { type: 'object', default?: Record<string, any> } |
9
+ { type: 'array', contains: { type: DeclarationTypes }, default?: (string | number | boolean)[] } |
10
+ { type: 'array', contains: { model: string }, default?: any[], defaultItems?: number } |
11
+ { model: string, default?: any };
12
+
13
+ // interface ModelDeclaration<T = GenericModel> {
14
+ // [key in keyof T]: SingleDeclaration
15
+ // }
16
+
17
+ type ModelDeclaration<T> = Record<keyof T, SingleDeclaration>;
18
+ type ModelDeclarationExtended<T, E> = Record<Exclude<keyof T, keyof E>, SingleDeclaration>;
19
+
20
+ interface ModelOptions {
21
+ /**
22
+ * uuid will be automatically added
23
+ */
24
+ uuid?: boolean
25
+ /**
26
+ * the name of the models will be added as type
27
+ ```TS
28
+ type: 'text-module'
29
+ ```
30
+ */
31
+ nameAsType?: boolean
32
+
33
+ /**
34
+ * defines which available model should be used as base
35
+ */
36
+ extends?: string
37
+ }
38
+ // eslint-disable-next-line no-unused-vars
39
+ type ModelHook<T> = (data: T) => void;
40
+
41
+ interface ModelHooks<T> {
42
+ legacy?: ModelHook<T>
43
+ preSave?: ModelHook<T>
44
+ // postSave?: ModelHook<T>
45
+ preAdd?: ModelHook<T>
46
+ // postAdd?: ModelHook<T>
47
+ preClone?: ModelHook<T>
48
+ // postClone?: ModelHook<T>
49
+ }
50
+
51
+ class Models {
52
+
53
+ registeredModels: string[] = [];
54
+
55
+ declarations: Record<string, ModelDeclaration<T>> = {};
56
+
57
+ options: Record<string, ModelOptions> = {};
58
+
59
+ hooks: Record<string, ModelHooks<T>> = {};
60
+
61
+ debug: boolean = false;
62
+
63
+ constructor (debug: boolean = false) {
64
+
65
+ this.debug = debug;
66
+
67
+ }
68
+
69
+ // eslint-disable-next-line no-unused-vars
70
+ register<T>(name: string, declaration: ModelDeclaration<T>, hooks?: ModelHooks<T>, options?: ModelOptions): void;
71
+
72
+ // eslint-disable-next-line no-unused-vars
73
+ register<T, E>(name: string, declaration: ModelDeclarationExtended<T, E>, hooks: ModelHooks<T> | undefined, options: ModelOptions): void;
74
+
75
+ register<T, E> (name: string, declaration: ModelDeclaration<T > | ModelDeclarationExtended<T, E>, hooks: ModelHooks<T> | undefined, options?: ModelOptions) {
76
+
77
+ if (this.debug) console.debug(`registed model ${name}`);
78
+ // this.registeredModels[name] = declaration;
79
+ this.registeredModels.push(name);
80
+ this.declarations[name] = options?.extends ? this.extendDeclaration(declaration, options.extends) : declaration;
81
+
82
+ if(options) this.options[name] = options;
83
+ if(hooks) this.hooks[name] = hooks;
84
+
85
+ }
86
+
87
+ getDeclaration (name: string): ModelDeclaration<any> {
88
+
89
+ if (!this.declarations[name]) console.error(`DECLARATION_NOT_FOUND - ${name}`);
90
+
91
+ return this.declarations[name] as ModelDeclaration<any> ;
92
+
93
+ }
94
+
95
+ getOptions (name: string): ModelOptions {
96
+
97
+ return this.options[name];
98
+
99
+ }
100
+
101
+ extendDeclaration (declaration: ModelDeclaration, extendBase: string) {
102
+
103
+ const base = this.getDeclaration(extendBase);
104
+
105
+ if (!base) throw new Error('MODELS_EXTENDS_BASE_NOT_FOUND');
106
+
107
+ return { ...base, ...declaration };
108
+
109
+ }
110
+
111
+ prepareTargetObject<T> (name: string, data: T & { uuid?: string }, usecase?: 'save' | 'add' | 'clone') {
112
+
113
+ const targetObject: GenericModel = {};
114
+ const options = this.getOptions(name);
115
+
116
+ if (options?.uuid) {
117
+
118
+ if (usecase === 'clone') {
119
+
120
+ targetObject.uuid = uuid();
121
+
122
+ } else {
123
+
124
+ targetObject.uuid = data.uuid || uuid();
125
+
126
+ }
127
+
128
+ }
129
+
130
+ if (options?.nameAsType) {
131
+
132
+ targetObject.type = name;
133
+
134
+ }
135
+
136
+ return targetObject;
137
+
138
+ }
139
+
140
+ add<T> (data: Partial<T>, name: string, declaration?: ModelDeclaration<T>): T {
141
+
142
+ const modelData = this.setDataV2(data, this.prepareTargetObject(name, data, 'add'), declaration || this.getDeclaration(name), name, 'add');
143
+
144
+ // if (this.hooks[name]?.preAdd) this.hooks[name].preAdd(modelData);
145
+
146
+ return modelData as T;
147
+
148
+ }
149
+
150
+ save<T> (data: Partial<T>, name: string, declaration?: ModelDeclaration<T>): T {
151
+
152
+ const modelData = this.setDataV2(data, this.prepareTargetObject(name, data, 'save'), declaration || this.getDeclaration(name), name, 'save') as T;
153
+
154
+ // if (this.hooks[name]?.postSave) this.hooks[name].postSave(modelData);
155
+
156
+ return modelData as T;
157
+
158
+ }
159
+
160
+ clone<T> (data: Partial<T>, name: string, declaration?: ModelDeclaration<T>): T {
161
+
162
+ const modelData = this.setDataV2(data, this.prepareTargetObject(name, data, 'clone'), declaration || this.getDeclaration(name), name, 'clone') as T;
163
+
164
+ // if (this.hooks[name].postClone) this.hooks[name].postClone(data);
165
+
166
+ return modelData as T;
167
+
168
+ }
169
+
170
+ setDataV2<T> (data: Partial<T>, targetObject: GenericModel | GenericModel[], declaration: ModelDeclaration, name: string, usecase: 'save' | 'add' | 'clone') {
171
+
172
+ if (this.debug) console.debug(data, declaration, targetObject, usecase);
173
+
174
+ const keys = Object.keys(declaration || {});
175
+
176
+ // if (typeof this.legacy === 'function' && legacy) {
177
+
178
+ // if (data) data = this.legacy(data);
179
+
180
+ // }
181
+
182
+ // if (typeof this.onSave === 'function' && usecase === 'save') {
183
+
184
+ // if (data) data = this.onSave(data);
185
+
186
+ // }
187
+
188
+ if (usecase === 'save') {
189
+
190
+ if (this.hooks[name]?.preSave) this.hooks[name].preSave(data);
191
+
192
+ }
193
+
194
+ if (usecase === 'clone') {
195
+
196
+ if (this.hooks[name]?.preClone) this.hooks[name].preClone(data);
197
+
198
+ }
199
+
200
+ if (usecase === 'add') {
201
+
202
+ if (this.hooks[name]?.preAdd) this.hooks[name].preAdd(data);
203
+
204
+ }
205
+
206
+ if (usecase === 'save' && Models.isEmpty(data)) return targetObject;
207
+
208
+ // remove the changed flag on save
209
+ // if (usecase === 'save') {
210
+
211
+ // delete this.changed;
212
+
213
+ // }
214
+
215
+ // delete this.legacy;
216
+ // delete this.onSave;
217
+ // delete this.onAdd;
218
+
219
+ keys.forEach((keyName: string) => {
220
+
221
+ if (this.debug) console.debug('START', keyName, data, declaration, declaration[keyName]);
222
+
223
+ const currentDeclaration = declaration[keyName];
224
+ let currentData: any;
225
+ let safeData: Partial<T>;
226
+
227
+ if (data && !Models.isEmpty(data)) safeData = hardCopy<Partial<T>>(data);
228
+ if (safeData && safeData[keyName]) currentData = hardCopy(safeData[keyName]);
229
+
230
+ if (usecase === 'save' && Models.isEmpty(currentData)) return;
231
+
232
+ /**
233
+ * SPECIAL CASE type
234
+ * dont override the type of the module
235
+ */
236
+ // if (name === 'type' && currentData) {
237
+
238
+ // targetObject.type = currentData;
239
+ // return;
240
+
241
+ // }
242
+
243
+ if ('type' in currentDeclaration) {
244
+
245
+ if (currentData) {
246
+
247
+ if (this.debug) console.debug('CHECK CURRENTDATA TYPE', typeof currentData === currentDeclaration.type, currentDeclaration.type, keyName, currentData, currentDeclaration);
248
+
249
+ if (typeof currentData !== currentDeclaration.type && currentDeclaration.type !== 'array' && !Models.isModel(currentDeclaration)) currentData = undefined;
250
+
251
+ }
252
+
253
+ /**
254
+ * if usecase is save an no data is given, dont add default values
255
+ */
256
+ if (usecase === 'save' && Models.isEmpty(currentData)) {
257
+
258
+ // delete declaration[name];
259
+ return;
260
+
261
+ }
262
+
263
+ // if (name === 'legacy') return targetObject;
264
+ // if (name === 'onSave') return targetObject;
265
+
266
+ /**
267
+ * string and number gets assigned
268
+ */
269
+ if (['string', 'number', 'boolean', 'object'].includes(currentDeclaration.type)) {
270
+
271
+ targetObject[keyName] = currentData || Models.getDefaultValue(currentDeclaration);
272
+
273
+ }
274
+
275
+ /**
276
+ * array
277
+ */
278
+ if (currentDeclaration.type === 'array') {
279
+
280
+ const arrayContains = currentDeclaration.contains;
281
+
282
+ if ('type' in arrayContains) {
283
+
284
+ if (['string', 'number'].includes(arrayContains.type)) {
285
+
286
+ if (this.debug) console.debug('SET ARRAY STRING/NUMBER', currentData);
287
+
288
+ targetObject[keyName] = currentData?.slice(0) || Models.getDefaultValue(currentDeclaration);
289
+
290
+ }
291
+
292
+ if (arrayContains.type === 'object') {
293
+
294
+ targetObject[keyName] = [];
295
+
296
+ // only add non empty objects to the array
297
+ currentData?.forEach((single) => {
298
+
299
+ // skip if single is empty
300
+ if (usecase === 'save' && Models.isEmpty(single)) return;
301
+
302
+ // only add if the result is not empty
303
+ if (!Models.isEmpty(single)) targetObject[keyName].push(single);
304
+
305
+ });
306
+
307
+ if (!targetObject[keyName].length) delete targetObject[keyName];
308
+
309
+ }
310
+
311
+ }
312
+
313
+ if ('model' in arrayContains) {
314
+
315
+ if (this.debug) console.debug('SET ARRAY MODEL', keyName, currentData, arrayContains?.model);
316
+
317
+ targetObject[keyName] = [];
318
+
319
+ if (this.debug) console.debug(keyName, currentData);
320
+
321
+ /**
322
+ * currentdata could be an array with an empty object [{}] which will not count as empty for the Model.isEmpty function
323
+ * therefore we need to handle the possible empty data here
324
+ */
325
+
326
+ if (currentData) {
327
+
328
+ currentData?.forEach((single) => {
329
+
330
+ // skip if single is empty
331
+ if (usecase === 'save' && Models.isEmpty(single)) return;
332
+
333
+ const pushData = this.setDataV2(single, {}, this.getDeclaration(arrayContains?.model), arrayContains?.model, usecase);
334
+
335
+ // only add if the result is not empty
336
+ if (!Models.isEmpty(pushData)) targetObject[keyName].push(pushData);
337
+
338
+ });
339
+
340
+ if (!targetObject[keyName].length) delete targetObject[keyName];
341
+
342
+ } else if (usecase !== 'save') {
343
+
344
+ targetObject[keyName].push(this.setDataV2({}, {}, this.getDeclaration(arrayContains?.model), arrayContains?.model, usecase));
345
+
346
+ }
347
+
348
+ if ('defaultItems' in currentDeclaration && usecase !== 'save') {
349
+
350
+ if (targetObject[keyName].length < currentDeclaration.defaultItems) {
351
+
352
+ const neededItems = currentDeclaration.defaultItems - targetObject[keyName].length;
353
+
354
+ for (let index = 0; index < neededItems; index += 1) {
355
+
356
+ targetObject[keyName].push(this.setDataV2({}, {}, this.getDeclaration(arrayContains?.model), arrayContains?.model, usecase));
357
+
358
+ }
359
+
360
+ }
361
+
362
+ }
363
+
364
+ }
365
+
366
+ }
367
+
368
+ }
369
+
370
+ /**
371
+ * if its an object, it will be a child model
372
+ */
373
+ if ('model' in currentDeclaration) {
374
+
375
+ if (this.debug) console.debug('its a model', keyName, currentDeclaration, currentDeclaration?.model, targetObject);
376
+
377
+ // if (usecase === 'save' && (!currentData || (Array.isArray(currentData) && !currentData.length))) {
378
+
379
+ // // delete declaration[name];
380
+ // return;
381
+
382
+ //
383
+
384
+ targetObject[keyName]= this.setDataV2(currentData, {}, this.getDeclaration(currentDeclaration?.model), currentDeclaration?.model, usecase);
385
+
386
+ if (usecase === 'save') {
387
+
388
+ if (this.debug) console.debug(124, this[name], Object.keys(this[name]).length);
389
+
390
+ if (Models.isEmpty(targetObject[keyName])) {
391
+
392
+ delete targetObject[keyName];
393
+
394
+ }
395
+
396
+ }
397
+
398
+ }
399
+
400
+ });
401
+
402
+ return targetObject;
403
+
404
+ }
405
+
406
+ static isEmpty (data: any[] | Record<string, any>) {
407
+
408
+ if (!data) return true;
409
+
410
+ if (Array.isArray(data)) {
411
+
412
+ return !data.length;
413
+
414
+ }
415
+
416
+ if (typeof data === 'object') {
417
+
418
+ return !Object.keys(data).length;
419
+
420
+ }
421
+
422
+ return false;
423
+
424
+ }
425
+
426
+ static isModel (declaration: SingleDeclaration) {
427
+
428
+ return 'model' in declaration;
429
+
430
+ }
431
+
432
+ static getDefaultValue (declaration: SingleDeclaration) {
433
+
434
+ if (declaration.default) {
435
+
436
+ return declaration.default;
437
+
438
+ }
439
+
440
+ if ('type' in declaration) {
441
+
442
+ if (declaration.type === 'string') {
443
+
444
+ return '';
445
+
446
+ }
447
+
448
+ if (declaration.type === 'number') {
449
+
450
+ return 0;
451
+
452
+ }
453
+
454
+ if (declaration.type === 'boolean') {
455
+
456
+ return false;
457
+
458
+ }
459
+
460
+ if (declaration.type === 'array') {
461
+
462
+ return [];
463
+
464
+ }
465
+
466
+ }
467
+
468
+ return null;
469
+
470
+ }
471
+
472
+ }
473
+
474
+ const ModelsClass = new Models();
475
+
476
+ export default ModelsClass;
477
+ export {
478
+ Models
479
+ };
480
+ export type {
481
+ ModelDeclaration, ModelDeclarationExtended, ModelOptions, ModelHooks, SingleDeclaration
482
+ };
package/src/main.ts ADDED
@@ -0,0 +1,84 @@
1
+ import { createApp, createSSRApp, type Component } from 'vue';
2
+ import { createPinia, type StateTree } from 'pinia';
3
+ import createRouter from './mixins/createRouter';
4
+ import { loadViaDeclarationSync } from './mixins/loadComponents';
5
+ import i18n from './plugins/translations';
6
+ import resizePlugin from './plugins/resize';
7
+ import HelpersPlugin from './plugins/filters';
8
+ import youtubePlugin from './plugins/youtube';
9
+ import traceablePlugin from './plugins/traceable';
10
+ import authPlugin from './plugins/auth';
11
+ import replacerPlugin from './plugins/replacer';
12
+ import currencyPlugin from './plugins/currency';
13
+ import eventsPlugin from './plugins/events';
14
+ import './models';
15
+ import type { RouteRecordRaw } from 'vue-router';
16
+ import logger from './mixins/logger';
17
+ import useMainStore from './stores/main.store';
18
+
19
+ /**
20
+ * everything the project owns and the package cannot know: the root component
21
+ * (App.vue carries the global styles and the editor wiring) and the module and
22
+ * partial registries for both render targets.
23
+ */
24
+ export interface AppComponents {
25
+ root: Component
26
+ modules: { name: string, component: Component }[]
27
+ partials: { name: string, component: Component }[]
28
+ modulesMail: { name: string, component: Component }[]
29
+ partialsMail: { name: string, component: Component }[]
30
+ }
31
+
32
+ export function getAppInstance (context: any, routes: readonly RouteRecordRaw[], isSSR: boolean, components: AppComponents) {
33
+
34
+ const app = isSSR
35
+ ? createSSRApp(components.root)
36
+ : createApp(components.root);
37
+ const pinia = createPinia();
38
+
39
+ app.use(pinia);
40
+
41
+ if (isSSR) {
42
+
43
+ logger.ssr('set initial state');
44
+ pinia.state.value = window.__INITIAL_STATE__ as Record<string, StateTree>;
45
+
46
+ } else {
47
+
48
+ const mainStore = useMainStore();
49
+
50
+ mainStore.data = context.data;
51
+ mainStore.layout = context.layout;
52
+ mainStore.target = context.data?.target || 'browser';
53
+ mainStore.configuration = context.settings;
54
+
55
+ }
56
+
57
+ if(context.data?.target === 'mail') {
58
+
59
+ loadViaDeclarationSync(components.modulesMail, 'lila', 'module', app);
60
+ loadViaDeclarationSync(components.partialsMail, 'lila', 'partial', app);
61
+
62
+ } else {
63
+
64
+ loadViaDeclarationSync(components.modules, 'lila', 'module', app);
65
+ loadViaDeclarationSync(components.partials, 'lila', 'partial', app);
66
+
67
+ }
68
+
69
+ const router = createRouter(routes);
70
+
71
+ app.use(i18n);
72
+ app.use(HelpersPlugin);
73
+ app.use(resizePlugin);
74
+ app.use(youtubePlugin);
75
+ app.use(traceablePlugin);
76
+ app.use(authPlugin);
77
+ app.use(replacerPlugin);
78
+ app.use(currencyPlugin);
79
+ app.use(eventsPlugin);
80
+
81
+ app.use(router);
82
+
83
+ return { app, router, pinia };
84
+ }
@@ -0,0 +1,78 @@
1
+ import dayjs from 'dayjs';
2
+
3
+ interface CookieOptions {
4
+ expires?: {
5
+ value: number;
6
+ unit: 'days' | 'weeks' | 'months' | 'years';
7
+ };
8
+ dev?: boolean;
9
+ path?: string;
10
+ domain?: string;
11
+ // Allow overriding the automatically set values if needed
12
+ sameSite?: 'None' | 'Lax' | 'Strict';
13
+ secure?: boolean;
14
+ }
15
+
16
+ /**
17
+ * Creates a cookie string for use with document.cookie
18
+ *
19
+ * @example
20
+ * // For production
21
+ * document.cookie = createCookieString('lila-cookies', '1');
22
+ * // For development
23
+ * document.cookie = createCookieString('lila-cookies', '1', { dev: true });
24
+ * // Custom values
25
+ * document.cookie = createCookieString('lila-cookies-accepted', cookieKeys.join(','), {
26
+ * expires: { value: 2, unit: 'years' }
27
+ * });
28
+ */
29
+ export function createCookieString (
30
+ name: string,
31
+ value: string,
32
+ options: CookieOptions = {}
33
+ ): string {
34
+ const {
35
+ expires = { value: 2, unit: 'years' },
36
+ dev = false,
37
+ path = '/',
38
+ domain
39
+ } = options;
40
+ // Set sameSite and secure based on dev mode
41
+ // Can be overridden by explicitly setting these values in options
42
+ const sameSite = options.sameSite ?? (dev ? 'Lax' : 'None');
43
+ const secure = options.secure ?? !dev;
44
+ const cookieParts = [`${name}=${value}`];
45
+ let isIframe = false;
46
+
47
+ try {
48
+ isIframe = window.self !== window.top;
49
+ } catch (e) {
50
+ // If an error occurs, assume the page is in an iframe.
51
+ isIframe = true;
52
+ }
53
+
54
+ if (expires) {
55
+ cookieParts.push(`expires=${dayjs().add(expires.value, expires.unit).toString()}`);
56
+ }
57
+
58
+ cookieParts.push(`path=${path}`);
59
+
60
+ if (domain) {
61
+ cookieParts.push(`domain=${domain}`);
62
+ }
63
+
64
+ cookieParts.push(`SameSite=${sameSite}`);
65
+
66
+ if (secure) {
67
+ cookieParts.push('Secure');
68
+ }
69
+
70
+ if(isIframe) {
71
+ cookieParts.push('Partitioned');
72
+ }
73
+
74
+ console.log(cookieParts.join('; ').trim());
75
+ return cookieParts.join('; ').trim();
76
+ }
77
+
78
+ export default createCookieString;
@@ -0,0 +1,29 @@
1
+ import type { SingleDeclaration } from '../libs/Models.class';
2
+ import type { BasicData, Structure } from '@lilaquadrat/interfaces';
3
+
4
+ export default function createModelDeclaration (structure: BasicData<Structure & {required: boolean}>): SingleDeclaration {
5
+
6
+ if(!structure) {
7
+ throw new Error('Structure is required');
8
+ }
9
+
10
+ switch(structure.type) {
11
+ case 'string':
12
+ case 'text':
13
+ return { type: 'string' };
14
+
15
+ case 'number':
16
+ return { type: 'number' };
17
+
18
+ case 'boolean':
19
+ return { type: 'boolean' };
20
+
21
+ case 'select':
22
+ return structure.multiple
23
+ ? { type: 'array', contains: { type: 'string' } }
24
+ : { type: 'string' };
25
+
26
+ default:
27
+ return {} as SingleDeclaration;
28
+ }
29
+ }
@@ -0,0 +1,30 @@
1
+ import { createMemoryHistory, createRouter, createWebHashHistory, createWebHistory, type RouteRecordRaw } from 'vue-router';
2
+ import { smartScrollBehavior } from './scroll';
3
+
4
+ function getHistory () {
5
+
6
+ if(import.meta.env.SSR) return createMemoryHistory('/');
7
+
8
+ /**
9
+ * the shareable static preview is opened straight from disk, where pushState
10
+ * is blocked and no server exists to rewrite deep links - so the route has
11
+ * to live in the hash
12
+ */
13
+ if(__PREVIEW__) return createWebHashHistory();
14
+
15
+ return createWebHistory('/');
16
+
17
+ }
18
+
19
+ export default (routes: readonly RouteRecordRaw[]) => {
20
+
21
+ const historyMode = getHistory();
22
+ const router = createRouter({
23
+ history : historyMode,
24
+ routes,
25
+ scrollBehavior: smartScrollBehavior
26
+ });
27
+
28
+ return router;
29
+
30
+ };