@uptrademedia/site-kit 1.0.1 → 1.0.4

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 (159) hide show
  1. package/dist/SetupWizard-Cki06kB0.d.mts +12 -0
  2. package/dist/SetupWizard-Cki06kB0.d.ts +12 -0
  3. package/dist/analytics/index.d.mts +87 -0
  4. package/dist/analytics/index.d.ts +87 -0
  5. package/dist/blog/index.d.mts +24 -0
  6. package/dist/blog/index.d.ts +24 -0
  7. package/dist/blog/index.js.map +1 -1
  8. package/dist/blog/index.mjs.map +1 -1
  9. package/dist/chunk-2IHTEKHU.mjs +332 -0
  10. package/dist/chunk-2IHTEKHU.mjs.map +1 -0
  11. package/dist/chunk-5R4R3WDP.js +1451 -0
  12. package/dist/chunk-5R4R3WDP.js.map +1 -0
  13. package/dist/{chunk-RV7H3I6J.js → chunk-ADHVEFWD.js} +68 -2
  14. package/dist/chunk-ADHVEFWD.js.map +1 -0
  15. package/dist/chunk-BGJLOJ7T.mjs +605 -0
  16. package/dist/chunk-BGJLOJ7T.mjs.map +1 -0
  17. package/dist/chunk-BZBJVG5Y.js +88 -0
  18. package/dist/chunk-BZBJVG5Y.js.map +1 -0
  19. package/dist/{chunk-COI6GOX2.mjs → chunk-DOHML47I.mjs} +3 -3
  20. package/dist/chunk-DOHML47I.mjs.map +1 -0
  21. package/dist/chunk-DRFTRTKV.js +809 -0
  22. package/dist/chunk-DRFTRTKV.js.map +1 -0
  23. package/dist/chunk-EL5QTAA3.mjs +805 -0
  24. package/dist/chunk-EL5QTAA3.mjs.map +1 -0
  25. package/dist/chunk-GAJLEDRD.js +334 -0
  26. package/dist/chunk-GAJLEDRD.js.map +1 -0
  27. package/dist/{chunk-3MUOUXHV.js → chunk-K2HWVOEO.js} +3 -3
  28. package/dist/chunk-K2HWVOEO.js.map +1 -0
  29. package/dist/chunk-O2OHHBUD.js +997 -0
  30. package/dist/chunk-O2OHHBUD.js.map +1 -0
  31. package/dist/chunk-QAYJV4KK.js +608 -0
  32. package/dist/chunk-QAYJV4KK.js.map +1 -0
  33. package/dist/{chunk-FEBYQGY4 2.mjs → chunk-SMUFNQLM.mjs} +67 -3
  34. package/dist/chunk-SMUFNQLM.mjs.map +1 -0
  35. package/dist/chunk-VDMZZL2O.mjs +83 -0
  36. package/dist/chunk-VDMZZL2O.mjs.map +1 -0
  37. package/dist/chunk-XFRPT5ZX.mjs +1449 -0
  38. package/dist/chunk-XFRPT5ZX.mjs.map +1 -0
  39. package/dist/chunk-XQJX252G.mjs +981 -0
  40. package/dist/chunk-XQJX252G.mjs.map +1 -0
  41. package/dist/commerce/index.d.mts +168 -0
  42. package/dist/commerce/index.d.ts +168 -0
  43. package/dist/commerce/index.js +38 -38
  44. package/dist/commerce/index.mjs +1 -1
  45. package/dist/commerce/server.d.mts +98 -0
  46. package/dist/commerce/server.d.ts +98 -0
  47. package/dist/engage/index.d.mts +27 -0
  48. package/dist/engage/index.d.ts +27 -0
  49. package/dist/engage/index.js +7 -40
  50. package/dist/engage/index.js.map +1 -1
  51. package/dist/engage/index.mjs +1 -41
  52. package/dist/engage/index.mjs.map +1 -1
  53. package/dist/forms/index.d.mts +437 -0
  54. package/dist/forms/index.d.ts +437 -0
  55. package/dist/forms/index.js +13 -5
  56. package/dist/forms/index.js.map +1 -1
  57. package/dist/forms/index.mjs +2 -2
  58. package/dist/forms/index.mjs.map +1 -1
  59. package/dist/{generators-7Y5ABRYV 2.mjs → generators-TO2FKJR6.mjs} +134 -3
  60. package/dist/generators-TO2FKJR6.mjs.map +1 -0
  61. package/dist/{generators-GWIYCA5M.js → generators-YZWIGHCO.js} +135 -2
  62. package/dist/generators-YZWIGHCO.js.map +1 -0
  63. package/dist/images/index.d.mts +133 -0
  64. package/dist/images/index.d.ts +133 -0
  65. package/dist/images/index.js +41 -0
  66. package/dist/images/index.js.map +1 -0
  67. package/dist/images/index.mjs +8 -0
  68. package/dist/images/index.mjs.map +1 -0
  69. package/dist/index.d.mts +649 -0
  70. package/dist/index.d.ts +649 -0
  71. package/dist/index.js +1355 -104
  72. package/dist/index.js.map +1 -1
  73. package/dist/index.mjs +1242 -76
  74. package/dist/index.mjs.map +1 -1
  75. package/dist/redirects/index.d.mts +72 -0
  76. package/dist/redirects/index.d.ts +72 -0
  77. package/dist/redirects/index.js +25 -0
  78. package/dist/redirects/index.js.map +1 -0
  79. package/dist/redirects/index.mjs +4 -0
  80. package/dist/redirects/index.mjs.map +1 -0
  81. package/dist/routing-BWjUF7lp.d.ts +105 -0
  82. package/dist/routing-CgmRi9tD.d.mts +105 -0
  83. package/dist/{scanner-MF7P3CDE 2.mjs → scanner-AZV5I6US.mjs} +123 -4
  84. package/dist/scanner-AZV5I6US.mjs.map +1 -0
  85. package/dist/{scanner-NT6YG4TD 2.js → scanner-ETJAMIT7.js} +124 -3
  86. package/dist/scanner-ETJAMIT7.js.map +1 -0
  87. package/dist/seo/index.d.mts +273 -0
  88. package/dist/seo/index.d.ts +273 -0
  89. package/dist/seo/server.d.mts +89 -0
  90. package/dist/seo/server.d.ts +89 -0
  91. package/dist/setup/client.d.mts +60 -0
  92. package/dist/setup/client.d.ts +60 -0
  93. package/dist/setup/client.js +30 -0
  94. package/dist/setup/client.js.map +1 -0
  95. package/dist/setup/client.mjs +5 -0
  96. package/dist/setup/client.mjs.map +1 -0
  97. package/dist/setup/index.d.mts +5 -0
  98. package/dist/setup/index.d.ts +5 -0
  99. package/dist/setup/index.js +28 -1043
  100. package/dist/setup/index.js.map +1 -1
  101. package/dist/setup/index.mjs +3 -1043
  102. package/dist/setup/index.mjs.map +1 -1
  103. package/dist/setup/server.d.mts +14 -0
  104. package/dist/setup/server.d.ts +14 -0
  105. package/dist/setup/server.js +13 -0
  106. package/dist/setup/server.js.map +1 -0
  107. package/dist/setup/server.mjs +4 -0
  108. package/dist/setup/server.mjs.map +1 -0
  109. package/dist/sitemap/index.d.mts +78 -0
  110. package/dist/sitemap/index.d.ts +78 -0
  111. package/dist/types-BDojCvvL.d.mts +156 -0
  112. package/dist/types-BDojCvvL.d.ts +156 -0
  113. package/dist/types-BmzutFwy.d.mts +227 -0
  114. package/dist/types-BmzutFwy.d.ts +227 -0
  115. package/dist/types-C0pJGfbH.d.mts +155 -0
  116. package/dist/types-C0pJGfbH.d.ts +155 -0
  117. package/dist/types-DA_Kocle.d.mts +127 -0
  118. package/dist/types-DA_Kocle.d.ts +127 -0
  119. package/dist/types-lFLKKn0G.d.mts +163 -0
  120. package/dist/types-lFLKKn0G.d.ts +163 -0
  121. package/dist/types-nB206tPK.d.mts +309 -0
  122. package/dist/types-nB206tPK.d.ts +309 -0
  123. package/dist/useEventModal-6U1pF3_g.d.mts +209 -0
  124. package/dist/useEventModal-BA8g-1-P.d.ts +209 -0
  125. package/package.json +21 -1
  126. package/dist/chunk-3MUOUXHV.js.map +0 -1
  127. package/dist/chunk-4HVYXYQL 2.mjs +0 -255
  128. package/dist/chunk-4HVYXYQL.mjs +0 -255
  129. package/dist/chunk-4HVYXYQL.mjs.map +0 -1
  130. package/dist/chunk-COI6GOX2.mjs.map +0 -1
  131. package/dist/chunk-EQCVQC35.js 2.map +0 -1
  132. package/dist/chunk-FEBYQGY4.mjs +0 -251
  133. package/dist/chunk-FEBYQGY4.mjs.map +0 -1
  134. package/dist/chunk-NYKRE2FL 2.mjs +0 -31
  135. package/dist/chunk-NYKRE2FL.mjs 2.map +0 -1
  136. package/dist/chunk-RV7H3I6J.js 2.map +0 -1
  137. package/dist/chunk-RV7H3I6J.js.map +0 -1
  138. package/dist/chunk-TUKGA3UK.js +0 -257
  139. package/dist/chunk-TUKGA3UK.js 2.map +0 -1
  140. package/dist/chunk-TUKGA3UK.js.map +0 -1
  141. package/dist/generators-7Y5ABRYV.mjs +0 -161
  142. package/dist/generators-7Y5ABRYV.mjs 2.map +0 -1
  143. package/dist/generators-7Y5ABRYV.mjs.map +0 -1
  144. package/dist/generators-GWIYCA5M.js 2.map +0 -1
  145. package/dist/generators-GWIYCA5M.js.map +0 -1
  146. package/dist/index 2.mjs +0 -74
  147. package/dist/index.js 2.map +0 -1
  148. package/dist/migrator-V6KS75EA 2.mjs +0 -265
  149. package/dist/migrator-V6KS75EA.mjs 2.map +0 -1
  150. package/dist/migrator-XKM7YQCY.js 2.map +0 -1
  151. package/dist/scanner-MF7P3CDE.mjs +0 -14386
  152. package/dist/scanner-MF7P3CDE.mjs 2.map +0 -1
  153. package/dist/scanner-MF7P3CDE.mjs.map +0 -1
  154. package/dist/scanner-NT6YG4TD.js +0 -14397
  155. package/dist/scanner-NT6YG4TD.js 2.map +0 -1
  156. package/dist/scanner-NT6YG4TD.js.map +0 -1
  157. package/dist/web-vitals-BH55V7EJ.js 2.map +0 -1
  158. package/dist/web-vitals-RJYPWAR3 2.mjs +0 -241
  159. package/dist/web-vitals-RJYPWAR3.mjs 2.map +0 -1
