@edgedev/create-edge-app 1.1.23 → 1.1.26

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 (116) hide show
  1. package/.env +1 -0
  2. package/.env.dev +1 -0
  3. package/README.md +55 -20
  4. package/{agent.md → agents.md} +2 -0
  5. package/bin/cli.js +6 -6
  6. package/edge/components/auth/login.vue +384 -0
  7. package/edge/components/auth/register.vue +396 -0
  8. package/edge/components/auth.vue +108 -0
  9. package/edge/components/autoFileUpload.vue +215 -0
  10. package/edge/components/billing.vue +8 -0
  11. package/edge/components/buttonDivider.vue +14 -0
  12. package/edge/components/chip.vue +34 -0
  13. package/edge/components/clipboardButton.vue +42 -0
  14. package/edge/components/cms/block.vue +529 -0
  15. package/edge/components/cms/blockApi.vue +212 -0
  16. package/edge/components/cms/blockEditor.vue +725 -0
  17. package/edge/components/cms/blockInput.vue +66 -0
  18. package/edge/components/cms/blockPicker.vue +486 -0
  19. package/edge/components/cms/blockRender.vue +78 -0
  20. package/edge/components/cms/blockSheetContent.vue +28 -0
  21. package/edge/components/cms/codeEditor.vue +466 -0
  22. package/edge/components/cms/fontUpload.vue +327 -0
  23. package/edge/components/cms/htmlContent.vue +807 -0
  24. package/edge/components/cms/init_blocks/api_with_subarrays.html +17 -0
  25. package/edge/components/cms/init_blocks/array_with_collection.html +7 -0
  26. package/edge/components/cms/init_blocks/array_with_objects.html +7 -0
  27. package/edge/components/cms/init_blocks/carousel.html +103 -0
  28. package/edge/components/cms/init_blocks/contact_us.html +69 -0
  29. package/edge/components/cms/init_blocks/content_with_left_image.html +27 -0
  30. package/edge/components/cms/init_blocks/footer.html +24 -0
  31. package/edge/components/cms/init_blocks/header_divider.html +7 -0
  32. package/edge/components/cms/init_blocks/hero.html +35 -0
  33. package/edge/components/cms/init_blocks/hero_carousel.html +52 -0
  34. package/edge/components/cms/init_blocks/newsletter.html +117 -0
  35. package/edge/components/cms/init_blocks/post_content.html +7 -0
  36. package/edge/components/cms/init_blocks/post_title_header.html +21 -0
  37. package/edge/components/cms/init_blocks/posts_list.html +20 -0
  38. package/edge/components/cms/init_blocks/properties_showcase.html +100 -0
  39. package/edge/components/cms/init_blocks/property_carousel.html +59 -0
  40. package/edge/components/cms/init_blocks/property_detail.html +112 -0
  41. package/edge/components/cms/init_blocks/property_detail_header.html +34 -0
  42. package/edge/components/cms/init_blocks/property_results.html +137 -0
  43. package/edge/components/cms/init_blocks/property_search.html +75 -0
  44. package/edge/components/cms/init_blocks/simple_array.html +7 -0
  45. package/edge/components/cms/mediaCard.vue +116 -0
  46. package/edge/components/cms/mediaManager.vue +386 -0
  47. package/edge/components/cms/menu.vue +1103 -0
  48. package/edge/components/cms/optionsSelect.vue +107 -0
  49. package/edge/components/cms/page.vue +1785 -0
  50. package/edge/components/cms/posts.vue +1083 -0
  51. package/edge/components/cms/site.vue +1298 -0
  52. package/edge/components/cms/themeDefaultMenu.vue +548 -0
  53. package/edge/components/cms/themeEditor.vue +426 -0
  54. package/edge/components/dashboard.vue +776 -0
  55. package/edge/components/editor.vue +671 -0
  56. package/edge/components/fileTree.vue +72 -0
  57. package/edge/components/files.vue +89 -0
  58. package/edge/components/formSubtypes/myOrgs.vue +214 -0
  59. package/edge/components/formSubtypes/users.vue +336 -0
  60. package/edge/components/functionChips.vue +57 -0
  61. package/edge/components/gError.vue +98 -0
  62. package/edge/components/gHelper.vue +67 -0
  63. package/edge/components/gInput.vue +1331 -0
  64. package/edge/components/loggingIn.vue +41 -0
  65. package/edge/components/menu.vue +137 -0
  66. package/edge/components/menuContent.vue +132 -0
  67. package/edge/components/myAccount.vue +317 -0
  68. package/edge/components/myOrganizations.vue +75 -0
  69. package/edge/components/myProfile.vue +122 -0
  70. package/edge/components/orgSwitcher.vue +25 -0
  71. package/edge/components/organizationMembers.vue +522 -0
  72. package/edge/components/organizationSettings.vue +271 -0
  73. package/edge/components/shad/breadcrumbs.vue +35 -0
  74. package/edge/components/shad/button.vue +43 -0
  75. package/edge/components/shad/checkbox.vue +73 -0
  76. package/edge/components/shad/combobox.vue +238 -0
  77. package/edge/components/shad/datepicker.vue +184 -0
  78. package/edge/components/shad/dialog.vue +32 -0
  79. package/edge/components/shad/dropdownMenu.vue +54 -0
  80. package/edge/components/shad/dropdownMenuItem.vue +21 -0
  81. package/edge/components/shad/form.vue +59 -0
  82. package/edge/components/shad/html.vue +877 -0
  83. package/edge/components/shad/input.vue +139 -0
  84. package/edge/components/shad/number.vue +109 -0
  85. package/edge/components/shad/select.vue +151 -0
  86. package/edge/components/shad/selectTags.vue +278 -0
  87. package/edge/components/shad/switch.vue +67 -0
  88. package/edge/components/shad/tags.vue +137 -0
  89. package/edge/components/shad/textarea.vue +102 -0
  90. package/edge/components/shad/typeMoney.vue +167 -0
  91. package/edge/components/sideBar.vue +288 -0
  92. package/edge/components/sideBarContent.vue +268 -0
  93. package/edge/components/sidebarProvider.vue +33 -0
  94. package/edge/components/tooltip.vue +16 -0
  95. package/edge/components/userMenu.vue +148 -0
  96. package/edge/components/v/alert.vue +59 -0
  97. package/edge/components/v/alertTitle.vue +18 -0
  98. package/edge/components/v/card.vue +53 -0
  99. package/edge/components/v/cardActions.vue +18 -0
  100. package/edge/components/v/cardText.vue +18 -0
  101. package/edge/components/v/cardTitle.vue +20 -0
  102. package/edge/components/v/col.vue +56 -0
  103. package/edge/components/v/list.vue +46 -0
  104. package/edge/components/v/listItem.vue +26 -0
  105. package/edge/components/v/listItemTitle.vue +18 -0
  106. package/edge/components/v/row.vue +42 -0
  107. package/edge/components/v/toolbar.vue +24 -0
  108. package/edge/composables/global.ts +519 -0
  109. package/edge-pull.sh +2 -0
  110. package/edge-push.sh +1 -0
  111. package/edge-status.sh +14 -0
  112. package/firebase.json +5 -2
  113. package/firebase_init.sh +21 -6
  114. package/package.json +1 -1
  115. package/plugins/firebase.client.ts +1 -0
  116. package/edge-components-install.sh +0 -1
