@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.
Files changed (33) hide show
  1. package/deploy.sh +77 -0
  2. package/edge/components/cms/block.vue +228 -18
  3. package/edge/components/cms/blockApi.vue +3 -3
  4. package/edge/components/cms/blockEditor.vue +374 -85
  5. package/edge/components/cms/blockPicker.vue +29 -3
  6. package/edge/components/cms/blockRender.vue +3 -3
  7. package/edge/components/cms/blocksManager.vue +755 -82
  8. package/edge/components/cms/codeEditor.vue +15 -6
  9. package/edge/components/cms/fontUpload.vue +318 -2
  10. package/edge/components/cms/htmlContent.vue +230 -89
  11. package/edge/components/cms/menu.vue +5 -4
  12. package/edge/components/cms/page.vue +750 -21
  13. package/edge/components/cms/site.vue +624 -84
  14. package/edge/components/cms/sitesManager.vue +5 -4
  15. package/edge/components/cms/themeEditor.vue +196 -162
  16. package/edge/components/editor.vue +5 -1
  17. package/edge/composables/global.ts +37 -5
  18. package/edge/composables/useCmsNewDocs.js +100 -0
  19. package/edge/composables/useEdgeCmsDialogPositionFix.js +19 -0
  20. package/edge/routes/cms/dashboard/blocks/[block].vue +5 -0
  21. package/edge/routes/cms/dashboard/blocks/index.vue +12 -1
  22. package/edge/routes/cms/dashboard/media/index.vue +5 -0
  23. package/edge/routes/cms/dashboard/sites/[site]/[[page]].vue +4 -0
  24. package/edge/routes/cms/dashboard/sites/[site].vue +4 -0
  25. package/edge/routes/cms/dashboard/sites/index.vue +4 -0
  26. package/edge/routes/cms/dashboard/templates/[page].vue +4 -0
  27. package/edge/routes/cms/dashboard/templates/index.vue +4 -0
  28. package/edge/routes/cms/dashboard/themes/[theme].vue +5 -0
  29. package/edge/routes/cms/dashboard/themes/index.vue +330 -1
  30. package/firebase.json +4 -0
  31. package/nuxt.config.ts +1 -1
  32. package/package.json +2 -2
  33. 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="w-full mx-auto flex-1 bg-transparent flex flex-col border-none shadow-none"
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-1 px-4">
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 flex flex-col gap-6 lg:flex-row">
410
- <div class="lg:w-72 lg:max-w-xs w-full space-y-4">
411
- <Card class="h-full">
412
- <CardHeader class="pb-2">
413
- <div class="flex items-center justify-between gap-2">
414
- <CardTitle class="text-base">
415
- Default Template Pages
416
- </CardTitle>
417
- <edge-shad-button
418
- size="icon"
419
- type="text"
420
- @click="state.defaultSettingsOpen = true"
421
- >
422
- <FolderCog class="h-4 w-4" />
423
- </edge-shad-button>
424
- </div>
425
- <CardDescription class="text-xs">
426
- Choose which template pages are created for new sites and organize them into Site Menu or Not In Menu.
427
- </CardDescription>
428
- </CardHeader>
429
- <CardContent>
430
- <edge-cms-theme-default-menu
431
- v-if="slotProps.workingDoc"
432
- v-model="slotProps.workingDoc.defaultMenus"
433
- :template-options="templatePageOptions"
434
- :template-pages="templatePages"
435
- />
436
- </CardContent>
437
- </Card>
438
- </div>
439
- <div class="flex-1 space-y-4">
440
- <edge-shad-input
441
- v-model="slotProps.workingDoc.name"
442
- label="Theme Name"
443
- name="name"
444
- />
445
- <div class="flex flex-col gap-4 xl:flex-row">
446
- <div class="w-1/2">
447
- <edge-cms-code-editor
448
- v-model="slotProps.workingDoc.theme"
449
- title="Theme JSON"
450
- language="json"
451
- name="content"
452
- height="400px"
453
- class="mb-4 w-full"
454
- />
455
- <edge-cms-font-upload
456
- v-if="slotProps.workingDoc"
457
- v-model:head-json="slotProps.workingDoc.headJSON"
458
- :theme-id="props.themeId"
459
- class="mb-4"
460
- />
461
- <edge-cms-code-editor
462
- v-model="slotProps.workingDoc.headJSON"
463
- title="Head JSON"
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
- </div>
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="py-4 bg-secondary text-foreground rounded-none sticky top-0">
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 value = meta[key].queryItems[queryKey]
455
- if (operator === 'array-contains-any' && !Array.isArray(value))
456
- value = [value]
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
+ }