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