@edgedev/create-edge-app 1.2.32 → 1.2.34
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/deploy.sh +77 -0
- package/edge/components/cms/block.vue +228 -18
- package/edge/components/cms/blockApi.vue +3 -3
- package/edge/components/cms/blockEditor.vue +374 -85
- package/edge/components/cms/blockPicker.vue +29 -3
- package/edge/components/cms/blockRender.vue +3 -3
- package/edge/components/cms/blocksManager.vue +755 -82
- package/edge/components/cms/codeEditor.vue +15 -6
- package/edge/components/cms/fontUpload.vue +318 -2
- package/edge/components/cms/htmlContent.vue +230 -89
- package/edge/components/cms/menu.vue +5 -4
- package/edge/components/cms/page.vue +750 -21
- package/edge/components/cms/site.vue +624 -84
- package/edge/components/cms/sitesManager.vue +5 -4
- package/edge/components/cms/themeEditor.vue +196 -162
- package/edge/components/editor.vue +5 -1
- package/edge/composables/global.ts +37 -5
- package/edge/composables/useCmsNewDocs.js +100 -0
- package/edge/composables/useEdgeCmsDialogPositionFix.js +19 -0
- package/edge/routes/cms/dashboard/blocks/[block].vue +5 -0
- package/edge/routes/cms/dashboard/blocks/index.vue +12 -1
- package/edge/routes/cms/dashboard/media/index.vue +5 -0
- package/edge/routes/cms/dashboard/sites/[site]/[[page]].vue +4 -0
- package/edge/routes/cms/dashboard/sites/[site].vue +4 -0
- package/edge/routes/cms/dashboard/sites/index.vue +4 -0
- package/edge/routes/cms/dashboard/templates/[page].vue +4 -0
- package/edge/routes/cms/dashboard/templates/index.vue +4 -0
- package/edge/routes/cms/dashboard/themes/[theme].vue +5 -0
- package/edge/routes/cms/dashboard/themes/index.vue +330 -1
- package/firebase.json +4 -0
- package/nuxt.config.ts +1 -1
- package/package.json +2 -2
- package/pages/app.vue +12 -12
|
@@ -7,6 +7,7 @@ const isAiBusy = status => status === 'queued' || status === 'running'
|
|
|
7
7
|
const state = reactive({
|
|
8
8
|
filter: '',
|
|
9
9
|
})
|
|
10
|
+
const cmsMultiOrg = useState('cmsMultiOrg', () => false)
|
|
10
11
|
|
|
11
12
|
const isAdmin = computed(() => {
|
|
12
13
|
return edgeGlobal.isAdminGlobal(edgeFirebase).value
|
|
@@ -25,21 +26,21 @@ const canAddSite = computed(() => {
|
|
|
25
26
|
})
|
|
26
27
|
|
|
27
28
|
const queryField = computed(() => {
|
|
28
|
-
if (!isAdmin.value) {
|
|
29
|
+
if (!isAdmin.value && !cmsMultiOrg.value) {
|
|
29
30
|
return 'users'
|
|
30
31
|
}
|
|
31
32
|
return ''
|
|
32
33
|
})
|
|
33
34
|
|
|
34
35
|
const queryValue = computed(() => {
|
|
35
|
-
if (!isAdmin.value) {
|
|
36
|
+
if (!isAdmin.value && !cmsMultiOrg.value) {
|
|
36
37
|
return [edgeFirebase?.user?.uid]
|
|
37
38
|
}
|
|
38
39
|
return ''
|
|
39
40
|
})
|
|
40
41
|
|
|
41
42
|
const queryOperator = computed(() => {
|
|
42
|
-
if (!isAdmin.value) {
|
|
43
|
+
if (!isAdmin.value && !cmsMultiOrg.value) {
|
|
43
44
|
return 'array-contains-any'
|
|
44
45
|
}
|
|
45
46
|
return ''
|
|
@@ -100,7 +101,7 @@ const queryOperator = computed(() => {
|
|
|
100
101
|
<Separator class="dark:bg-slate-600" />
|
|
101
102
|
</template>
|
|
102
103
|
<div
|
|
103
|
-
v-if="slotProps.filtered.length === 0 && !isAdmin && disableAddSiteForNonAdmin"
|
|
104
|
+
v-if="slotProps.filtered.length === 0 && !isAdmin && disableAddSiteForNonAdmin && !cmsMultiOrg"
|
|
104
105
|
class="px-4 py-6 text-sm text-muted-foreground"
|
|
105
106
|
>
|
|
106
107
|
No sites are assigned to your account. Contact an organization admin to add a site for you.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { toTypedSchema } from '@vee-validate/zod'
|
|
3
|
-
import { FolderCog } from 'lucide-vue-next'
|
|
3
|
+
import { Download, FolderCog } from 'lucide-vue-next'
|
|
4
4
|
import * as z from 'zod'
|
|
5
5
|
const props = defineProps({
|
|
6
6
|
themeId: {
|
|
@@ -11,98 +11,21 @@ const props = defineProps({
|
|
|
11
11
|
|
|
12
12
|
const emit = defineEmits(['head'])
|
|
13
13
|
const edgeFirebase = inject('edgeFirebase')
|
|
14
|
+
const { themes: themeNewDocSchema } = useCmsNewDocs()
|
|
14
15
|
const { createDefaults: createSiteSettingsDefaults } = useSiteSettingsTemplate()
|
|
15
16
|
const state = reactive({
|
|
16
17
|
filter: '',
|
|
17
18
|
workingDoc: {},
|
|
18
19
|
newDocs: {
|
|
19
|
-
themes:
|
|
20
|
-
name: { value: '' },
|
|
21
|
-
headJSON: {
|
|
22
|
-
value: `{
|
|
23
|
-
"link": [
|
|
24
|
-
{
|
|
25
|
-
"rel": "preconnect",
|
|
26
|
-
"href": "https://fonts.googleapis.com"
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"rel": "preconnect",
|
|
30
|
-
"href": "https://fonts.gstatic.com",
|
|
31
|
-
"crossorigin": ""
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"rel": "stylesheet",
|
|
35
|
-
"href": "https://fonts.googleapis.com/css2?family=Overpass:wght@400;700&family=Kode+Mono:wght@400;700&display=swap"
|
|
36
|
-
}
|
|
37
|
-
]
|
|
38
|
-
}`,
|
|
39
|
-
},
|
|
40
|
-
theme: {
|
|
41
|
-
value: `{
|
|
42
|
-
"extend": {
|
|
43
|
-
"colors": {
|
|
44
|
-
"brand": "#3B82F6",
|
|
45
|
-
"accent": "#F59E0B",
|
|
46
|
-
"surface": "#FAFAFA",
|
|
47
|
-
"subtle": "#F3F4F6",
|
|
48
|
-
"text": "#1F2937",
|
|
49
|
-
"muted": "#9CA3AF",
|
|
50
|
-
"success": "#22C55E",
|
|
51
|
-
"danger": "#EF4444",
|
|
52
|
-
"border": "#E5E7EB",
|
|
53
|
-
"ring": "#93C5FD",
|
|
54
|
-
"link": "#3B82F6",
|
|
55
|
-
"linkHover": "#1D4ED8",
|
|
56
|
-
"navBg": "#000000",
|
|
57
|
-
"navText": "#FFFFFF",
|
|
58
|
-
"navMuted": "#6B7280",
|
|
59
|
-
"navBorder": "",
|
|
60
|
-
"navActive": "#3B82F6",
|
|
61
|
-
"navHoverBg": "",
|
|
62
|
-
"navActiveBg": "",
|
|
63
|
-
"sideNavBg": "#FFFFFF",
|
|
64
|
-
"sideNavText": "#000000",
|
|
65
|
-
"sideNavActive": "#AFBD23"
|
|
66
|
-
},
|
|
67
|
-
"fontFamily": {
|
|
68
|
-
"sans": ["Overpass", "sans-serif"],
|
|
69
|
-
"serif": ["Kode Mono", "monospace"],
|
|
70
|
-
"mono": ["Overpass", "sans-serif"],
|
|
71
|
-
"brand": ["Kode Mono", "monospace"]
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
"apply": {},
|
|
75
|
-
"slots": {},
|
|
76
|
-
"variants": {
|
|
77
|
-
"light": {
|
|
78
|
-
"apply": {}
|
|
79
|
-
},
|
|
80
|
-
"dark": {
|
|
81
|
-
"apply": {},
|
|
82
|
-
"slots": {}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}`,
|
|
86
|
-
},
|
|
87
|
-
extraCSS: {
|
|
88
|
-
value: '',
|
|
89
|
-
},
|
|
90
|
-
version: 1,
|
|
91
|
-
defaultPages: { value: [] },
|
|
92
|
-
defaultMenus: {
|
|
93
|
-
value: {
|
|
94
|
-
'Site Root': [],
|
|
95
|
-
'Not In Menu': [],
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
defaultSiteSettings: { value: createSiteSettingsDefaults() },
|
|
99
|
-
},
|
|
20
|
+
themes: themeNewDocSchema.value,
|
|
100
21
|
},
|
|
101
22
|
mounted: false,
|
|
102
23
|
loading: false,
|
|
103
24
|
defaultSettingsOpen: false,
|
|
104
25
|
})
|
|
105
26
|
|
|
27
|
+
const editorViewportHeight = 'calc(100vh - 420px)'
|
|
28
|
+
|
|
106
29
|
const blockSchema = toTypedSchema(z.object({
|
|
107
30
|
name: z.string({
|
|
108
31
|
required_error: 'Name is required',
|
|
@@ -126,6 +49,16 @@ const parseJsonSafe = (value, fallback) => {
|
|
|
126
49
|
}
|
|
127
50
|
|
|
128
51
|
const headObject = computed(() => lastValidHead.value)
|
|
52
|
+
const previewTheme = computed(() => {
|
|
53
|
+
const isObjectTheme = !!lastValidTheme.value
|
|
54
|
+
&& typeof lastValidTheme.value === 'object'
|
|
55
|
+
&& !Array.isArray(lastValidTheme.value)
|
|
56
|
+
const baseTheme = isObjectTheme ? lastValidTheme.value : {}
|
|
57
|
+
return {
|
|
58
|
+
...baseTheme,
|
|
59
|
+
extraCSS: typeof state.workingDoc?.extraCSS === 'string' ? state.workingDoc.extraCSS : '',
|
|
60
|
+
}
|
|
61
|
+
})
|
|
129
62
|
|
|
130
63
|
watch(headObject, (newHeadElements) => {
|
|
131
64
|
emit('head', newHeadElements)
|
|
@@ -325,6 +258,62 @@ const templatePageOptions = computed(() => {
|
|
|
325
258
|
.sort((a, b) => a.label.localeCompare(b.label))
|
|
326
259
|
})
|
|
327
260
|
|
|
261
|
+
const themesCollectionPath = computed(() => `${edgeGlobal.edgeState.organizationDocPath}/themes`)
|
|
262
|
+
const themesCollection = computed(() => edgeFirebase.data?.[themesCollectionPath.value] || {})
|
|
263
|
+
|
|
264
|
+
const downloadJsonFile = (payload, filename) => {
|
|
265
|
+
if (typeof window === 'undefined')
|
|
266
|
+
return
|
|
267
|
+
const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' })
|
|
268
|
+
const objectUrl = URL.createObjectURL(blob)
|
|
269
|
+
const anchor = document.createElement('a')
|
|
270
|
+
anchor.href = objectUrl
|
|
271
|
+
anchor.download = filename
|
|
272
|
+
document.body.appendChild(anchor)
|
|
273
|
+
anchor.click()
|
|
274
|
+
anchor.remove()
|
|
275
|
+
URL.revokeObjectURL(objectUrl)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const isPlainObject = value => !!value && typeof value === 'object' && !Array.isArray(value)
|
|
279
|
+
|
|
280
|
+
const cloneSchemaValue = (value) => {
|
|
281
|
+
if (isPlainObject(value) || Array.isArray(value))
|
|
282
|
+
return edgeGlobal.dupObject(value)
|
|
283
|
+
return value
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const getDocDefaultsFromSchema = (schema = {}) => {
|
|
287
|
+
const defaults = {}
|
|
288
|
+
for (const [key, schemaEntry] of Object.entries(schema || {})) {
|
|
289
|
+
const hasValueProp = isPlainObject(schemaEntry) && Object.prototype.hasOwnProperty.call(schemaEntry, 'value')
|
|
290
|
+
const baseValue = hasValueProp ? schemaEntry.value : schemaEntry
|
|
291
|
+
defaults[key] = cloneSchemaValue(baseValue)
|
|
292
|
+
}
|
|
293
|
+
return defaults
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const getThemeDocDefaults = () => getDocDefaultsFromSchema(themeNewDocSchema.value || {})
|
|
297
|
+
|
|
298
|
+
const notifySuccess = (message) => {
|
|
299
|
+
edgeFirebase?.toast?.success?.(message)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const notifyError = (message) => {
|
|
303
|
+
edgeFirebase?.toast?.error?.(message)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const exportCurrentTheme = () => {
|
|
307
|
+
const doc = themesCollection.value?.[props.themeId]
|
|
308
|
+
if (!doc || !doc.docId) {
|
|
309
|
+
notifyError('Save this theme before exporting.')
|
|
310
|
+
return
|
|
311
|
+
}
|
|
312
|
+
const exportPayload = { ...getThemeDocDefaults(), ...doc }
|
|
313
|
+
downloadJsonFile(exportPayload, `theme-${doc.docId}.json`)
|
|
314
|
+
notifySuccess(`Exported theme "${doc.docId}".`)
|
|
315
|
+
}
|
|
316
|
+
|
|
328
317
|
watch (sites, async (newSites) => {
|
|
329
318
|
state.loading = true
|
|
330
319
|
const selectedSite = String(edgeGlobal.edgeState.blockEditorSite || '').trim()
|
|
@@ -380,7 +369,9 @@ onBeforeMount(async () => {
|
|
|
380
369
|
:doc-id="props.themeId"
|
|
381
370
|
:schema="blockSchema"
|
|
382
371
|
:new-doc-schema="state.newDocs.themes"
|
|
383
|
-
class="
|
|
372
|
+
header-class="py-2 bg-secondary text-foreground rounded-none sticky top-0 border"
|
|
373
|
+
class="w-full mx-auto flex-1 bg-transparent flex flex-col border-none shadow-none pt-0 px-0"
|
|
374
|
+
card-content-class="px-0"
|
|
384
375
|
:show-footer="false"
|
|
385
376
|
:no-close-after-save="true"
|
|
386
377
|
:working-doc-overrides="state.workingDoc"
|
|
@@ -391,99 +382,142 @@ onBeforeMount(async () => {
|
|
|
391
382
|
{{ slotProps.title }}
|
|
392
383
|
</template>
|
|
393
384
|
<template #header-center>
|
|
394
|
-
<div class="w-full flex gap-
|
|
385
|
+
<div class="w-full flex gap-2 px-4 items-center">
|
|
395
386
|
<div class="w-full">
|
|
396
387
|
<edge-shad-select
|
|
397
388
|
v-if="!state.loading"
|
|
398
389
|
v-model="edgeGlobal.edgeState.blockEditorSite"
|
|
399
|
-
label="Preview Site"
|
|
400
390
|
name="site"
|
|
401
391
|
:items="sites.map(s => ({ title: s.name, name: s.docId }))"
|
|
402
392
|
placeholder="Select Site"
|
|
403
393
|
class="w-full"
|
|
404
394
|
/>
|
|
405
395
|
</div>
|
|
396
|
+
<div class="flex items-center gap-2">
|
|
397
|
+
<edge-shad-button
|
|
398
|
+
type="button"
|
|
399
|
+
size="icon"
|
|
400
|
+
variant="outline"
|
|
401
|
+
class="h-9 w-9"
|
|
402
|
+
:disabled="props.themeId === 'new' || !themesCollection?.[props.themeId]"
|
|
403
|
+
title="Export Theme"
|
|
404
|
+
aria-label="Export Theme"
|
|
405
|
+
@click="exportCurrentTheme"
|
|
406
|
+
>
|
|
407
|
+
<Download class="h-4 w-4" />
|
|
408
|
+
</edge-shad-button>
|
|
409
|
+
</div>
|
|
406
410
|
</div>
|
|
407
411
|
</template>
|
|
408
412
|
<template #main="slotProps">
|
|
409
|
-
<div class="pt-4
|
|
410
|
-
<
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
>
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
<
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
language="json"
|
|
465
|
-
name="headJSON"
|
|
466
|
-
height="400px"
|
|
467
|
-
class="mb-4 w-full"
|
|
468
|
-
/>
|
|
469
|
-
<edge-cms-code-editor
|
|
470
|
-
v-model="slotProps.workingDoc.extraCSS"
|
|
471
|
-
title="Extra CSS"
|
|
472
|
-
language="css"
|
|
473
|
-
name="extraCSS"
|
|
474
|
-
height="300px"
|
|
475
|
-
class="mb-4 w-full"
|
|
476
|
-
/>
|
|
477
|
-
</div>
|
|
478
|
-
<div class="w-1/2">
|
|
479
|
-
<div class="w-full mx-auto bg-white drop-shadow-[4px_4px_6px_rgba(0,0,0,0.5)] shadow-lg shadow-black/30">
|
|
480
|
-
<edge-cms-block-picker
|
|
481
|
-
:site-id="edgeGlobal.edgeState.blockEditorSite"
|
|
482
|
-
class="!h-[calc(100vh-220px)] overflow-y-auto"
|
|
483
|
-
list-only
|
|
484
|
-
:theme="lastValidTheme"
|
|
413
|
+
<div class="pt-4 space-y-4">
|
|
414
|
+
<edge-shad-input
|
|
415
|
+
v-model="slotProps.workingDoc.name"
|
|
416
|
+
label="Theme Name"
|
|
417
|
+
name="name"
|
|
418
|
+
/>
|
|
419
|
+
<div class="flex flex-col gap-4 xl:flex-row">
|
|
420
|
+
<div class="w-full xl:w-1/2">
|
|
421
|
+
<Tabs class="w-full" default-value="theme-json">
|
|
422
|
+
<TabsList class="w-full mt-3 bg-secondary rounded-sm grid grid-cols-2 xl:grid-cols-5">
|
|
423
|
+
<TabsTrigger value="theme-json" class="w-full text-black data-[state=active]:bg-black data-[state=active]:text-white">
|
|
424
|
+
Theme JSON
|
|
425
|
+
</TabsTrigger>
|
|
426
|
+
<TabsTrigger value="head-json" class="w-full text-black data-[state=active]:bg-black data-[state=active]:text-white">
|
|
427
|
+
Head JSON
|
|
428
|
+
</TabsTrigger>
|
|
429
|
+
<TabsTrigger value="custom-fonts" class="w-full text-black data-[state=active]:bg-black data-[state=active]:text-white">
|
|
430
|
+
Custom Fonts
|
|
431
|
+
</TabsTrigger>
|
|
432
|
+
<TabsTrigger value="extra-css" class="w-full text-black data-[state=active]:bg-black data-[state=active]:text-white">
|
|
433
|
+
Extra CSS
|
|
434
|
+
</TabsTrigger>
|
|
435
|
+
<TabsTrigger value="default-templates" class="w-full text-black data-[state=active]:bg-black data-[state=active]:text-white">
|
|
436
|
+
Default Templates
|
|
437
|
+
</TabsTrigger>
|
|
438
|
+
</TabsList>
|
|
439
|
+
|
|
440
|
+
<TabsContent value="theme-json" class="mt-4">
|
|
441
|
+
<edge-cms-code-editor
|
|
442
|
+
v-model="slotProps.workingDoc.theme"
|
|
443
|
+
title="Theme JSON"
|
|
444
|
+
language="json"
|
|
445
|
+
name="content"
|
|
446
|
+
:height="editorViewportHeight"
|
|
447
|
+
class="w-full"
|
|
448
|
+
/>
|
|
449
|
+
</TabsContent>
|
|
450
|
+
|
|
451
|
+
<TabsContent value="head-json" class="mt-4">
|
|
452
|
+
<edge-cms-code-editor
|
|
453
|
+
v-model="slotProps.workingDoc.headJSON"
|
|
454
|
+
title="Head JSON"
|
|
455
|
+
language="json"
|
|
456
|
+
name="headJSON"
|
|
457
|
+
:height="editorViewportHeight"
|
|
458
|
+
class="w-full"
|
|
459
|
+
/>
|
|
460
|
+
</TabsContent>
|
|
461
|
+
|
|
462
|
+
<TabsContent value="custom-fonts" class="mt-4">
|
|
463
|
+
<edge-cms-font-upload
|
|
464
|
+
v-if="slotProps.workingDoc"
|
|
465
|
+
v-model:head-json="slotProps.workingDoc.headJSON"
|
|
466
|
+
:theme-id="props.themeId"
|
|
467
|
+
class="w-full"
|
|
485
468
|
/>
|
|
486
|
-
</
|
|
469
|
+
</TabsContent>
|
|
470
|
+
|
|
471
|
+
<TabsContent value="extra-css" class="mt-4">
|
|
472
|
+
<edge-cms-code-editor
|
|
473
|
+
v-model="slotProps.workingDoc.extraCSS"
|
|
474
|
+
title="Extra CSS"
|
|
475
|
+
language="css"
|
|
476
|
+
name="extraCSS"
|
|
477
|
+
:height="editorViewportHeight"
|
|
478
|
+
class="w-full"
|
|
479
|
+
/>
|
|
480
|
+
</TabsContent>
|
|
481
|
+
|
|
482
|
+
<TabsContent value="default-templates" class="mt-4">
|
|
483
|
+
<Card class="h-full">
|
|
484
|
+
<CardHeader class="pb-2">
|
|
485
|
+
<div class="flex items-center justify-between gap-2">
|
|
486
|
+
<CardTitle class="text-base">
|
|
487
|
+
Default Templates
|
|
488
|
+
</CardTitle>
|
|
489
|
+
<edge-shad-button
|
|
490
|
+
size="icon"
|
|
491
|
+
type="text"
|
|
492
|
+
@click="state.defaultSettingsOpen = true"
|
|
493
|
+
>
|
|
494
|
+
<FolderCog class="h-4 w-4" />
|
|
495
|
+
</edge-shad-button>
|
|
496
|
+
</div>
|
|
497
|
+
<CardDescription class="text-xs">
|
|
498
|
+
Choose which template pages are created for new sites and organize them into Site Menu or Not In Menu.
|
|
499
|
+
</CardDescription>
|
|
500
|
+
</CardHeader>
|
|
501
|
+
<CardContent>
|
|
502
|
+
<edge-cms-theme-default-menu
|
|
503
|
+
v-if="slotProps.workingDoc"
|
|
504
|
+
v-model="slotProps.workingDoc.defaultMenus"
|
|
505
|
+
:template-options="templatePageOptions"
|
|
506
|
+
:template-pages="templatePages"
|
|
507
|
+
/>
|
|
508
|
+
</CardContent>
|
|
509
|
+
</Card>
|
|
510
|
+
</TabsContent>
|
|
511
|
+
</Tabs>
|
|
512
|
+
</div>
|
|
513
|
+
<div class="w-full xl:w-1/2">
|
|
514
|
+
<div class="w-full mx-auto bg-white drop-shadow-[4px_4px_6px_rgba(0,0,0,0.5)] shadow-lg shadow-black/30">
|
|
515
|
+
<edge-cms-block-picker
|
|
516
|
+
:site-id="edgeGlobal.edgeState.blockEditorSite"
|
|
517
|
+
class="!h-[calc(100vh-220px)] overflow-y-auto"
|
|
518
|
+
list-only
|
|
519
|
+
:theme="previewTheme"
|
|
520
|
+
/>
|
|
487
521
|
</div>
|
|
488
522
|
</div>
|
|
489
523
|
</div>
|
|
@@ -27,6 +27,10 @@ const props = defineProps({
|
|
|
27
27
|
type: Boolean,
|
|
28
28
|
default: true,
|
|
29
29
|
},
|
|
30
|
+
headerClass: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: 'py-4 bg-secondary text-foreground rounded-none sticky top-0',
|
|
33
|
+
},
|
|
30
34
|
class: {
|
|
31
35
|
type: String,
|
|
32
36
|
default: '',
|
|
@@ -583,7 +587,7 @@ const onError = async () => {
|
|
|
583
587
|
@error="onError"
|
|
584
588
|
>
|
|
585
589
|
<slot name="header" :on-submit="triggerSubmit" :on-cancel="onCancel" :submitting="state.submitting" :unsaved-changes="unsavedChanges" :title="title" :working-doc="state.workingDoc" :errors="state.errors">
|
|
586
|
-
<edge-menu v-if="props.showHeader" class="
|
|
590
|
+
<edge-menu v-if="props.showHeader" :class="props.headerClass">
|
|
587
591
|
<template #start>
|
|
588
592
|
<slot name="header-start" :unsaved-changes="unsavedChanges" :title="title" :errors="state.errors" :working-doc="state.workingDoc">
|
|
589
593
|
<FilePenLine class="mr-2" />
|
|
@@ -439,22 +439,54 @@ const allowMenuItem = (item: any, isAdmin: boolean) => {
|
|
|
439
439
|
return true
|
|
440
440
|
}
|
|
441
441
|
|
|
442
|
+
const resolveCmsCollectionTokens = (input: any, currentSite: any = '') => {
|
|
443
|
+
const orgId = String(edgeState.currentOrganization || '')
|
|
444
|
+
const siteId = String(currentSite || '')
|
|
445
|
+
|
|
446
|
+
const replaceTokens = (raw: string) => {
|
|
447
|
+
let resolved = raw
|
|
448
|
+
if (orgId && resolved.includes('{orgId}'))
|
|
449
|
+
resolved = resolved.replaceAll('{orgId}', orgId)
|
|
450
|
+
if (siteId && resolved.includes('{siteId}'))
|
|
451
|
+
resolved = resolved.replaceAll('{siteId}', siteId)
|
|
452
|
+
return resolved
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const walk = (value: any): any => {
|
|
456
|
+
if (typeof value === 'string')
|
|
457
|
+
return replaceTokens(value)
|
|
458
|
+
if (Array.isArray(value))
|
|
459
|
+
return value.map(item => walk(item))
|
|
460
|
+
if (value && typeof value === 'object') {
|
|
461
|
+
const out: Record<string, any> = {}
|
|
462
|
+
for (const [key, child] of Object.entries(value))
|
|
463
|
+
out[key] = walk(child)
|
|
464
|
+
return out
|
|
465
|
+
}
|
|
466
|
+
return value
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return walk(input)
|
|
470
|
+
}
|
|
471
|
+
|
|
442
472
|
const cmsCollectionData = async (edgeFirebase: any, value: any, meta: any, currentSite: any = '') => {
|
|
443
473
|
for (const key in meta) {
|
|
444
474
|
if (meta[key]?.collection) {
|
|
445
475
|
const staticSearch = new edgeFirebase.SearchStaticData()
|
|
446
476
|
|
|
447
|
-
const currentQuery = meta[key].collection.query
|
|
477
|
+
const currentQuery = Array.isArray(meta[key].collection.query)
|
|
478
|
+
? resolveCmsCollectionTokens(dupObject(meta[key].collection.query), currentSite)
|
|
479
|
+
: []
|
|
448
480
|
for (const queryKey in meta[key].queryItems || {}) {
|
|
449
481
|
console.log('key', queryKey)
|
|
450
482
|
if (meta[key].queryItems[queryKey]) {
|
|
451
483
|
const findIndex = currentQuery.findIndex((q: any) => q.field === queryKey)
|
|
452
484
|
const queryOption = meta[key]?.queryOptions?.find((o: any) => o.field === queryKey)
|
|
453
485
|
const operator = queryOption?.operator || '=='
|
|
454
|
-
let
|
|
455
|
-
if (operator === 'array-contains-any' && !Array.isArray(
|
|
456
|
-
|
|
457
|
-
const newQuery = { field: queryKey, operator, value }
|
|
486
|
+
let queryValue = resolveCmsCollectionTokens(meta[key].queryItems[queryKey], currentSite)
|
|
487
|
+
if (operator === 'array-contains-any' && !Array.isArray(queryValue))
|
|
488
|
+
queryValue = [queryValue]
|
|
489
|
+
const newQuery = { field: queryKey, operator, value: queryValue }
|
|
458
490
|
if (findIndex > -1) {
|
|
459
491
|
currentQuery[findIndex] = newQuery
|
|
460
492
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
export const useCmsNewDocs = () => {
|
|
2
|
+
const { createDefaults: createSiteSettingsDefaults } = useSiteSettingsTemplate()
|
|
3
|
+
|
|
4
|
+
const blocks = useState('edge-cms-new-docs-blocks', () => ({
|
|
5
|
+
name: { value: '' },
|
|
6
|
+
content: { value: '' },
|
|
7
|
+
tags: { value: [] },
|
|
8
|
+
themes: { value: [] },
|
|
9
|
+
previewType: { value: 'light' },
|
|
10
|
+
synced: { value: false },
|
|
11
|
+
version: 1,
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
const themes = useState('edge-cms-new-docs-themes', () => ({
|
|
15
|
+
name: { value: '' },
|
|
16
|
+
headJSON: {
|
|
17
|
+
value: `{
|
|
18
|
+
"link": [
|
|
19
|
+
{
|
|
20
|
+
"rel": "preconnect",
|
|
21
|
+
"href": "https://fonts.googleapis.com"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"rel": "preconnect",
|
|
25
|
+
"href": "https://fonts.gstatic.com",
|
|
26
|
+
"crossorigin": ""
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"rel": "stylesheet",
|
|
30
|
+
"href": "https://fonts.googleapis.com/css2?family=Overpass:wght@400;700&family=Kode+Mono:wght@400;700&display=swap"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}`,
|
|
34
|
+
},
|
|
35
|
+
theme: {
|
|
36
|
+
value: `{
|
|
37
|
+
"extend": {
|
|
38
|
+
"colors": {
|
|
39
|
+
"brand": "#3B82F6",
|
|
40
|
+
"accent": "#F59E0B",
|
|
41
|
+
"surface": "#FAFAFA",
|
|
42
|
+
"subtle": "#F3F4F6",
|
|
43
|
+
"text": "#1F2937",
|
|
44
|
+
"muted": "#9CA3AF",
|
|
45
|
+
"success": "#22C55E",
|
|
46
|
+
"danger": "#EF4444",
|
|
47
|
+
"border": "#E5E7EB",
|
|
48
|
+
"ring": "#93C5FD",
|
|
49
|
+
"link": "#3B82F6",
|
|
50
|
+
"linkHover": "#1D4ED8",
|
|
51
|
+
"navBg": "#000000",
|
|
52
|
+
"navText": "#FFFFFF",
|
|
53
|
+
"navMuted": "#6B7280",
|
|
54
|
+
"navBorder": "",
|
|
55
|
+
"navActive": "#3B82F6",
|
|
56
|
+
"navHoverBg": "",
|
|
57
|
+
"navActiveBg": "",
|
|
58
|
+
"sideNavBg": "#FFFFFF",
|
|
59
|
+
"sideNavText": "#000000",
|
|
60
|
+
"sideNavActive": "#AFBD23"
|
|
61
|
+
},
|
|
62
|
+
"fontFamily": {
|
|
63
|
+
"sans": ["Overpass", "sans-serif"],
|
|
64
|
+
"serif": ["Kode Mono", "monospace"],
|
|
65
|
+
"mono": ["Overpass", "sans-serif"],
|
|
66
|
+
"brand": ["Kode Mono", "monospace"]
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"apply": {},
|
|
70
|
+
"slots": {},
|
|
71
|
+
"variants": {
|
|
72
|
+
"light": {
|
|
73
|
+
"apply": {}
|
|
74
|
+
},
|
|
75
|
+
"dark": {
|
|
76
|
+
"apply": {},
|
|
77
|
+
"slots": {}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}`,
|
|
81
|
+
},
|
|
82
|
+
extraCSS: {
|
|
83
|
+
value: '',
|
|
84
|
+
},
|
|
85
|
+
version: 1,
|
|
86
|
+
defaultPages: { value: [] },
|
|
87
|
+
defaultMenus: {
|
|
88
|
+
value: {
|
|
89
|
+
'Site Root': [],
|
|
90
|
+
'Not In Menu': [],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
defaultSiteSettings: { value: createSiteSettingsDefaults() },
|
|
94
|
+
}))
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
blocks,
|
|
98
|
+
themes,
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useHead } from '#imports'
|
|
2
|
+
|
|
3
|
+
export const useEdgeCmsDialogPositionFix = () => {
|
|
4
|
+
useHead({
|
|
5
|
+
style: [
|
|
6
|
+
{
|
|
7
|
+
key: 'edge-cms-dialog-position-fix',
|
|
8
|
+
id: 'edge-cms-dialog-position-fix',
|
|
9
|
+
children: `
|
|
10
|
+
.fixed.left-1\\/2.top-1\\/2.-translate-x-1\\/2.-translate-y-1\\/2 {
|
|
11
|
+
translate: initial !important;
|
|
12
|
+
--un-translate-x: initial !important;
|
|
13
|
+
--un-translate-y: initial !important;
|
|
14
|
+
}
|
|
15
|
+
`,
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
})
|
|
19
|
+
}
|