@lilaquadrat/design-core 0.2.2 → 0.3.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 (78) hide show
  1. package/README.md +71 -3
  2. package/html/index.server.html +1 -8
  3. package/package.json +53 -53
  4. package/src/client-entry.ts +8 -8
  5. package/src/components/partials/error.partial.vue +19 -19
  6. package/src/components/partials/main-components.partial.vue +75 -70
  7. package/src/components/partials/qrcode.partial.vue +8 -8
  8. package/src/functions/AuthProviderFactory.ts +30 -0
  9. package/src/functions/PaymenyProviderFactory.ts +11 -11
  10. package/src/functions/auth0.provider.ts +75 -0
  11. package/src/functions/keycloak.provider.ts +228 -0
  12. package/src/functions/lila-dom.ts +50 -50
  13. package/src/functions/shopify.provider.ts +176 -154
  14. package/src/functions/stripe.provider.ts +120 -108
  15. package/src/globals.d.ts +1 -2
  16. package/src/index.ts +9 -7
  17. package/src/interfaces/AuthCallbackResult.interface.ts +5 -0
  18. package/src/interfaces/AuthConfig.interface.ts +13 -0
  19. package/src/interfaces/AuthProvider.interface.ts +15 -0
  20. package/src/interfaces/FrontendConfig.interface.ts +11 -40
  21. package/src/interfaces/GenericEvents.interface.ts +1 -1
  22. package/src/interfaces/IdTokenExtended.interface.ts +13 -4
  23. package/src/interfaces/PaymentProvider.interface.ts +2 -2
  24. package/src/interfaces/RenderOptions.interface.ts +12 -0
  25. package/src/libs/ActionNotice.ts +125 -125
  26. package/src/libs/Models.class.ts +219 -221
  27. package/src/main.ts +41 -36
  28. package/src/mixins/createCookieString.ts +50 -36
  29. package/src/mixins/createModelDeclaration.ts +22 -19
  30. package/src/mixins/createRouter.ts +12 -12
  31. package/src/mixins/date.ts +4 -2
  32. package/src/mixins/formatSize.ts +5 -5
  33. package/src/mixins/getAnchor.ts +1 -1
  34. package/src/mixins/getRoutes.ts +13 -25
  35. package/src/mixins/hasSlotContent.ts +22 -16
  36. package/src/mixins/hooks.ts +101 -60
  37. package/src/mixins/loadComponents.ts +60 -58
  38. package/src/mixins/logger.ts +17 -13
  39. package/src/mixins/replaceVariables.ts +10 -8
  40. package/src/mixins/scroll.ts +61 -45
  41. package/src/models/Address.model.ts +7 -7
  42. package/src/models/Contact.model.ts +14 -14
  43. package/src/plugins/analytics.ts +198 -0
  44. package/src/plugins/auth.ts +74 -60
  45. package/src/plugins/currency.ts +10 -10
  46. package/src/plugins/events.ts +101 -97
  47. package/src/plugins/filters.ts +21 -18
  48. package/src/plugins/replacer.ts +7 -6
  49. package/src/plugins/signupFlow.ts +45 -43
  50. package/src/plugins/traceable.ts +28 -26
  51. package/src/plugins/translations.ts +9 -9
  52. package/src/plugins/youtube.ts +39 -34
  53. package/src/routes.ts +108 -108
  54. package/src/server-entry.ts +75 -77
  55. package/src/stores/calls.store.ts +14 -14
  56. package/src/stores/cart.store.ts +116 -107
  57. package/src/stores/content.store.ts +87 -45
  58. package/src/stores/editor.store.ts +16 -16
  59. package/src/stores/files.store.ts +72 -72
  60. package/src/stores/main.store.ts +155 -109
  61. package/src/stores/user.store.ts +72 -68
  62. package/src/translations/de.ts +127 -127
  63. package/src/views/content.view.vue +81 -143
  64. package/src/views/download.view.vue +25 -23
  65. package/src/views/editor.view.vue +150 -125
  66. package/src/views/login.view.vue +35 -36
  67. package/src/views/signup-account.view.vue +14 -14
  68. package/tooling/cypress/config.ts +68 -54
  69. package/tooling/cypress/manifest-utils.mjs +34 -22
  70. package/tooling/cypress/run-parallel.mjs +41 -35
  71. package/tooling/cypress/support/commands.ts +458 -300
  72. package/tooling/eslint.config.js +1 -223
  73. package/tooling/preview.plugin.js +68 -68
  74. package/tooling/ssr-test/index.mjs +205 -203
  75. package/tooling/vite.d.ts +0 -6
  76. package/tooling/vite.js +170 -162
  77. package/src/interfaces/EditorConfiguration.interface.ts +0 -15
  78. package/tooling/stylelint.config.mjs +0 -24
