@edgedev/create-edge-app 1.1.25 → 1.1.27

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 (111) hide show
  1. package/README.md +55 -20
  2. package/{agent.md → agents.md} +2 -0
  3. package/bin/cli.js +6 -6
  4. package/edge/components/auth/login.vue +384 -0
  5. package/edge/components/auth/register.vue +396 -0
  6. package/edge/components/auth.vue +108 -0
  7. package/edge/components/autoFileUpload.vue +215 -0
  8. package/edge/components/billing.vue +8 -0
  9. package/edge/components/buttonDivider.vue +14 -0
  10. package/edge/components/chip.vue +34 -0
  11. package/edge/components/clipboardButton.vue +42 -0
  12. package/edge/components/cms/block.vue +529 -0
  13. package/edge/components/cms/blockApi.vue +212 -0
  14. package/edge/components/cms/blockEditor.vue +725 -0
  15. package/edge/components/cms/blockInput.vue +66 -0
  16. package/edge/components/cms/blockPicker.vue +486 -0
  17. package/edge/components/cms/blockRender.vue +78 -0
  18. package/edge/components/cms/blockSheetContent.vue +28 -0
  19. package/edge/components/cms/codeEditor.vue +466 -0
  20. package/edge/components/cms/fontUpload.vue +327 -0
  21. package/edge/components/cms/htmlContent.vue +807 -0
  22. package/edge/components/cms/init_blocks/api_with_subarrays.html +17 -0
  23. package/edge/components/cms/init_blocks/array_with_collection.html +7 -0
  24. package/edge/components/cms/init_blocks/array_with_objects.html +7 -0
  25. package/edge/components/cms/init_blocks/carousel.html +103 -0
  26. package/edge/components/cms/init_blocks/contact_us.html +69 -0
  27. package/edge/components/cms/init_blocks/content_with_left_image.html +27 -0
  28. package/edge/components/cms/init_blocks/footer.html +24 -0
  29. package/edge/components/cms/init_blocks/header_divider.html +7 -0
  30. package/edge/components/cms/init_blocks/hero.html +35 -0
  31. package/edge/components/cms/init_blocks/hero_carousel.html +52 -0
  32. package/edge/components/cms/init_blocks/newsletter.html +117 -0
  33. package/edge/components/cms/init_blocks/post_content.html +7 -0
  34. package/edge/components/cms/init_blocks/post_title_header.html +21 -0
  35. package/edge/components/cms/init_blocks/posts_list.html +20 -0
  36. package/edge/components/cms/init_blocks/properties_showcase.html +100 -0
  37. package/edge/components/cms/init_blocks/property_carousel.html +59 -0
  38. package/edge/components/cms/init_blocks/property_detail.html +112 -0
  39. package/edge/components/cms/init_blocks/property_detail_header.html +34 -0
  40. package/edge/components/cms/init_blocks/property_results.html +137 -0
  41. package/edge/components/cms/init_blocks/property_search.html +75 -0
  42. package/edge/components/cms/init_blocks/simple_array.html +7 -0
  43. package/edge/components/cms/mediaCard.vue +116 -0
  44. package/edge/components/cms/mediaManager.vue +386 -0
  45. package/edge/components/cms/menu.vue +1103 -0
  46. package/edge/components/cms/optionsSelect.vue +107 -0
  47. package/edge/components/cms/page.vue +1785 -0
  48. package/edge/components/cms/posts.vue +1083 -0
  49. package/edge/components/cms/site.vue +1475 -0
  50. package/edge/components/cms/themeDefaultMenu.vue +548 -0
  51. package/edge/components/cms/themeEditor.vue +429 -0
  52. package/edge/components/dashboard.vue +776 -0
  53. package/edge/components/editor.vue +671 -0
  54. package/edge/components/fileTree.vue +72 -0
  55. package/edge/components/files.vue +89 -0
  56. package/edge/components/formSubtypes/myOrgs.vue +214 -0
  57. package/edge/components/formSubtypes/users.vue +336 -0
  58. package/edge/components/functionChips.vue +57 -0
  59. package/edge/components/gError.vue +98 -0
  60. package/edge/components/gHelper.vue +67 -0
  61. package/edge/components/gInput.vue +1331 -0
  62. package/edge/components/loggingIn.vue +41 -0
  63. package/edge/components/menu.vue +137 -0
  64. package/edge/components/menuContent.vue +132 -0
  65. package/edge/components/myAccount.vue +317 -0
  66. package/edge/components/myOrganizations.vue +75 -0
  67. package/edge/components/myProfile.vue +122 -0
  68. package/edge/components/orgSwitcher.vue +25 -0
  69. package/edge/components/organizationMembers.vue +522 -0
  70. package/edge/components/organizationSettings.vue +271 -0
  71. package/edge/components/shad/breadcrumbs.vue +35 -0
  72. package/edge/components/shad/button.vue +43 -0
  73. package/edge/components/shad/checkbox.vue +73 -0
  74. package/edge/components/shad/combobox.vue +238 -0
  75. package/edge/components/shad/datepicker.vue +184 -0
  76. package/edge/components/shad/dialog.vue +32 -0
  77. package/edge/components/shad/dropdownMenu.vue +54 -0
  78. package/edge/components/shad/dropdownMenuItem.vue +21 -0
  79. package/edge/components/shad/form.vue +59 -0
  80. package/edge/components/shad/html.vue +877 -0
  81. package/edge/components/shad/input.vue +139 -0
  82. package/edge/components/shad/number.vue +109 -0
  83. package/edge/components/shad/select.vue +151 -0
  84. package/edge/components/shad/selectTags.vue +278 -0
  85. package/edge/components/shad/switch.vue +67 -0
  86. package/edge/components/shad/tags.vue +137 -0
  87. package/edge/components/shad/textarea.vue +102 -0
  88. package/edge/components/shad/typeMoney.vue +167 -0
  89. package/edge/components/sideBar.vue +288 -0
  90. package/edge/components/sideBarContent.vue +268 -0
  91. package/edge/components/sidebarProvider.vue +33 -0
  92. package/edge/components/tooltip.vue +16 -0
  93. package/edge/components/userMenu.vue +148 -0
  94. package/edge/components/v/alert.vue +59 -0
  95. package/edge/components/v/alertTitle.vue +18 -0
  96. package/edge/components/v/card.vue +53 -0
  97. package/edge/components/v/cardActions.vue +18 -0
  98. package/edge/components/v/cardText.vue +18 -0
  99. package/edge/components/v/cardTitle.vue +20 -0
  100. package/edge/components/v/col.vue +56 -0
  101. package/edge/components/v/list.vue +46 -0
  102. package/edge/components/v/listItem.vue +26 -0
  103. package/edge/components/v/listItemTitle.vue +18 -0
  104. package/edge/components/v/row.vue +42 -0
  105. package/edge/components/v/toolbar.vue +24 -0
  106. package/edge/composables/global.ts +519 -0
  107. package/edge-pull.sh +2 -0
  108. package/edge-push.sh +1 -0
  109. package/edge-status.sh +14 -0
  110. package/package.json +1 -1
  111. package/edge-components-install.sh +0 -1
