@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.
- package/.env +1 -0
- package/.env.dev +1 -0
- package/README.md +55 -20
- package/{agent.md → agents.md} +2 -0
- package/bin/cli.js +6 -6
- package/edge/components/auth/login.vue +384 -0
- package/edge/components/auth/register.vue +396 -0
- package/edge/components/auth.vue +108 -0
- package/edge/components/autoFileUpload.vue +215 -0
- package/edge/components/billing.vue +8 -0
- package/edge/components/buttonDivider.vue +14 -0
- package/edge/components/chip.vue +34 -0
- package/edge/components/clipboardButton.vue +42 -0
- package/edge/components/cms/block.vue +529 -0
- package/edge/components/cms/blockApi.vue +212 -0
- package/edge/components/cms/blockEditor.vue +725 -0
- package/edge/components/cms/blockInput.vue +66 -0
- package/edge/components/cms/blockPicker.vue +486 -0
- package/edge/components/cms/blockRender.vue +78 -0
- package/edge/components/cms/blockSheetContent.vue +28 -0
- package/edge/components/cms/codeEditor.vue +466 -0
- package/edge/components/cms/fontUpload.vue +327 -0
- package/edge/components/cms/htmlContent.vue +807 -0
- package/edge/components/cms/init_blocks/api_with_subarrays.html +17 -0
- package/edge/components/cms/init_blocks/array_with_collection.html +7 -0
- package/edge/components/cms/init_blocks/array_with_objects.html +7 -0
- package/edge/components/cms/init_blocks/carousel.html +103 -0
- package/edge/components/cms/init_blocks/contact_us.html +69 -0
- package/edge/components/cms/init_blocks/content_with_left_image.html +27 -0
- package/edge/components/cms/init_blocks/footer.html +24 -0
- package/edge/components/cms/init_blocks/header_divider.html +7 -0
- package/edge/components/cms/init_blocks/hero.html +35 -0
- package/edge/components/cms/init_blocks/hero_carousel.html +52 -0
- package/edge/components/cms/init_blocks/newsletter.html +117 -0
- package/edge/components/cms/init_blocks/post_content.html +7 -0
- package/edge/components/cms/init_blocks/post_title_header.html +21 -0
- package/edge/components/cms/init_blocks/posts_list.html +20 -0
- package/edge/components/cms/init_blocks/properties_showcase.html +100 -0
- package/edge/components/cms/init_blocks/property_carousel.html +59 -0
- package/edge/components/cms/init_blocks/property_detail.html +112 -0
- package/edge/components/cms/init_blocks/property_detail_header.html +34 -0
- package/edge/components/cms/init_blocks/property_results.html +137 -0
- package/edge/components/cms/init_blocks/property_search.html +75 -0
- package/edge/components/cms/init_blocks/simple_array.html +7 -0
- package/edge/components/cms/mediaCard.vue +116 -0
- package/edge/components/cms/mediaManager.vue +386 -0
- package/edge/components/cms/menu.vue +1103 -0
- package/edge/components/cms/optionsSelect.vue +107 -0
- package/edge/components/cms/page.vue +1785 -0
- package/edge/components/cms/posts.vue +1083 -0
- package/edge/components/cms/site.vue +1298 -0
- package/edge/components/cms/themeDefaultMenu.vue +548 -0
- package/edge/components/cms/themeEditor.vue +426 -0
- package/edge/components/dashboard.vue +776 -0
- package/edge/components/editor.vue +671 -0
- package/edge/components/fileTree.vue +72 -0
- package/edge/components/files.vue +89 -0
- package/edge/components/formSubtypes/myOrgs.vue +214 -0
- package/edge/components/formSubtypes/users.vue +336 -0
- package/edge/components/functionChips.vue +57 -0
- package/edge/components/gError.vue +98 -0
- package/edge/components/gHelper.vue +67 -0
- package/edge/components/gInput.vue +1331 -0
- package/edge/components/loggingIn.vue +41 -0
- package/edge/components/menu.vue +137 -0
- package/edge/components/menuContent.vue +132 -0
- package/edge/components/myAccount.vue +317 -0
- package/edge/components/myOrganizations.vue +75 -0
- package/edge/components/myProfile.vue +122 -0
- package/edge/components/orgSwitcher.vue +25 -0
- package/edge/components/organizationMembers.vue +522 -0
- package/edge/components/organizationSettings.vue +271 -0
- package/edge/components/shad/breadcrumbs.vue +35 -0
- package/edge/components/shad/button.vue +43 -0
- package/edge/components/shad/checkbox.vue +73 -0
- package/edge/components/shad/combobox.vue +238 -0
- package/edge/components/shad/datepicker.vue +184 -0
- package/edge/components/shad/dialog.vue +32 -0
- package/edge/components/shad/dropdownMenu.vue +54 -0
- package/edge/components/shad/dropdownMenuItem.vue +21 -0
- package/edge/components/shad/form.vue +59 -0
- package/edge/components/shad/html.vue +877 -0
- package/edge/components/shad/input.vue +139 -0
- package/edge/components/shad/number.vue +109 -0
- package/edge/components/shad/select.vue +151 -0
- package/edge/components/shad/selectTags.vue +278 -0
- package/edge/components/shad/switch.vue +67 -0
- package/edge/components/shad/tags.vue +137 -0
- package/edge/components/shad/textarea.vue +102 -0
- package/edge/components/shad/typeMoney.vue +167 -0
- package/edge/components/sideBar.vue +288 -0
- package/edge/components/sideBarContent.vue +268 -0
- package/edge/components/sidebarProvider.vue +33 -0
- package/edge/components/tooltip.vue +16 -0
- package/edge/components/userMenu.vue +148 -0
- package/edge/components/v/alert.vue +59 -0
- package/edge/components/v/alertTitle.vue +18 -0
- package/edge/components/v/card.vue +53 -0
- package/edge/components/v/cardActions.vue +18 -0
- package/edge/components/v/cardText.vue +18 -0
- package/edge/components/v/cardTitle.vue +20 -0
- package/edge/components/v/col.vue +56 -0
- package/edge/components/v/list.vue +46 -0
- package/edge/components/v/listItem.vue +26 -0
- package/edge/components/v/listItemTitle.vue +18 -0
- package/edge/components/v/row.vue +42 -0
- package/edge/components/v/toolbar.vue +24 -0
- package/edge/composables/global.ts +519 -0
- package/edge-pull.sh +2 -0
- package/edge-push.sh +1 -0
- package/edge-status.sh +14 -0
- package/firebase.json +5 -2
- package/firebase_init.sh +21 -6
- package/package.json +1 -1
- package/plugins/firebase.client.ts +1 -0
- 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,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>
|