@@ -8,131 +8,131 @@
8
8
  * addMessages() - see plugins/translations.
9
9
  */
10
10
  export default {
11
- 'home' : 'Home',
12
- 'validation-error-type-number' : 'muss eine Zahl sein',
13
- 'validation-error-type-string' : 'muss Text sein',
14
- 'validation-error-minLength' : 'muss mindestens {0} Zeichen lang sein',
15
- 'validation-error-maxLength' : 'darf maximal {0} Zeichen lang sein',
16
- 'validation-error-additionalProperties' : 'Das zusätzliche Attribut {0} ist nicht erlaubt',
17
- 'validation-error-maxItems' : 'darf maximal {0} Elemente besitzen',
18
- 'validation-error-minItems' : 'muss mindestens {0} Elemente besitzen',
19
- 'validation-error-contains' : 'muss mindestens {0} valide(s) Element(e) besitzen',
20
- 'validation-error-required' : 'muss gesetzt sein',
21
- 'validation-error-accepted' : 'Vereinbarungen müssen akzeptiert werden',
22
- 'validation-error-invalidId' : 'ist keine valide ID',
23
- 'validation-error-USER_ALREADY_CONNECTED' : 'Der Benutzer ist bereits mit einem Account verbunden',
24
- 'city' : 'Stadt',
25
- 'zipcode' : 'Postleitzahl',
26
- 'street & number' : 'Straße & Hausnummer',
27
- 'street' : 'Straße',
28
- 'streetnumber' : 'Hausnummer',
29
- 'prename' : 'Vorname',
30
- 'name' : 'Name',
31
- 'country' : 'Land',
32
- 'country-aut' : 'Österreich',
33
- 'country-che' : 'Schweiz',
34
- 'country-deu' : 'Deutschland',
35
- 'email' : 'E-Mail',
36
- 'phone' : 'Telefon',
37
- 'personal' : 'Persönliche Daten',
38
- 'address' : 'Adresse',
39
- 'addressAddition' : 'Adresszusatz',
40
- 'contact' : 'Kontakt',
41
- 'price_with_tax' : 'inkl. {0}% MwSt.',
42
- 'category' : 'Kategorie',
43
- 'message' : 'Nachricht',
44
- 'order with payment' : 'Zahlungspflichtig bestellen',
45
- 'back to the form' : 'Zurück zum Formular',
46
- 'not available' : 'nicht verfügbar',
47
- 'no charge' : 'kostenlos',
48
- 'address addition' : 'Adresszusatz',
49
- 'address search' : 'Adresssuche',
50
- 'no matching addresses' : 'Keine passende Adresse gefunden',
51
- 'provide at least your street and housenumber to find your address. city and zipcode increase accuracy.': 'Bitte geben Sie mindestens Ihre Straße und Hausnummer an, um Ihre Adresse zu finden. Stadt und Postleitzahl erhöhen die Genauigkeit.',
52
- 'type your street and number' : 'Strasse und Hausnummer',
53
- 'validation-error-LIST_CANNOT_JOIN' : 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
54
- 'validation-error-LIST_NOT_FOUND' : 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
55
- 'validation-error-LIST_NO_SPOT_AVAILABLE' : 'Es ist keine weiteren Plätze verfügbar.',
56
- 'validation-error-LIST_UNIQUE_CUSTOMER_CONFIRMED' : 'Die maximale Anzahl wurde erreicht.',
57
- 'validation-error-EMAIL_INVALID' : 'Bitte überprüfe deine E-Mail Adresse',
58
- 'LIST_CANNOT_JOIN_reservation' : 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
59
- 'LIST_UNIQUE_CUSTOMER_CONFIRMED_reservation' : 'Sie sind bereits für eine Reservierung vorgemerkt.',
60
- 'LIST_NOT_FOUND_reservation' : 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
61
- 'LIST_NO_SPOT_AVAILABLE_reservation' : 'Leider sind keine Plätze mehr verfügbar.',
62
- 'LIST_CANNOT_JOIN_contact' : 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
63
- 'LIST_UNIQUE_CUSTOMER_CONFIRMED_contact' : 'Sie haben bereits die maximale Anzahl an Nachrichten gesendet.',
64
- 'LIST_NOT_FOUND_contact' : 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
65
- 'LIST_NO_SPOT_AVAILABLE_contact' : 'Die maximale Anzahl an Nachrichten wurde erreicht.',
66
- 'LIST_CATEGORY_LIMITED_AVAILABILITY_SINGULAR' : 'Nur einmalig verfügbar',
67
- 'LIST_CATEGORY_LIMITED_AVAILABILITY_PLURAL' : 'Limitiert auf {0} Plätze.',
68
- 'LIST_CATEGORY_LIMITED_AVAILABILITY' : 'Nur einmalig verfügbar | Limitiert auf {0} Plätze.',
69
- 'LIST_LIMITED_AVAILABILITY_SINGULAR' : 'Für diese Veranstaltung ist maximal ein Platz verfügbar.',
70
- 'LIST_LIMITED_AVAILABILITY_PLURAL' : 'Für diese Veranstaltung sind maximal {0} Plätze verfügbar.',
71
- 'LIST_LIMITED_AVAILABILITY' : 'Für diese Veranstaltung ist maximal ein Platz verfügbar. | Für diese Veranstaltung sind maximal {0} Plätze verfügbar.',
72
- 'LIST_LIMITED_AVAILABILITY_STATE' : 'Für diese Veranstaltung sind noch {0} von {1} Plätze verfügbar.',
73
- 'LIST_CATEGORY_LAST_CHANCE_PERCENT' : 'Mehr als {0}% gebucht',
74
- 'LIST_CATEGORY_LAST_CHANCE_SINGULAR' : 'Nur noch {0} Platz verfügbar',
75
- 'LIST_CATEGORY_LAST_CHANCE_PLURAL' : 'Nur noch {0} Plätze verfügbar',
76
- 'LIST_CATEGORY_LAST_CHANCE' : 'Nur noch {0} Platz verfügbar | Nur noch {0} Plätze verfügbar',
77
- 'LIST_CATEGORY_SOLD_OUT' : 'AUSVERKAUFT',
78
- 'LIST_SOLD_OUT' : 'Es sind keine weiteren Plätze verfügbar',
79
- 'EMAIL_INVALID_contact' : 'Bitte überprüfe deine E-Mail Adresse',
80
- 'EMAIL_INVALID_reservation' : 'Bitte überprüfe deine E-Mail Adresse',
81
- 'EMAIL_INVALID_content' : 'Bitte überprüfe deine E-Mail Adresse',
82
- 'euro' : '€',
83
- 'required' : 'erforderlich',
84
- 'disabled' : 'deaktiviert',
85
- 'loading' : 'wird geladen',
86
- 'Something went wrong' : 'Hier ist etwas schief gelaufen',
87
- 'The content is missing' : 'Der Inhalt wurde nicht gefunden',
88
- 'CONTENT_NOT_FOUND' : 'Inhalt wurde nicht gefunden',
89
- 'CONTENT_LOADING' : 'Wird geladen',
90
- 'customerId' : 'Kunden ID',
91
- 'connect-to-user' : 'Account verbinden',
92
- 'confirm-email' : 'E-Mail Adresse bestätigen',
93
- 'signup-step-register' : 'Registrierung',
94
- 'signup-step-account' : 'Konto erstellen',
95
- 'signup-step-connect' : 'Account verbinden',
96
- 'signup-step-verify' : 'E-Mail bestätigen',
97
- 'ORDER_SUCCESS_TITLE' : 'Vielen Dank für deinen Kauf',
98
- 'INVOICE_NOT_YET_READY_TITLE' : 'Deine Rechnung ist noch nicht verfügbar.',
99
- 'INVOICE_NOT_YET_READY_DESCRIPTION' : 'Du kannst diese Seite neu laden um den Status zu aktualisieren.',
100
- 'INVOICE_DOWNLOAD' : 'Rechnung herunterladen',
101
- 'ORDER_ERROR_TITLE' : 'Ein Fehler ist aufgetreten',
102
- 'ORDER_ERROR_DESCRIPTION' : 'Deine Bestellung konnte leider nicht gefunden werden. Bitte versuche es später erneut.',
103
- 'confirmationCode' : 'Bestätigungscode',
104
- 'EMAIL_CONFIRMATION_FAILED' : 'E-Mail Adresse konnte nicht bestaetigt werden.',
105
- 'validation-error-EMAIL_CONFIRMATION_FAILED' : 'E-Mail Adresse konnte nicht bestaetigt werden.',
106
- 'CONFIRM_BUTTON' : 'Aktion bestätigen',
107
- 'files-add' : 'Dateien hinzufügen',
108
- 'files-start-upload' : 'Upload starten',
109
- 'files-clear-finished' : 'Abgeschlossene entfernen',
110
- 'files-remove' : 'Entfernen',
111
- 'files-delete' : 'Löschen',
112
- 'files-download' : 'Herunterladen',
113
- 'files-uploaded-at' : 'Hochgeladen',
114
- 'files-loading' : 'Dateien werden geladen...',
115
- 'files-empty' : 'Keine Dateien vorhanden',
116
- 'files-list' : 'Dateien',
117
- 'files-state-pending' : 'Wartet',
118
- 'files-state-creating' : 'Erstelle...',
119
- 'files-state-processing' : 'Verarbeitet',
120
- 'files-state-uploading' : 'Lädt hoch',
121
- 'files-state-done' : 'Fertig',
122
- 'files-state-error' : 'Fehler',
123
- 'files-asset' : 'Asset',
124
- 'files-max-size' : 'Max. Dateigröße',
125
- 'files-max-count' : 'Max. Anzahl',
126
- 'files-allowed-types' : 'Erlaubte Dateitypen',
127
- 'files-error-mime' : 'Dateityp nicht erlaubt',
128
- 'files-error-too-large' : 'Datei überschreitet maximale Größe',
129
- 'files-error-max-count' : 'Maximale Anzahl Dateien erreicht',
130
- 'files-error-no-asset' : 'Asset auswählen vor dem Hochladen',
131
- 'files-error-select-structure' : 'Bitte zuerst eine Kategorie auswählen',
132
- 'files-select-structure' : 'Kategorie auswählen',
133
- 'files-category-all' : 'Alle Dateien',
134
- 'files-download-start' : 'Download starten',
135
- 'files-error-no-url' : 'Download-URL konnte nicht erstellt werden',
136
- 'FILE_LIMIT_EXCEEDED' : 'Maximale Anzahl Dateien überschritten',
137
- 'UPLOAD_FAILED' : 'Upload fehlgeschlagen',
11
+ 'home': 'Home',
12
+ 'validation-error-type-number': 'muss eine Zahl sein',
13
+ 'validation-error-type-string': 'muss Text sein',
14
+ 'validation-error-minLength': 'muss mindestens {0} Zeichen lang sein',
15
+ 'validation-error-maxLength': 'darf maximal {0} Zeichen lang sein',
16
+ 'validation-error-additionalProperties': 'Das zusätzliche Attribut {0} ist nicht erlaubt',
17
+ 'validation-error-maxItems': 'darf maximal {0} Elemente besitzen',
18
+ 'validation-error-minItems': 'muss mindestens {0} Elemente besitzen',
19
+ 'validation-error-contains': 'muss mindestens {0} valide(s) Element(e) besitzen',
20
+ 'validation-error-required': 'muss gesetzt sein',
21
+ 'validation-error-accepted': 'Vereinbarungen müssen akzeptiert werden',
22
+ 'validation-error-invalidId': 'ist keine valide ID',
23
+ 'validation-error-USER_ALREADY_CONNECTED': 'Der Benutzer ist bereits mit einem Account verbunden',
24
+ 'city': 'Stadt',
25
+ 'zipcode': 'Postleitzahl',
26
+ 'street & number': 'Straße & Hausnummer',
27
+ 'street': 'Straße',
28
+ 'streetnumber': 'Hausnummer',
29
+ 'prename': 'Vorname',
30
+ 'name': 'Name',
31
+ 'country': 'Land',
32
+ 'country-aut': 'Österreich',
33
+ 'country-che': 'Schweiz',
34
+ 'country-deu': 'Deutschland',
35
+ 'email': 'E-Mail',
36
+ 'phone': 'Telefon',
37
+ 'personal': 'Persönliche Daten',
38
+ 'address': 'Adresse',
39
+ 'addressAddition': 'Adresszusatz',
40
+ 'contact': 'Kontakt',
41
+ 'price_with_tax': 'inkl. {0}% MwSt.',
42
+ 'category': 'Kategorie',
43
+ 'message': 'Nachricht',
44
+ 'order with payment': 'Zahlungspflichtig bestellen',
45
+ 'back to the form': 'Zurück zum Formular',
46
+ 'not available': 'nicht verfügbar',
47
+ 'no charge': 'kostenlos',
48
+ 'address addition': 'Adresszusatz',
49
+ 'address search': 'Adresssuche',
50
+ 'no matching addresses': 'Keine passende Adresse gefunden',
51
+ 'provide at least your street and housenumber to find your address. city and zipcode increase accuracy.': 'Bitte geben Sie mindestens Ihre Straße und Hausnummer an, um Ihre Adresse zu finden. Stadt und Postleitzahl erhöhen die Genauigkeit.',
52
+ 'type your street and number': 'Strasse und Hausnummer',
53
+ 'validation-error-LIST_CANNOT_JOIN': 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
54
+ 'validation-error-LIST_NOT_FOUND': 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
55
+ 'validation-error-LIST_NO_SPOT_AVAILABLE': 'Es ist keine weiteren Plätze verfügbar.',
56
+ 'validation-error-LIST_UNIQUE_CUSTOMER_CONFIRMED': 'Die maximale Anzahl wurde erreicht.',
57
+ 'validation-error-EMAIL_INVALID': 'Bitte überprüfe deine E-Mail Adresse',
58
+ 'LIST_CANNOT_JOIN_reservation': 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
59
+ 'LIST_UNIQUE_CUSTOMER_CONFIRMED_reservation': 'Sie sind bereits für eine Reservierung vorgemerkt.',
60
+ 'LIST_NOT_FOUND_reservation': 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
61
+ 'LIST_NO_SPOT_AVAILABLE_reservation': 'Leider sind keine Plätze mehr verfügbar.',
62
+ 'LIST_CANNOT_JOIN_contact': 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
63
+ 'LIST_UNIQUE_CUSTOMER_CONFIRMED_contact': 'Sie haben bereits die maximale Anzahl an Nachrichten gesendet.',
64
+ 'LIST_NOT_FOUND_contact': 'Es ist leider ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.',
65
+ 'LIST_NO_SPOT_AVAILABLE_contact': 'Die maximale Anzahl an Nachrichten wurde erreicht.',
66
+ 'LIST_CATEGORY_LIMITED_AVAILABILITY_SINGULAR': 'Nur einmalig verfügbar',
67
+ 'LIST_CATEGORY_LIMITED_AVAILABILITY_PLURAL': 'Limitiert auf {0} Plätze.',
68
+ 'LIST_CATEGORY_LIMITED_AVAILABILITY': 'Nur einmalig verfügbar | Limitiert auf {0} Plätze.',
69
+ 'LIST_LIMITED_AVAILABILITY_SINGULAR': 'Für diese Veranstaltung ist maximal ein Platz verfügbar.',
70
+ 'LIST_LIMITED_AVAILABILITY_PLURAL': 'Für diese Veranstaltung sind maximal {0} Plätze verfügbar.',
71
+ 'LIST_LIMITED_AVAILABILITY': 'Für diese Veranstaltung ist maximal ein Platz verfügbar. | Für diese Veranstaltung sind maximal {0} Plätze verfügbar.',
72
+ 'LIST_LIMITED_AVAILABILITY_STATE': 'Für diese Veranstaltung sind noch {0} von {1} Plätze verfügbar.',
73
+ 'LIST_CATEGORY_LAST_CHANCE_PERCENT': 'Mehr als {0}% gebucht',
74
+ 'LIST_CATEGORY_LAST_CHANCE_SINGULAR': 'Nur noch {0} Platz verfügbar',
75
+ 'LIST_CATEGORY_LAST_CHANCE_PLURAL': 'Nur noch {0} Plätze verfügbar',
76
+ 'LIST_CATEGORY_LAST_CHANCE': 'Nur noch {0} Platz verfügbar | Nur noch {0} Plätze verfügbar',
77
+ 'LIST_CATEGORY_SOLD_OUT': 'AUSVERKAUFT',
78
+ 'LIST_SOLD_OUT': 'Es sind keine weiteren Plätze verfügbar',
79
+ 'EMAIL_INVALID_contact': 'Bitte überprüfe deine E-Mail Adresse',
80
+ 'EMAIL_INVALID_reservation': 'Bitte überprüfe deine E-Mail Adresse',
81
+ 'EMAIL_INVALID_content': 'Bitte überprüfe deine E-Mail Adresse',
82
+ 'euro': '€',
83
+ 'required': 'erforderlich',
84
+ 'disabled': 'deaktiviert',
85
+ 'loading': 'wird geladen',
86
+ 'Something went wrong': 'Hier ist etwas schief gelaufen',
87
+ 'The content is missing': 'Der Inhalt wurde nicht gefunden',
88
+ 'CONTENT_NOT_FOUND': 'Inhalt wurde nicht gefunden',
89
+ 'CONTENT_LOADING': 'Wird geladen',
90
+ 'customerId': 'Kunden ID',
91
+ 'connect-to-user': 'Account verbinden',
92
+ 'confirm-email': 'E-Mail Adresse bestätigen',
93
+ 'signup-step-register': 'Registrierung',
94
+ 'signup-step-account': 'Konto erstellen',
95
+ 'signup-step-connect': 'Account verbinden',
96
+ 'signup-step-verify': 'E-Mail bestätigen',
97
+ 'ORDER_SUCCESS_TITLE': 'Vielen Dank für deinen Kauf',
98
+ 'INVOICE_NOT_YET_READY_TITLE': 'Deine Rechnung ist noch nicht verfügbar.',
99
+ 'INVOICE_NOT_YET_READY_DESCRIPTION': 'Du kannst diese Seite neu laden um den Status zu aktualisieren.',
100
+ 'INVOICE_DOWNLOAD': 'Rechnung herunterladen',
101
+ 'ORDER_ERROR_TITLE': 'Ein Fehler ist aufgetreten',
102
+ 'ORDER_ERROR_DESCRIPTION': 'Deine Bestellung konnte leider nicht gefunden werden. Bitte versuche es später erneut.',
103
+ 'confirmationCode': 'Bestätigungscode',
104
+ 'EMAIL_CONFIRMATION_FAILED': 'E-Mail Adresse konnte nicht bestaetigt werden.',
105
+ 'validation-error-EMAIL_CONFIRMATION_FAILED': 'E-Mail Adresse konnte nicht bestaetigt werden.',
106
+ 'CONFIRM_BUTTON': 'Aktion bestätigen',
107
+ 'files-add': 'Dateien hinzufügen',
108
+ 'files-start-upload': 'Upload starten',
109
+ 'files-clear-finished': 'Abgeschlossene entfernen',
110
+ 'files-remove': 'Entfernen',
111
+ 'files-delete': 'Löschen',
112
+ 'files-download': 'Herunterladen',
113
+ 'files-uploaded-at': 'Hochgeladen',
114
+ 'files-loading': 'Dateien werden geladen...',
115
+ 'files-empty': 'Keine Dateien vorhanden',
116
+ 'files-list': 'Dateien',
117
+ 'files-state-pending': 'Wartet',
118
+ 'files-state-creating': 'Erstelle...',
119
+ 'files-state-processing': 'Verarbeitet',
120
+ 'files-state-uploading': 'Lädt hoch',
121
+ 'files-state-done': 'Fertig',
122
+ 'files-state-error': 'Fehler',
123
+ 'files-asset': 'Asset',
124
+ 'files-max-size': 'Max. Dateigröße',
125
+ 'files-max-count': 'Max. Anzahl',
126
+ 'files-allowed-types': 'Erlaubte Dateitypen',
127
+ 'files-error-mime': 'Dateityp nicht erlaubt',
128
+ 'files-error-too-large': 'Datei überschreitet maximale Größe',
129
+ 'files-error-max-count': 'Maximale Anzahl Dateien erreicht',
130
+ 'files-error-no-asset': 'Asset auswählen vor dem Hochladen',
131
+ 'files-error-select-structure': 'Bitte zuerst eine Kategorie auswählen',
132
+ 'files-select-structure': 'Kategorie auswählen',
133
+ 'files-category-all': 'Alle Dateien',
134
+ 'files-download-start': 'Download starten',
135
+ 'files-error-no-url': 'Download-URL konnte nicht erstellt werden',
136
+ 'FILE_LIMIT_EXCEEDED': 'Maximale Anzahl Dateien überschritten',
137
+ 'UPLOAD_FAILED': 'Upload fehlgeschlagen',
138
138
  };