@@ -0,0 +1,429 @@
1
+ <script setup>
2
+ import { toTypedSchema } from '@vee-validate/zod'
3
+ import * as z from 'zod'
4
+ const props = defineProps({
5
+ themeId: {
6
+ type: String,
7
+ required: true,
8
+ },
9
+ })
10
+
11
+ const emit = defineEmits(['head'])
12
+ const edgeFirebase = inject('edgeFirebase')
13
+ const state = reactive({
14
+ filter: '',
15
+ workingDoc: {},
16
+ newDocs: {
17
+ themes: {
18
+ name: { value: '' },
19
+ headJSON: {
20
+ value: `{
21
+ "link": [
22
+ {
23
+ "rel": "preconnect",
24
+ "href": "https://fonts.googleapis.com"
25
+ },
26
+ {
27
+ "rel": "preconnect",
28
+ "href": "https://fonts.gstatic.com",
29
+ "crossorigin": ""
30
+ },
31
+ {
32
+ "rel": "stylesheet",
33
+ "href": "https://fonts.googleapis.com/css2?family=Overpass:wght@400;700&family=Kode+Mono:wght@400;700&display=swap"
34
+ }
35
+ ]
36
+ }`,
37
+ },
38
+ theme: {
39
+ value: `{
40
+ "extend": {
41
+ "colors": {
42
+ "brand": "#3B82F6",
43
+ "accent": "#F59E0B",
44
+ "surface": "#FAFAFA",
45
+ "subtle": "#F3F4F6",
46
+ "text": "#1F2937",
47
+ "muted": "#9CA3AF",
48
+ "success": "#22C55E",
49
+ "danger": "#EF4444",
50
+ "border": "#E5E7EB",
51
+ "ring": "#93C5FD",
52
+ "link": "#3B82F6",
53
+ "linkHover": "#1D4ED8",
54
+ "navBg": "#000000",
55
+ "navText": "#FFFFFF",
56
+ "navMuted": "#6B7280",
57
+ "navBorder": "",
58
+ "navActive": "#3B82F6",
59
+ "navHoverBg": "",
60
+ "navActiveBg": "",
61
+ "sideNavBg": "#FFFFFF",
62
+ "sideNavText": "#000000",
63
+ "sideNavActive": "#AFBD23"
64
+ },
65
+ "fontFamily": {
66
+ "sans": ["Overpass", "sans-serif"],
67
+ "serif": ["Kode Mono", "monospace"],
68
+ "mono": ["Overpass", "sans-serif"],
69
+ "brand": ["Kode Mono", "monospace"]
70
+ }
71
+ },
72
+ "apply": {},
73
+ "slots": {},
74
+ "variants": {
75
+ "light": {
76
+ "apply": {}
77
+ },
78
+ "dark": {
79
+ "apply": {},
80
+ "slots": {}
81
+ }
82
+ }
83
+ }`,
84
+ },
85
+ version: 1,
86
+ defaultPages: { value: [] },
87
+ defaultMenus: {
88
+ value: {
89
+ 'Site Root': [],
90
+ 'Not In Menu': [],
91
+ },
92
+ },
93
+ },
94
+ },
95
+ mounted: false,
96
+ loading: false,
97
+ })
98
+
99
+ const blockSchema = toTypedSchema(z.object({
100
+ name: z.string({
101
+ required_error: 'Name is required',
102
+ }).min(1, { message: 'Name is required' }),
103
+ }))
104
+
105
+ onMounted(() => {
106
+ // state.mounted = true
107
+ })
108
+
109
+ const headObject = computed(() => {
110
+ try {
111
+ return JSON.parse(state.workingDoc.headJSON || '{}')
112
+ }
113
+ catch (e) {
114
+ return {}
115
+ }
116
+ })
117
+
118
+ watch(headObject, (newHeadElements) => {
119
+ emit('head', newHeadElements)
120
+ }, { immediate: true, deep: true })
121
+
122
+ const sites = computed(() => {
123
+ return Object.values(edgeFirebase.data?.[`${edgeGlobal.edgeState.organizationDocPath}/sites`] || {})
124
+ })
125
+
126
+ const templatePages = computed(() => {
127
+ return edgeFirebase.data?.[`${edgeGlobal.edgeState.organizationDocPath}/sites/templates/pages`] || {}
128
+ })
129
+
130
+ const templatePageName = (pageId, fallback) => {
131
+ return templatePages.value?.[pageId]?.name || fallback || 'Untitled Page'
132
+ }
133
+
134
+ const DEFAULT_MENU_KEYS = ['Site Root', 'Not In Menu']
135
+
136
+ const ensureDefaultPagesArray = (doc = state.workingDoc) => {
137
+ if (!doc)
138
+ return []
139
+ if (!Array.isArray(doc.defaultPages))
140
+ doc.defaultPages = []
141
+ return doc.defaultPages
142
+ }
143
+
144
+ const ensureDefaultMenusObject = (doc = state.workingDoc) => {
145
+ if (!doc)
146
+ return {}
147
+ if (!doc.defaultMenus || typeof doc.defaultMenus !== 'object' || Array.isArray(doc.defaultMenus))
148
+ doc.defaultMenus = {}
149
+ for (const key of DEFAULT_MENU_KEYS) {
150
+ if (!Array.isArray(doc.defaultMenus[key]))
151
+ doc.defaultMenus[key] = []
152
+ }
153
+ return doc.defaultMenus
154
+ }
155
+
156
+ const collectTemplateIdsFromMenus = (menus = {}) => {
157
+ const ids = new Set()
158
+ const traverse = (items = []) => {
159
+ if (!Array.isArray(items))
160
+ return
161
+ for (const entry of items) {
162
+ if (!entry || entry.item === undefined || entry.item === null)
163
+ continue
164
+ if (typeof entry.item === 'string' && entry.item)
165
+ ids.add(entry.item)
166
+ else if (typeof entry.item === 'object') {
167
+ for (const nested of Object.values(entry.item || {}))
168
+ traverse(nested)
169
+ }
170
+ }
171
+ }
172
+ for (const key of Object.keys(menus))
173
+ traverse(menus[key])
174
+ return ids
175
+ }
176
+
177
+ const collectMenuSlugs = (menus = {}) => {
178
+ const slugs = new Set()
179
+ const traverse = (items = []) => {
180
+ if (!Array.isArray(items))
181
+ return
182
+ for (const entry of items) {
183
+ if (!entry || entry.item === undefined || entry.item === null)
184
+ continue
185
+ if (typeof entry.item === 'string' && entry.name)
186
+ slugs.add(entry.name)
187
+ else if (typeof entry.item === 'object') {
188
+ for (const nested of Object.values(entry.item || {}))
189
+ traverse(nested)
190
+ }
191
+ }
192
+ }
193
+ for (const key of Object.keys(menus))
194
+ traverse(menus[key])
195
+ return slugs
196
+ }
197
+
198
+ const slugify = (value) => {
199
+ return String(value || '')
200
+ .trim()
201
+ .toLowerCase()
202
+ .replace(/[^a-z0-9]+/g, '-')
203
+ .replace(/(^-|-$)+/g, '') || 'page'
204
+ }
205
+
206
+ const makeUniqueSlug = (value, existing = new Set()) => {
207
+ const base = slugify(value)
208
+ let candidate = base || 'page'
209
+ let suffix = 1
210
+ while (existing.has(candidate)) {
211
+ candidate = `${base}-${suffix}`
212
+ suffix += 1
213
+ }
214
+ return candidate
215
+ }
216
+
217
+ const hydrateMenusFromDefaultPages = (doc = state.workingDoc) => {
218
+ const menus = ensureDefaultMenusObject(doc)
219
+ const hasExistingMenus = Object.values(menus).some(items => Array.isArray(items) && items.length)
220
+ if (hasExistingMenus)
221
+ return
222
+ const defaults = ensureDefaultPagesArray(doc)
223
+ if (!defaults.length)
224
+ return
225
+ const existingSlugs = collectMenuSlugs(menus)
226
+ menus['Site Root'] = defaults.map((entry) => {
227
+ const slug = makeUniqueSlug(entry?.name || templatePageName(entry.pageId), existingSlugs)
228
+ existingSlugs.add(slug)
229
+ return {
230
+ name: slug,
231
+ item: entry.pageId,
232
+ }
233
+ })
234
+ }
235
+
236
+ const flattenMenusToDefaultPages = (menus = {}) => {
237
+ const collected = []
238
+ const traverse = (items = []) => {
239
+ if (!Array.isArray(items))
240
+ return
241
+ for (const entry of items) {
242
+ if (!entry || entry.item === undefined || entry.item === null)
243
+ continue
244
+ if (typeof entry.item === 'string' && entry.item) {
245
+ collected.push({
246
+ pageId: entry.item,
247
+ name: templatePageName(entry.item, entry.name),
248
+ })
249
+ }
250
+ else if (typeof entry.item === 'object') {
251
+ for (const nested of Object.values(entry.item || {}))
252
+ traverse(nested)
253
+ }
254
+ }
255
+ }
256
+ for (const key of DEFAULT_MENU_KEYS)
257
+ traverse(menus[key])
258
+ return collected
259
+ }
260
+
261
+ const syncDefaultPagesFromMenus = () => {
262
+ if (!state.workingDoc)
263
+ return
264
+ const menus = ensureDefaultMenusObject()
265
+ const normalized = flattenMenusToDefaultPages(menus)
266
+ const defaults = ensureDefaultPagesArray()
267
+ const sameLength = defaults.length === normalized.length
268
+ const sameOrder = sameLength && defaults.every((entry, index) => entry.pageId === normalized[index].pageId)
269
+ if (sameLength && sameOrder)
270
+ return
271
+ defaults.splice(0, defaults.length, ...normalized)
272
+ }
273
+
274
+ const editorDocUpdates = (workingDoc) => {
275
+ state.workingDoc = workingDoc
276
+ ensureDefaultPagesArray(state.workingDoc)
277
+ ensureDefaultMenusObject(state.workingDoc)
278
+ hydrateMenusFromDefaultPages(state.workingDoc)
279
+ syncDefaultPagesFromMenus()
280
+ }
281
+
282
+ const templatePageOptions = computed(() => {
283
+ return Object.entries(templatePages.value)
284
+ .map(([value, doc]) => ({
285
+ value,
286
+ label: doc?.name || 'Untitled Page',
287
+ }))
288
+ .sort((a, b) => a.label.localeCompare(b.label))
289
+ })
290
+
291
+ watch (sites, async (newSites) => {
292
+ state.loading = true
293
+ if (!edgeGlobal.edgeState.blockEditorSite && newSites.length > 0) {
294
+ edgeGlobal.edgeState.blockEditorSite = newSites[0].docId
295
+ }
296
+ await nextTick()
297
+ state.loading = false
298
+ }, { immediate: true, deep: true })
299
+
300
+ watch(templatePages, (pages) => {
301
+ const selected = ensureDefaultPagesArray()
302
+ for (const entry of selected) {
303
+ const latestName = pages?.[entry.pageId]?.name
304
+ if (latestName && entry.name !== latestName)
305
+ entry.name = latestName
306
+ }
307
+ }, { deep: true })
308
+
309
+ watch(() => state.workingDoc?.defaultMenus, () => {
310
+ if (!state.workingDoc)
311
+ return
312
+ syncDefaultPagesFromMenus()
313
+ }, { deep: true })
314
+
315
+ onBeforeMount(async () => {
316
+ if (!edgeFirebase.data?.[`organizations/${edgeGlobal.edgeState.currentOrganization}/sites`]) {
317
+ await edgeFirebase.startSnapshot(`organizations/${edgeGlobal.edgeState.currentOrganization}/sites`)
318
+ }
319
+ if (!edgeFirebase.data?.[`organizations/${edgeGlobal.edgeState.currentOrganization}/sites/templates/pages`]) {
320
+ await edgeFirebase.startSnapshot(`organizations/${edgeGlobal.edgeState.currentOrganization}/sites/templates/pages`)
321
+ }
322
+ state.mounted = true
323
+ })
324
+ </script>
325
+
326
+ <template>
327
+ <div
328
+ v-if="edgeGlobal.edgeState.organizationDocPath && state.mounted"
329
+ >
330
+ <edge-editor
331
+ collection="themes"
332
+ :doc-id="props.themeId"
333
+ :schema="blockSchema"
334
+ :new-doc-schema="state.newDocs.themes"
335
+ class="w-full mx-auto flex-1 bg-transparent flex flex-col border-none shadow-none"
336
+ :show-footer="false"
337
+ :no-close-after-save="true"
338
+ :working-doc-overrides="state.workingDoc"
339
+ @working-doc="editorDocUpdates"
340
+ >
341
+ <template #header-start="slotProps">
342
+ <FilePenLine class="mr-2" />
343
+ {{ slotProps.title }}
344
+ </template>
345
+ <template #header-center>
346
+ <div class="w-full flex gap-1 px-4">
347
+ <div class="w-full">
348
+ <edge-shad-select
349
+ v-if="!state.loading"
350
+ v-model="edgeGlobal.edgeState.blockEditorSite"
351
+ label="Preview Site"
352
+ name="site"
353
+ :items="sites.map(s => ({ title: s.name, name: s.docId }))"
354
+ placeholder="Select Site"
355
+ class="w-full"
356
+ />
357
+ </div>
358
+ </div>
359
+ </template>
360
+ <template #main="slotProps">
361
+ <div class="pt-4 flex flex-col gap-6 lg:flex-row">
362
+ <div class="lg:w-1/3 lg:max-w-sm w-full space-y-4">
363
+ <Card class="h-full">
364
+ <CardHeader class="pb-2">
365
+ <CardTitle class="text-base">
366
+ Default Template Pages
367
+ </CardTitle>
368
+ <CardDescription class="text-xs">
369
+ Choose which template pages are created for new sites and organize them into Site Menu or Not In Menu.
370
+ </CardDescription>
371
+ </CardHeader>
372
+ <CardContent>
373
+ <edge-cms-theme-default-menu
374
+ v-if="slotProps.workingDoc"
375
+ v-model="slotProps.workingDoc.defaultMenus"
376
+ :template-options="templatePageOptions"
377
+ :template-pages="templatePages"
378
+ />
379
+ </CardContent>
380
+ </Card>
381
+ </div>
382
+ <div class="flex-1 space-y-4">
383
+ <edge-shad-input
384
+ v-model="slotProps.workingDoc.name"
385
+ label="Theme Name"
386
+ name="name"
387
+ />
388
+ <div class="flex flex-col gap-4 xl:flex-row">
389
+ <div class="w-1/2">
390
+ <edge-cms-code-editor
391
+ v-model="slotProps.workingDoc.theme"
392
+ title="Theme JSON"
393
+ language="json"
394
+ name="content"
395
+ height="400px"
396
+ class="mb-4 w-full"
397
+ />
398
+ <edge-cms-font-upload
399
+ v-if="slotProps.workingDoc"
400
+ v-model:head-json="slotProps.workingDoc.headJSON"
401
+ :theme-id="props.themeId"
402
+ class="mb-4"
403
+ />
404
+ <edge-cms-code-editor
405
+ v-model="slotProps.workingDoc.headJSON"
406
+ title="Head JSON"
407
+ language="json"
408
+ name="headJSON"
409
+ height="400px"
410
+ class="mb-4 w-full"
411
+ />
412
+ </div>
413
+ <div class="w-1/2">
414
+ <div class="w-full mx-auto bg-white drop-shadow-[4px_4px_6px_rgba(0,0,0,0.5)] shadow-lg shadow-black/30">
415
+ <edge-cms-block-picker
416
+ :site-id="edgeGlobal.edgeState.blockEditorSite"
417
+ class="!h-[calc(100vh-220px)] overflow-y-auto"
418
+ list-only
419
+ :theme="JSON.parse(slotProps.workingDoc.theme)"
420
+ />
421
+ </div>
422
+ </div>
423
+ </div>
424
+ </div>
425
+ </div>
426
+ </template>
427
+ </edge-editor>
428
+ </div>
429
+ </template>