@contractspec/bundle.marketing 3.8.9 → 3.8.10
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/.turbo/turbo-build.log +54 -42
- package/CHANGELOG.md +33 -0
- package/dist/browser/components/templates/TemplatesBrowseControls.js +37 -22
- package/dist/browser/components/templates/TemplatesCatalogSection.js +29 -6
- package/dist/browser/components/templates/TemplatesClientPage.js +269 -89
- package/dist/browser/components/templates/TemplatesOverlays.js +2874 -0
- package/dist/browser/components/templates/index.js +301 -121
- package/dist/browser/components/templates/template-catalog.js +5 -3
- package/dist/browser/components/templates/template-filters.js +99 -0
- package/dist/browser/components/templates/template-tag-visibility.js +40 -0
- package/dist/browser/components/templates/useTemplateBrowseState.js +191 -0
- package/dist/browser/index.js +301 -121
- package/dist/components/templates/TemplatesBrowseControls.d.ts +7 -2
- package/dist/components/templates/TemplatesBrowseControls.js +37 -22
- package/dist/components/templates/TemplatesCatalogSection.d.ts +4 -1
- package/dist/components/templates/TemplatesCatalogSection.js +29 -6
- package/dist/components/templates/TemplatesClientPage.js +269 -89
- package/dist/components/templates/TemplatesOverlays.d.ts +10 -0
- package/dist/components/templates/TemplatesOverlays.js +2869 -0
- package/dist/components/templates/index.js +301 -121
- package/dist/components/templates/template-catalog.d.ts +1 -0
- package/dist/components/templates/template-catalog.js +5 -3
- package/dist/components/templates/template-filters.d.ts +12 -0
- package/dist/components/templates/template-filters.js +94 -0
- package/dist/components/templates/template-tag-visibility.d.ts +10 -0
- package/dist/components/templates/template-tag-visibility.js +35 -0
- package/dist/components/templates/useTemplateBrowseState.d.ts +22 -0
- package/dist/components/templates/useTemplateBrowseState.js +186 -0
- package/dist/index.js +301 -121
- package/dist/node/components/templates/TemplatesBrowseControls.js +37 -22
- package/dist/node/components/templates/TemplatesCatalogSection.js +29 -6
- package/dist/node/components/templates/TemplatesClientPage.js +269 -89
- package/dist/node/components/templates/TemplatesOverlays.js +2869 -0
- package/dist/node/components/templates/index.js +301 -121
- package/dist/node/components/templates/template-catalog.js +5 -3
- package/dist/node/components/templates/template-filters.js +94 -0
- package/dist/node/components/templates/template-tag-visibility.js +35 -0
- package/dist/node/components/templates/useTemplateBrowseState.js +186 -0
- package/dist/node/index.js +301 -121
- package/package.json +82 -26
- package/src/components/templates/TemplatesBrowseControls.tsx +59 -35
- package/src/components/templates/TemplatesCatalogSection.tsx +29 -4
- package/src/components/templates/TemplatesClientPage.tsx +41 -97
- package/src/components/templates/TemplatesOverlays.tsx +65 -0
- package/src/components/templates/template-catalog.test.ts +96 -0
- package/src/components/templates/template-catalog.ts +14 -6
- package/src/components/templates/template-filters.ts +57 -0
- package/src/components/templates/template-tag-visibility.ts +58 -0
- package/src/components/templates/useTemplateBrowseState.ts +101 -0
|
@@ -15,7 +15,11 @@ function TemplatesBrowseControls({
|
|
|
15
15
|
onSearchChange,
|
|
16
16
|
selectedTag,
|
|
17
17
|
onTagChange,
|
|
18
|
-
|
|
18
|
+
showTagFilters,
|
|
19
|
+
visibleTagFacets,
|
|
20
|
+
hiddenTagFacets,
|
|
21
|
+
showAllTags,
|
|
22
|
+
onShowAllTagsChange
|
|
19
23
|
}) {
|
|
20
24
|
return /* @__PURE__ */ jsxDEV("section", {
|
|
21
25
|
className: "editorial-section",
|
|
@@ -76,29 +80,40 @@ function TemplatesBrowseControls({
|
|
|
76
80
|
}, undefined, false, undefined, this)
|
|
77
81
|
]
|
|
78
82
|
}, undefined, true, undefined, this),
|
|
79
|
-
/* @__PURE__ */ jsxDEV("div", {
|
|
80
|
-
className: "
|
|
83
|
+
showTagFilters ? /* @__PURE__ */ jsxDEV("div", {
|
|
84
|
+
className: "space-y-3",
|
|
81
85
|
children: [
|
|
82
|
-
/* @__PURE__ */ jsxDEV("
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
86
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
87
|
+
className: "flex flex-wrap gap-2",
|
|
88
|
+
children: [
|
|
89
|
+
/* @__PURE__ */ jsxDEV("button", {
|
|
90
|
+
onClick: () => onTagChange(null),
|
|
91
|
+
className: cn("rounded-full px-4 py-2 font-medium text-sm transition-colors", {
|
|
92
|
+
"bg-primary text-primary-foreground": selectedTag === null,
|
|
93
|
+
"border border-border bg-card hover:bg-card/80": selectedTag !== null
|
|
94
|
+
}),
|
|
95
|
+
"aria-pressed": selectedTag === null,
|
|
96
|
+
children: "All"
|
|
97
|
+
}, undefined, false, undefined, this),
|
|
98
|
+
visibleTagFacets.map((facet) => /* @__PURE__ */ jsxDEV("button", {
|
|
99
|
+
onClick: () => onTagChange(facet.tag),
|
|
100
|
+
className: cn("rounded-full px-4 py-2 font-medium text-sm transition-colors", {
|
|
101
|
+
"bg-primary text-primary-foreground": selectedTag === facet.tag,
|
|
102
|
+
"border border-border bg-card hover:bg-card/80": selectedTag !== facet.tag
|
|
103
|
+
}),
|
|
104
|
+
"aria-pressed": selectedTag === facet.tag,
|
|
105
|
+
children: facet.tag
|
|
106
|
+
}, facet.tag, false, undefined, this))
|
|
107
|
+
]
|
|
108
|
+
}, undefined, true, undefined, this),
|
|
109
|
+
hiddenTagFacets.length > 0 || showAllTags ? /* @__PURE__ */ jsxDEV("button", {
|
|
110
|
+
type: "button",
|
|
111
|
+
onClick: () => onShowAllTagsChange(!showAllTags),
|
|
112
|
+
className: "text-muted-foreground text-sm transition-colors hover:text-foreground",
|
|
113
|
+
children: showAllTags ? "Show fewer" : "More tags"
|
|
114
|
+
}, undefined, false, undefined, this) : null
|
|
100
115
|
]
|
|
101
|
-
}, undefined, true, undefined, this)
|
|
116
|
+
}, undefined, true, undefined, this) : null
|
|
102
117
|
]
|
|
103
118
|
}, undefined, true, undefined, this)
|
|
104
119
|
]
|
|
@@ -111,15 +111,16 @@ function buildLocalTemplateCatalog(examples = listExamples(), templates = listTe
|
|
|
111
111
|
}).sort(compareLocalTemplateCatalogItems);
|
|
112
112
|
}
|
|
113
113
|
function matchesTemplateFilters(template, search, selectedTag) {
|
|
114
|
+
return matchesTemplateSearch(template, search) && (selectedTag === null || template.tags.includes(selectedTag));
|
|
115
|
+
}
|
|
116
|
+
function matchesTemplateSearch(template, search) {
|
|
114
117
|
const haystack = [
|
|
115
118
|
template.title,
|
|
116
119
|
template.description,
|
|
117
120
|
template.tags.join(" ")
|
|
118
121
|
].join(" ").toLowerCase();
|
|
119
122
|
const searchTokens = search.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
120
|
-
|
|
121
|
-
const matchesTag = selectedTag === null || template.tags.includes(selectedTag);
|
|
122
|
-
return matchesSearch && matchesTag;
|
|
123
|
+
return searchTokens.length === 0 || searchTokens.every((token) => haystack.includes(token));
|
|
123
124
|
}
|
|
124
125
|
function formatExampleKindLabel(kind) {
|
|
125
126
|
return kind.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
@@ -180,13 +181,17 @@ function TemplatesCatalogSection({
|
|
|
180
181
|
source,
|
|
181
182
|
registryConfigured,
|
|
182
183
|
registryLoading,
|
|
184
|
+
registryHasTemplates,
|
|
183
185
|
localTemplates,
|
|
184
186
|
registryTemplates,
|
|
185
187
|
localTemplateById,
|
|
186
188
|
onPreview,
|
|
187
|
-
onUseTemplate
|
|
189
|
+
onUseTemplate,
|
|
190
|
+
hasSearch,
|
|
191
|
+
selectedTag
|
|
188
192
|
}) {
|
|
189
193
|
const showRegistry = source === "registry" && registryConfigured;
|
|
194
|
+
const emptyStateMessage = getEmptyStateMessage(hasSearch, selectedTag);
|
|
190
195
|
return /* @__PURE__ */ jsxDEV2("section", {
|
|
191
196
|
className: "section-padding",
|
|
192
197
|
children: /* @__PURE__ */ jsxDEV2("div", {
|
|
@@ -197,12 +202,18 @@ function TemplatesCatalogSection({
|
|
|
197
202
|
className: "text-muted-foreground",
|
|
198
203
|
children: "Loading community templates…"
|
|
199
204
|
}, undefined, false, undefined, this)
|
|
200
|
-
}, undefined, false, undefined, this) :
|
|
205
|
+
}, undefined, false, undefined, this) : !registryHasTemplates ? /* @__PURE__ */ jsxDEV2("div", {
|
|
201
206
|
className: "py-12 text-center",
|
|
202
207
|
children: /* @__PURE__ */ jsxDEV2("p", {
|
|
203
208
|
className: "text-muted-foreground",
|
|
204
209
|
children: "No community templates found."
|
|
205
210
|
}, undefined, false, undefined, this)
|
|
211
|
+
}, undefined, false, undefined, this) : registryTemplates.length === 0 ? /* @__PURE__ */ jsxDEV2("div", {
|
|
212
|
+
className: "py-12 text-center",
|
|
213
|
+
children: /* @__PURE__ */ jsxDEV2("p", {
|
|
214
|
+
className: "text-muted-foreground",
|
|
215
|
+
children: emptyStateMessage
|
|
216
|
+
}, undefined, false, undefined, this)
|
|
206
217
|
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV2("div", {
|
|
207
218
|
className: "grid gap-6 md:grid-cols-2 lg:grid-cols-3",
|
|
208
219
|
children: registryTemplates.map((template) => {
|
|
@@ -238,7 +249,7 @@ function TemplatesCatalogSection({
|
|
|
238
249
|
className: "py-12 text-center",
|
|
239
250
|
children: /* @__PURE__ */ jsxDEV2("p", {
|
|
240
251
|
className: "text-muted-foreground",
|
|
241
|
-
children:
|
|
252
|
+
children: emptyStateMessage
|
|
242
253
|
}, undefined, false, undefined, this)
|
|
243
254
|
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV2("div", {
|
|
244
255
|
className: "grid gap-6 md:grid-cols-2 lg:grid-cols-3",
|
|
@@ -274,6 +285,18 @@ function TemplatesCatalogSection({
|
|
|
274
285
|
}, undefined, false, undefined, this)
|
|
275
286
|
}, undefined, false, undefined, this);
|
|
276
287
|
}
|
|
288
|
+
function getEmptyStateMessage(hasSearch, selectedTag) {
|
|
289
|
+
if (selectedTag !== null && hasSearch) {
|
|
290
|
+
return "No templates match this tag for the current search.";
|
|
291
|
+
}
|
|
292
|
+
if (selectedTag !== null) {
|
|
293
|
+
return "No templates match this tag. Try another tag or reset filters.";
|
|
294
|
+
}
|
|
295
|
+
if (hasSearch) {
|
|
296
|
+
return "No templates match your search. Try a different keyword.";
|
|
297
|
+
}
|
|
298
|
+
return "No templates match your filters. Try a different search.";
|
|
299
|
+
}
|
|
277
300
|
export {
|
|
278
301
|
TemplatesCatalogSection
|
|
279
302
|
};
|
|
@@ -2834,7 +2834,11 @@ function TemplatesBrowseControls({
|
|
|
2834
2834
|
onSearchChange,
|
|
2835
2835
|
selectedTag,
|
|
2836
2836
|
onTagChange,
|
|
2837
|
-
|
|
2837
|
+
showTagFilters,
|
|
2838
|
+
visibleTagFacets,
|
|
2839
|
+
hiddenTagFacets,
|
|
2840
|
+
showAllTags,
|
|
2841
|
+
onShowAllTagsChange
|
|
2838
2842
|
}) {
|
|
2839
2843
|
return /* @__PURE__ */ jsxDEV14("section", {
|
|
2840
2844
|
className: "editorial-section",
|
|
@@ -2895,29 +2899,40 @@ function TemplatesBrowseControls({
|
|
|
2895
2899
|
}, undefined, false, undefined, this)
|
|
2896
2900
|
]
|
|
2897
2901
|
}, undefined, true, undefined, this),
|
|
2898
|
-
/* @__PURE__ */ jsxDEV14("div", {
|
|
2899
|
-
className: "
|
|
2902
|
+
showTagFilters ? /* @__PURE__ */ jsxDEV14("div", {
|
|
2903
|
+
className: "space-y-3",
|
|
2900
2904
|
children: [
|
|
2901
|
-
/* @__PURE__ */ jsxDEV14("
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2905
|
+
/* @__PURE__ */ jsxDEV14("div", {
|
|
2906
|
+
className: "flex flex-wrap gap-2",
|
|
2907
|
+
children: [
|
|
2908
|
+
/* @__PURE__ */ jsxDEV14("button", {
|
|
2909
|
+
onClick: () => onTagChange(null),
|
|
2910
|
+
className: cn("rounded-full px-4 py-2 font-medium text-sm transition-colors", {
|
|
2911
|
+
"bg-primary text-primary-foreground": selectedTag === null,
|
|
2912
|
+
"border border-border bg-card hover:bg-card/80": selectedTag !== null
|
|
2913
|
+
}),
|
|
2914
|
+
"aria-pressed": selectedTag === null,
|
|
2915
|
+
children: "All"
|
|
2916
|
+
}, undefined, false, undefined, this),
|
|
2917
|
+
visibleTagFacets.map((facet) => /* @__PURE__ */ jsxDEV14("button", {
|
|
2918
|
+
onClick: () => onTagChange(facet.tag),
|
|
2919
|
+
className: cn("rounded-full px-4 py-2 font-medium text-sm transition-colors", {
|
|
2920
|
+
"bg-primary text-primary-foreground": selectedTag === facet.tag,
|
|
2921
|
+
"border border-border bg-card hover:bg-card/80": selectedTag !== facet.tag
|
|
2922
|
+
}),
|
|
2923
|
+
"aria-pressed": selectedTag === facet.tag,
|
|
2924
|
+
children: facet.tag
|
|
2925
|
+
}, facet.tag, false, undefined, this))
|
|
2926
|
+
]
|
|
2927
|
+
}, undefined, true, undefined, this),
|
|
2928
|
+
hiddenTagFacets.length > 0 || showAllTags ? /* @__PURE__ */ jsxDEV14("button", {
|
|
2929
|
+
type: "button",
|
|
2930
|
+
onClick: () => onShowAllTagsChange(!showAllTags),
|
|
2931
|
+
className: "text-muted-foreground text-sm transition-colors hover:text-foreground",
|
|
2932
|
+
children: showAllTags ? "Show fewer" : "More tags"
|
|
2933
|
+
}, undefined, false, undefined, this) : null
|
|
2919
2934
|
]
|
|
2920
|
-
}, undefined, true, undefined, this)
|
|
2935
|
+
}, undefined, true, undefined, this) : null
|
|
2921
2936
|
]
|
|
2922
2937
|
}, undefined, true, undefined, this)
|
|
2923
2938
|
]
|
|
@@ -2962,15 +2977,16 @@ function buildLocalTemplateCatalog(examples = listExamples(), templates = listTe
|
|
|
2962
2977
|
}).sort(compareLocalTemplateCatalogItems);
|
|
2963
2978
|
}
|
|
2964
2979
|
function matchesTemplateFilters(template, search, selectedTag) {
|
|
2980
|
+
return matchesTemplateSearch(template, search) && (selectedTag === null || template.tags.includes(selectedTag));
|
|
2981
|
+
}
|
|
2982
|
+
function matchesTemplateSearch(template, search) {
|
|
2965
2983
|
const haystack = [
|
|
2966
2984
|
template.title,
|
|
2967
2985
|
template.description,
|
|
2968
2986
|
template.tags.join(" ")
|
|
2969
2987
|
].join(" ").toLowerCase();
|
|
2970
2988
|
const searchTokens = search.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
2971
|
-
|
|
2972
|
-
const matchesTag = selectedTag === null || template.tags.includes(selectedTag);
|
|
2973
|
-
return matchesSearch && matchesTag;
|
|
2989
|
+
return searchTokens.length === 0 || searchTokens.every((token) => haystack.includes(token));
|
|
2974
2990
|
}
|
|
2975
2991
|
function formatExampleKindLabel(kind) {
|
|
2976
2992
|
return kind.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
@@ -3031,13 +3047,17 @@ function TemplatesCatalogSection({
|
|
|
3031
3047
|
source,
|
|
3032
3048
|
registryConfigured,
|
|
3033
3049
|
registryLoading,
|
|
3050
|
+
registryHasTemplates,
|
|
3034
3051
|
localTemplates,
|
|
3035
3052
|
registryTemplates,
|
|
3036
3053
|
localTemplateById,
|
|
3037
3054
|
onPreview,
|
|
3038
|
-
onUseTemplate
|
|
3055
|
+
onUseTemplate,
|
|
3056
|
+
hasSearch,
|
|
3057
|
+
selectedTag
|
|
3039
3058
|
}) {
|
|
3040
3059
|
const showRegistry = source === "registry" && registryConfigured;
|
|
3060
|
+
const emptyStateMessage = getEmptyStateMessage(hasSearch, selectedTag);
|
|
3041
3061
|
return /* @__PURE__ */ jsxDEV15("section", {
|
|
3042
3062
|
className: "section-padding",
|
|
3043
3063
|
children: /* @__PURE__ */ jsxDEV15("div", {
|
|
@@ -3048,12 +3068,18 @@ function TemplatesCatalogSection({
|
|
|
3048
3068
|
className: "text-muted-foreground",
|
|
3049
3069
|
children: "Loading community templates…"
|
|
3050
3070
|
}, undefined, false, undefined, this)
|
|
3051
|
-
}, undefined, false, undefined, this) :
|
|
3071
|
+
}, undefined, false, undefined, this) : !registryHasTemplates ? /* @__PURE__ */ jsxDEV15("div", {
|
|
3052
3072
|
className: "py-12 text-center",
|
|
3053
3073
|
children: /* @__PURE__ */ jsxDEV15("p", {
|
|
3054
3074
|
className: "text-muted-foreground",
|
|
3055
3075
|
children: "No community templates found."
|
|
3056
3076
|
}, undefined, false, undefined, this)
|
|
3077
|
+
}, undefined, false, undefined, this) : registryTemplates.length === 0 ? /* @__PURE__ */ jsxDEV15("div", {
|
|
3078
|
+
className: "py-12 text-center",
|
|
3079
|
+
children: /* @__PURE__ */ jsxDEV15("p", {
|
|
3080
|
+
className: "text-muted-foreground",
|
|
3081
|
+
children: emptyStateMessage
|
|
3082
|
+
}, undefined, false, undefined, this)
|
|
3057
3083
|
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV15("div", {
|
|
3058
3084
|
className: "grid gap-6 md:grid-cols-2 lg:grid-cols-3",
|
|
3059
3085
|
children: registryTemplates.map((template) => {
|
|
@@ -3089,7 +3115,7 @@ function TemplatesCatalogSection({
|
|
|
3089
3115
|
className: "py-12 text-center",
|
|
3090
3116
|
children: /* @__PURE__ */ jsxDEV15("p", {
|
|
3091
3117
|
className: "text-muted-foreground",
|
|
3092
|
-
children:
|
|
3118
|
+
children: emptyStateMessage
|
|
3093
3119
|
}, undefined, false, undefined, this)
|
|
3094
3120
|
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV15("div", {
|
|
3095
3121
|
className: "grid gap-6 md:grid-cols-2 lg:grid-cols-3",
|
|
@@ -3125,6 +3151,18 @@ function TemplatesCatalogSection({
|
|
|
3125
3151
|
}, undefined, false, undefined, this)
|
|
3126
3152
|
}, undefined, false, undefined, this);
|
|
3127
3153
|
}
|
|
3154
|
+
function getEmptyStateMessage(hasSearch, selectedTag) {
|
|
3155
|
+
if (selectedTag !== null && hasSearch) {
|
|
3156
|
+
return "No templates match this tag for the current search.";
|
|
3157
|
+
}
|
|
3158
|
+
if (selectedTag !== null) {
|
|
3159
|
+
return "No templates match this tag. Try another tag or reset filters.";
|
|
3160
|
+
}
|
|
3161
|
+
if (hasSearch) {
|
|
3162
|
+
return "No templates match your search. Try a different keyword.";
|
|
3163
|
+
}
|
|
3164
|
+
return "No templates match your filters. Try a different search.";
|
|
3165
|
+
}
|
|
3128
3166
|
|
|
3129
3167
|
// src/components/templates/TemplatesHeroSection.tsx
|
|
3130
3168
|
import { jsxDEV as jsxDEV16 } from "react/jsx-dev-runtime";
|
|
@@ -3351,6 +3389,82 @@ function TemplatePreviewModal({
|
|
|
3351
3389
|
}, undefined, false, undefined, this);
|
|
3352
3390
|
}
|
|
3353
3391
|
|
|
3392
|
+
// src/components/templates/TemplatesOverlays.tsx
|
|
3393
|
+
import {
|
|
3394
|
+
Dialog as Dialog4,
|
|
3395
|
+
DialogContent as DialogContent4,
|
|
3396
|
+
DialogDescription as DialogDescription3,
|
|
3397
|
+
DialogHeader as DialogHeader3,
|
|
3398
|
+
DialogTitle as DialogTitle3
|
|
3399
|
+
} from "@contractspec/lib.ui-kit-web/ui/dialog";
|
|
3400
|
+
import { jsxDEV as jsxDEV19, Fragment } from "react/jsx-dev-runtime";
|
|
3401
|
+
"use client";
|
|
3402
|
+
function TemplatesOverlays({
|
|
3403
|
+
previewTemplateId,
|
|
3404
|
+
onPreviewClose,
|
|
3405
|
+
studioSignupModalOpen,
|
|
3406
|
+
onStudioSignupModalOpenChange,
|
|
3407
|
+
selectedTemplateId,
|
|
3408
|
+
onTemplateCommandClose,
|
|
3409
|
+
onDeployStudio
|
|
3410
|
+
}) {
|
|
3411
|
+
return /* @__PURE__ */ jsxDEV19(Fragment, {
|
|
3412
|
+
children: [
|
|
3413
|
+
previewTemplateId ? /* @__PURE__ */ jsxDEV19(TemplatePreviewModal, {
|
|
3414
|
+
templateId: previewTemplateId,
|
|
3415
|
+
onClose: onPreviewClose
|
|
3416
|
+
}, undefined, false, undefined, this) : null,
|
|
3417
|
+
/* @__PURE__ */ jsxDEV19(Dialog4, {
|
|
3418
|
+
open: studioSignupModalOpen,
|
|
3419
|
+
onOpenChange: onStudioSignupModalOpenChange,
|
|
3420
|
+
children: /* @__PURE__ */ jsxDEV19(DialogContent4, {
|
|
3421
|
+
className: "max-h-[90vh] max-w-2xl overflow-y-auto",
|
|
3422
|
+
children: [
|
|
3423
|
+
/* @__PURE__ */ jsxDEV19(DialogHeader3, {
|
|
3424
|
+
children: [
|
|
3425
|
+
/* @__PURE__ */ jsxDEV19(DialogTitle3, {
|
|
3426
|
+
children: "Deploy in Studio"
|
|
3427
|
+
}, undefined, false, undefined, this),
|
|
3428
|
+
/* @__PURE__ */ jsxDEV19(DialogDescription3, {
|
|
3429
|
+
children: "Deploy templates in ContractSpec Studio and run the full evidence-to-spec loop with your team."
|
|
3430
|
+
}, undefined, false, undefined, this)
|
|
3431
|
+
]
|
|
3432
|
+
}, undefined, true, undefined, this),
|
|
3433
|
+
/* @__PURE__ */ jsxDEV19(StudioSignupSection, {
|
|
3434
|
+
variant: "compact"
|
|
3435
|
+
}, undefined, false, undefined, this)
|
|
3436
|
+
]
|
|
3437
|
+
}, undefined, true, undefined, this)
|
|
3438
|
+
}, undefined, false, undefined, this),
|
|
3439
|
+
/* @__PURE__ */ jsxDEV19(TemplateCommandDialog, {
|
|
3440
|
+
templateId: selectedTemplateId,
|
|
3441
|
+
onClose: onTemplateCommandClose,
|
|
3442
|
+
onDeployStudio
|
|
3443
|
+
}, undefined, false, undefined, this)
|
|
3444
|
+
]
|
|
3445
|
+
}, undefined, true, undefined, this);
|
|
3446
|
+
}
|
|
3447
|
+
|
|
3448
|
+
// src/components/templates/template-filters.ts
|
|
3449
|
+
function buildTemplateFilterState(templates, search, selectedTag, getCandidate) {
|
|
3450
|
+
const searchScopedTemplates = templates.filter((template) => matchesTemplateSearch(getCandidate(template), search));
|
|
3451
|
+
const finalTemplates = selectedTag === null ? searchScopedTemplates : searchScopedTemplates.filter((template) => getCandidate(template).tags.includes(selectedTag));
|
|
3452
|
+
return {
|
|
3453
|
+
searchScopedTemplates,
|
|
3454
|
+
finalTemplates,
|
|
3455
|
+
tagFacets: buildTemplateTagFacets(searchScopedTemplates, getCandidate)
|
|
3456
|
+
};
|
|
3457
|
+
}
|
|
3458
|
+
function buildTemplateTagFacets(templates, getCandidate) {
|
|
3459
|
+
const counts = new Map;
|
|
3460
|
+
for (const template of templates) {
|
|
3461
|
+
for (const tag of new Set(getCandidate(template).tags)) {
|
|
3462
|
+
counts.set(tag, (counts.get(tag) ?? 0) + 1);
|
|
3463
|
+
}
|
|
3464
|
+
}
|
|
3465
|
+
return [...counts.entries()].map(([tag, count]) => ({ tag, count })).sort((left, right) => right.count - left.count || left.tag.localeCompare(right.tag));
|
|
3466
|
+
}
|
|
3467
|
+
|
|
3354
3468
|
// src/components/templates/template-source.ts
|
|
3355
3469
|
function isRegistryConfigured(registryUrl) {
|
|
3356
3470
|
return Boolean(registryUrl?.trim());
|
|
@@ -3359,51 +3473,132 @@ function getAvailableTemplateSources(registryUrl) {
|
|
|
3359
3473
|
return isRegistryConfigured(registryUrl) ? ["local", "registry"] : ["local"];
|
|
3360
3474
|
}
|
|
3361
3475
|
|
|
3362
|
-
// src/components/templates/
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3476
|
+
// src/components/templates/template-tag-visibility.ts
|
|
3477
|
+
var DEFAULT_VISIBLE_TEMPLATE_TAGS = 10;
|
|
3478
|
+
function getVisibleTemplateTagFacets(tagFacets, selectedTag, expanded, visibleCount = DEFAULT_VISIBLE_TEMPLATE_TAGS) {
|
|
3479
|
+
if (expanded) {
|
|
3480
|
+
return {
|
|
3481
|
+
visibleTagFacets: pinSelectedTagFacet(tagFacets, selectedTag),
|
|
3482
|
+
hiddenTagFacets: []
|
|
3483
|
+
};
|
|
3484
|
+
}
|
|
3485
|
+
const visibleTagFacets = pinSelectedTagFacet(tagFacets.slice(0, visibleCount), selectedTag, tagFacets);
|
|
3486
|
+
const visibleTags = new Set(visibleTagFacets.map((facet) => facet.tag));
|
|
3487
|
+
return {
|
|
3488
|
+
visibleTagFacets,
|
|
3489
|
+
hiddenTagFacets: tagFacets.filter((facet) => !visibleTags.has(facet.tag))
|
|
3490
|
+
};
|
|
3491
|
+
}
|
|
3492
|
+
function pinSelectedTagFacet(tagFacets, selectedTag, fallbackTagFacets = tagFacets) {
|
|
3493
|
+
if (selectedTag === null || tagFacets.some((facet) => facet.tag === selectedTag)) {
|
|
3494
|
+
return [...tagFacets];
|
|
3495
|
+
}
|
|
3496
|
+
return [
|
|
3497
|
+
...tagFacets,
|
|
3498
|
+
fallbackTagFacets.find((facet) => facet.tag === selectedTag) ?? {
|
|
3499
|
+
tag: selectedTag,
|
|
3500
|
+
count: 0
|
|
3501
|
+
}
|
|
3502
|
+
];
|
|
3503
|
+
}
|
|
3504
|
+
|
|
3505
|
+
// src/components/templates/useTemplateBrowseState.ts
|
|
3367
3506
|
import { useRegistryTemplates } from "@contractspec/lib.example-shared-ui";
|
|
3368
|
-
import {
|
|
3369
|
-
Dialog as Dialog4,
|
|
3370
|
-
DialogContent as DialogContent4,
|
|
3371
|
-
DialogDescription as DialogDescription3,
|
|
3372
|
-
DialogHeader as DialogHeader3,
|
|
3373
|
-
DialogTitle as DialogTitle3
|
|
3374
|
-
} from "@contractspec/lib.ui-kit-web/ui/dialog";
|
|
3375
|
-
import { useMemo, useState as useState2 } from "react";
|
|
3376
|
-
import { jsxDEV as jsxDEV19, Fragment } from "react/jsx-dev-runtime";
|
|
3507
|
+
import { useEffect, useMemo, useState as useState2 } from "react";
|
|
3377
3508
|
"use client";
|
|
3378
3509
|
var REGISTRY_URL = process.env.NEXT_PUBLIC_CONTRACTSPEC_REGISTRY_URL;
|
|
3379
|
-
|
|
3510
|
+
function useTemplateBrowseState() {
|
|
3380
3511
|
const [selectedTag, setSelectedTag] = useState2(null);
|
|
3381
3512
|
const [search, setSearch] = useState2("");
|
|
3382
|
-
const [previewTemplateId, setPreviewTemplateId] = useState2(null);
|
|
3383
|
-
const [studioSignupModalOpen, setStudioSignupModalOpen] = useState2(false);
|
|
3384
|
-
const [selectedTemplateId, setSelectedTemplateId] = useState2(null);
|
|
3385
3513
|
const [source, setSource] = useState2("local");
|
|
3514
|
+
const [showAllTags, setShowAllTags] = useState2(false);
|
|
3386
3515
|
const registryConfigured = isRegistryConfigured(REGISTRY_URL);
|
|
3387
3516
|
const availableSources = getAvailableTemplateSources(REGISTRY_URL);
|
|
3388
3517
|
const localTemplates = useMemo(() => buildLocalTemplateCatalog(), []);
|
|
3389
3518
|
const localTemplateById = useMemo(() => new Map(localTemplates.map((template) => [template.id, template])), [localTemplates]);
|
|
3390
|
-
const availableTags = useMemo(() => Array.from(new Set(localTemplates.flatMap((template) => template.tags))).sort((left, right) => left.localeCompare(right)), [localTemplates]);
|
|
3391
3519
|
const { data: registryTemplates = [], isLoading: registryLoading } = useRegistryTemplates();
|
|
3392
|
-
const
|
|
3393
|
-
|
|
3520
|
+
const localFilterState = useMemo(() => buildTemplateFilterState(localTemplates, search, selectedTag, (template) => ({
|
|
3521
|
+
title: template.title,
|
|
3522
|
+
description: template.description,
|
|
3523
|
+
tags: template.tags
|
|
3524
|
+
})), [localTemplates, search, selectedTag]);
|
|
3525
|
+
const registryFilterState = useMemo(() => buildTemplateFilterState(registryTemplates, search, selectedTag, (template) => ({
|
|
3394
3526
|
title: template.name,
|
|
3395
3527
|
description: template.description,
|
|
3396
3528
|
tags: template.tags
|
|
3397
|
-
}
|
|
3398
|
-
|
|
3529
|
+
})), [registryTemplates, search, selectedTag]);
|
|
3530
|
+
const activeFilterState = source === "registry" ? registryFilterState : localFilterState;
|
|
3531
|
+
const suppressTagRail = source === "registry" && (registryLoading || registryTemplates.length === 0);
|
|
3532
|
+
const { visibleTagFacets, hiddenTagFacets } = useMemo(() => getVisibleTemplateTagFacets(activeFilterState.tagFacets, selectedTag, showAllTags), [activeFilterState.tagFacets, selectedTag, showAllTags]);
|
|
3533
|
+
const showTagFilters = !suppressTagRail && (visibleTagFacets.length > 0 || hiddenTagFacets.length > 0);
|
|
3534
|
+
useEffect(() => {
|
|
3535
|
+
setShowAllTags(false);
|
|
3536
|
+
}, [search, showTagFilters, source]);
|
|
3537
|
+
return {
|
|
3538
|
+
selectedTag,
|
|
3539
|
+
setSelectedTag,
|
|
3540
|
+
search,
|
|
3541
|
+
setSearch,
|
|
3542
|
+
source,
|
|
3543
|
+
setSource,
|
|
3544
|
+
showAllTags,
|
|
3545
|
+
setShowAllTags,
|
|
3546
|
+
registryConfigured,
|
|
3547
|
+
availableSources,
|
|
3548
|
+
localTemplates,
|
|
3549
|
+
localTemplateById,
|
|
3550
|
+
registryTemplates,
|
|
3551
|
+
registryLoading,
|
|
3552
|
+
localFilterState,
|
|
3553
|
+
registryFilterState,
|
|
3554
|
+
visibleTagFacets,
|
|
3555
|
+
hiddenTagFacets,
|
|
3556
|
+
showTagFilters
|
|
3557
|
+
};
|
|
3558
|
+
}
|
|
3559
|
+
|
|
3560
|
+
// src/components/templates/TemplatesClientPage.tsx
|
|
3561
|
+
import {
|
|
3562
|
+
analyticsEventNames as analyticsEventNames3,
|
|
3563
|
+
captureAnalyticsEvent as captureAnalyticsEvent3
|
|
3564
|
+
} from "@contractspec/bundle.library/libs/posthog/client";
|
|
3565
|
+
import { useState as useState3 } from "react";
|
|
3566
|
+
import { jsxDEV as jsxDEV20, Fragment as Fragment2 } from "react/jsx-dev-runtime";
|
|
3567
|
+
"use client";
|
|
3568
|
+
var TemplatesPage = () => {
|
|
3569
|
+
const [previewTemplateId, setPreviewTemplateId] = useState3(null);
|
|
3570
|
+
const [studioSignupModalOpen, setStudioSignupModalOpen] = useState3(false);
|
|
3571
|
+
const [selectedTemplateId, setSelectedTemplateId] = useState3(null);
|
|
3572
|
+
const {
|
|
3573
|
+
selectedTag,
|
|
3574
|
+
setSelectedTag,
|
|
3575
|
+
search,
|
|
3576
|
+
setSearch,
|
|
3577
|
+
source,
|
|
3578
|
+
setSource,
|
|
3579
|
+
showAllTags,
|
|
3580
|
+
setShowAllTags,
|
|
3581
|
+
registryConfigured,
|
|
3582
|
+
availableSources,
|
|
3583
|
+
localTemplates,
|
|
3584
|
+
localTemplateById,
|
|
3585
|
+
registryTemplates,
|
|
3586
|
+
registryLoading,
|
|
3587
|
+
localFilterState,
|
|
3588
|
+
registryFilterState,
|
|
3589
|
+
visibleTagFacets,
|
|
3590
|
+
hiddenTagFacets,
|
|
3591
|
+
showTagFilters
|
|
3592
|
+
} = useTemplateBrowseState();
|
|
3593
|
+
return /* @__PURE__ */ jsxDEV20(Fragment2, {
|
|
3399
3594
|
children: [
|
|
3400
|
-
/* @__PURE__ */
|
|
3595
|
+
/* @__PURE__ */ jsxDEV20("main", {
|
|
3401
3596
|
children: [
|
|
3402
|
-
/* @__PURE__ */
|
|
3597
|
+
/* @__PURE__ */ jsxDEV20(TemplatesHeroSection, {
|
|
3403
3598
|
localTemplateCount: localTemplates.length,
|
|
3404
3599
|
sourceCount: availableSources.length
|
|
3405
3600
|
}, undefined, false, undefined, this),
|
|
3406
|
-
/* @__PURE__ */
|
|
3601
|
+
/* @__PURE__ */ jsxDEV20(TemplatesBrowseControls, {
|
|
3407
3602
|
registryConfigured,
|
|
3408
3603
|
availableSources,
|
|
3409
3604
|
source,
|
|
@@ -3412,14 +3607,19 @@ var TemplatesPage = () => {
|
|
|
3412
3607
|
onSearchChange: setSearch,
|
|
3413
3608
|
selectedTag,
|
|
3414
3609
|
onTagChange: setSelectedTag,
|
|
3415
|
-
|
|
3610
|
+
showTagFilters,
|
|
3611
|
+
visibleTagFacets,
|
|
3612
|
+
hiddenTagFacets,
|
|
3613
|
+
showAllTags,
|
|
3614
|
+
onShowAllTagsChange: setShowAllTags
|
|
3416
3615
|
}, undefined, false, undefined, this),
|
|
3417
|
-
/* @__PURE__ */
|
|
3616
|
+
/* @__PURE__ */ jsxDEV20(TemplatesCatalogSection, {
|
|
3418
3617
|
source,
|
|
3419
3618
|
registryConfigured,
|
|
3420
3619
|
registryLoading,
|
|
3421
|
-
|
|
3422
|
-
|
|
3620
|
+
registryHasTemplates: registryTemplates.length > 0,
|
|
3621
|
+
localTemplates: localFilterState.finalTemplates,
|
|
3622
|
+
registryTemplates: registryFilterState.finalTemplates,
|
|
3423
3623
|
localTemplateById,
|
|
3424
3624
|
onPreview: setPreviewTemplateId,
|
|
3425
3625
|
onUseTemplate: (templateId, templateSource) => {
|
|
@@ -3429,40 +3629,20 @@ var TemplatesPage = () => {
|
|
|
3429
3629
|
source: templateSource
|
|
3430
3630
|
});
|
|
3431
3631
|
setSelectedTemplateId(templateId);
|
|
3432
|
-
}
|
|
3632
|
+
},
|
|
3633
|
+
hasSearch: search.trim().length > 0,
|
|
3634
|
+
selectedTag
|
|
3433
3635
|
}, undefined, false, undefined, this),
|
|
3434
|
-
/* @__PURE__ */
|
|
3636
|
+
/* @__PURE__ */ jsxDEV20(TemplatesNextStepsSection, {}, undefined, false, undefined, this)
|
|
3435
3637
|
]
|
|
3436
3638
|
}, undefined, true, undefined, this),
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
children: /* @__PURE__ */ jsxDEV19(DialogContent4, {
|
|
3445
|
-
className: "max-h-[90vh] max-w-2xl overflow-y-auto",
|
|
3446
|
-
children: [
|
|
3447
|
-
/* @__PURE__ */ jsxDEV19(DialogHeader3, {
|
|
3448
|
-
children: [
|
|
3449
|
-
/* @__PURE__ */ jsxDEV19(DialogTitle3, {
|
|
3450
|
-
children: "Deploy in Studio"
|
|
3451
|
-
}, undefined, false, undefined, this),
|
|
3452
|
-
/* @__PURE__ */ jsxDEV19(DialogDescription3, {
|
|
3453
|
-
children: "Deploy templates in ContractSpec Studio and run the full evidence-to-spec loop with your team."
|
|
3454
|
-
}, undefined, false, undefined, this)
|
|
3455
|
-
]
|
|
3456
|
-
}, undefined, true, undefined, this),
|
|
3457
|
-
/* @__PURE__ */ jsxDEV19(StudioSignupSection, {
|
|
3458
|
-
variant: "compact"
|
|
3459
|
-
}, undefined, false, undefined, this)
|
|
3460
|
-
]
|
|
3461
|
-
}, undefined, true, undefined, this)
|
|
3462
|
-
}, undefined, false, undefined, this),
|
|
3463
|
-
/* @__PURE__ */ jsxDEV19(TemplateCommandDialog, {
|
|
3464
|
-
templateId: selectedTemplateId,
|
|
3465
|
-
onClose: () => setSelectedTemplateId(null),
|
|
3639
|
+
/* @__PURE__ */ jsxDEV20(TemplatesOverlays, {
|
|
3640
|
+
previewTemplateId,
|
|
3641
|
+
onPreviewClose: () => setPreviewTemplateId(null),
|
|
3642
|
+
studioSignupModalOpen,
|
|
3643
|
+
onStudioSignupModalOpenChange: setStudioSignupModalOpen,
|
|
3644
|
+
selectedTemplateId,
|
|
3645
|
+
onTemplateCommandClose: () => setSelectedTemplateId(null),
|
|
3466
3646
|
onDeployStudio: () => {
|
|
3467
3647
|
setSelectedTemplateId(null);
|
|
3468
3648
|
setStudioSignupModalOpen(true);
|