@@ -1,13 +1,11 @@
1
1
  <script setup lang="ts">
2
- import { computed, ref, watch } from 'vue';
2
+ import { computed, onBeforeMount, onBeforeUnmount, onServerPrefetch, ref, watch } from 'vue';
3
3
  import { distributeGenericData, generateDataWithContent, hardCopy, prepareContent } from '@lilaquadrat/frontend/content';
4
4
  import type { BasicData, Content, ContentWithPositions, GenericData } from '@lilaquadrat/interfaces';
5
5
  import useMainStore from '../stores/main.store';
6
6
  import { useRoute } from 'vue-router';
7
- import { onBeforeMount } from 'vue';
8
- import type { SDKResponse } from '@lilaquadrat/sdk';
7
+ import { isAxiosError } from 'axios';
9
8
  import useUserStore from '../stores/user.store';
10
- import { onServerPrefetch } from 'vue';
11
9
  import useContentStore from '../stores/content.store';
12
10
  import { HelpersPlugin } from '../plugins/filters';
13
11
 
@@ -16,204 +14,144 @@ const userStore = useUserStore();
16
14
  const mainStore = useMainStore();
17
15
  const contentStore = useContentStore();
18
16
  const dataMerged = ref<ContentWithPositions>();
19
- const layout = ref<SDKResponse<BasicData<Content>> | undefined>();
20
- const loading = ref<number>(0);
21
- const error = ref<boolean>(false);
17
+ const status = ref(0);
18
+ let requestId = 0;
22
19
 
