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