@@ -0,0 +1,809 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ // src/setup/integration-generator.ts
7
+ function generateIntegrationCode(context) {
8
+ const snippets = [];
9
+ const apiUrl = context.apiUrl || "https://api.uptrademedia.com";
10
+ let order = 0;
11
+ snippets.push(...generateProviderSnippets(context, apiUrl, order));
12
+ order += 10;
13
+ for (const module of context.enabledModules) {
14
+ switch (module) {
15
+ case "analytics":
16
+ snippets.push(...generateAnalyticsSnippets(context, order));
17
+ order += 10;
18
+ break;
19
+ case "engage":
20
+ snippets.push(...generateEngageSnippets(context, order));
21
+ order += 10;
22
+ break;
23
+ case "forms":
24
+ snippets.push(...generateFormsSnippets(context, order));
25
+ order += 10;
26
+ break;
27
+ case "commerce":
28
+ snippets.push(...generateCommerceSnippets(context, order));
29
+ order += 10;
30
+ break;
31
+ case "seo":
32
+ snippets.push(...generateSEOSnippets(context, order));
33
+ order += 10;
34
+ break;
35
+ case "blog":
36
+ snippets.push(...generateBlogSnippets(context, order));
37
+ order += 10;
38
+ break;
39
+ }
40
+ }
41
+ return snippets;
42
+ }
43
+ function getSnippetsByModule(snippets) {
44
+ return snippets.reduce((acc, snippet) => {
45
+ if (!acc[snippet.module]) {
46
+ acc[snippet.module] = [];
47
+ }
48
+ acc[snippet.module].push(snippet);
49
+ return acc;
50
+ }, {});
51
+ }
52
+ function generateProviderSnippets(ctx, apiUrl, startOrder) {
53
+ const enabledModulesConfig = ctx.enabledModules.map((m) => {
54
+ if (m === "analytics") return " analytics={{ enabled: true }}";
55
+ if (m === "engage") return " engage={{ enabled: true }}";
56
+ return null;
57
+ }).filter(Boolean).join("\n");
58
+ return [
59
+ {
60
+ module: "provider",
61
+ snippetType: "install",
62
+ title: "Install @uptrade/site-kit",
63
+ description: "Install the Uptrade Site Kit package",
64
+ code: `pnpm add @uptrade/site-kit`,
65
+ language: "bash",
66
+ order: startOrder,
67
+ required: true
68
+ },
69
+ {
70
+ module: "provider",
71
+ snippetType: "env",
72
+ title: "Environment Variables",
73
+ description: "Add these to your .env.local file",
74
+ filePath: ".env.local",
75
+ code: `# Uptrade Integration
76
+ NEXT_PUBLIC_UPTRADE_API_URL=${apiUrl}
77
+ NEXT_PUBLIC_UPTRADE_PROJECT_ID=${ctx.projectId}
78
+ UPTRADE_API_KEY=your-api-key-here`,
79
+ language: "env",
80
+ order: startOrder + 1,
81
+ required: true
82
+ },
83
+ {
84
+ module: "provider",
85
+ snippetType: "layout",
86
+ title: "Root Layout Provider",
87
+ description: "Wrap your app with SiteKitProvider in app/layout.tsx",
88
+ filePath: "app/layout.tsx",
89
+ code: `import { SiteKitProvider } from '@uptrade/site-kit'
90
+
91
+ export default function RootLayout({
92
+ children,
93
+ }: {
94
+ children: React.ReactNode
95
+ }) {
96
+ return (
97
+ <html lang="en">
98
+ <body>
99
+ <SiteKitProvider
100
+ apiUrl={process.env.NEXT_PUBLIC_UPTRADE_API_URL!}
101
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!}
102
+ ${enabledModulesConfig}
103
+ >
104
+ {children}
105
+ </SiteKitProvider>
106
+ </body>
107
+ </html>
108
+ )
109
+ }`,
110
+ language: "tsx",
111
+ order: startOrder + 2,
112
+ required: true
113
+ }
114
+ ];
115
+ }
116
+ function generateAnalyticsSnippets(ctx, startOrder) {
117
+ return [
118
+ {
119
+ module: "analytics",
120
+ snippetType: "component",
121
+ title: "Custom Event Tracking",
122
+ description: "Track custom events throughout your app",
123
+ filePath: "components/TrackableButton.tsx",
124
+ code: `'use client'
125
+
126
+ import { useSiteKit } from '@uptrade/site-kit'
127
+
128
+ interface TrackableButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
129
+ eventName: string
130
+ eventData?: Record<string, unknown>
131
+ children: React.ReactNode
132
+ }
133
+
134
+ export function TrackableButton({
135
+ children,
136
+ eventName,
137
+ eventData,
138
+ ...props
139
+ }: TrackableButtonProps) {
140
+ const { analytics } = useSiteKit()
141
+
142
+ const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
143
+ analytics?.trackEvent(eventName, eventData)
144
+ props.onClick?.(e)
145
+ }
146
+
147
+ return (
148
+ <button {...props} onClick={handleClick}>
149
+ {children}
150
+ </button>
151
+ )
152
+ }`,
153
+ language: "tsx",
154
+ order: startOrder,
155
+ required: false
156
+ }
157
+ ];
158
+ }
159
+ function generateEngageSnippets(ctx, startOrder) {
160
+ const primaryColor = ctx.brand?.primaryColor || "#0066cc";
161
+ return [
162
+ {
163
+ module: "engage",
164
+ snippetType: "component",
165
+ title: "Chat Widget",
166
+ description: "Add the AI chat widget to your site. This is unstyled - customize to match your brand.",
167
+ filePath: "components/ChatWidget.tsx",
168
+ code: `'use client'
169
+
170
+ import { ChatWidget } from '@uptrade/site-kit/engage'
171
+
172
+ export function SiteChat() {
173
+ return (
174
+ <ChatWidget
175
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!}
176
+ config={{
177
+ position: 'bottom-right',
178
+ buttonColor: '${primaryColor}',
179
+ greeting: 'Hi! How can I help you today?',
180
+ placeholder: 'Type your message...',
181
+ }}
182
+ />
183
+ )
184
+ }`,
185
+ language: "tsx",
186
+ order: startOrder,
187
+ required: true
188
+ },
189
+ {
190
+ module: "engage",
191
+ snippetType: "layout",
192
+ title: "Add Chat to Layout",
193
+ description: "Add the ChatWidget component to your root layout",
194
+ filePath: "app/layout.tsx",
195
+ code: `// Add import at top:
196
+ import { SiteChat } from '@/components/ChatWidget'
197
+
198
+ // Add inside your layout body, after SiteKitProvider children:
199
+ <SiteChat />`,
200
+ language: "tsx",
201
+ order: startOrder + 1,
202
+ required: true
203
+ }
204
+ ];
205
+ }
206
+ function generateFormsSnippets(ctx, startOrder) {
207
+ return [
208
+ {
209
+ module: "forms",
210
+ snippetType: "component",
211
+ title: "Managed Form Component",
212
+ description: "Embed a managed form from the Portal. Form slug must match one created in Forms module.",
213
+ filePath: "components/ContactForm.tsx",
214
+ code: `import { ManagedForm } from '@uptrade/site-kit/forms'
215
+
216
+ interface ContactFormProps {
217
+ formSlug?: string
218
+ className?: string
219
+ }
220
+
221
+ export async function ContactForm({
222
+ formSlug = 'contact',
223
+ className
224
+ }: ContactFormProps) {
225
+ return (
226
+ <ManagedForm
227
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!}
228
+ formSlug={formSlug}
229
+ className={className}
230
+ />
231
+ )
232
+ }`,
233
+ language: "tsx",
234
+ order: startOrder,
235
+ required: false
236
+ },
237
+ {
238
+ module: "forms",
239
+ snippetType: "api-route",
240
+ title: "Form Submission Handler",
241
+ description: "API route to proxy form submissions to Portal API",
242
+ filePath: "app/api/forms/[formId]/submit/route.ts",
243
+ code: `import { NextRequest, NextResponse } from 'next/server'
244
+
245
+ export async function POST(
246
+ request: NextRequest,
247
+ { params }: { params: { formId: string } }
248
+ ) {
249
+ const body = await request.json()
250
+
251
+ const response = await fetch(
252
+ \`\${process.env.NEXT_PUBLIC_UPTRADE_API_URL}/forms/\${params.formId}/submit\`,
253
+ {
254
+ method: 'POST',
255
+ headers: {
256
+ 'Content-Type': 'application/json',
257
+ 'X-API-Key': process.env.UPTRADE_API_KEY!,
258
+ },
259
+ body: JSON.stringify(body),
260
+ }
261
+ )
262
+
263
+ const data = await response.json()
264
+ return NextResponse.json(data, { status: response.status })
265
+ }`,
266
+ language: "typescript",
267
+ order: startOrder + 1,
268
+ required: true
269
+ }
270
+ ];
271
+ }
272
+ function generateCommerceSnippets(ctx, startOrder) {
273
+ return [
274
+ {
275
+ module: "commerce",
276
+ snippetType: "component",
277
+ title: "Product Grid",
278
+ description: "Display products from your commerce catalog",
279
+ filePath: "components/Products.tsx",
280
+ code: `import { ProductGrid } from '@uptrade/site-kit/commerce'
281
+
282
+ interface ProductsSectionProps {
283
+ category?: string
284
+ limit?: number
285
+ }
286
+
287
+ export async function ProductsSection({
288
+ category = 'featured',
289
+ limit = 8
290
+ }: ProductsSectionProps) {
291
+ return (
292
+ <section className="py-12">
293
+ <h2 className="text-2xl font-bold mb-6">Our Products</h2>
294
+ <ProductGrid
295
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!}
296
+ category={category}
297
+ limit={limit}
298
+ />
299
+ </section>
300
+ )
301
+ }`,
302
+ language: "tsx",
303
+ order: startOrder,
304
+ required: false
305
+ },
306
+ {
307
+ module: "commerce",
308
+ snippetType: "component",
309
+ title: "Upcoming Events",
310
+ description: "Display upcoming events and classes",
311
+ filePath: "components/Events.tsx",
312
+ code: `import { UpcomingEvents, EventCalendar } from '@uptrade/site-kit/commerce'
313
+
314
+ export async function EventsSection({ limit = 6 }: { limit?: number }) {
315
+ return (
316
+ <section className="py-12">
317
+ <h2 className="text-2xl font-bold mb-6">Upcoming Events</h2>
318
+ <UpcomingEvents
319
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!}
320
+ limit={limit}
321
+ />
322
+ </section>
323
+ )
324
+ }
325
+
326
+ export async function FullCalendar() {
327
+ return (
328
+ <EventCalendar
329
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!}
330
+ />
331
+ )
332
+ }`,
333
+ language: "tsx",
334
+ order: startOrder + 1,
335
+ required: false
336
+ }
337
+ ];
338
+ }
339
+ function generateSEOSnippets(ctx, startOrder) {
340
+ return [
341
+ {
342
+ module: "seo",
343
+ snippetType: "component",
344
+ title: "Managed FAQ Section",
345
+ description: "Render FAQs with automatic JSON-LD schema markup. FAQs are managed in Portal SEO module.",
346
+ filePath: "components/FAQSection.tsx",
347
+ code: `import { ManagedFAQ } from '@uptrade/site-kit/seo'
348
+
349
+ interface FAQSectionProps {
350
+ path: string // Page path to fetch FAQs for (e.g., '/services/plumbing')
351
+ className?: string
352
+ }
353
+
354
+ export async function FAQSection({ path, className }: FAQSectionProps) {
355
+ return (
356
+ <section className={className}>
357
+ <ManagedFAQ
358
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!}
359
+ path={path}
360
+ showTitle
361
+ includeSchema
362
+ />
363
+ </section>
364
+ )
365
+ }`,
366
+ language: "tsx",
367
+ order: startOrder,
368
+ required: true
369
+ },
370
+ {
371
+ module: "seo",
372
+ snippetType: "page",
373
+ title: "Page with Managed Metadata + FAQs",
374
+ description: "Example dynamic page using managed metadata and FAQ sections",
375
+ filePath: "app/services/[slug]/page.tsx",
376
+ code: `import { getManagedMetadata, ManagedFAQ } from '@uptrade/site-kit/seo'
377
+ import type { Metadata } from 'next'
378
+
379
+ interface Props {
380
+ params: { slug: string }
381
+ }
382
+
383
+ export async function generateMetadata({ params }: Props): Promise<Metadata> {
384
+ const path = \`/services/\${params.slug}\`
385
+ return getManagedMetadata({
386
+ projectId: process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!,
387
+ path,
388
+ })
389
+ }
390
+
391
+ export default async function ServicePage({ params }: Props) {
392
+ const path = \`/services/\${params.slug}\`
393
+
394
+ return (
395
+ <main>
396
+ <h1 className="text-3xl font-bold">Service: {params.slug}</h1>
397
+
398
+ {/* Your page content here */}
399
+
400
+ {/* FAQs section with JSON-LD schema */}
401
+ <section className="mt-12">
402
+ <ManagedFAQ
403
+ projectId={process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!}
404
+ path={path}
405
+ showTitle
406
+ includeSchema
407
+ />
408
+ </section>
409
+ </main>
410
+ )
411
+ }`,
412
+ language: "tsx",
413
+ order: startOrder + 1,
414
+ required: false
415
+ }
416
+ ];
417
+ }
418
+ function generateBlogSnippets(ctx, startOrder) {
419
+ return [
420
+ {
421
+ module: "blog",
422
+ snippetType: "page",
423
+ title: "Blog List Page",
424
+ description: "Display all blog posts from Portal",
425
+ filePath: "app/blog/page.tsx",
426
+ code: `import { getBlogPosts } from '@uptrade/site-kit/blog'
427
+ import Link from 'next/link'
428
+
429
+ export default async function BlogPage() {
430
+ const posts = await getBlogPosts({
431
+ projectId: process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!,
432
+ limit: 10,
433
+ })
434
+
435
+ return (
436
+ <main className="py-12">
437
+ <h1 className="text-3xl font-bold mb-8">Blog</h1>
438
+ <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
439
+ {posts.map((post) => (
440
+ <article key={post.id} className="border rounded-lg p-4">
441
+ {post.featured_image && (
442
+ <img
443
+ src={post.featured_image}
444
+ alt={post.title}
445
+ className="w-full h-48 object-cover rounded mb-4"
446
+ />
447
+ )}
448
+ <h2 className="text-xl font-semibold mb-2">
449
+ <Link href={\`/blog/\${post.slug}\`}>{post.title}</Link>
450
+ </h2>
451
+ <p className="text-gray-600">{post.excerpt}</p>
452
+ </article>
453
+ ))}
454
+ </div>
455
+ </main>
456
+ )
457
+ }`,
458
+ language: "tsx",
459
+ order: startOrder,
460
+ required: false
461
+ },
462
+ {
463
+ module: "blog",
464
+ snippetType: "page",
465
+ title: "Blog Post Page",
466
+ description: "Individual blog post page with SEO metadata",
467
+ filePath: "app/blog/[slug]/page.tsx",
468
+ code: `import { getBlogPost, getBlogPosts } from '@uptrade/site-kit/blog'
469
+ import type { Metadata } from 'next'
470
+ import { notFound } from 'next/navigation'
471
+
472
+ interface Props {
473
+ params: { slug: string }
474
+ }
475
+
476
+ export async function generateStaticParams() {
477
+ const posts = await getBlogPosts({
478
+ projectId: process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!,
479
+ })
480
+ return posts.map((post) => ({ slug: post.slug }))
481
+ }
482
+
483
+ export async function generateMetadata({ params }: Props): Promise<Metadata> {
484
+ const post = await getBlogPost({
485
+ projectId: process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!,
486
+ slug: params.slug,
487
+ })
488
+
489
+ if (!post) return {}
490
+
491
+ return {
492
+ title: post.title,
493
+ description: post.excerpt,
494
+ openGraph: {
495
+ title: post.title,
496
+ description: post.excerpt,
497
+ images: post.featured_image ? [post.featured_image] : [],
498
+ },
499
+ }
500
+ }
501
+
502
+ export default async function BlogPostPage({ params }: Props) {
503
+ const post = await getBlogPost({
504
+ projectId: process.env.NEXT_PUBLIC_UPTRADE_PROJECT_ID!,
505
+ slug: params.slug,
506
+ })
507
+
508
+ if (!post) notFound()
509
+
510
+ return (
511
+ <article className="py-12 max-w-3xl mx-auto">
512
+ <h1 className="text-4xl font-bold mb-4">{post.title}</h1>
513
+ {post.featured_image && (
514
+ <img
515
+ src={post.featured_image}
516
+ alt={post.title}
517
+ className="w-full rounded-lg mb-8"
518
+ />
519
+ )}
520
+ <div
521
+ className="prose prose-lg"
522
+ dangerouslySetInnerHTML={{ __html: post.content }}
523
+ />
524
+ </article>
525
+ )
526
+ }`,
527
+ language: "tsx",
528
+ order: startOrder + 1,
529
+ required: false
530
+ }
531
+ ];
532
+ }
533
+ function CopyIcon({ className }) {
534
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { className, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
535
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
536
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
537
+ ] });
538
+ }
539
+ function CheckIcon({ className }) {
540
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) });
541
+ }
542
+ function ChevronDownIcon({ className }) {
543
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" }) });
544
+ }
545
+ function ChevronRightIcon({ className }) {
546
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className, width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 18 15 12 9 6" }) });
547
+ }
548
+ var moduleLabels = {
549
+ provider: "Setup",
550
+ analytics: "Analytics",
551
+ engage: "Engage (Chat)",
552
+ forms: "Forms",
553
+ commerce: "Commerce",
554
+ seo: "SEO",
555
+ blog: "Blog"
556
+ };
557
+ var moduleColors = {
558
+ provider: "#6366f1",
559
+ // indigo
560
+ analytics: "#8b5cf6",
561
+ // violet
562
+ engage: "#ec4899",
563
+ // pink
564
+ forms: "#14b8a6",
565
+ // teal
566
+ commerce: "#f59e0b",
567
+ // amber
568
+ seo: "#10b981",
569
+ // emerald
570
+ blog: "#3b82f6"
571
+ // blue
572
+ };
573
+ function IntegrationCodeView({
574
+ projectId,
575
+ enabledModules,
576
+ apiUrl,
577
+ brand,
578
+ className,
579
+ onCopy
580
+ }) {
581
+ const [expandedModules, setExpandedModules] = react.useState(/* @__PURE__ */ new Set(["provider"]));
582
+ const [copiedId, setCopiedId] = react.useState(null);
583
+ const snippets = react.useMemo(() => {
584
+ return generateIntegrationCode({
585
+ projectId,
586
+ enabledModules,
587
+ apiUrl,
588
+ brand
589
+ });
590
+ }, [projectId, enabledModules, apiUrl, brand]);
591
+ const snippetsByModule = react.useMemo(() => {
592
+ return getSnippetsByModule(snippets);
593
+ }, [snippets]);
594
+ const toggleModule = (module) => {
595
+ setExpandedModules((prev) => {
596
+ const next = new Set(prev);
597
+ if (next.has(module)) {
598
+ next.delete(module);
599
+ } else {
600
+ next.add(module);
601
+ }
602
+ return next;
603
+ });
604
+ };
605
+ const copyCode = async (code, id, title) => {
606
+ try {
607
+ await navigator.clipboard.writeText(code);
608
+ setCopiedId(id);
609
+ onCopy?.(code, title);
610
+ setTimeout(() => setCopiedId(null), 2e3);
611
+ } catch (err) {
612
+ console.error("Failed to copy:", err);
613
+ }
614
+ };
615
+ const copyAll = async () => {
616
+ const allCode = snippets.map((s) => `// ${s.title}
617
+ ${s.filePath ? `// File: ${s.filePath}
618
+ ` : ""}${s.code}`).join("\n\n// ---\n\n");
619
+ try {
620
+ await navigator.clipboard.writeText(allCode);
621
+ onCopy?.(allCode, "All snippets");
622
+ } catch (err) {
623
+ console.error("Failed to copy:", err);
624
+ }
625
+ };
626
+ if (enabledModules.length === 0) {
627
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { textAlign: "center", padding: "2rem", color: "#666" }, children: [
628
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No modules enabled for this project." }),
629
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.875rem", marginTop: "0.5rem" }, children: "Enable modules in Project Settings to generate integration code." })
630
+ ] });
631
+ }
632
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
633
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
634
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
635
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { margin: 0, fontWeight: 600 }, children: "Integration Code" }),
636
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { margin: "0.25rem 0 0", fontSize: "0.875rem", color: "#666" }, children: [
637
+ snippets.length,
638
+ " snippets for ",
639
+ enabledModules.length,
640
+ " modules"
641
+ ] })
642
+ ] }),
643
+ /* @__PURE__ */ jsxRuntime.jsxs(
644
+ "button",
645
+ {
646
+ onClick: copyAll,
647
+ style: {
648
+ display: "flex",
649
+ alignItems: "center",
650
+ gap: "0.5rem",
651
+ padding: "0.5rem 1rem",
652
+ border: "1px solid #e5e7eb",
653
+ borderRadius: "0.375rem",
654
+ background: "white",
655
+ cursor: "pointer",
656
+ fontSize: "0.875rem"
657
+ },
658
+ children: [
659
+ /* @__PURE__ */ jsxRuntime.jsx(CopyIcon, {}),
660
+ "Copy All"
661
+ ]
662
+ }
663
+ )
664
+ ] }),
665
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: Object.entries(snippetsByModule).map(([module, moduleSnippets]) => {
666
+ const isExpanded = expandedModules.has(module);
667
+ const color = moduleColors[module] || "#6366f1";
668
+ return /* @__PURE__ */ jsxRuntime.jsxs(
669
+ "div",
670
+ {
671
+ style: {
672
+ border: "1px solid #e5e7eb",
673
+ borderRadius: "0.5rem",
674
+ overflow: "hidden"
675
+ },
676
+ children: [
677
+ /* @__PURE__ */ jsxRuntime.jsxs(
678
+ "button",
679
+ {
680
+ onClick: () => toggleModule(module),
681
+ style: {
682
+ width: "100%",
683
+ display: "flex",
684
+ alignItems: "center",
685
+ justifyContent: "space-between",
686
+ padding: "0.75rem 1rem",
687
+ background: "#f9fafb",
688
+ border: "none",
689
+ cursor: "pointer",
690
+ textAlign: "left"
691
+ },
692
+ children: [
693
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.75rem" }, children: [
694
+ /* @__PURE__ */ jsxRuntime.jsx(
695
+ "div",
696
+ {
697
+ style: {
698
+ width: "0.5rem",
699
+ height: "0.5rem",
700
+ borderRadius: "50%",
701
+ background: color
702
+ }
703
+ }
704
+ ),
705
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: moduleLabels[module] || module }),
706
+ /* @__PURE__ */ jsxRuntime.jsx(
707
+ "span",
708
+ {
709
+ style: {
710
+ fontSize: "0.75rem",
711
+ padding: "0.125rem 0.5rem",
712
+ background: "#e5e7eb",
713
+ borderRadius: "9999px"
714
+ },
715
+ children: moduleSnippets.length
716
+ }
717
+ )
718
+ ] }),
719
+ isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(ChevronRightIcon, {})
720
+ ]
721
+ }
722
+ ),
723
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { children: moduleSnippets.map((snippet, idx) => {
724
+ const snippetId = `${module}-${idx}`;
725
+ const isCopied = copiedId === snippetId;
726
+ return /* @__PURE__ */ jsxRuntime.jsxs(
727
+ "div",
728
+ {
729
+ style: {
730
+ padding: "1rem",
731
+ borderTop: "1px solid #e5e7eb"
732
+ },
733
+ children: [
734
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "0.75rem" }, children: [
735
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
736
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
737
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500, fontSize: "0.875rem" }, children: snippet.title }),
738
+ snippet.required && /* @__PURE__ */ jsxRuntime.jsx(
739
+ "span",
740
+ {
741
+ style: {
742
+ fontSize: "0.625rem",
743
+ padding: "0.125rem 0.375rem",
744
+ border: "1px solid #e5e7eb",
745
+ borderRadius: "0.25rem",
746
+ textTransform: "uppercase"
747
+ },
748
+ children: "Required"
749
+ }
750
+ )
751
+ ] }),
752
+ snippet.description && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0.25rem 0 0", fontSize: "0.75rem", color: "#666" }, children: snippet.description }),
753
+ snippet.filePath && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0.25rem 0 0", fontSize: "0.75rem", color, fontFamily: "monospace" }, children: snippet.filePath })
754
+ ] }),
755
+ /* @__PURE__ */ jsxRuntime.jsx(
756
+ "button",
757
+ {
758
+ onClick: () => copyCode(snippet.code, snippetId, snippet.title),
759
+ style: {
760
+ display: "flex",
761
+ alignItems: "center",
762
+ justifyContent: "center",
763
+ width: "2rem",
764
+ height: "2rem",
765
+ border: "none",
766
+ background: "transparent",
767
+ cursor: "pointer",
768
+ borderRadius: "0.25rem"
769
+ },
770
+ title: "Copy code",
771
+ children: isCopied ? /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "text-green-500" }) : /* @__PURE__ */ jsxRuntime.jsx(CopyIcon, {})
772
+ }
773
+ )
774
+ ] }),
775
+ /* @__PURE__ */ jsxRuntime.jsx(
776
+ "pre",
777
+ {
778
+ style: {
779
+ margin: 0,
780
+ padding: "0.75rem",
781
+ background: "#1f2937",
782
+ color: "#e5e7eb",
783
+ borderRadius: "0.375rem",
784
+ overflow: "auto",
785
+ fontSize: "0.75rem",
786
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
787
+ lineHeight: 1.5
788
+ },
789
+ children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: snippet.code })
790
+ }
791
+ )
792
+ ]
793
+ },
794
+ idx
795
+ );
796
+ }) })
797
+ ]
798
+ },
799
+ module
800
+ );
801
+ }) })
802
+ ] });
803
+ }
804
+
805
+ exports.IntegrationCodeView = IntegrationCodeView;
806
+ exports.generateIntegrationCode = generateIntegrationCode;
807
+ exports.getSnippetsByModule = getSnippetsByModule;
808
+ //# sourceMappingURL=chunk-DRFTRTKV.js.map
809
+ //# sourceMappingURL=chunk-DRFTRTKV.js.map