23
- watch(route, async () => await getContent());
24
- watch(() => userStore.locked, () => getContent());
25
- onBeforeMount(async () => await getContent());
26
- onServerPrefetch(() => getStoreContent(HelpersPlugin.getFilename(contentType.value, route.path)));
27
-
28
- const linkMode = computed(() => {
29
-
30
- if(mainStore.config?.dynamic !== true) return 'link';
31
-
32
- return undefined
33
-
34
- });
20
+ const linkMode = computed(() => mainStore.dynamic === true ? undefined : 'link');
35
21
  const contentType = computed(() => route.meta.contentType as 'public' | 'members');
36
- const isLocked = computed(() => contentType.value == 'members' && userStore.locked?.length);
22
+ const filename = computed(() => HelpersPlugin.getFilename(contentType.value, route.path));
23
+ const isLocked = computed(() => contentType.value === 'members' && Boolean(userStore.locked));
24
+ const error = computed(() => status.value !== 0 && status.value !== 200);
37
25
  const hint = computed(() => {
38
26
 
39
- if(loading.value === 404) {
40
- return 'error-404'
41
- }
42
-
43
- if(isLocked.value) {
27
+ if(status.value === 404) return 'error-404';
28
+ return isLocked.value ? `error-${userStore.locked}-${contentType.value}` : undefined;
44
29
 
45
- return `error-${userStore.locked}-${contentType.value}`;
30
+ });
46
31
 
47
- }
32
+ watch([() => route.path, contentType, () => userStore.locked], getContent);
33
+ onBeforeMount(getContent);
34
+ onServerPrefetch(() => {
48
35
 
49
- return undefined;
36
+ if(isLocked.value) status.value = 403;
37
+ else useStoreContent();
50
38
 
51
39
  });
