@contractspec/bundle.marketing 3.8.7 → 3.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/.turbo/turbo-build.log +64 -32
  2. package/CHANGELOG.md +63 -0
  3. package/dist/browser/components/templates/TemplateCard.js +83 -0
  4. package/dist/browser/components/templates/TemplateCommandDialog.js +110 -0
  5. package/dist/browser/components/templates/TemplatePreviewContent.js +96 -0
  6. package/dist/browser/components/templates/TemplatesBrowseControls.js +115 -0
  7. package/dist/browser/components/templates/TemplatesCatalogSection.js +284 -0
  8. package/dist/browser/components/templates/TemplatesClientPage.js +840 -917
  9. package/dist/browser/components/templates/TemplatesHeroSection.js +87 -0
  10. package/dist/browser/components/templates/TemplatesNextStepsSection.js +126 -0
  11. package/dist/browser/components/templates/TemplatesPreviewModal.js +136 -126
  12. package/dist/browser/components/templates/index.js +873 -950
  13. package/dist/browser/components/templates/template-catalog.js +81 -0
  14. package/dist/browser/components/templates/template-new.js +23 -0
  15. package/dist/browser/components/templates/template-preview.js +43 -0
  16. package/dist/browser/components/templates/template-source.js +19 -0
  17. package/dist/browser/index.js +873 -950
  18. package/dist/components/templates/TemplateCard.d.ts +12 -0
  19. package/dist/components/templates/TemplateCard.js +78 -0
  20. package/dist/components/templates/TemplateCommandDialog.d.ts +6 -0
  21. package/dist/components/templates/TemplateCommandDialog.js +105 -0
  22. package/dist/components/templates/TemplatePreviewContent.d.ts +5 -0
  23. package/dist/components/templates/TemplatePreviewContent.js +91 -0
  24. package/dist/components/templates/TemplatesBrowseControls.d.ts +13 -0
  25. package/dist/components/templates/TemplatesBrowseControls.js +110 -0
  26. package/dist/components/templates/TemplatesCatalogSection.d.ts +14 -0
  27. package/dist/components/templates/TemplatesCatalogSection.js +279 -0
  28. package/dist/components/templates/TemplatesClientPage.js +840 -917
  29. package/dist/components/templates/TemplatesHeroSection.d.ts +5 -0
  30. package/dist/components/templates/TemplatesHeroSection.js +82 -0
  31. package/dist/components/templates/TemplatesNextStepsSection.d.ts +1 -0
  32. package/dist/components/templates/TemplatesNextStepsSection.js +121 -0
  33. package/dist/components/templates/TemplatesPreviewModal.d.ts +3 -4
  34. package/dist/components/templates/TemplatesPreviewModal.js +136 -126
  35. package/dist/components/templates/index.js +873 -950
  36. package/dist/components/templates/template-catalog.d.ts +27 -0
  37. package/dist/components/templates/template-catalog.js +76 -0
  38. package/dist/components/templates/template-catalog.test.d.ts +1 -0
  39. package/dist/components/templates/template-new.d.ts +2 -0
  40. package/dist/components/templates/template-new.js +18 -0
  41. package/dist/components/templates/template-preview.d.ts +18 -0
  42. package/dist/components/templates/template-preview.js +38 -0
  43. package/dist/components/templates/template-source.d.ts +3 -0
  44. package/dist/components/templates/template-source.js +14 -0
  45. package/dist/index.js +873 -950
  46. package/dist/node/components/templates/TemplateCard.js +78 -0
  47. package/dist/node/components/templates/TemplateCommandDialog.js +105 -0
  48. package/dist/node/components/templates/TemplatePreviewContent.js +91 -0
  49. package/dist/node/components/templates/TemplatesBrowseControls.js +110 -0
  50. package/dist/node/components/templates/TemplatesCatalogSection.js +279 -0
  51. package/dist/node/components/templates/TemplatesClientPage.js +840 -917
  52. package/dist/node/components/templates/TemplatesHeroSection.js +82 -0
  53. package/dist/node/components/templates/TemplatesNextStepsSection.js +121 -0
  54. package/dist/node/components/templates/TemplatesPreviewModal.js +136 -126
  55. package/dist/node/components/templates/index.js +873 -950
  56. package/dist/node/components/templates/template-catalog.js +76 -0
  57. package/dist/node/components/templates/template-new.js +18 -0
  58. package/dist/node/components/templates/template-preview.js +38 -0
  59. package/dist/node/components/templates/template-source.js +14 -0
  60. package/dist/node/index.js +873 -950
  61. package/package.json +185 -30
  62. package/src/components/templates/TemplateCard.tsx +74 -0
  63. package/src/components/templates/TemplateCommandDialog.tsx +92 -0
  64. package/src/components/templates/TemplatePreviewContent.tsx +182 -0
  65. package/src/components/templates/TemplatesBrowseControls.tsx +120 -0
  66. package/src/components/templates/TemplatesCatalogSection.tsx +166 -0
  67. package/src/components/templates/TemplatesClientPage.tsx +109 -741
  68. package/src/components/templates/TemplatesHeroSection.tsx +41 -0
  69. package/src/components/templates/TemplatesNextStepsSection.tsx +80 -0
  70. package/src/components/templates/TemplatesPreviewModal.tsx +19 -294
  71. package/src/components/templates/template-catalog.test.ts +66 -0
  72. package/src/components/templates/template-catalog.ts +132 -0
  73. package/src/components/templates/template-new.ts +12 -0
  74. package/src/components/templates/template-preview.ts +57 -0
  75. package/src/components/templates/template-source.ts +13 -0
  76. package/.turbo/turbo-prebuild.log +0 -1