@@ -0,0 +1,59 @@
1
+ <div
2
+ data-carousel
3
+ class="relative overflow-hidden"
4
+ data-carousel-autoplay
5
+ data-carousel-interval="4000"
6
+ data-carousel-loop
7
+ data-carousel-slides-to-scroll="1"
8
+ data-carousel-slides-to-scroll-lg="4"
9
+ >
10
+ <div data-carousel-track class="flex">
11
+ {{{#array {"field":"List","schema":{"listing_price":"money","square_feet":"number","acres":"number"},"api":"https://api.clearwaterproperties.com/api/front/properties","apiField":"data","apiQuery":"?limit=20&filter_scope[agent][]=mt_nmar-mt.545000478","queryOptions":[{"field":"sort","optionsKey":"label","optionsValue":"value","options":[{"label":"Highest Price","value":"listing_price"},{"label":"Lowest Price","value":"-listing_price"},{"label":"Newest","value":"-list_date"}]},{"field":"filter_scope[agent][]","title":"Agent","optionsKey":"name","optionsValue":"mls.primary","options":"users"}],"limit":10,"value":[]}}}}
12
+ <div class="shrink-0 min-w-0 flex-[0_0_100%] lg:flex-[0_0_25%] p-4">
13
+ <div class="{{loading}}">
14
+ <div class="block bg-white shadow-md rounded-lg overflow-hidden animate-pulse">
15
+ <div class="relative w-full h-64 bg-gray-300">
16
+ <div class="absolute top-2 left-2 w-16 h-5 bg-gray-300 rounded"></div>
17
+ <div class="absolute bottom-2 right-2 w-20 h-5 bg-gray-300 rounded"></div>
18
+ </div>
19
+ <div class="p-4 space-y-3">
20
+ <div class="w-32 h-6 bg-gray-300 rounded"></div>
21
+ <div class="w-48 h-4 bg-gray-200 rounded"></div>
22
+ <div class="flex gap-4 mt-2">
23
+ <div class="w-12 h-4 bg-gray-200 rounded"></div>
24
+ <div class="w-12 h-4 bg-gray-200 rounded"></div>
25
+ <div class="w-16 h-4 bg-gray-200 rounded"></div>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ </div>
30
+
31
+ <a class="block bg-white shadow-md rounded-lg overflow-hidden {{loaded}}">
32
+ <div class="relative w-full h-64 bg-gray-200 bg-[url('/images/placeholder.jpg')] bg-cover bg-center">
33
+ <img src="{{item.thumbnail_url}}" alt="For Sale" loading="lazy" class="w-full h-full object-cover">
34
+ <div class="absolute top-2 left-2 bg-black/70 text-white px-2 py-1 rounded text-xs">{{item.listing_status}}</div>
35
+ <div class="absolute bottom-2 right-2 bg-white/80 text-gray-800 px-2 py-1 rounded text-xs">MLS® {{item.display_mlsnumber}}</div>
36
+ </div>
37
+
38
+ <div class="p-4">
39
+ <h4 class="text-xl font-bold text-gray-800">{{item.listing_price}}</h4>
40
+ <div class="text-gray-600 mt-1 truncate">{{item.display_address}}</div>
41
+ <div class="flex gap-4 mt-2 text-sm text-gray-700">
42
+ {{{#if {"cond": "item.total_bedrooms > 0"}}}}<span>{{item.total_bedrooms}} Beds</span>{{{/if}}}
43
+ {{{#if {"cond": "item.total_bathrooms > 0"}}}}<span>{{item.total_bathrooms}} Baths</span>{{{/if}}}
44
+ {{{#if {"cond": "item.property_type == 'ranch'"}}}}<span>{{item.acres}} Acres</span>
45
+ {{{#else}}}{{{#if {"cond": "item.square_feet > 0"}}}}<span>{{item.square_feet}} Sq.Ft.</span>{{{/if}}}{{{/else}}}
46
+ </div>
47
+ </div>
48
+ </a>
49
+ </div>
50
+ {{{/array}}}
51
+ </div>
52
+
53
+ <button type="button" data-carousel-prev
54
+ class="absolute left-2 top-1/2 -translate-y-1/2 p-2 bg-black/60 text-white rounded-full">‹</button>
55
+ <button type="button" data-carousel-next
56
+ class="absolute right-2 top-1/2 -translate-y-1/2 p-2 bg-black/60 text-white rounded-full">›</button>
57
+
58
+ <div data-carousel-dots class="mt-3 flex justify-center gap-2"></div>
59
+ </div>
@@ -0,0 +1,112 @@
1
+ <section
2
+ class="relative cms-block cms-block-property-detail rounded-2xl border border-dashed border-slate-300 bg-slate-50/70 px-4 py-6 sm:px-6 sm:py-8"
3
+ data-block-type="property-detail"
4
+ >
5
+ <!-- OVERLAY: Marks this entire block as a placeholder -->
6
+ <div
7
+ class="pointer-events-none absolute inset-x-0 top-0 z-20 flex justify-center pt-3"
8
+ >
9
+ <div
10
+ class="rounded-full border border-slate-300 bg-white/95 px-4 py-1 text-[11px] font-semibold uppercase tracking-wide text-slate-600 shadow-sm"
11
+ >
12
+ Property Detail Placeholder
13
+ </div>
14
+ </div>
15
+
16
+ <div class="mx-auto max-w-6xl pt-6">
17
+ <!-- Top label skeletons -->
18
+ <div class="mb-4 flex items-center justify-between gap-3">
19
+ <div class="h-4 w-40 rounded bg-slate-200"></div>
20
+ <div class="h-4 w-24 rounded bg-slate-200"></div>
21
+ </div>
22
+
23
+ <div class="grid gap-6 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]">
24
+ <!-- LEFT COLUMN -->
25
+ <div class="space-y-5">
26
+ <!-- Hero image -->
27
+ <div class="overflow-hidden rounded-xl bg-slate-200">
28
+ <div class="relative h-64 w-full sm:h-80">
29
+ <div class="absolute left-3 top-3 h-6 w-20 rounded bg-slate-300"></div>
30
+ <div class="absolute bottom-3 left-3 h-6 w-32 rounded bg-slate-300"></div>
31
+ </div>
32
+ </div>
33
+
34
+ <!-- Price + address -->
35
+ <div class="space-y-2">
36
+ <div class="h-7 w-40 rounded bg-slate-300"></div>
37
+ <div class="h-4 w-64 rounded bg-slate-200"></div>
38
+ </div>
39
+
40
+ <!-- Stats -->
41
+ <div class="flex flex-wrap gap-4">
42
+ <div class="h-4 w-20 rounded bg-slate-200"></div>
43
+ <div class="h-4 w-20 rounded bg-slate-200"></div>
44
+ <div class="h-4 w-24 rounded bg-slate-200"></div>
45
+ <div class="h-4 w-20 rounded bg-slate-200"></div>
46
+ </div>
47
+
48
+ <!-- Description -->
49
+ <div class="space-y-2">
50
+ <div class="h-4 w-full rounded bg-slate-200"></div>
51
+ <div class="h-4 w-[90%] rounded bg-slate-200"></div>
52
+ <div class="h-4 w-[80%] rounded bg-slate-200"></div>
53
+ <div class="h-4 w-[70%] rounded bg-slate-200"></div>
54
+ </div>
55
+
56
+ <!-- Features / extras -->
57
+ <div class="grid gap-4 sm:grid-cols-2">
58
+ <div class="space-y-2">
59
+ <div class="h-4 w-32 rounded bg-slate-200"></div>
60
+ <div class="h-3 w-[80%] rounded bg-slate-100"></div>
61
+ <div class="h-3 w-[70%] rounded bg-slate-100"></div>
62
+ <div class="h-3 w-[60%] rounded bg-slate-100"></div>
63
+ </div>
64
+ <div class="space-y-2">
65
+ <div class="h-4 w-28 rounded bg-slate-200"></div>
66
+ <div class="h-3 w-[75%] rounded bg-slate-100"></div>
67
+ <div class="h-3 w-[65%] rounded bg-slate-100"></div>
68
+ <div class="h-3 w-[55%] rounded bg-slate-100"></div>
69
+ </div>
70
+ </div>
71
+ </div>
72
+
73
+ <!-- RIGHT COLUMN — contact form style -->
74
+ <aside class="flex flex-col gap-4 rounded-xl border border-slate-200 bg-white p-5 shadow-sm">
75
+ <div class="space-y-1">
76
+ <div class="h-4 w-40 rounded bg-slate-200"></div>
77
+ <div class="h-3 w-28 rounded bg-slate-100"></div>
78
+ </div>
79
+
80
+ <div class="space-y-3">
81
+ <div class="space-y-1">
82
+ <div class="h-3 w-12 rounded bg-slate-200"></div>
83
+ <div class="h-9 w-full rounded-lg bg-slate-100"></div>
84
+ </div>
85
+
86
+ <div class="space-y-1">
87
+ <div class="h-3 w-10 rounded bg-slate-200"></div>
88
+ <div class="h-9 w-full rounded-lg bg-slate-100"></div>
89
+ </div>
90
+
91
+ <div class="space-y-1">
92
+ <div class="h-3 w-12 rounded bg-slate-200"></div>
93
+ <div class="h-9 w-full rounded-lg bg-slate-100"></div>
94
+ </div>
95
+
96
+ <div class="space-y-1">
97
+ <div class="h-3 w-16 rounded bg-slate-200"></div>
98
+ <div class="h-20 w-full rounded-lg bg-slate-100"></div>
99
+ </div>
100
+ </div>
101
+
102
+ <button
103
+ type="button"
104
+ class="mt-2 w-full rounded-lg bg-slate-900 px-4 py-2.5 text-sm font-semibold text-white shadow-sm disabled:cursor-not-allowed disabled:opacity-60"
105
+ disabled
106
+ >
107
+ Contact About This Property (Placeholder)
108
+ </button>
109
+ </aside>
110
+ </div>
111
+ </div>
112
+ </section>
@@ -0,0 +1,34 @@
1
+ <section
2
+ class="relative h-[50dvh] min-h-[260px] w-full bg-cover bg-center rounded-2xl border border-dashed border-slate-300"
3
+ data-block-type="property-detail-page-header"
4
+ style="background-image: url('{{{#image {"field":"backgroundImage","value":"https://www.clearwaterproperties.com/image/static/hp-recreational.jpg","tags":["Backgrounds"]}}}}')"
5
+ >
6
+ <!-- Full placeholder overlay badge -->
7
+ <div class="pointer-events-none absolute inset-x-0 top-3 z-30 flex justify-center">
8
+ <div
9
+ class="rounded-full border border-white/60 bg-white/90 px-4 py-1 text-[11px] font-semibold uppercase tracking-wide text-slate-700 shadow-sm"
10
+ >
11
+ Property Detail Header Placeholder
12
+ </div>
13
+ </div>
14
+
15
+ <!-- Dark overlay -->
16
+ <div class="absolute inset-0 bg-black/40 z-10"></div>
17
+
18
+ <!-- Centered content -->
19
+ <div class="relative z-20 flex h-full items-center justify-center px-6 text-center text-white">
20
+ <div>
21
+ <!-- Address placeholder -->
22
+ <div class="mx-auto h-7 w-72 rounded bg-white/60"></div>
23
+
24
+ <!-- Subheader placeholder -->
25
+ <div class="mx-auto mt-4 h-4 w-52 rounded bg-white/40"></div>
26
+
27
+ <!-- Optional CTA placeholder -->
28
+ <div class="mx-auto mt-8 h-10 w-40 rounded border border-white/40 bg-white/20"></div>
29
+ </div>
30
+ </div>
31
+
32
+ <!-- Vignette (matches your original aesthetic) -->
33
+ <div class="pointer-events-none absolute inset-0 bg-gradient-to-b from-black/20 via-transparent to-black/30 z-20"></div>
34
+ </section>
@@ -0,0 +1,137 @@
1
+ <section
2
+ class="relative cms-block cms-block-property-results rounded-2xl border border-dashed border-slate-300 bg-slate-50/70 px-4 py-6 sm:px-6 sm:py-8"
3
+ data-block-type="property-search-results"
4
+ >
5
+ <!-- Overlay label -->
6
+ <div
7
+ class="pointer-events-none absolute inset-x-0 top-0 z-20 flex justify-center pt-3"
8
+ >
9
+ <div
10
+ class="rounded-full border border-slate-300 bg-white/95 px-4 py-1 text-[11px] font-semibold uppercase tracking-wide text-slate-600 shadow-sm"
11
+ >
12
+ Property Results Placeholder
13
+ </div>
14
+ </div>
15
+
16
+ <!-- Optional top skeleton bar -->
17
+ <div class="mb-4 flex flex-wrap items-center justify-between gap-3 pt-6">
18
+ <div class="h-4 w-32 rounded bg-slate-200"></div>
19
+ <div class="h-4 w-40 rounded bg-slate-200"></div>
20
+ </div>
21
+
22
+ <!-- 6-up grid -->
23
+ <div class="grid gap-5 sm:grid-cols-2 lg:grid-cols-3">
24
+ <!-- Repeat this card x6 -->
25
+ <!-- Card -->
26
+ <div class="block overflow-hidden rounded-lg bg-white shadow-md animate-pulse">
27
+ <div class="relative h-52 w-full bg-gray-200">
28
+ <div class="absolute left-2 top-2 h-5 w-16 rounded bg-gray-300"></div>
29
+ <div class="absolute bottom-2 right-2 h-5 w-20 rounded bg-gray-300"></div>
30
+ </div>
31
+
32
+ <div class="space-y-3 p-4">
33
+ <div class="h-6 w-32 rounded bg-gray-300"></div>
34
+ <div class="h-4 w-48 rounded bg-gray-200"></div>
35
+ <div class="mt-2 flex gap-4">
36
+ <div class="h-4 w-12 rounded bg-gray-200"></div>
37
+ <div class="h-4 w-12 rounded bg-gray-200"></div>
38
+ <div class="h-4 w-16 rounded bg-gray-200"></div>
39
+ </div>
40
+ </div>
41
+ </div>
42
+
43
+ <!-- Card -->
44
+ <div class="block overflow-hidden rounded-lg bg-white shadow-md animate-pulse">
45
+ <div class="relative h-52 w-full bg-gray-200">
46
+ <div class="absolute left-2 top-2 h-5 w-16 rounded bg-gray-300"></div>
47
+ <div class="absolute bottom-2 right-2 h-5 w-20 rounded bg-gray-300"></div>
48
+ </div>
49
+
50
+ <div class="space-y-3 p-4">
51
+ <div class="h-6 w-28 rounded bg-gray-300"></div>
52
+ <div class="h-4 w-40 rounded bg-gray-200"></div>
53
+ <div class="mt-2 flex gap-4">
54
+ <div class="h-4 w-10 rounded bg-gray-200"></div>
55
+ <div class="h-4 w-14 rounded bg-gray-200"></div>
56
+ <div class="h-4 w-16 rounded bg-gray-200"></div>
57
+ </div>
58
+ </div>
59
+ </div>
60
+
61
+ <!-- Card -->
62
+ <div class="block overflow-hidden rounded-lg bg-white shadow-md animate-pulse">
63
+ <div class="relative h-52 w-full bg-gray-200">
64
+ <div class="absolute left-2 top-2 h-5 w-16 rounded bg-gray-300"></div>
65
+ <div class="absolute bottom-2 right-2 h-5 w-20 rounded bg-gray-300"></div>
66
+ </div>
67
+
68
+ <div class="space-y-3 p-4">
69
+ <div class="h-6 w-36 rounded bg-gray-300"></div>
70
+ <div class="h-4 w-44 rounded bg-gray-200"></div>
71
+ <div class="mt-2 flex gap-4">
72
+ <div class="h-4 w-12 rounded bg-gray-200"></div>
73
+ <div class="h-4 w-12 rounded bg-gray-200"></div>
74
+ <div class="h-4 w-20 rounded bg-gray-200"></div>
75
+ </div>
76
+ </div>
77
+ </div>
78
+
79
+ <!-- Card -->
80
+ <div class="block overflow-hidden rounded-lg bg-white shadow-md animate-pulse">
81
+ <div class="relative h-52 w-full bg-gray-200">
82
+ <div class="absolute left-2 top-2 h-5 w-16 rounded bg-gray-300"></div>
83
+ <div class="absolute bottom-2 right-2 h-5 w-20 rounded bg-gray-300"></div>
84
+ </div>
85
+
86
+ <div class="space-y-3 p-4">
87
+ <div class="h-6 w-32 rounded bg-gray-300"></div>
88
+ <div class="h-4 w-48 rounded bg-gray-200"></div>
89
+ <div class="mt-2 flex gap-4">
90
+ <div class="h-4 w-12 rounded bg-gray-200"></div>
91
+ <div class="h-4 w-12 rounded bg-gray-200"></div>
92
+ <div class="h-4 w-16 rounded bg-gray-200"></div>
93
+ </div>
94
+ </div>
95
+ </div>
96
+
97
+ <!-- Card -->
98
+ <div class="block overflow-hidden rounded-lg bg-white shadow-md animate-pulse">
99
+ <div class="relative h-52 w-full bg-gray-200">
100
+ <div class="absolute left-2 top-2 h-5 w-16 rounded bg-gray-300"></div>
101
+ <div class="absolute bottom-2 right-2 h-5 w-20 rounded bg-gray-300"></div>
102
+ </div>
103
+
104
+ <div class="space-y-3 p-4">
105
+ <div class="h-6 w-28 rounded bg-gray-300"></div>
106
+ <div class="h-4 w-40 rounded bg-gray-200"></div>
107
+ <div class="mt-2 flex gap-4">
108
+ <div class="h-4 w-10 rounded bg-gray-200"></div>
109
+ <div class="h-4 w-14 rounded bg-gray-200"></div>
110
+ <div class="h-4 w-16 rounded bg-gray-200"></div>
111
+ </div>
112
+ </div>
113
+ </div>
114
+
115
+ <!-- Card -->
116
+ <div class="block overflow-hidden rounded-lg bg-white shadow-md animate-pulse">
117
+ <div class="relative h-52 w-full bg-gray-200">
118
+ <div class="absolute left-2 top-2 h-5 w-16 rounded bg-gray-300"></div>
119
+ <div class="absolute bottom-2 right-2 h-5 w-20 rounded bg-gray-300"></div>
120
+ </div>
121
+
122
+ <div class="space-y-3 p-4">
123
+ <div class="h-6 w-36 rounded bg-gray-300"></div>
124
+ <div class="h-4 w-44 rounded bg-gray-200"></div>
125
+ <div class="mt-2 flex gap-4">
126
+ <div class="h-4 w-12 rounded bg-gray-200"></div>
127
+ <div class="h-4 w-12 rounded bg-gray-200"></div>
128
+ <div class="h-4 w-20 rounded bg-gray-200"></div>
129
+ </div>
130
+ </div>
131
+ </div>
132
+ </div>
133
+
134
+ <span class="sr-only">
135
+ Property search results placeholder grid (6 cards).
136
+ </span>
137
+ </section>
@@ -0,0 +1,75 @@
1
+ <div
2
+ class="relative cms-block cms-block-property-search-toolbar"
3
+ data-block-type="property-search-toolbar"
4
+ >
5
+ <!-- Overlay -->
6
+ <div
7
+ class="pointer-events-none absolute inset-0 z-20 flex items-center justify-center bg-white/65"
8
+ >
9
+ <div
10
+ class="rounded-full border border-slate-300 bg-white px-5 py-1.5 text-xs font-semibold tracking-wide text-slate-600 shadow-sm uppercase"
11
+ >
12
+ Property Search Placeholder
13
+ </div>
14
+ </div>
15
+
16
+ <!-- Toolbar -->
17
+ <div
18
+ class="flex flex-wrap items-center gap-3 rounded-xl border border-slate-200 bg-white px-4 py-3 shadow-sm"
19
+ >
20
+ <!-- Location / Keyword -->
21
+ <div
22
+ class="flex min-w-[220px] flex-1 items-center gap-2 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2"
23
+ >
24
+ <span class="text-[11px] font-medium uppercase tracking-wide text-slate-400">
25
+ Location / Keyword
26
+ </span>
27
+ </div>
28
+
29
+ <!-- Price -->
30
+ <div
31
+ class="flex min-w-[150px] flex-none items-center gap-2 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2"
32
+ >
33
+ <span class="text-[11px] font-medium uppercase tracking-wide text-slate-400">
34
+ Price
35
+ </span>
36
+ </div>
37
+
38
+ <!-- Beds -->
39
+ <div
40
+ class="flex min-w-[110px] flex-none items-center gap-2 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2"
41
+ >
42
+ <span class="text-[11px] font-medium uppercase tracking-wide text-slate-400">
43
+ Beds
44
+ </span>
45
+ </div>
46
+
47
+ <!-- Baths -->
48
+ <div
49
+ class="flex min-w-[110px] flex-none items-center gap-2 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2"
50
+ >
51
+ <span class="text-[11px] font-medium uppercase tracking-wide text-slate-400">
52
+ Baths
53
+ </span>
54
+ </div>
55
+
56
+ <!-- More Filters -->
57
+ <button
58
+ type="button"
59
+ class="inline-flex items-center gap-2 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-xs font-medium text-slate-600"
60
+ disabled
61
+ >
62
+ <span class="h-1.5 w-1.5 rounded-full bg-slate-300"></span>
63
+ <span class="uppercase tracking-wide">More Filters</span>
64
+ </button>
65
+
66
+ <!-- Search Button -->
67
+ <button
68
+ type="button"
69
+ class="inline-flex items-center justify-center rounded-lg bg-slate-900 px-4 py-2 text-sm font-semibold text-white shadow-sm"
70
+ disabled
71
+ >
72
+ Search
73
+ </button>
74
+ </div>
75
+ </div>
@@ -0,0 +1,7 @@
1
+ <div class="p-1 w-full bg-red-200">
2
+ <ul class="list-inside">
3
+ {{{#array {"field":"listThing", value: [] }}}}
4
+ <li class="list-disc">{{item}}</li>
5
+ {{{/array}}}
6
+ </ul>
7
+ </div>
@@ -0,0 +1,116 @@
1
+ <script setup>
2
+ import { ImagePlus, Loader2, Square, SquareCheckBig, Trash } from 'lucide-vue-next'
3
+ const props = defineProps({
4
+ item: {
5
+ type: Object,
6
+ required: true,
7
+ },
8
+ selected: {
9
+ type: Boolean,
10
+ default: false,
11
+ },
12
+ selectMode: {
13
+ type: Boolean,
14
+ default: false,
15
+ },
16
+ canDelete: {
17
+ type: Boolean,
18
+ default: true,
19
+ },
20
+ })
21
+ const emits = defineEmits(['select', 'delete'])
22
+
23
+ const getThumbnail = (file) => {
24
+ const images = file.cloudflareImageVariants
25
+ if (images) {
26
+ for (const img of images) {
27
+ if (img.endsWith('thumbnail')) {
28
+ return img
29
+ }
30
+ }
31
+ }
32
+ return null
33
+ }
34
+
35
+ const state = reactive({
36
+ tags: [],
37
+ })
38
+
39
+ const timeAgo = (timestamp) => {
40
+ if (!timestamp)
41
+ return ''
42
+
43
+ const now = Date.now()
44
+ const difference = now - timestamp
45
+ const seconds = Math.floor(difference / 1000)
46
+ const minutes = Math.floor(seconds / 60)
47
+ const hours = Math.floor(minutes / 60)
48
+ const days = Math.floor(hours / 24)
49
+
50
+ if (days > 0)
51
+ return `${days} day${days > 1 ? 's' : ''} ago`
52
+ if (hours > 0)
53
+ return `${hours} hour${hours > 1 ? 's' : ''} ago`
54
+ if (minutes > 0)
55
+ return `${minutes} minute${minutes > 1 ? 's' : ''} ago`
56
+ return `${seconds} second${seconds > 1 ? 's' : ''} ago`
57
+ }
58
+ </script>
59
+
60
+ <template>
61
+ <Card
62
+ class="w-full group overflow-hidden rounded-2xl border bg-card hover:shadow-md hover:border-muted-foreground/20 transition-all"
63
+ >
64
+ <div class="relative w-full h-[200px] bg-muted">
65
+ <div class="z-10 absolute w-full flex inset-0 bg-black/10 dark:bg-black/30 justify-between items-start p-2">
66
+ <edge-shad-button
67
+ v-if="!props.selectMode"
68
+ size="icon"
69
+ class="bg-primary/80 text-primary-foreground hover:bg-primary shadow-sm"
70
+ @click.stop="emits('select', !props.selected, item.docId)"
71
+ >
72
+ <Square v-if="!props.selected" class="!w-5 !h-5" />
73
+ <SquareCheckBig v-else class="!w-5 !h-5" />
74
+ </edge-shad-button>
75
+ <div v-else class="w-5 h-5" />
76
+ <edge-shad-button
77
+ v-if="props.canDelete"
78
+ size="icon"
79
+ class="bg-destructive/80 text-destructive-foreground hover:bg-destructive h-9 w-9 sm:h-10 sm:w-10 rounded-xl border border-destructive/40 shadow-sm"
80
+ @click.stop="emits('delete', item.docId)"
81
+ >
82
+ <Trash class="!h-5 !w-5" />
83
+ </edge-shad-button>
84
+ </div>
85
+ <Loader2
86
+ v-if="!edgeGlobal.getImage(item, 'thumbnail')"
87
+ class="absolute inset-0 m-auto animate-spin h-6 w-6 text-muted-foreground"
88
+ />
89
+ <img
90
+ v-else
91
+ :src="edgeGlobal.getImage(item, 'thumbnail')"
92
+ alt=""
93
+ class="absolute inset-0 h-full w-full object-cover transition-transform duration-200 group-hover:scale-[1.02]"
94
+ >
95
+ </div>
96
+
97
+ <!-- Main Content -->
98
+ <CardContent class="p-3 sm:p-4">
99
+ <div class="min-w-0 text-left">
100
+ <div class="flex items-center gap-1.5 text-xs sm:text-sm text-muted-foreground font-light italic">
101
+ <ImagePlus class="w-4 h-4 shrink-0" />
102
+ <span class="truncate">Uploaded {{ timeAgo(item.uploadTime) }}</span>
103
+ </div>
104
+
105
+ <div
106
+ class="mt-1.5 sm:mt-2 text-base sm:text-sm font-semibold tracking-wide uppercase text-foreground line-clamp-1"
107
+ :title="item.name"
108
+ >
109
+ {{ item.name }}
110
+ </div>
111
+ </div>
112
+ </CardContent>
113
+
114
+ <!-- Footer with actions -->
115
+ </Card>
116
+ </template>