@motor-cms/ui-admin 1.1.0-alpha.3 → 1.1.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/assets/css/v-onboarding.css +64 -0
- package/app/components/OnboardingStep.vue +42 -0
- package/app/components/UsersOnboarding.vue +84 -0
- package/app/components/client/FooterSlotCard.vue +313 -0
- package/app/components/client/GlobalComponentsSection.vue +65 -0
- package/app/components/dashboard/DashboardActivity.vue +71 -0
- package/app/components/dashboard/DashboardActivityItem.vue +96 -0
- package/app/components/dashboard/DashboardAnnouncementModal.vue +327 -0
- package/app/components/dashboard/DashboardAnnouncements.vue +93 -0
- package/app/components/dashboard/DashboardOnboarding.vue +285 -0
- package/app/components/dashboard/DashboardPublishingQueue.vue +47 -0
- package/app/components/dashboard/DashboardQuickActions.vue +44 -0
- package/app/components/dashboard/DashboardStats.vue +63 -0
- package/app/components/form/inputs/CategoryTreePicker.vue +265 -109
- package/app/components/form/inputs/EntityConfigurationsPanel.vue +235 -0
- package/app/composables/useClientFormExtensions.ts +89 -0
- package/app/composables/useClientLanguages.ts +81 -0
- package/app/composables/useDashboardData.ts +169 -0
- package/app/composables/useOnboardingState.ts +151 -0
- package/app/data/footerTemplate.ts +283 -0
- package/app/lang/de/motor-admin/ai_system_prompts.json +1 -0
- package/app/lang/de/motor-admin/categories.json +1 -0
- package/app/lang/de/motor-admin/category_trees.json +2 -1
- package/app/lang/de/motor-admin/clients.json +17 -1
- package/app/lang/de/motor-admin/config_variables.json +1 -0
- package/app/lang/de/motor-admin/dashboard.json +83 -0
- package/app/lang/de/motor-admin/domains.json +6 -1
- package/app/lang/de/motor-admin/email_templates.json +1 -0
- package/app/lang/de/motor-admin/entity_configurations.json +12 -0
- package/app/lang/de/motor-admin/languages.json +1 -0
- package/app/lang/de/motor-admin/onboarding.json +60 -0
- package/app/lang/de/motor-admin/permissions.json +1 -0
- package/app/lang/de/motor-admin/roles.json +1 -0
- package/app/lang/de/motor-admin/users.json +1 -0
- package/app/lang/en/motor-admin/ai_system_prompts.json +1 -0
- package/app/lang/en/motor-admin/categories.json +1 -0
- package/app/lang/en/motor-admin/category_trees.json +2 -1
- package/app/lang/en/motor-admin/clients.json +17 -1
- package/app/lang/en/motor-admin/config_variables.json +1 -0
- package/app/lang/en/motor-admin/dashboard.json +83 -0
- package/app/lang/en/motor-admin/domains.json +6 -1
- package/app/lang/en/motor-admin/email_templates.json +1 -0
- package/app/lang/en/motor-admin/entity_configurations.json +12 -0
- package/app/lang/en/motor-admin/languages.json +1 -0
- package/app/lang/en/motor-admin/onboarding.json +60 -0
- package/app/lang/en/motor-admin/permissions.json +1 -0
- package/app/lang/en/motor-admin/roles.json +1 -0
- package/app/lang/en/motor-admin/users.json +1 -0
- package/app/pages/index.vue +119 -22
- package/app/pages/login.vue +6 -0
- package/app/pages/motor-admin/ai-system-prompts/[id]/edit.vue +4 -4
- package/app/pages/motor-admin/category-trees/[id]/categories/[categoryId]/edit.vue +4 -3
- package/app/pages/motor-admin/category-trees/[id]/edit.vue +4 -4
- package/app/pages/motor-admin/clients/[id]/edit.vue +146 -6
- package/app/pages/motor-admin/clients/create.vue +34 -2
- package/app/pages/motor-admin/config-variables/[id]/edit.vue +4 -4
- package/app/pages/motor-admin/domains/[id]/edit.vue +18 -5
- package/app/pages/motor-admin/email-templates/[id]/edit.vue +4 -4
- package/app/pages/motor-admin/email-templates/index.vue +36 -25
- package/app/pages/motor-admin/languages/[id]/edit.vue +17 -4
- package/app/pages/motor-admin/languages/create.vue +13 -0
- package/app/pages/motor-admin/permission-groups/[id]/edit.vue +4 -4
- package/app/pages/motor-admin/roles/[id]/edit.vue +4 -4
- package/app/pages/motor-admin/roles/create.vue +4 -1
- package/app/pages/motor-admin/users/[id]/edit.vue +4 -3
- package/app/pages/motor-admin/users/index.vue +1 -0
- package/app/pages/profile.vue +47 -1
- package/app/pages/search.vue +13 -3
- package/app/types/generated/form-meta.ts +24 -20
- package/app/types/generated/grid-meta.ts +5 -3
- package/nuxt.config.ts +15 -1
- package/package.json +6 -2
- package/app/pages/dashboard.vue +0 -5
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { User } from '@motor-cms/ui-core/app/types/auth'
|
|
2
|
+
|
|
3
|
+
// Extend this union as new areas are added
|
|
4
|
+
export type OnboardingArea =
|
|
5
|
+
| 'dashboard-announcements'
|
|
6
|
+
| 'notifications'
|
|
7
|
+
| 'search'
|
|
8
|
+
| 'admin-nav'
|
|
9
|
+
| 'admin-grid'
|
|
10
|
+
| 'user-profile'
|
|
11
|
+
| 'builder-pages'
|
|
12
|
+
|
|
13
|
+
const STORAGE_KEY = 'motor-onboarding-completed'
|
|
14
|
+
const PENDING_KEY = 'motor-onboarding-pending'
|
|
15
|
+
// Written before the completeOnboarding() API call so a hard reload between
|
|
16
|
+
// skip/complete and the network response does not trigger a false restart.
|
|
17
|
+
// Cleared by resetAll() so "restart tour" from profile overrides any prior done state.
|
|
18
|
+
const DONE_KEY = 'motor-onboarding-done'
|
|
19
|
+
|
|
20
|
+
function getCompleted(): Set<string> {
|
|
21
|
+
try {
|
|
22
|
+
const raw = localStorage.getItem(STORAGE_KEY)
|
|
23
|
+
return new Set(raw ? JSON.parse(raw) : [])
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return new Set()
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function persistCompleted(ids: Set<string>) {
|
|
31
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify([...ids]))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function useOnboardingState(area: OnboardingArea) {
|
|
35
|
+
const { user } = useSanctumAuth<User>()
|
|
36
|
+
const userId = computed(() => user.value?.data?.id?.toString() ?? 'anonymous')
|
|
37
|
+
const key = computed(() => `${userId.value}:${area}`)
|
|
38
|
+
|
|
39
|
+
const isCompleted = computed(() => getCompleted().has(key.value))
|
|
40
|
+
|
|
41
|
+
function markCompleted() {
|
|
42
|
+
const completed = getCompleted()
|
|
43
|
+
completed.add(key.value)
|
|
44
|
+
persistCompleted(completed)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function reset() {
|
|
48
|
+
const completed = getCompleted()
|
|
49
|
+
completed.delete(key.value)
|
|
50
|
+
persistCompleted(completed)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { isCompleted, markCompleted, reset }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Clears all completed onboarding areas for the current user from localStorage.
|
|
58
|
+
* Also clears the skip-committed flag so a "restart tour" from profile
|
|
59
|
+
* correctly overrides any previous skip.
|
|
60
|
+
*/
|
|
61
|
+
export function useOnboardingResetAll() {
|
|
62
|
+
const { user } = useSanctumAuth<User>()
|
|
63
|
+
const userId = computed(() => user.value?.data?.id?.toString() ?? 'anonymous')
|
|
64
|
+
|
|
65
|
+
function resetAll() {
|
|
66
|
+
const completed = getCompleted()
|
|
67
|
+
const areas: OnboardingArea[] = [
|
|
68
|
+
'dashboard-announcements',
|
|
69
|
+
'notifications',
|
|
70
|
+
'search',
|
|
71
|
+
'admin-nav',
|
|
72
|
+
'admin-grid',
|
|
73
|
+
'user-profile',
|
|
74
|
+
'builder-pages',
|
|
75
|
+
]
|
|
76
|
+
for (const area of areas) {
|
|
77
|
+
completed.delete(`${userId.value}:${area}`)
|
|
78
|
+
}
|
|
79
|
+
persistCompleted(completed)
|
|
80
|
+
localStorage.removeItem(`${DONE_KEY}:${userId.value}`)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return { resetAll }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Cross-page trigger: marks which onboarding area should auto-start
|
|
88
|
+
* on the next page load. Scoped by user ID to prevent cross-user leakage.
|
|
89
|
+
*/
|
|
90
|
+
export function usePendingOnboarding() {
|
|
91
|
+
const { user } = useSanctumAuth<User>()
|
|
92
|
+
const userId = computed(() => user.value?.data?.id?.toString() ?? 'anonymous')
|
|
93
|
+
|
|
94
|
+
function setPending(area: OnboardingArea) {
|
|
95
|
+
localStorage.setItem(`${PENDING_KEY}:${userId.value}`, area)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function getPending(): OnboardingArea | null {
|
|
99
|
+
return (localStorage.getItem(`${PENDING_KEY}:${userId.value}`) as OnboardingArea) || null
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function clearPending() {
|
|
103
|
+
localStorage.removeItem(`${PENDING_KEY}:${userId.value}`)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { setPending, getPending, clearPending }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Records that the user has intentionally ended the tour (via skip OR normal
|
|
111
|
+
* completion). Written to localStorage BEFORE the completeOnboarding() API
|
|
112
|
+
* call so the flag survives a hard reload if the browser cancels the request.
|
|
113
|
+
* DashboardOnboarding checks this flag before calling resetOnboardingState()
|
|
114
|
+
* so a stale show_onboarding=true in the sanctum auth cache never triggers a
|
|
115
|
+
* false restart. Cleared by resetAll() so "restart tour" from the profile
|
|
116
|
+
* page correctly overrides any prior done state.
|
|
117
|
+
*/
|
|
118
|
+
export function useOnboardingDone() {
|
|
119
|
+
const { user } = useSanctumAuth<User>()
|
|
120
|
+
const userId = computed(() => user.value?.data?.id?.toString() ?? 'anonymous')
|
|
121
|
+
|
|
122
|
+
function commitDone() {
|
|
123
|
+
localStorage.setItem(`${DONE_KEY}:${userId.value}`, '1')
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function isDone(): boolean {
|
|
127
|
+
return !!localStorage.getItem(`${DONE_KEY}:${userId.value}`)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return { commitDone, isDone }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Central guard: should the onboarding tour run for this user?
|
|
135
|
+
*
|
|
136
|
+
* Returns true only when BOTH conditions are met:
|
|
137
|
+
* 1. Backend says show_onboarding=true (fresh user or "restart tour" from profile)
|
|
138
|
+
* 2. User hasn't already completed/skipped the tour in this browser (isDone=false)
|
|
139
|
+
*
|
|
140
|
+
* Use this everywhere instead of hand-rolling the check.
|
|
141
|
+
*/
|
|
142
|
+
export function useOnboardingEnabled() {
|
|
143
|
+
const { user } = useSanctumAuth<User>()
|
|
144
|
+
const { isDone } = useOnboardingDone()
|
|
145
|
+
|
|
146
|
+
const isEnabled = computed(() => {
|
|
147
|
+
return !!user.value?.data?.show_onboarding && !isDone()
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
return { isEnabled }
|
|
151
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { generateUuid } from '@motor-cms/ui-core/app/utils/uuid'
|
|
2
|
+
|
|
3
|
+
// Types mirror @zrmdev/ui-builder/app/types/builder/page-definition. Names
|
|
4
|
+
// (HeadlineParagraphComponent, ImageComponent, HeadlineAtom, ParagraphAtom,
|
|
5
|
+
// ButtonAtom, ImageAtom) match the renderer registry in
|
|
6
|
+
// motor-ui-components/app/builder-registry/bootstrap.ts.
|
|
7
|
+
|
|
8
|
+
// ============================================
|
|
9
|
+
// Local type definitions (mirror page-definition)
|
|
10
|
+
// ============================================
|
|
11
|
+
|
|
12
|
+
interface CssProp {
|
|
13
|
+
key: string
|
|
14
|
+
value: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface PageAtom {
|
|
18
|
+
uuid: string
|
|
19
|
+
display_name: string
|
|
20
|
+
component_name: string
|
|
21
|
+
classes: string
|
|
22
|
+
attributes: Record<string, unknown>
|
|
23
|
+
locked_attributes: string[]
|
|
24
|
+
disabled: boolean
|
|
25
|
+
visible: boolean
|
|
26
|
+
cssProps?: CssProp[]
|
|
27
|
+
admin_scss?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface ComponentSlot {
|
|
31
|
+
uuid: string
|
|
32
|
+
name: string
|
|
33
|
+
display_name: string
|
|
34
|
+
allowedAtoms: string[]
|
|
35
|
+
atoms: PageAtom[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface PageComponent {
|
|
39
|
+
uuid: string
|
|
40
|
+
name: string
|
|
41
|
+
display_name: string
|
|
42
|
+
icon: string
|
|
43
|
+
classes: string
|
|
44
|
+
cssClassName: string
|
|
45
|
+
visible: boolean
|
|
46
|
+
disabled: boolean
|
|
47
|
+
attributes: Record<string, unknown>
|
|
48
|
+
component_slot_name: string | null
|
|
49
|
+
component_slot_prefix: string | null
|
|
50
|
+
is_removable: number
|
|
51
|
+
is_duplicatable: number
|
|
52
|
+
min_amount_in_another_component: number
|
|
53
|
+
display_viewports: string
|
|
54
|
+
slots: ComponentSlot[]
|
|
55
|
+
components: PageComponent[]
|
|
56
|
+
scorings: unknown[]
|
|
57
|
+
scoring_component_configuration: { score: number; topic_id: number; comparison_operator: string }
|
|
58
|
+
anchors: unknown[]
|
|
59
|
+
admin_scss?: string
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface PageColumn {
|
|
63
|
+
uuid: string
|
|
64
|
+
classes: string
|
|
65
|
+
display_name: string
|
|
66
|
+
value_as_grid_column: number
|
|
67
|
+
rows: PageRow[]
|
|
68
|
+
components: PageComponent[]
|
|
69
|
+
admin_scss?: string
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface PageRow {
|
|
73
|
+
uuid: string
|
|
74
|
+
display_name: string
|
|
75
|
+
classes: string
|
|
76
|
+
global_css: string
|
|
77
|
+
cols: PageColumn[]
|
|
78
|
+
admin_scss?: string
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
type PageDefinition = PageRow[]
|
|
82
|
+
|
|
83
|
+
// ============================================
|
|
84
|
+
// Builder helpers
|
|
85
|
+
// ============================================
|
|
86
|
+
|
|
87
|
+
function makeAtom(
|
|
88
|
+
display_name: string,
|
|
89
|
+
component_name: string,
|
|
90
|
+
attributes: Record<string, unknown> = {}
|
|
91
|
+
): PageAtom {
|
|
92
|
+
return {
|
|
93
|
+
uuid: generateUuid(),
|
|
94
|
+
display_name,
|
|
95
|
+
component_name,
|
|
96
|
+
classes: '',
|
|
97
|
+
attributes,
|
|
98
|
+
locked_attributes: [],
|
|
99
|
+
disabled: false,
|
|
100
|
+
visible: true
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function makeSlot(
|
|
105
|
+
name: string,
|
|
106
|
+
display_name: string,
|
|
107
|
+
allowedAtoms: string[],
|
|
108
|
+
atoms: PageAtom[]
|
|
109
|
+
): ComponentSlot {
|
|
110
|
+
return {
|
|
111
|
+
uuid: generateUuid(),
|
|
112
|
+
name,
|
|
113
|
+
display_name,
|
|
114
|
+
allowedAtoms,
|
|
115
|
+
atoms
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function makeComponent(
|
|
120
|
+
name: string,
|
|
121
|
+
display_name: string,
|
|
122
|
+
cssClassName: string,
|
|
123
|
+
slots: ComponentSlot[],
|
|
124
|
+
attributes: Record<string, unknown> = {},
|
|
125
|
+
components: PageComponent[] = []
|
|
126
|
+
): PageComponent {
|
|
127
|
+
return {
|
|
128
|
+
uuid: generateUuid(),
|
|
129
|
+
name,
|
|
130
|
+
display_name,
|
|
131
|
+
icon: '',
|
|
132
|
+
classes: '',
|
|
133
|
+
cssClassName,
|
|
134
|
+
visible: true,
|
|
135
|
+
disabled: false,
|
|
136
|
+
attributes,
|
|
137
|
+
component_slot_name: null,
|
|
138
|
+
component_slot_prefix: null,
|
|
139
|
+
is_removable: 1,
|
|
140
|
+
is_duplicatable: 1,
|
|
141
|
+
min_amount_in_another_component: 0,
|
|
142
|
+
display_viewports: 's,t,m,l,xl',
|
|
143
|
+
slots,
|
|
144
|
+
components,
|
|
145
|
+
scorings: [],
|
|
146
|
+
scoring_component_configuration: { score: 0, topic_id: 0, comparison_operator: '' },
|
|
147
|
+
anchors: []
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function makeColumn(
|
|
152
|
+
display_name: string,
|
|
153
|
+
value_as_grid_column: number,
|
|
154
|
+
components: PageComponent[]
|
|
155
|
+
): PageColumn {
|
|
156
|
+
return {
|
|
157
|
+
uuid: generateUuid(),
|
|
158
|
+
classes: '',
|
|
159
|
+
display_name,
|
|
160
|
+
value_as_grid_column,
|
|
161
|
+
rows: [],
|
|
162
|
+
components
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function makeRow(display_name: string, cols: PageColumn[], classes = ''): PageRow {
|
|
167
|
+
return {
|
|
168
|
+
uuid: generateUuid(),
|
|
169
|
+
display_name,
|
|
170
|
+
classes,
|
|
171
|
+
global_css: '',
|
|
172
|
+
cols
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ============================================
|
|
177
|
+
// Footer template factory
|
|
178
|
+
// ============================================
|
|
179
|
+
|
|
180
|
+
const PLACEHOLDER_IMAGE = '/images/general/frau_mit_kind.jpeg'
|
|
181
|
+
|
|
182
|
+
const TEXT_SLOT_ALLOWED = ['OverlineAtom', 'HeadlineAtom', 'ParagraphAtom', 'ButtonAtom', 'ImageAtom', 'VideoAtom']
|
|
183
|
+
|
|
184
|
+
function textContentComponent(
|
|
185
|
+
display_name: string,
|
|
186
|
+
atoms: PageAtom[],
|
|
187
|
+
attributes: Record<string, unknown> = { has_background: false }
|
|
188
|
+
): PageComponent {
|
|
189
|
+
return makeComponent(
|
|
190
|
+
'HeadlineParagraphComponent',
|
|
191
|
+
display_name,
|
|
192
|
+
'headline-paragraph',
|
|
193
|
+
[makeSlot('content', 'Content', TEXT_SLOT_ALLOWED, atoms)],
|
|
194
|
+
attributes
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function headlineAtom(text: string, level: 'h2' | 'h3' | 'h4' = 'h3'): PageAtom {
|
|
199
|
+
return makeAtom('Headline', 'HeadlineAtom', {
|
|
200
|
+
text,
|
|
201
|
+
type: level,
|
|
202
|
+
displayedLevel: level,
|
|
203
|
+
weight: 'bold'
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function paragraphAtom(text: string): PageAtom {
|
|
208
|
+
return makeAtom('Paragraph', 'ParagraphAtom', {
|
|
209
|
+
text,
|
|
210
|
+
bullet_type: 'check__default',
|
|
211
|
+
orderedlist_type: 'decimal'
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function buttonAtom(title: string): PageAtom {
|
|
216
|
+
return makeAtom('Button', 'ButtonAtom', {
|
|
217
|
+
title,
|
|
218
|
+
link: '',
|
|
219
|
+
variant: 'dark',
|
|
220
|
+
has_arrow: false
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function imageAtom(display_name: string): PageAtom {
|
|
225
|
+
return makeAtom(display_name, 'ImageAtom', {
|
|
226
|
+
src: PLACEHOLDER_IMAGE,
|
|
227
|
+
alt: display_name
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function imageComponent(display_name: string, extraClasses = ''): PageComponent {
|
|
232
|
+
const c = makeComponent(
|
|
233
|
+
'ImageComponent',
|
|
234
|
+
display_name,
|
|
235
|
+
'image',
|
|
236
|
+
[makeSlot('content', 'Content', ['ImageAtom'], [imageAtom(display_name)])]
|
|
237
|
+
)
|
|
238
|
+
if (extraClasses) c.classes = extraClasses
|
|
239
|
+
return c
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function createFooterTemplate(): PageDefinition {
|
|
243
|
+
// ---- Row 1: 6/6 split ----
|
|
244
|
+
// Col 1: intro text (Headline + Paragraph)
|
|
245
|
+
// Col 2: three award badges, each its own ImageComponent
|
|
246
|
+
const row1 = makeRow('Row 1', [
|
|
247
|
+
makeColumn('Column 1', 6, [
|
|
248
|
+
textContentComponent('Intro', [
|
|
249
|
+
headlineAtom('Headline', 'h2'),
|
|
250
|
+
paragraphAtom('Paragraph')
|
|
251
|
+
])
|
|
252
|
+
]),
|
|
253
|
+
makeColumn('Column 2', 6, [
|
|
254
|
+
imageComponent('Badge 1', 'footer-badge'),
|
|
255
|
+
imageComponent('Badge 2', 'footer-badge'),
|
|
256
|
+
imageComponent('Badge 3', 'footer-badge')
|
|
257
|
+
])
|
|
258
|
+
])
|
|
259
|
+
|
|
260
|
+
// ---- Row 2: four 3/12 columns ----
|
|
261
|
+
// Col 1: Kontakt (pre-filled headline)
|
|
262
|
+
// Col 2-4: nav-style headline + paragraph + CTA button
|
|
263
|
+
// Row gets the white inset card chrome inside the peach FooterFrame.
|
|
264
|
+
const row2 = makeRow('Row 2', [
|
|
265
|
+
makeColumn('Column 1', 3, [
|
|
266
|
+
textContentComponent('Kontakt', [
|
|
267
|
+
headlineAtom('Kontakt', 'h3'),
|
|
268
|
+
paragraphAtom('Paragraph')
|
|
269
|
+
])
|
|
270
|
+
]),
|
|
271
|
+
...['Column 2', 'Column 3', 'Column 4'].map((label) =>
|
|
272
|
+
makeColumn(label, 3, [
|
|
273
|
+
textContentComponent(label, [
|
|
274
|
+
headlineAtom('Headline', 'h3'),
|
|
275
|
+
paragraphAtom('Paragraph'),
|
|
276
|
+
buttonAtom('CTA Button')
|
|
277
|
+
])
|
|
278
|
+
])
|
|
279
|
+
)
|
|
280
|
+
], 'footer-content-card')
|
|
281
|
+
|
|
282
|
+
return [row1, row2]
|
|
283
|
+
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
"prompt_description": "Der System-Prompt-Text, der an das KI-Modell gesendet wird",
|
|
8
8
|
"create_title": "KI-System-Prompt erstellen",
|
|
9
9
|
"edit_title": "KI-System-Prompt bearbeiten",
|
|
10
|
+
"view_title": "KI-System-Prompt ansehen",
|
|
10
11
|
"created_success": "KI-System-Prompt erfolgreich erstellt.",
|
|
11
12
|
"updated_success": "KI-System-Prompt erfolgreich aktualisiert."
|
|
12
13
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"add": "Kategorie hinzufügen",
|
|
6
6
|
"create_title": "Kategorie erstellen",
|
|
7
7
|
"edit_title": "Kategorie bearbeiten",
|
|
8
|
+
"view_title": "Kategorie ansehen",
|
|
8
9
|
"created_success": "Kategorie wurde erfolgreich erstellt",
|
|
9
10
|
"updated_success": "Kategorie wurde erfolgreich aktualisiert",
|
|
10
11
|
"parent": "Übergeordnete Kategorie",
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
"add": "Kategoriebaum hinzufügen",
|
|
7
7
|
"create_title": "Kategoriebaum erstellen",
|
|
8
8
|
"edit_title": "Kategoriebaum bearbeiten",
|
|
9
|
+
"view_title": "Kategoriebaum ansehen",
|
|
9
10
|
"created_success": "Kategoriebaum wurde erfolgreich erstellt",
|
|
10
11
|
"updated_success": "Kategoriebaum wurde erfolgreich aktualisiert",
|
|
11
|
-
"children": "
|
|
12
|
+
"children": "Kategorien",
|
|
12
13
|
"children_title": "Kategorien in \"{name}\"",
|
|
13
14
|
"children_subtitle": "Kategorien in diesem Baum verwalten"
|
|
14
15
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"add": "Mandant hinzufügen",
|
|
7
7
|
"create_title": "Mandant erstellen",
|
|
8
8
|
"edit_title": "Mandant bearbeiten",
|
|
9
|
+
"view_title": "Mandant ansehen",
|
|
9
10
|
"created_success": "Mandant erfolgreich erstellt.",
|
|
10
11
|
"updated_success": "Mandant erfolgreich aktualisiert.",
|
|
11
12
|
"slug": "Slug",
|
|
@@ -22,5 +23,20 @@
|
|
|
22
23
|
"contact_phone": "Telefon",
|
|
23
24
|
"group_address": "Adresse",
|
|
24
25
|
"group_contact": "Kontakt",
|
|
25
|
-
"group_other": "Sonstiges"
|
|
26
|
+
"group_other": "Sonstiges",
|
|
27
|
+
"frontend_config_title": "Frontend-Konfiguration",
|
|
28
|
+
"global_components": {
|
|
29
|
+
"title": "Globale Komponenten",
|
|
30
|
+
"footer": "Footer",
|
|
31
|
+
"no_footer": "Kein Footer konfiguriert",
|
|
32
|
+
"create_footer": "Footer erstellen",
|
|
33
|
+
"edit_footer": "Footer bearbeiten",
|
|
34
|
+
"unlink_footer": "Verknüpfung lösen",
|
|
35
|
+
"footer_created": "Footer erfolgreich erstellt.",
|
|
36
|
+
"published": "Veröffentlicht",
|
|
37
|
+
"draft": "Entwurf",
|
|
38
|
+
"unlink_confirm": "Möchten Sie die Verknüpfung zu diesem Footer wirklich lösen?",
|
|
39
|
+
"unlink_effect": "Der Footer wird nicht gelöscht, sondern nur die Verknüpfung zum Mandanten entfernt.",
|
|
40
|
+
"no_languages": "Keine Sprachen für diesen Mandanten konfiguriert. Erstellen Sie zuerst Navigationsbäume."
|
|
41
|
+
}
|
|
26
42
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"is_invisible": "Versteckt",
|
|
10
10
|
"create_title": "Konfigurationsvariable erstellen",
|
|
11
11
|
"edit_title": "Konfigurationsvariable bearbeiten",
|
|
12
|
+
"view_title": "Konfigurationsvariable ansehen",
|
|
12
13
|
"created_success": "Konfigurationsvariable erfolgreich erstellt.",
|
|
13
14
|
"updated_success": "Konfigurationsvariable erfolgreich aktualisiert."
|
|
14
15
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"welcome": "Willkommen, {name}",
|
|
3
|
+
"announcement_created": "Meldung erstellt",
|
|
4
|
+
"announcement_dismissed": "Meldung ausgeblendet",
|
|
5
|
+
"stats": {
|
|
6
|
+
"pages": "Seiten",
|
|
7
|
+
"pages_total": "Gesamt",
|
|
8
|
+
"drafts": "Entwürfe",
|
|
9
|
+
"drafts_subtitle": "In Bearbeitung",
|
|
10
|
+
"scheduled": "Geplant",
|
|
11
|
+
"scheduled_subtitle": "Veröffentlichung",
|
|
12
|
+
"media": "Medien",
|
|
13
|
+
"media_subtitle": "Dateien"
|
|
14
|
+
},
|
|
15
|
+
"activity": {
|
|
16
|
+
"title": "Letzte Aktivitäten",
|
|
17
|
+
"empty": "Noch keine Aktivitäten",
|
|
18
|
+
"unknown": "Unbekannt",
|
|
19
|
+
"system": "System",
|
|
20
|
+
"verbs": {
|
|
21
|
+
"created": "erstellt",
|
|
22
|
+
"updated": "aktualisiert",
|
|
23
|
+
"deleted": "gelöscht",
|
|
24
|
+
"published": "veröffentlicht",
|
|
25
|
+
"unpublished": "offline genommen"
|
|
26
|
+
},
|
|
27
|
+
"types": {
|
|
28
|
+
"page": "Seite",
|
|
29
|
+
"navigation": "Navigation",
|
|
30
|
+
"media": "Medien",
|
|
31
|
+
"content_type": "Inhaltstyp",
|
|
32
|
+
"assistant": "Assistent",
|
|
33
|
+
"scoring": "Scoring",
|
|
34
|
+
"scheduled": "Geplant",
|
|
35
|
+
"approval": "Freigabe",
|
|
36
|
+
"seo": "SEO",
|
|
37
|
+
"search": "Suche"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"announcements": {
|
|
41
|
+
"title": "Meldungen",
|
|
42
|
+
"empty": "Keine Meldungen",
|
|
43
|
+
"modal_title": "Neue Meldung",
|
|
44
|
+
"field_title": "Titel",
|
|
45
|
+
"field_title_placeholder": "Meldung eingeben...",
|
|
46
|
+
"field_body": "Beschreibung",
|
|
47
|
+
"field_body_placeholder": "Optionale Details...",
|
|
48
|
+
"field_type": "Typ",
|
|
49
|
+
"field_audience": "Zielgruppe",
|
|
50
|
+
"field_users": "Nutzer auswählen",
|
|
51
|
+
"field_users_placeholder": "Nutzer suchen...",
|
|
52
|
+
"field_client": "Mandant auswählen",
|
|
53
|
+
"field_client_placeholder": "Mandant wählen...",
|
|
54
|
+
"field_link": "Verknüpfung (optional)",
|
|
55
|
+
"field_link_type_placeholder": "Typ wählen...",
|
|
56
|
+
"field_link_item": "Element",
|
|
57
|
+
"field_link_item_placeholder": "Element suchen...",
|
|
58
|
+
"field_starts_at": "Sichtbar ab",
|
|
59
|
+
"field_expires_at": "Sichtbar bis",
|
|
60
|
+
"cancel": "Abbrechen",
|
|
61
|
+
"create": "Erstellen",
|
|
62
|
+
"type_info": "Info",
|
|
63
|
+
"type_warning": "Warnung",
|
|
64
|
+
"type_error": "Fehler",
|
|
65
|
+
"audience_self": "Nur für mich",
|
|
66
|
+
"audience_users": "Bestimmte Nutzer",
|
|
67
|
+
"audience_client": "Alle im Mandanten",
|
|
68
|
+
"linkable_page": "Seite",
|
|
69
|
+
"linkable_navigation": "Navigationspunkt",
|
|
70
|
+
"linkable_file": "Datei",
|
|
71
|
+
"linkable_content_type": "Inhaltstyp"
|
|
72
|
+
},
|
|
73
|
+
"quick_actions": {
|
|
74
|
+
"title": "Schnellaktionen",
|
|
75
|
+
"new_page": "Neue Seite",
|
|
76
|
+
"upload_media": "Medien hochladen",
|
|
77
|
+
"navigation": "Navigation"
|
|
78
|
+
},
|
|
79
|
+
"publishing_queue": {
|
|
80
|
+
"title": "Geplante Veröffentlichungen",
|
|
81
|
+
"empty": "Keine geplanten Veröffentlichungen"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"add": "Domain hinzufügen",
|
|
7
7
|
"create_title": "Domain erstellen",
|
|
8
8
|
"edit_title": "Domain bearbeiten",
|
|
9
|
+
"view_title": "Domain ansehen",
|
|
9
10
|
"created_success": "Domain erfolgreich erstellt.",
|
|
10
11
|
"updated_success": "Domain erfolgreich aktualisiert.",
|
|
11
12
|
"host": "Host",
|
|
@@ -14,6 +15,10 @@
|
|
|
14
15
|
"path": "Pfad",
|
|
15
16
|
"target": "Ziel",
|
|
16
17
|
"parameters": "Parameter",
|
|
18
|
+
"is_preview_domain": "Vorschau-Domain",
|
|
19
|
+
"is_canonical": "Kanonische Domain für SEO",
|
|
20
|
+
"is_canonical_description": "Wenn dieser Client mehrere Domains hat (z. B. Vanity-URLs): Diese ist die kanonische Domain — Canonical-Tags zeigen darauf und konsolidieren das SEO-Signal. Nur eine Domain pro Client kann kanonisch sein.",
|
|
17
21
|
"group_connection": "Verbindung",
|
|
18
|
-
"group_routing": "Routing"
|
|
22
|
+
"group_routing": "Routing",
|
|
23
|
+
"group_seo": "SEO"
|
|
19
24
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"add": "E-Mail-Vorlage hinzufügen",
|
|
6
6
|
"create_title": "E-Mail-Vorlage erstellen",
|
|
7
7
|
"edit_title": "E-Mail-Vorlage bearbeiten",
|
|
8
|
+
"view_title": "E-Mail-Vorlage ansehen",
|
|
8
9
|
"slug": "Slug",
|
|
9
10
|
"slug_description": "URL-freundlicher Bezeichner, automatisch aus dem Namen generiert",
|
|
10
11
|
"subject": "Betreff",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Entity-Konfigurationen",
|
|
3
|
+
"config_variable": "Konfigurationsvariable",
|
|
4
|
+
"value": "Wert",
|
|
5
|
+
"add": "Konfiguration hinzufügen",
|
|
6
|
+
"save": "Speichern",
|
|
7
|
+
"saved": "Konfiguration gespeichert",
|
|
8
|
+
"removed": "Konfiguration entfernt",
|
|
9
|
+
"no_configurations": "Noch keine Konfigurationen zugeordnet.",
|
|
10
|
+
"select_variable": "Konfigurationsvariable auswählen",
|
|
11
|
+
"confirm_remove": "Diese Konfiguration entfernen?"
|
|
12
|
+
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"native_name": "Eigenname",
|
|
10
10
|
"create_title": "Sprache erstellen",
|
|
11
11
|
"edit_title": "Sprache bearbeiten",
|
|
12
|
+
"view_title": "Sprache ansehen",
|
|
12
13
|
"created_success": "Sprache erfolgreich erstellt.",
|
|
13
14
|
"updated_success": "Sprache erfolgreich aktualisiert.",
|
|
14
15
|
"iso_639_1": "ISO 639-1 Code",
|