40
+ onBeforeUnmount(() => { requestId++; });
52
41
 
53
- function getStoreContent (filename: string) {
54
-
55
- const storeContent = mainStore.data;
56
- const storeLayout = mainStore.layout;
42
+ function useStoreContent(): boolean {
57
43
 
58
- if(!storeContent) return false;
44
+ const storeContent = contentStore.content;
45
+ if(!storeContent) return false;
59
46
 
60
- /**
61
- * if the current data matches the required filename or the target is mail, because emails dont have filenames
62
- * we can use the store data
63
- */
64
- if(storeContent && (storeContent.settings?.filename?.includes(filename) || storeContent.target === 'mail' || filename === '__pdf')) {
65
-
66
- dataMerged.value = mergeContent(storeContent, storeLayout);
67
- loading.value = 200;
68
- error.value = false;
47
+ // Published mail and PDF renders do not need a matching page filename.
48
+ const matches = storeContent.settings?.filename?.includes(filename.value)
49
+ || storeContent.target === 'mail' || filename.value === '__pdf';
50
+ if(!matches) return false;
69
51
 
70
- updateContext();
52
+ renderContent(storeContent, contentStore.layout);
71
53
  return true;
72
-
73
- } else {
74
-
75
- dataMerged.value = undefined;
76
- return false;
77
-
78
- }
79
-
80
54
  }
81
55
 
82
- function updateContext () {
83
-
84
- contentStore.setContext({
85
- sitetitle : mainStore.data?.settings?.title,
86
- description: mainStore.data?.settings?.description,
87
- })
56
+ function renderContent(content: BasicData<Content>, layout?: BasicData<Content>) {
88
57
 
58
+ dataMerged.value = mergeContent(content, layout);
59
+ contentStore.content = content;
60
+ contentStore.layout = layout;
61
+ contentStore.setContext({
62
+ sitetitle: content.settings?.title,
63
+ description: content.settings?.description,
64
+ });
65
+ status.value = 200;
89
66
  }
90
67
 
91
- async function getContent () {
92
-
93
- let content: SDKResponse<BasicData<Content>> | undefined;
94
-
95
- if(isLocked.value) {
96
-
97
- error.value = true;
98
- loading.value = 403;
99
- return;
68
+ async function getContent() {
100
69
 
101
- }
70
+ const currentRequest = ++requestId;
71
+ const type = contentType.value;
102
72
 
103
- const filename = HelpersPlugin.getFilename(contentType.value, route.path);
73
+ if(isLocked.value) {
104
74
 
105
- /**
106
- * while hydration we need to check if the store has the content
107
- * to avoid fetching it again from the server
108
- */
75
+ status.value = 403;
76
+ return;
109
77
 
110
- if(getStoreContent(filename)) return;
78
+ }
111
79
 
112
- // if(data.value?.data?.settings?.filename?.includes(filename)) return;
80
+ try {
113
81
 
114
- loading.value = 0;
115
- error.value = false;
116
-
117
- try {
118
-
119
- content = await mainStore.getContent({filename}, contentType.value) as SDKResponse<BasicData<Content>>;
120
-
121
- } catch (e) {
122
-
123
- console.error(error);
124
- loading.value = e.response.status;
82
+ // Hydration reuses the server's page and layout without fetching either again.
83
+ if(useStoreContent()) return;
125
84
 
126
- }
85
+ // Keep the previous merge mounted until the next page and layout are ready.
86
+ status.value = 0;
87
+ const response = await mainStore.getContent({ filename: filename.value }, type);
88
+ if(currentRequest !== requestId) return;
127
89
 
128
- if(content) {
90
+ if(response.status !== 200 || !response.data) {
129
91
 
130
- mainStore.data = content.data;
131
- loading.value = content.status;
132
- updateContext();
133
-
134
- if(loading.value === 200) {
92
+ status.value = response.status === 204 || response.status === 200 ? 404 : response.status || 404;
93
+ return;
135
94
 
136
- error.value = false;
95
+ }
137
96
 
138
- if(mainStore.data?.settings?.useLayout) {
97
+ const content = response.data;
98
+ const layoutResponse = await getLayout(content, type);
99
+ if(currentRequest !== requestId) return;
139
100
 
140
- // a layout explicitly assigned to the page always wins (also in dynamic mode)
141
- layout.value = await mainStore.getContent({internalId: mainStore.data.settings.useLayout.toString()}, contentType.value) as SDKResponse<BasicData<Content>>;
142
- mainStore.layout = layout.value.data;
101
+ // A page remains valid when its optional layout has not been published.
102
+ const layoutMissing = layoutResponse?.status === 204 || layoutResponse?.status === 404;
103
+ if(layoutResponse && !layoutMissing && (layoutResponse.status !== 200 || !layoutResponse.data)) {
143
104
 
144
- } else if(mainStore.config?.dynamic === true) {
105
+ status.value = layoutResponse.status === 200 ? 404 : layoutResponse.status || 404;
106
+ return;
145
107
 
146
- layout.value = await mainStore.getContent({id: `${contentType.value}-layout`}, contentType.value) as SDKResponse<BasicData<Content>>;
147
- mainStore.layout = layout.value.data;
108
+ }
148
109
 
149
- } else {
110
+ renderContent(content, layoutMissing ? undefined : layoutResponse?.data);
150
111
 
151
- mainStore.layout = undefined;
152
- layout.value = undefined;
112
+ } catch (cause: unknown) {
153
113
 
154
- }
114
+ if(currentRequest !== requestId) return;
115
+ console.error(cause);
116
+ status.value = isAxiosError(cause) ? cause.response?.status ?? 400 : 400;
155
117
 
156
118
  }
157
-
158
- }
159
-
160
- if ([400, 401, 403].includes(loading.value)) {
161
-
162
- error.value = true;
163
-
164
- } else if ([204, 404].includes(loading.value) || !loading.value) {
165
-
166
- error.value = true;
167
- loading.value = 404;
119
+ }
168
120
 
169
- }
121
+ async function getLayout(content: BasicData<Content>, type: 'public' | 'members') {
170
122
 
171
- if(mainStore.data) {
123
+ // An explicitly assigned layout takes precedence over the dynamic default.
124
+ if(content.settings?.useLayout) {
172
125
 
173
- dataMerged.value = mergeContent(mainStore.data, mainStore.layout);
126
+ return mainStore.getContent({ internalId: content.settings.useLayout.toString() }, type);
174
127
 
175
- } else {
128
+ }
176
129
 
177
- dataMerged.value = undefined;
130
+ if(mainStore.dynamic === true) {
178
131
 
179
- }
132
+ return mainStore.getContent({ id: `${type}-layout` }, type);
180
133
 
134
+ }
181
135
  }
182
136
 
183
- function mergeContent (baseContent: Partial<BasicData<Content>>, layout?: Content) {
137
+ function mergeContent(baseContent: BasicData<Content>, layout?: BasicData<Content>) {
184
138
 
185
- if(baseContent) {
186
-
187
139
  const safeData = hardCopy(baseContent);
188
140
 
189
- if(safeData.modules) {
190
-
191
- /**
192
- * content without generic data is the normal case for a static page, and
193
- * generateDataWithContent reads Object.keys of what it is given - so it
194
- * throws on undefined instead of returning nothing
195
- */
196
- if(safeData.genericData) {
141
+ // Static pages commonly have no generic data; generation requires an object.
142
+ if(safeData.modules && safeData.genericData) {
197
143
 
198
144
  distributeGenericData(safeData.modules, generateDataWithContent(safeData.genericData as GenericData));
199
-
200
- }
201
-
202
145
  }
203
146
 
204
147
  return prepareContent(safeData, layout);
205
-
206
- }
207
-
208
- return prepareContent({})
209
-
210
- }
148
+ }
211
149
 
212
150
  </script>
213
151
 
214
152
  <template>
215
153
  <article class="content-screen screen">
216
- <lila-error-partial v-if="error" :status="loading" :hint="hint" :type="contentType" />
154
+ <lila-error-partial v-if="error" :status="status" :hint="hint" :type="contentType" />
217
155
  <lila-content-module v-if="dataMerged && !error" :link-mode="linkMode" :content="dataMerged" />
218
156
  </article>
219
- </template>
157
+ </template>