@@ -0,0 +1,120 @@
1
+ 'use client';
2
+
3
+ import { cn } from '@contractspec/lib.ui-kit-core/utils';
4
+ import { Search } from 'lucide-react';
5
+ import type { TemplateSource } from './template-source';
6
+
7
+ export interface TemplatesBrowseControlsProps {
8
+ registryConfigured: boolean;
9
+ availableSources: readonly TemplateSource[];
10
+ source: TemplateSource;
11
+ onSourceChange: (source: TemplateSource) => void;
12
+ search: string;
13
+ onSearchChange: (value: string) => void;
14
+ selectedTag: string | null;
15
+ onTagChange: (tag: string | null) => void;
16
+ availableTags: readonly string[];
17
+ }
18
+
19
+ export function TemplatesBrowseControls({
20
+ registryConfigured,
21
+ availableSources,
22
+ source,
23
+ onSourceChange,
24
+ search,
25
+ onSearchChange,
26
+ selectedTag,
27
+ onTagChange,
28
+ availableTags,
29
+ }: TemplatesBrowseControlsProps) {
30
+ return (
31
+ <section className="editorial-section">
32
+ <div className="editorial-shell space-y-6">
33
+ <div className="flex flex-col gap-6 lg:flex-row lg:items-end lg:justify-between">
34
+ <div className="max-w-3xl space-y-3">
35
+ <p className="editorial-kicker">Browse by source</p>
36
+ <h2 className="font-serif text-4xl tracking-[-0.04em]">
37
+ Use local scenarios for core proof, then scan the community.
38
+ </h2>
39
+ <p className="text-muted-foreground text-sm leading-7">
40
+ {registryConfigured
41
+ ? 'Local templates show the official adoption path. Community templates show where the ecosystem is pushing the system next.'
42
+ : 'Local templates show the official adoption path. Community browsing appears automatically when a registry URL is configured.'}
43
+ </p>
44
+ </div>
45
+ {registryConfigured ? (
46
+ <div className="flex gap-2">
47
+ {availableSources.map((option) => (
48
+ <button
49
+ key={option}
50
+ onClick={() => onSourceChange(option)}
51
+ className={cn(
52
+ 'rounded-full px-4 py-2 font-medium text-sm transition-colors',
53
+ {
54
+ 'bg-primary text-primary-foreground': source === option,
55
+ 'border border-border bg-card hover:bg-card/80':
56
+ source !== option,
57
+ }
58
+ )}
59
+ aria-pressed={source === option}
60
+ >
61
+ {option === 'local' ? 'Local' : 'Community'}
62
+ </button>
63
+ ))}
64
+ </div>
65
+ ) : null}
66
+ </div>
67
+
68
+ <div className="editorial-panel space-y-5">
69
+ <div className="relative">
70
+ <Search
71
+ className="absolute top-3.5 left-4 text-muted-foreground"
72
+ size={18}
73
+ />
74
+ <input
75
+ type="text"
76
+ placeholder="Search scenarios, industries, or tags"
77
+ value={search}
78
+ onChange={(event) => onSearchChange(event.target.value)}
79
+ className="w-full rounded-full border border-border bg-background px-12 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
80
+ aria-label="Search templates"
81
+ />
82
+ </div>
83
+ <div className="flex flex-wrap gap-2">
84
+ <button
85
+ onClick={() => onTagChange(null)}
86
+ className={cn(
87
+ 'rounded-full px-4 py-2 font-medium text-sm transition-colors',
88
+ {
89
+ 'bg-primary text-primary-foreground': selectedTag === null,
90
+ 'border border-border bg-card hover:bg-card/80':
91
+ selectedTag !== null,
92
+ }
93
+ )}
94
+ aria-pressed={selectedTag === null}
95
+ >
96
+ All
97
+ </button>
98
+ {availableTags.map((tag) => (
99
+ <button
100
+ key={tag}
101
+ onClick={() => onTagChange(tag)}
102
+ className={cn(
103
+ 'rounded-full px-4 py-2 font-medium text-sm transition-colors',
104
+ {
105
+ 'bg-primary text-primary-foreground': selectedTag === tag,
106
+ 'border border-border bg-card hover:bg-card/80':
107
+ selectedTag !== tag,
108
+ }
109
+ )}
110
+ aria-pressed={selectedTag === tag}
111
+ >
112
+ {tag}
113
+ </button>
114
+ ))}
115
+ </div>
116
+ </div>
117
+ </div>
118
+ </section>
119
+ );
120
+ }
@@ -0,0 +1,166 @@
1
+ 'use client';
2
+
3
+ import type { RegistryTemplate } from '@contractspec/lib.example-shared-ui';
4
+ import Link from 'next/link';
5
+ import { TemplateCard } from './TemplateCard';
6
+ import {
7
+ formatExampleKindLabel,
8
+ formatStabilityLabel,
9
+ type LocalTemplateCatalogItem,
10
+ } from './template-catalog';
11
+ import {
12
+ getLocalTemplatePreviewAction,
13
+ getRegistryTemplatePreviewAction,
14
+ } from './template-preview';
15
+ import type { TemplateSource } from './template-source';
16
+
17
+ export interface TemplatesCatalogSectionProps {
18
+ source: TemplateSource;
19
+ registryConfigured: boolean;
20
+ registryLoading: boolean;
21
+ localTemplates: readonly LocalTemplateCatalogItem[];
22
+ registryTemplates: readonly RegistryTemplate[];
23
+ localTemplateById: ReadonlyMap<string, LocalTemplateCatalogItem>;
24
+ onPreview: (templateId: string) => void;
25
+ onUseTemplate: (templateId: string, source: TemplateSource) => void;
26
+ }
27
+
28
+ export function TemplatesCatalogSection({
29
+ source,
30
+ registryConfigured,
31
+ registryLoading,
32
+ localTemplates,
33
+ registryTemplates,
34
+ localTemplateById,
35
+ onPreview,
36
+ onUseTemplate,
37
+ }: TemplatesCatalogSectionProps) {
38
+ const showRegistry = source === 'registry' && registryConfigured;
39
+
40
+ return (
41
+ <section className="section-padding">
42
+ <div className="editorial-shell">
43
+ {showRegistry ? (
44
+ registryLoading ? (
45
+ <div className="py-12 text-center">
46
+ <p className="text-muted-foreground">
47
+ Loading community templates…
48
+ </p>
49
+ </div>
50
+ ) : registryTemplates.length === 0 ? (
51
+ <div className="py-12 text-center">
52
+ <p className="text-muted-foreground">
53
+ No community templates found.
54
+ </p>
55
+ </div>
56
+ ) : (
57
+ <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
58
+ {registryTemplates.map((template) => {
59
+ const localTemplate = localTemplateById.get(template.id);
60
+ const previewAction = getRegistryTemplatePreviewAction(
61
+ template,
62
+ localTemplate
63
+ );
64
+
65
+ return (
66
+ <TemplateCard
67
+ key={template.id}
68
+ title={template.name}
69
+ description={template.description}
70
+ metaBadges={['Community']}
71
+ tags={template.tags}
72
+ previewAction={
73
+ previewAction.kind === 'modal' ? (
74
+ <button
75
+ className="btn-ghost flex-1 text-center text-xs"
76
+ onClick={() => onPreview(template.id)}
77
+ >
78
+ Preview
79
+ </button>
80
+ ) : previewAction.kind === 'sandbox' ? (
81
+ <Link
82
+ href={previewAction.href}
83
+ className="btn-ghost flex-1 text-center text-xs"
84
+ >
85
+ Open Sandbox
86
+ </Link>
87
+ ) : (
88
+ <button
89
+ className="btn-ghost flex-1 cursor-not-allowed text-center text-xs opacity-60"
90
+ type="button"
91
+ disabled
92
+ >
93
+ Preview Unavailable
94
+ </button>
95
+ )
96
+ }
97
+ useAction={
98
+ <button
99
+ className="btn-primary flex-1 text-center text-xs"
100
+ onClick={() => onUseTemplate(template.id, 'registry')}
101
+ >
102
+ Use Template
103
+ </button>
104
+ }
105
+ />
106
+ );
107
+ })}
108
+ </div>
109
+ )
110
+ ) : localTemplates.length === 0 ? (
111
+ <div className="py-12 text-center">
112
+ <p className="text-muted-foreground">
113
+ No templates match your filters. Try a different search.
114
+ </p>
115
+ </div>
116
+ ) : (
117
+ <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
118
+ {localTemplates.map((template) => {
119
+ const previewAction = getLocalTemplatePreviewAction(template);
120
+
121
+ return (
122
+ <TemplateCard
123
+ key={template.id}
124
+ title={template.title}
125
+ description={template.description}
126
+ isNew={template.isNew}
127
+ metaBadges={[
128
+ formatExampleKindLabel(template.kind),
129
+ formatStabilityLabel(template.stability),
130
+ ]}
131
+ tags={template.tags}
132
+ featureList={template.featureList}
133
+ previewAction={
134
+ previewAction.kind === 'modal' ? (
135
+ <button
136
+ className="btn-ghost flex-1 text-center text-xs"
137
+ onClick={() => onPreview(template.id)}
138
+ >
139
+ Preview
140
+ </button>
141
+ ) : (
142
+ <Link
143
+ href={previewAction.href}
144
+ className="btn-ghost flex-1 text-center text-xs"
145
+ >
146
+ Open Sandbox
147
+ </Link>
148
+ )
149
+ }
150
+ useAction={
151
+ <button
152
+ className="btn-primary flex-1 text-center text-xs"
153
+ onClick={() => onUseTemplate(template.id, 'local')}
154
+ >
155
+ Use Template
156
+ </button>
157
+ }
158
+ />
159
+ );
160
+ })}
161
+ </div>
162
+ )}
163
+ </div>
164
+ </section>
165
+ );
166
+ }