@contractspec/bundle.marketing 3.8.8 → 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 +73 -29
- package/CHANGELOG.md +63 -0
- package/dist/browser/components/templates/TemplateCard.js +83 -0
- package/dist/browser/components/templates/TemplateCommandDialog.js +110 -0
- package/dist/browser/components/templates/TemplatePreviewContent.js +96 -0
- package/dist/browser/components/templates/TemplatesBrowseControls.js +130 -0
- package/dist/browser/components/templates/TemplatesCatalogSection.js +307 -0
- package/dist/browser/components/templates/TemplatesClientPage.js +1020 -917
- package/dist/browser/components/templates/TemplatesHeroSection.js +87 -0
- package/dist/browser/components/templates/TemplatesNextStepsSection.js +126 -0
- package/dist/browser/components/templates/TemplatesOverlays.js +2874 -0
- package/dist/browser/components/templates/TemplatesPreviewModal.js +136 -126
- package/dist/browser/components/templates/index.js +1055 -952
- package/dist/browser/components/templates/template-catalog.js +83 -0
- package/dist/browser/components/templates/template-filters.js +99 -0
- package/dist/browser/components/templates/template-new.js +23 -0
- package/dist/browser/components/templates/template-preview.js +43 -0
- package/dist/browser/components/templates/template-source.js +19 -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 +1055 -952
- package/dist/components/templates/TemplateCard.d.ts +12 -0
- package/dist/components/templates/TemplateCard.js +78 -0
- package/dist/components/templates/TemplateCommandDialog.d.ts +6 -0
- package/dist/components/templates/TemplateCommandDialog.js +105 -0
- package/dist/components/templates/TemplatePreviewContent.d.ts +5 -0
- package/dist/components/templates/TemplatePreviewContent.js +91 -0
- package/dist/components/templates/TemplatesBrowseControls.d.ts +18 -0
- package/dist/components/templates/TemplatesBrowseControls.js +125 -0
- package/dist/components/templates/TemplatesCatalogSection.d.ts +17 -0
- package/dist/components/templates/TemplatesCatalogSection.js +302 -0
- package/dist/components/templates/TemplatesClientPage.js +1020 -917
- package/dist/components/templates/TemplatesHeroSection.d.ts +5 -0
- package/dist/components/templates/TemplatesHeroSection.js +82 -0
- package/dist/components/templates/TemplatesNextStepsSection.d.ts +1 -0
- package/dist/components/templates/TemplatesNextStepsSection.js +121 -0
- package/dist/components/templates/TemplatesOverlays.d.ts +10 -0
- package/dist/components/templates/TemplatesOverlays.js +2869 -0
- package/dist/components/templates/TemplatesPreviewModal.d.ts +3 -4
- package/dist/components/templates/TemplatesPreviewModal.js +136 -126
- package/dist/components/templates/index.js +1055 -952
- package/dist/components/templates/template-catalog.d.ts +28 -0
- package/dist/components/templates/template-catalog.js +78 -0
- package/dist/components/templates/template-catalog.test.d.ts +1 -0
- package/dist/components/templates/template-filters.d.ts +12 -0
- package/dist/components/templates/template-filters.js +94 -0
- package/dist/components/templates/template-new.d.ts +2 -0
- package/dist/components/templates/template-new.js +18 -0
- package/dist/components/templates/template-preview.d.ts +18 -0
- package/dist/components/templates/template-preview.js +38 -0
- package/dist/components/templates/template-source.d.ts +3 -0
- package/dist/components/templates/template-source.js +14 -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 +1055 -952
- package/dist/node/components/templates/TemplateCard.js +78 -0
- package/dist/node/components/templates/TemplateCommandDialog.js +105 -0
- package/dist/node/components/templates/TemplatePreviewContent.js +91 -0
- package/dist/node/components/templates/TemplatesBrowseControls.js +125 -0
- package/dist/node/components/templates/TemplatesCatalogSection.js +302 -0
- package/dist/node/components/templates/TemplatesClientPage.js +1020 -917
- package/dist/node/components/templates/TemplatesHeroSection.js +82 -0
- package/dist/node/components/templates/TemplatesNextStepsSection.js +121 -0
- package/dist/node/components/templates/TemplatesOverlays.js +2869 -0
- package/dist/node/components/templates/TemplatesPreviewModal.js +136 -126
- package/dist/node/components/templates/index.js +1055 -952
- package/dist/node/components/templates/template-catalog.js +78 -0
- package/dist/node/components/templates/template-filters.js +94 -0
- package/dist/node/components/templates/template-new.js +18 -0
- package/dist/node/components/templates/template-preview.js +38 -0
- package/dist/node/components/templates/template-source.js +14 -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 +1055 -952
- package/package.json +237 -26
- package/src/components/templates/TemplateCard.tsx +74 -0
- package/src/components/templates/TemplateCommandDialog.tsx +92 -0
- package/src/components/templates/TemplatePreviewContent.tsx +182 -0
- package/src/components/templates/TemplatesBrowseControls.tsx +144 -0
- package/src/components/templates/TemplatesCatalogSection.tsx +191 -0
- package/src/components/templates/TemplatesClientPage.tsx +85 -773
- package/src/components/templates/TemplatesHeroSection.tsx +41 -0
- package/src/components/templates/TemplatesNextStepsSection.tsx +80 -0
- package/src/components/templates/TemplatesOverlays.tsx +65 -0
- package/src/components/templates/TemplatesPreviewModal.tsx +19 -294
- package/src/components/templates/template-catalog.test.ts +162 -0
- package/src/components/templates/template-catalog.ts +140 -0
- package/src/components/templates/template-filters.ts +57 -0
- package/src/components/templates/template-new.ts +12 -0
- package/src/components/templates/template-preview.ts +57 -0
- package/src/components/templates/template-source.ts +13 -0
- package/src/components/templates/template-tag-visibility.ts +58 -0
- package/src/components/templates/useTemplateBrowseState.ts +101 -0
- package/.turbo/turbo-prebuild.log +0 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ExampleKind, ExampleSandboxMode, ExampleSpec } from '@contractspec/lib.contracts-spec/examples/types';
|
|
2
|
+
import type { Stability } from '@contractspec/lib.contracts-spec/ownership';
|
|
3
|
+
import type { TemplateDefinition, TemplateId } from '@contractspec/lib.example-shared-ui';
|
|
4
|
+
export interface LocalTemplateCatalogItem {
|
|
5
|
+
id: TemplateId;
|
|
6
|
+
title: string;
|
|
7
|
+
description: string;
|
|
8
|
+
tags: string[];
|
|
9
|
+
kind: ExampleKind;
|
|
10
|
+
stability: Stability;
|
|
11
|
+
previewUrl: string;
|
|
12
|
+
featureList: string[];
|
|
13
|
+
sandboxModes: readonly ExampleSandboxMode[];
|
|
14
|
+
renderTargets: string[];
|
|
15
|
+
isNew: boolean;
|
|
16
|
+
packageName: string;
|
|
17
|
+
}
|
|
18
|
+
interface TemplateFilterCandidate {
|
|
19
|
+
title: string;
|
|
20
|
+
description: string;
|
|
21
|
+
tags: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
export declare function buildLocalTemplateCatalog(examples?: readonly ExampleSpec[], templates?: readonly TemplateDefinition[]): LocalTemplateCatalogItem[];
|
|
24
|
+
export declare function matchesTemplateFilters(template: TemplateFilterCandidate, search: string, selectedTag: string | null): boolean;
|
|
25
|
+
export declare function matchesTemplateSearch(template: TemplateFilterCandidate, search: string): boolean;
|
|
26
|
+
export declare function formatExampleKindLabel(kind: ExampleKind): string;
|
|
27
|
+
export declare function formatStabilityLabel(stability: Stability): string;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __require = import.meta.require;
|
|
3
|
+
|
|
4
|
+
// src/components/templates/template-new.ts
|
|
5
|
+
var NEW_TEMPLATE_IDS = [
|
|
6
|
+
"minimal",
|
|
7
|
+
"messaging-agent-actions",
|
|
8
|
+
"policy-safe-knowledge-assistant",
|
|
9
|
+
"visualization-showcase"
|
|
10
|
+
];
|
|
11
|
+
var NEW_TEMPLATE_ID_SET = new Set(NEW_TEMPLATE_IDS);
|
|
12
|
+
function isNewTemplateId(templateId) {
|
|
13
|
+
return NEW_TEMPLATE_ID_SET.has(templateId);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/components/templates/template-catalog.ts
|
|
17
|
+
import { listExamples, listTemplates } from "@contractspec/module.examples";
|
|
18
|
+
var NEW_TEMPLATE_INDEX = new Map(NEW_TEMPLATE_IDS.map((templateId, index) => [templateId, index]));
|
|
19
|
+
function buildLocalTemplateCatalog(examples = listExamples(), templates = listTemplates()) {
|
|
20
|
+
const templatesById = new Map(templates.map((template) => [template.id, template]));
|
|
21
|
+
return examples.filter((example) => example.meta.visibility === "public" && example.surfaces.templates).map((example) => {
|
|
22
|
+
const template = templatesById.get(example.meta.key);
|
|
23
|
+
const tags = Array.from(new Set(example.meta.tags.map((tag) => tag.trim()).filter(Boolean))).sort((left, right) => left.localeCompare(right));
|
|
24
|
+
return {
|
|
25
|
+
id: example.meta.key,
|
|
26
|
+
title: example.meta.title ?? template?.name ?? example.meta.key,
|
|
27
|
+
description: example.meta.summary ?? example.meta.description,
|
|
28
|
+
tags,
|
|
29
|
+
kind: example.meta.kind,
|
|
30
|
+
stability: example.meta.stability,
|
|
31
|
+
previewUrl: template?.preview?.demoUrl ?? `/sandbox?template=${encodeURIComponent(example.meta.key)}`,
|
|
32
|
+
featureList: [...template?.features ?? []],
|
|
33
|
+
sandboxModes: example.surfaces.sandbox.modes,
|
|
34
|
+
renderTargets: [...template?.renderTargets ?? []],
|
|
35
|
+
isNew: isNewTemplateId(example.meta.key),
|
|
36
|
+
packageName: example.entrypoints.packageName
|
|
37
|
+
};
|
|
38
|
+
}).sort(compareLocalTemplateCatalogItems);
|
|
39
|
+
}
|
|
40
|
+
function matchesTemplateFilters(template, search, selectedTag) {
|
|
41
|
+
return matchesTemplateSearch(template, search) && (selectedTag === null || template.tags.includes(selectedTag));
|
|
42
|
+
}
|
|
43
|
+
function matchesTemplateSearch(template, search) {
|
|
44
|
+
const haystack = [
|
|
45
|
+
template.title,
|
|
46
|
+
template.description,
|
|
47
|
+
template.tags.join(" ")
|
|
48
|
+
].join(" ").toLowerCase();
|
|
49
|
+
const searchTokens = search.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
50
|
+
return searchTokens.length === 0 || searchTokens.every((token) => haystack.includes(token));
|
|
51
|
+
}
|
|
52
|
+
function formatExampleKindLabel(kind) {
|
|
53
|
+
return kind.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
54
|
+
}
|
|
55
|
+
function formatStabilityLabel(stability) {
|
|
56
|
+
return stability.split("_").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
57
|
+
}
|
|
58
|
+
function compareLocalTemplateCatalogItems(left, right) {
|
|
59
|
+
const leftNewIndex = NEW_TEMPLATE_INDEX.get(left.id);
|
|
60
|
+
const rightNewIndex = NEW_TEMPLATE_INDEX.get(right.id);
|
|
61
|
+
if (leftNewIndex !== undefined || rightNewIndex !== undefined) {
|
|
62
|
+
if (leftNewIndex === undefined) {
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
if (rightNewIndex === undefined) {
|
|
66
|
+
return -1;
|
|
67
|
+
}
|
|
68
|
+
return leftNewIndex - rightNewIndex;
|
|
69
|
+
}
|
|
70
|
+
return left.title.localeCompare(right.title);
|
|
71
|
+
}
|
|
72
|
+
export {
|
|
73
|
+
matchesTemplateSearch,
|
|
74
|
+
matchesTemplateFilters,
|
|
75
|
+
formatStabilityLabel,
|
|
76
|
+
formatExampleKindLabel,
|
|
77
|
+
buildLocalTemplateCatalog
|
|
78
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TemplateTagFacet } from './template-tag-visibility';
|
|
2
|
+
export interface TemplateFilterCandidate {
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
tags: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
export interface TemplateFilterState<TTemplate> {
|
|
8
|
+
searchScopedTemplates: TTemplate[];
|
|
9
|
+
finalTemplates: TTemplate[];
|
|
10
|
+
tagFacets: TemplateTagFacet[];
|
|
11
|
+
}
|
|
12
|
+
export declare function buildTemplateFilterState<TTemplate>(templates: readonly TTemplate[], search: string, selectedTag: string | null, getCandidate: (template: TTemplate) => TemplateFilterCandidate): TemplateFilterState<TTemplate>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __require = import.meta.require;
|
|
3
|
+
|
|
4
|
+
// src/components/templates/template-new.ts
|
|
5
|
+
var NEW_TEMPLATE_IDS = [
|
|
6
|
+
"minimal",
|
|
7
|
+
"messaging-agent-actions",
|
|
8
|
+
"policy-safe-knowledge-assistant",
|
|
9
|
+
"visualization-showcase"
|
|
10
|
+
];
|
|
11
|
+
var NEW_TEMPLATE_ID_SET = new Set(NEW_TEMPLATE_IDS);
|
|
12
|
+
function isNewTemplateId(templateId) {
|
|
13
|
+
return NEW_TEMPLATE_ID_SET.has(templateId);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/components/templates/template-catalog.ts
|
|
17
|
+
import { listExamples, listTemplates } from "@contractspec/module.examples";
|
|
18
|
+
var NEW_TEMPLATE_INDEX = new Map(NEW_TEMPLATE_IDS.map((templateId, index) => [templateId, index]));
|
|
19
|
+
function buildLocalTemplateCatalog(examples = listExamples(), templates = listTemplates()) {
|
|
20
|
+
const templatesById = new Map(templates.map((template) => [template.id, template]));
|
|
21
|
+
return examples.filter((example) => example.meta.visibility === "public" && example.surfaces.templates).map((example) => {
|
|
22
|
+
const template = templatesById.get(example.meta.key);
|
|
23
|
+
const tags = Array.from(new Set(example.meta.tags.map((tag) => tag.trim()).filter(Boolean))).sort((left, right) => left.localeCompare(right));
|
|
24
|
+
return {
|
|
25
|
+
id: example.meta.key,
|
|
26
|
+
title: example.meta.title ?? template?.name ?? example.meta.key,
|
|
27
|
+
description: example.meta.summary ?? example.meta.description,
|
|
28
|
+
tags,
|
|
29
|
+
kind: example.meta.kind,
|
|
30
|
+
stability: example.meta.stability,
|
|
31
|
+
previewUrl: template?.preview?.demoUrl ?? `/sandbox?template=${encodeURIComponent(example.meta.key)}`,
|
|
32
|
+
featureList: [...template?.features ?? []],
|
|
33
|
+
sandboxModes: example.surfaces.sandbox.modes,
|
|
34
|
+
renderTargets: [...template?.renderTargets ?? []],
|
|
35
|
+
isNew: isNewTemplateId(example.meta.key),
|
|
36
|
+
packageName: example.entrypoints.packageName
|
|
37
|
+
};
|
|
38
|
+
}).sort(compareLocalTemplateCatalogItems);
|
|
39
|
+
}
|
|
40
|
+
function matchesTemplateFilters(template, search, selectedTag) {
|
|
41
|
+
return matchesTemplateSearch(template, search) && (selectedTag === null || template.tags.includes(selectedTag));
|
|
42
|
+
}
|
|
43
|
+
function matchesTemplateSearch(template, search) {
|
|
44
|
+
const haystack = [
|
|
45
|
+
template.title,
|
|
46
|
+
template.description,
|
|
47
|
+
template.tags.join(" ")
|
|
48
|
+
].join(" ").toLowerCase();
|
|
49
|
+
const searchTokens = search.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
50
|
+
return searchTokens.length === 0 || searchTokens.every((token) => haystack.includes(token));
|
|
51
|
+
}
|
|
52
|
+
function formatExampleKindLabel(kind) {
|
|
53
|
+
return kind.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
54
|
+
}
|
|
55
|
+
function formatStabilityLabel(stability) {
|
|
56
|
+
return stability.split("_").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
57
|
+
}
|
|
58
|
+
function compareLocalTemplateCatalogItems(left, right) {
|
|
59
|
+
const leftNewIndex = NEW_TEMPLATE_INDEX.get(left.id);
|
|
60
|
+
const rightNewIndex = NEW_TEMPLATE_INDEX.get(right.id);
|
|
61
|
+
if (leftNewIndex !== undefined || rightNewIndex !== undefined) {
|
|
62
|
+
if (leftNewIndex === undefined) {
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
if (rightNewIndex === undefined) {
|
|
66
|
+
return -1;
|
|
67
|
+
}
|
|
68
|
+
return leftNewIndex - rightNewIndex;
|
|
69
|
+
}
|
|
70
|
+
return left.title.localeCompare(right.title);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/components/templates/template-filters.ts
|
|
74
|
+
function buildTemplateFilterState(templates, search, selectedTag, getCandidate) {
|
|
75
|
+
const searchScopedTemplates = templates.filter((template) => matchesTemplateSearch(getCandidate(template), search));
|
|
76
|
+
const finalTemplates = selectedTag === null ? searchScopedTemplates : searchScopedTemplates.filter((template) => getCandidate(template).tags.includes(selectedTag));
|
|
77
|
+
return {
|
|
78
|
+
searchScopedTemplates,
|
|
79
|
+
finalTemplates,
|
|
80
|
+
tagFacets: buildTemplateTagFacets(searchScopedTemplates, getCandidate)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function buildTemplateTagFacets(templates, getCandidate) {
|
|
84
|
+
const counts = new Map;
|
|
85
|
+
for (const template of templates) {
|
|
86
|
+
for (const tag of new Set(getCandidate(template).tags)) {
|
|
87
|
+
counts.set(tag, (counts.get(tag) ?? 0) + 1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return [...counts.entries()].map(([tag, count]) => ({ tag, count })).sort((left, right) => right.count - left.count || left.tag.localeCompare(right.tag));
|
|
91
|
+
}
|
|
92
|
+
export {
|
|
93
|
+
buildTemplateFilterState
|
|
94
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __require = import.meta.require;
|
|
3
|
+
|
|
4
|
+
// src/components/templates/template-new.ts
|
|
5
|
+
var NEW_TEMPLATE_IDS = [
|
|
6
|
+
"minimal",
|
|
7
|
+
"messaging-agent-actions",
|
|
8
|
+
"policy-safe-knowledge-assistant",
|
|
9
|
+
"visualization-showcase"
|
|
10
|
+
];
|
|
11
|
+
var NEW_TEMPLATE_ID_SET = new Set(NEW_TEMPLATE_IDS);
|
|
12
|
+
function isNewTemplateId(templateId) {
|
|
13
|
+
return NEW_TEMPLATE_ID_SET.has(templateId);
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
isNewTemplateId,
|
|
17
|
+
NEW_TEMPLATE_IDS
|
|
18
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { RegistryTemplate, TemplateId } from '@contractspec/lib.example-shared-ui';
|
|
2
|
+
import type { LocalTemplateCatalogItem } from './template-catalog';
|
|
3
|
+
export type TemplatePreviewAction = {
|
|
4
|
+
kind: 'modal';
|
|
5
|
+
templateId: TemplateId;
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'sandbox';
|
|
8
|
+
href: string;
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'disabled';
|
|
11
|
+
};
|
|
12
|
+
export type LocalTemplatePreviewAction = Exclude<TemplatePreviewAction, {
|
|
13
|
+
kind: 'disabled';
|
|
14
|
+
}>;
|
|
15
|
+
export declare const INLINE_TEMPLATE_PREVIEW_IDS: readonly ["agent-console", "ai-chat-assistant", "analytics-dashboard", "crm-pipeline", "data-grid-showcase", "integration-hub", "marketplace", "saas-boilerplate", "visualization-showcase", "workflow-system"];
|
|
16
|
+
export declare function supportsInlineTemplatePreview(templateId: TemplateId): boolean;
|
|
17
|
+
export declare function getLocalTemplatePreviewAction(template: LocalTemplateCatalogItem): LocalTemplatePreviewAction;
|
|
18
|
+
export declare function getRegistryTemplatePreviewAction(template: RegistryTemplate, localTemplate?: LocalTemplateCatalogItem): TemplatePreviewAction;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __require = import.meta.require;
|
|
3
|
+
|
|
4
|
+
// src/components/templates/template-preview.ts
|
|
5
|
+
var INLINE_TEMPLATE_PREVIEW_IDS = [
|
|
6
|
+
"agent-console",
|
|
7
|
+
"ai-chat-assistant",
|
|
8
|
+
"analytics-dashboard",
|
|
9
|
+
"crm-pipeline",
|
|
10
|
+
"data-grid-showcase",
|
|
11
|
+
"integration-hub",
|
|
12
|
+
"marketplace",
|
|
13
|
+
"saas-boilerplate",
|
|
14
|
+
"visualization-showcase",
|
|
15
|
+
"workflow-system"
|
|
16
|
+
];
|
|
17
|
+
var INLINE_TEMPLATE_PREVIEW_SET = new Set(INLINE_TEMPLATE_PREVIEW_IDS);
|
|
18
|
+
function supportsInlineTemplatePreview(templateId) {
|
|
19
|
+
return INLINE_TEMPLATE_PREVIEW_SET.has(templateId);
|
|
20
|
+
}
|
|
21
|
+
function getLocalTemplatePreviewAction(template) {
|
|
22
|
+
if (supportsInlineTemplatePreview(template.id)) {
|
|
23
|
+
return { kind: "modal", templateId: template.id };
|
|
24
|
+
}
|
|
25
|
+
return { kind: "sandbox", href: template.previewUrl };
|
|
26
|
+
}
|
|
27
|
+
function getRegistryTemplatePreviewAction(template, localTemplate) {
|
|
28
|
+
if (!localTemplate) {
|
|
29
|
+
return { kind: "disabled" };
|
|
30
|
+
}
|
|
31
|
+
return getLocalTemplatePreviewAction(localTemplate);
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
supportsInlineTemplatePreview,
|
|
35
|
+
getRegistryTemplatePreviewAction,
|
|
36
|
+
getLocalTemplatePreviewAction,
|
|
37
|
+
INLINE_TEMPLATE_PREVIEW_IDS
|
|
38
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __require = import.meta.require;
|
|
3
|
+
|
|
4
|
+
// src/components/templates/template-source.ts
|
|
5
|
+
function isRegistryConfigured(registryUrl) {
|
|
6
|
+
return Boolean(registryUrl?.trim());
|
|
7
|
+
}
|
|
8
|
+
function getAvailableTemplateSources(registryUrl) {
|
|
9
|
+
return isRegistryConfigured(registryUrl) ? ["local", "registry"] : ["local"];
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
isRegistryConfigured,
|
|
13
|
+
getAvailableTemplateSources
|
|
14
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const DEFAULT_VISIBLE_TEMPLATE_TAGS = 10;
|
|
2
|
+
export interface TemplateTagFacet {
|
|
3
|
+
tag: string;
|
|
4
|
+
count: number;
|
|
5
|
+
}
|
|
6
|
+
export interface VisibleTemplateTagFacets {
|
|
7
|
+
visibleTagFacets: TemplateTagFacet[];
|
|
8
|
+
hiddenTagFacets: TemplateTagFacet[];
|
|
9
|
+
}
|
|
10
|
+
export declare function getVisibleTemplateTagFacets(tagFacets: readonly TemplateTagFacet[], selectedTag: string | null, expanded: boolean, visibleCount?: number): VisibleTemplateTagFacets;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __require = import.meta.require;
|
|
3
|
+
|
|
4
|
+
// src/components/templates/template-tag-visibility.ts
|
|
5
|
+
var DEFAULT_VISIBLE_TEMPLATE_TAGS = 10;
|
|
6
|
+
function getVisibleTemplateTagFacets(tagFacets, selectedTag, expanded, visibleCount = DEFAULT_VISIBLE_TEMPLATE_TAGS) {
|
|
7
|
+
if (expanded) {
|
|
8
|
+
return {
|
|
9
|
+
visibleTagFacets: pinSelectedTagFacet(tagFacets, selectedTag),
|
|
10
|
+
hiddenTagFacets: []
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const visibleTagFacets = pinSelectedTagFacet(tagFacets.slice(0, visibleCount), selectedTag, tagFacets);
|
|
14
|
+
const visibleTags = new Set(visibleTagFacets.map((facet) => facet.tag));
|
|
15
|
+
return {
|
|
16
|
+
visibleTagFacets,
|
|
17
|
+
hiddenTagFacets: tagFacets.filter((facet) => !visibleTags.has(facet.tag))
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function pinSelectedTagFacet(tagFacets, selectedTag, fallbackTagFacets = tagFacets) {
|
|
21
|
+
if (selectedTag === null || tagFacets.some((facet) => facet.tag === selectedTag)) {
|
|
22
|
+
return [...tagFacets];
|
|
23
|
+
}
|
|
24
|
+
return [
|
|
25
|
+
...tagFacets,
|
|
26
|
+
fallbackTagFacets.find((facet) => facet.tag === selectedTag) ?? {
|
|
27
|
+
tag: selectedTag,
|
|
28
|
+
count: 0
|
|
29
|
+
}
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
getVisibleTemplateTagFacets,
|
|
34
|
+
DEFAULT_VISIBLE_TEMPLATE_TAGS
|
|
35
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type TemplateSource } from './template-source';
|
|
2
|
+
export declare function useTemplateBrowseState(): {
|
|
3
|
+
selectedTag: string | null;
|
|
4
|
+
setSelectedTag: import("react").Dispatch<import("react").SetStateAction<string | null>>;
|
|
5
|
+
search: string;
|
|
6
|
+
setSearch: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
7
|
+
source: TemplateSource;
|
|
8
|
+
setSource: import("react").Dispatch<import("react").SetStateAction<TemplateSource>>;
|
|
9
|
+
showAllTags: boolean;
|
|
10
|
+
setShowAllTags: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
11
|
+
registryConfigured: boolean;
|
|
12
|
+
availableSources: readonly TemplateSource[];
|
|
13
|
+
localTemplates: import("./template-catalog").LocalTemplateCatalogItem[];
|
|
14
|
+
localTemplateById: Map<string, import("./template-catalog").LocalTemplateCatalogItem>;
|
|
15
|
+
registryTemplates: import("@contractspec/lib.example-shared-ui").RegistryTemplate[];
|
|
16
|
+
registryLoading: boolean;
|
|
17
|
+
localFilterState: import("./template-filters").TemplateFilterState<import("./template-catalog").LocalTemplateCatalogItem>;
|
|
18
|
+
registryFilterState: import("./template-filters").TemplateFilterState<import("@contractspec/lib.example-shared-ui").RegistryTemplate>;
|
|
19
|
+
visibleTagFacets: import("./template-tag-visibility").TemplateTagFacet[];
|
|
20
|
+
hiddenTagFacets: import("./template-tag-visibility").TemplateTagFacet[];
|
|
21
|
+
showTagFilters: boolean;
|
|
22
|
+
};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __require = import.meta.require;
|
|
3
|
+
|
|
4
|
+
// src/components/templates/template-new.ts
|
|
5
|
+
var NEW_TEMPLATE_IDS = [
|
|
6
|
+
"minimal",
|
|
7
|
+
"messaging-agent-actions",
|
|
8
|
+
"policy-safe-knowledge-assistant",
|
|
9
|
+
"visualization-showcase"
|
|
10
|
+
];
|
|
11
|
+
var NEW_TEMPLATE_ID_SET = new Set(NEW_TEMPLATE_IDS);
|
|
12
|
+
function isNewTemplateId(templateId) {
|
|
13
|
+
return NEW_TEMPLATE_ID_SET.has(templateId);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/components/templates/template-catalog.ts
|
|
17
|
+
import { listExamples, listTemplates } from "@contractspec/module.examples";
|
|
18
|
+
var NEW_TEMPLATE_INDEX = new Map(NEW_TEMPLATE_IDS.map((templateId, index) => [templateId, index]));
|
|
19
|
+
function buildLocalTemplateCatalog(examples = listExamples(), templates = listTemplates()) {
|
|
20
|
+
const templatesById = new Map(templates.map((template) => [template.id, template]));
|
|
21
|
+
return examples.filter((example) => example.meta.visibility === "public" && example.surfaces.templates).map((example) => {
|
|
22
|
+
const template = templatesById.get(example.meta.key);
|
|
23
|
+
const tags = Array.from(new Set(example.meta.tags.map((tag) => tag.trim()).filter(Boolean))).sort((left, right) => left.localeCompare(right));
|
|
24
|
+
return {
|
|
25
|
+
id: example.meta.key,
|
|
26
|
+
title: example.meta.title ?? template?.name ?? example.meta.key,
|
|
27
|
+
description: example.meta.summary ?? example.meta.description,
|
|
28
|
+
tags,
|
|
29
|
+
kind: example.meta.kind,
|
|
30
|
+
stability: example.meta.stability,
|
|
31
|
+
previewUrl: template?.preview?.demoUrl ?? `/sandbox?template=${encodeURIComponent(example.meta.key)}`,
|
|
32
|
+
featureList: [...template?.features ?? []],
|
|
33
|
+
sandboxModes: example.surfaces.sandbox.modes,
|
|
34
|
+
renderTargets: [...template?.renderTargets ?? []],
|
|
35
|
+
isNew: isNewTemplateId(example.meta.key),
|
|
36
|
+
packageName: example.entrypoints.packageName
|
|
37
|
+
};
|
|
38
|
+
}).sort(compareLocalTemplateCatalogItems);
|
|
39
|
+
}
|
|
40
|
+
function matchesTemplateFilters(template, search, selectedTag) {
|
|
41
|
+
return matchesTemplateSearch(template, search) && (selectedTag === null || template.tags.includes(selectedTag));
|
|
42
|
+
}
|
|
43
|
+
function matchesTemplateSearch(template, search) {
|
|
44
|
+
const haystack = [
|
|
45
|
+
template.title,
|
|
46
|
+
template.description,
|
|
47
|
+
template.tags.join(" ")
|
|
48
|
+
].join(" ").toLowerCase();
|
|
49
|
+
const searchTokens = search.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
50
|
+
return searchTokens.length === 0 || searchTokens.every((token) => haystack.includes(token));
|
|
51
|
+
}
|
|
52
|
+
function formatExampleKindLabel(kind) {
|
|
53
|
+
return kind.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
54
|
+
}
|
|
55
|
+
function formatStabilityLabel(stability) {
|
|
56
|
+
return stability.split("_").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
57
|
+
}
|
|
58
|
+
function compareLocalTemplateCatalogItems(left, right) {
|
|
59
|
+
const leftNewIndex = NEW_TEMPLATE_INDEX.get(left.id);
|
|
60
|
+
const rightNewIndex = NEW_TEMPLATE_INDEX.get(right.id);
|
|
61
|
+
if (leftNewIndex !== undefined || rightNewIndex !== undefined) {
|
|
62
|
+
if (leftNewIndex === undefined) {
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
if (rightNewIndex === undefined) {
|
|
66
|
+
return -1;
|
|
67
|
+
}
|
|
68
|
+
return leftNewIndex - rightNewIndex;
|
|
69
|
+
}
|
|
70
|
+
return left.title.localeCompare(right.title);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/components/templates/template-filters.ts
|
|
74
|
+
function buildTemplateFilterState(templates, search, selectedTag, getCandidate) {
|
|
75
|
+
const searchScopedTemplates = templates.filter((template) => matchesTemplateSearch(getCandidate(template), search));
|
|
76
|
+
const finalTemplates = selectedTag === null ? searchScopedTemplates : searchScopedTemplates.filter((template) => getCandidate(template).tags.includes(selectedTag));
|
|
77
|
+
return {
|
|
78
|
+
searchScopedTemplates,
|
|
79
|
+
finalTemplates,
|
|
80
|
+
tagFacets: buildTemplateTagFacets(searchScopedTemplates, getCandidate)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function buildTemplateTagFacets(templates, getCandidate) {
|
|
84
|
+
const counts = new Map;
|
|
85
|
+
for (const template of templates) {
|
|
86
|
+
for (const tag of new Set(getCandidate(template).tags)) {
|
|
87
|
+
counts.set(tag, (counts.get(tag) ?? 0) + 1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return [...counts.entries()].map(([tag, count]) => ({ tag, count })).sort((left, right) => right.count - left.count || left.tag.localeCompare(right.tag));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/components/templates/template-source.ts
|
|
94
|
+
function isRegistryConfigured(registryUrl) {
|
|
95
|
+
return Boolean(registryUrl?.trim());
|
|
96
|
+
}
|
|
97
|
+
function getAvailableTemplateSources(registryUrl) {
|
|
98
|
+
return isRegistryConfigured(registryUrl) ? ["local", "registry"] : ["local"];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/components/templates/template-tag-visibility.ts
|
|
102
|
+
var DEFAULT_VISIBLE_TEMPLATE_TAGS = 10;
|
|
103
|
+
function getVisibleTemplateTagFacets(tagFacets, selectedTag, expanded, visibleCount = DEFAULT_VISIBLE_TEMPLATE_TAGS) {
|
|
104
|
+
if (expanded) {
|
|
105
|
+
return {
|
|
106
|
+
visibleTagFacets: pinSelectedTagFacet(tagFacets, selectedTag),
|
|
107
|
+
hiddenTagFacets: []
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const visibleTagFacets = pinSelectedTagFacet(tagFacets.slice(0, visibleCount), selectedTag, tagFacets);
|
|
111
|
+
const visibleTags = new Set(visibleTagFacets.map((facet) => facet.tag));
|
|
112
|
+
return {
|
|
113
|
+
visibleTagFacets,
|
|
114
|
+
hiddenTagFacets: tagFacets.filter((facet) => !visibleTags.has(facet.tag))
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function pinSelectedTagFacet(tagFacets, selectedTag, fallbackTagFacets = tagFacets) {
|
|
118
|
+
if (selectedTag === null || tagFacets.some((facet) => facet.tag === selectedTag)) {
|
|
119
|
+
return [...tagFacets];
|
|
120
|
+
}
|
|
121
|
+
return [
|
|
122
|
+
...tagFacets,
|
|
123
|
+
fallbackTagFacets.find((facet) => facet.tag === selectedTag) ?? {
|
|
124
|
+
tag: selectedTag,
|
|
125
|
+
count: 0
|
|
126
|
+
}
|
|
127
|
+
];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/components/templates/useTemplateBrowseState.ts
|
|
131
|
+
import { useRegistryTemplates } from "@contractspec/lib.example-shared-ui";
|
|
132
|
+
import { useEffect, useMemo, useState } from "react";
|
|
133
|
+
"use client";
|
|
134
|
+
var REGISTRY_URL = process.env.NEXT_PUBLIC_CONTRACTSPEC_REGISTRY_URL;
|
|
135
|
+
function useTemplateBrowseState() {
|
|
136
|
+
const [selectedTag, setSelectedTag] = useState(null);
|
|
137
|
+
const [search, setSearch] = useState("");
|
|
138
|
+
const [source, setSource] = useState("local");
|
|
139
|
+
const [showAllTags, setShowAllTags] = useState(false);
|
|
140
|
+
const registryConfigured = isRegistryConfigured(REGISTRY_URL);
|
|
141
|
+
const availableSources = getAvailableTemplateSources(REGISTRY_URL);
|
|
142
|
+
const localTemplates = useMemo(() => buildLocalTemplateCatalog(), []);
|
|
143
|
+
const localTemplateById = useMemo(() => new Map(localTemplates.map((template) => [template.id, template])), [localTemplates]);
|
|
144
|
+
const { data: registryTemplates = [], isLoading: registryLoading } = useRegistryTemplates();
|
|
145
|
+
const localFilterState = useMemo(() => buildTemplateFilterState(localTemplates, search, selectedTag, (template) => ({
|
|
146
|
+
title: template.title,
|
|
147
|
+
description: template.description,
|
|
148
|
+
tags: template.tags
|
|
149
|
+
})), [localTemplates, search, selectedTag]);
|
|
150
|
+
const registryFilterState = useMemo(() => buildTemplateFilterState(registryTemplates, search, selectedTag, (template) => ({
|
|
151
|
+
title: template.name,
|
|
152
|
+
description: template.description,
|
|
153
|
+
tags: template.tags
|
|
154
|
+
})), [registryTemplates, search, selectedTag]);
|
|
155
|
+
const activeFilterState = source === "registry" ? registryFilterState : localFilterState;
|
|
156
|
+
const suppressTagRail = source === "registry" && (registryLoading || registryTemplates.length === 0);
|
|
157
|
+
const { visibleTagFacets, hiddenTagFacets } = useMemo(() => getVisibleTemplateTagFacets(activeFilterState.tagFacets, selectedTag, showAllTags), [activeFilterState.tagFacets, selectedTag, showAllTags]);
|
|
158
|
+
const showTagFilters = !suppressTagRail && (visibleTagFacets.length > 0 || hiddenTagFacets.length > 0);
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
setShowAllTags(false);
|
|
161
|
+
}, [search, showTagFilters, source]);
|
|
162
|
+
return {
|
|
163
|
+
selectedTag,
|
|
164
|
+
setSelectedTag,
|
|
165
|
+
search,
|
|
166
|
+
setSearch,
|
|
167
|
+
source,
|
|
168
|
+
setSource,
|
|
169
|
+
showAllTags,
|
|
170
|
+
setShowAllTags,
|
|
171
|
+
registryConfigured,
|
|
172
|
+
availableSources,
|
|
173
|
+
localTemplates,
|
|
174
|
+
localTemplateById,
|
|
175
|
+
registryTemplates,
|
|
176
|
+
registryLoading,
|
|
177
|
+
localFilterState,
|
|
178
|
+
registryFilterState,
|
|
179
|
+
visibleTagFacets,
|
|
180
|
+
hiddenTagFacets,
|
|
181
|
+
showTagFilters
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
export {
|
|
185
|
+
useTemplateBrowseState
|
|
186
|
+
};
|