@salesmind-ai/design-system 1.8.0 → 1.10.0
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/dist/ChangeEmail-BuUhjW0o.d.cts +226 -0
- package/dist/ChangeEmail-BuUhjW0o.d.ts +226 -0
- package/dist/{SectionShell-CrgrzWK6.d.cts → SectionShell-C_pxaLbf.d.cts} +8 -0
- package/dist/{SectionShell-CrgrzWK6.d.ts → SectionShell-C_pxaLbf.d.ts} +8 -0
- package/dist/{StatsSection-WaiVrRH0.d.cts → StatsSection-CKTgV4Z1.d.cts} +1 -1
- package/dist/{StatsSection-BvgUXtrd.d.ts → StatsSection-DjFHz0nM.d.ts} +1 -1
- package/dist/blog/index.cjs +9 -9
- package/dist/blog/index.d.cts +1 -1
- package/dist/blog/index.d.ts +1 -1
- package/dist/blog/index.js +2 -2
- package/dist/{chunk-CVLD5RQK.cjs → chunk-32B2EWHK.cjs} +8 -8
- package/dist/chunk-AI2YEYT4.js +1368 -0
- package/dist/chunk-AI2YEYT4.js.map +1 -0
- package/dist/{chunk-6QIQCUYC.cjs → chunk-HWEIKJCR.cjs} +12 -3
- package/dist/chunk-HWEIKJCR.cjs.map +1 -0
- package/dist/{chunk-CLXLQCNQ.js → chunk-ICELMF2C.js} +2 -2
- package/dist/{chunk-2TC5EVSJ.js → chunk-IQQSEYJP.js} +4 -4
- package/dist/{chunk-2TC5EVSJ.js.map → chunk-IQQSEYJP.js.map} +1 -1
- package/dist/{chunk-K7NQ7TQG.cjs → chunk-M4MLGT4B.cjs} +84 -27
- package/dist/chunk-M4MLGT4B.cjs.map +1 -0
- package/dist/{chunk-AMNY5TS3.js → chunk-MPOYZNAA.js} +12 -3
- package/dist/chunk-MPOYZNAA.js.map +1 -0
- package/dist/{chunk-25TUCNN6.js → chunk-QVGDMAZY.js} +84 -27
- package/dist/chunk-QVGDMAZY.js.map +1 -0
- package/dist/{chunk-4QQKREVH.cjs → chunk-S4367EZF.cjs} +22 -22
- package/dist/{chunk-4QQKREVH.cjs.map → chunk-S4367EZF.cjs.map} +1 -1
- package/dist/{chunk-PBYRTNQ5.js → chunk-VUCQTZ2W.js} +2 -2
- package/dist/{chunk-65DTHLVX.cjs → chunk-WUKUWW7U.cjs} +4 -4
- package/dist/chunk-YWJKSY5C.cjs +1381 -0
- package/dist/chunk-YWJKSY5C.cjs.map +1 -0
- package/dist/{index-CUkONzzC.d.ts → index-BsL1M4Mu.d.ts} +1 -1
- package/dist/{index-kMlM7caH.d.cts → index-C22gn6z6.d.cts} +1 -1
- package/dist/index.cjs +63 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +2372 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/marketing/index.cjs +28 -28
- package/dist/marketing/index.d.cts +2 -2
- package/dist/marketing/index.d.ts +2 -2
- package/dist/marketing/index.js +2 -2
- package/dist/onboarding/index.cjs +5870 -0
- package/dist/onboarding/index.cjs.map +1 -0
- package/dist/onboarding/index.css +557 -0
- package/dist/onboarding/index.css.map +1 -0
- package/dist/onboarding/index.d.cts +1589 -0
- package/dist/onboarding/index.d.ts +1589 -0
- package/dist/onboarding/index.js +5736 -0
- package/dist/onboarding/index.js.map +1 -0
- package/dist/sections/index.cjs +8 -8
- package/dist/sections/index.d.cts +2 -2
- package/dist/sections/index.d.ts +2 -2
- package/dist/sections/index.js +2 -2
- package/dist/styles/styles.css +2539 -0
- package/dist/v2-auth/index.cjs +59 -0
- package/dist/v2-auth/index.cjs.map +1 -0
- package/dist/v2-auth/index.css +3360 -0
- package/dist/v2-auth/index.css.map +1 -0
- package/dist/v2-auth/index.d.cts +76 -0
- package/dist/v2-auth/index.d.ts +76 -0
- package/dist/v2-auth/index.js +24 -0
- package/dist/v2-auth/index.js.map +1 -0
- package/dist/web/index.cjs +7 -7
- package/dist/web/index.d.cts +1 -1
- package/dist/web/index.d.ts +1 -1
- package/dist/web/index.js +1 -1
- package/dist/web/server/index.cjs +7 -7
- package/dist/web/server/index.d.cts +91 -27
- package/dist/web/server/index.d.ts +91 -27
- package/dist/web/server/index.js +1 -1
- package/package.json +14 -2
- package/dist/chunk-25TUCNN6.js.map +0 -1
- package/dist/chunk-6QIQCUYC.cjs.map +0 -1
- package/dist/chunk-AMNY5TS3.js.map +0 -1
- package/dist/chunk-K7NQ7TQG.cjs.map +0 -1
- /package/dist/{chunk-CVLD5RQK.cjs.map → chunk-32B2EWHK.cjs.map} +0 -0
- /package/dist/{chunk-65DTHLVX.cjs.map → chunk-ICELMF2C.js.map} +0 -0
- /package/dist/{chunk-PBYRTNQ5.js.map → chunk-VUCQTZ2W.js.map} +0 -0
- /package/dist/{chunk-CLXLQCNQ.js.map → chunk-WUKUWW7U.cjs.map} +0 -0
|
@@ -59,8 +59,15 @@ function createEntityIds(brand) {
|
|
|
59
59
|
function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"]) {
|
|
60
60
|
const ENTITY_IDS = createEntityIds(brand);
|
|
61
61
|
return {
|
|
62
|
-
/**
|
|
63
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Organization schema — Homepage + About page.
|
|
64
|
+
*
|
|
65
|
+
* Note: schema.org does NOT allow `inLanguage` or `availableLanguage` on
|
|
66
|
+
* Organization. The multilingual signal is carried by `knowsLanguage`
|
|
67
|
+
* (valid on Organization, BCP-47 codes). The `locale` param is retained
|
|
68
|
+
* for call-site signature stability but no longer emitted here.
|
|
69
|
+
*/
|
|
70
|
+
organization(_locale = "en") {
|
|
64
71
|
return {
|
|
65
72
|
"@context": "https://schema.org",
|
|
66
73
|
"@type": "Organization",
|
|
@@ -72,8 +79,7 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
72
79
|
url: `${brand.url}/logo.svg`
|
|
73
80
|
},
|
|
74
81
|
description: brand.description,
|
|
75
|
-
|
|
76
|
-
availableLanguage: [...supportedLanguages],
|
|
82
|
+
knowsLanguage: [...supportedLanguages],
|
|
77
83
|
founder: {
|
|
78
84
|
"@type": "Person",
|
|
79
85
|
name: brand.founder
|
|
@@ -124,7 +130,17 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
124
130
|
name: title,
|
|
125
131
|
description,
|
|
126
132
|
inLanguage: locale,
|
|
127
|
-
|
|
133
|
+
// Reference stub to the site-wide WebSite node. `url`/`name` are
|
|
134
|
+
// included (when the brand provides them) so the reference stands as a
|
|
135
|
+
// complete WebSite on pages rendered independently of the WebSite node,
|
|
136
|
+
// per schema.org @id-linking guidance. Guarded so a brand without
|
|
137
|
+
// `url`/`name` never emits `undefined`.
|
|
138
|
+
isPartOf: {
|
|
139
|
+
"@type": "WebSite",
|
|
140
|
+
"@id": ENTITY_IDS.website,
|
|
141
|
+
...brand.url ? { url: brand.url } : {},
|
|
142
|
+
...brand.name ? { name: brand.name } : {}
|
|
143
|
+
},
|
|
128
144
|
breadcrumb: { "@id": ENTITY_IDS.breadcrumb(path) },
|
|
129
145
|
potentialAction: {
|
|
130
146
|
"@type": "ReadAction",
|
|
@@ -136,6 +152,7 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
136
152
|
/** SoftwareApplication schema — Platform Hub, Platform Feature, Pricing. */
|
|
137
153
|
softwareApplication(name, description, url, locale = "en", options = {}) {
|
|
138
154
|
const aggregateRating = options.aggregateRating ?? brand.aggregateRating;
|
|
155
|
+
const offers = options.offers ?? brand.softwareApplicationOffers;
|
|
139
156
|
return {
|
|
140
157
|
"@context": "https://schema.org",
|
|
141
158
|
"@type": "SoftwareApplication",
|
|
@@ -145,8 +162,21 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
145
162
|
url: url || brand.url,
|
|
146
163
|
applicationCategory: "BusinessApplication",
|
|
147
164
|
operatingSystem: "Web",
|
|
165
|
+
// `inLanguage` is valid — SoftwareApplication is a CreativeWork subtype.
|
|
166
|
+
// `availableLanguage` is NOT valid on SoftwareApplication and is dropped.
|
|
148
167
|
inLanguage: locale,
|
|
149
|
-
|
|
168
|
+
// Google requires `offers` with a price. We expose only the price floor
|
|
169
|
+
// via AggregateOffer so A/B-tested tier prices stay hidden.
|
|
170
|
+
...offers ? {
|
|
171
|
+
offers: {
|
|
172
|
+
"@type": "AggregateOffer",
|
|
173
|
+
lowPrice: offers.lowPrice,
|
|
174
|
+
priceCurrency: offers.priceCurrency,
|
|
175
|
+
offerCount: offers.offerCount,
|
|
176
|
+
url: offers.url ?? `${brand.url}/pricing`,
|
|
177
|
+
availability: "https://schema.org/InStock"
|
|
178
|
+
}
|
|
179
|
+
} : {},
|
|
150
180
|
...aggregateRating ? {
|
|
151
181
|
aggregateRating: {
|
|
152
182
|
"@type": "AggregateRating",
|
|
@@ -226,15 +256,18 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
226
256
|
}))
|
|
227
257
|
};
|
|
228
258
|
},
|
|
229
|
-
/**
|
|
230
|
-
|
|
259
|
+
/**
|
|
260
|
+
* BreadcrumbList schema — Every public page.
|
|
261
|
+
* `inLanguage` is NOT valid on BreadcrumbList and is not emitted. The
|
|
262
|
+
* `locale` param is retained for call-site signature stability.
|
|
263
|
+
*/
|
|
264
|
+
breadcrumb(items, _locale = "en") {
|
|
231
265
|
const lastUrl = items.length > 0 ? items[items.length - 1].url : "/";
|
|
232
266
|
const path = lastUrl.startsWith("http") ? new URL(lastUrl).pathname : lastUrl;
|
|
233
267
|
return {
|
|
234
268
|
"@context": "https://schema.org",
|
|
235
269
|
"@type": "BreadcrumbList",
|
|
236
270
|
"@id": ENTITY_IDS.breadcrumb(path),
|
|
237
|
-
inLanguage: locale,
|
|
238
271
|
itemListElement: items.map((item, index) => ({
|
|
239
272
|
"@type": "ListItem",
|
|
240
273
|
position: index + 1,
|
|
@@ -243,8 +276,12 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
243
276
|
}))
|
|
244
277
|
};
|
|
245
278
|
},
|
|
246
|
-
/**
|
|
247
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Person schema — Team page, Blog author, Comparison author.
|
|
281
|
+
* `inLanguage` is NOT valid on Person (Person is not a CreativeWork) and is
|
|
282
|
+
* not emitted. The `locale` param is retained for signature stability.
|
|
283
|
+
*/
|
|
284
|
+
person(person, _locale = "en") {
|
|
248
285
|
const slug = person.slug || person.name.toLowerCase().replace(/\s+/g, "-");
|
|
249
286
|
return {
|
|
250
287
|
"@context": "https://schema.org",
|
|
@@ -254,7 +291,6 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
254
291
|
jobTitle: person.jobTitle,
|
|
255
292
|
url: person.url,
|
|
256
293
|
image: person.image,
|
|
257
|
-
inLanguage: locale,
|
|
258
294
|
worksFor: person.worksFor || {
|
|
259
295
|
"@type": "Organization",
|
|
260
296
|
"@id": ENTITY_IDS.organization,
|
|
@@ -298,8 +334,12 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
298
334
|
} : {}
|
|
299
335
|
};
|
|
300
336
|
},
|
|
301
|
-
/**
|
|
302
|
-
|
|
337
|
+
/**
|
|
338
|
+
* Product + multiple Offers schema — Pricing page.
|
|
339
|
+
* `inLanguage` is NOT valid on Product and is not emitted. The `locale`
|
|
340
|
+
* param is retained for call-site signature stability.
|
|
341
|
+
*/
|
|
342
|
+
productWithOffers(plans, testimonials = [], _locale = "en") {
|
|
303
343
|
return {
|
|
304
344
|
"@context": "https://schema.org",
|
|
305
345
|
"@type": "Product",
|
|
@@ -311,7 +351,6 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
311
351
|
"@id": ENTITY_IDS.organization,
|
|
312
352
|
name: brand.name
|
|
313
353
|
},
|
|
314
|
-
inLanguage: locale,
|
|
315
354
|
...testimonials.length > 0 ? { aggregateRating: aggregateRatingFromTestimonials(testimonials) } : {},
|
|
316
355
|
offers: plans.map((plan) => ({
|
|
317
356
|
"@type": "Offer",
|
|
@@ -355,7 +394,12 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
355
394
|
...transcript.transcript_text ? { transcript: transcript.transcript_text } : {}
|
|
356
395
|
};
|
|
357
396
|
},
|
|
358
|
-
/**
|
|
397
|
+
/**
|
|
398
|
+
* CustomerOrganization schema — Customer's company for Success Story pages.
|
|
399
|
+
* `industry` is NOT valid on Organization (schema.org allows only the coded
|
|
400
|
+
* `naics` / `isicV4`, plus free-text `keywords`). The free-text industry
|
|
401
|
+
* value is carried by `keywords`.
|
|
402
|
+
*/
|
|
359
403
|
customerOrganization(meta) {
|
|
360
404
|
return {
|
|
361
405
|
"@context": "https://schema.org",
|
|
@@ -365,7 +409,7 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
365
409
|
...meta.url ? { url: meta.url } : {},
|
|
366
410
|
...meta.logo ? { logo: meta.logo } : {},
|
|
367
411
|
...meta.description ? { description: meta.description } : {},
|
|
368
|
-
...meta.industry ? {
|
|
412
|
+
...meta.industry ? { keywords: meta.industry } : {},
|
|
369
413
|
...meta.sameAs && meta.sameAs.length > 0 ? { sameAs: meta.sameAs } : {}
|
|
370
414
|
};
|
|
371
415
|
},
|
|
@@ -408,8 +452,12 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
408
452
|
}))
|
|
409
453
|
};
|
|
410
454
|
},
|
|
411
|
-
/**
|
|
412
|
-
|
|
455
|
+
/**
|
|
456
|
+
* Service schema — Growth motion service offerings.
|
|
457
|
+
* Neither `inLanguage` nor `availableLanguage` is valid on Service, so both
|
|
458
|
+
* are dropped. The `locale` param is retained for signature stability.
|
|
459
|
+
*/
|
|
460
|
+
service(motion, _locale = "en") {
|
|
413
461
|
return {
|
|
414
462
|
"@context": "https://schema.org",
|
|
415
463
|
"@type": "Service",
|
|
@@ -422,8 +470,6 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
422
470
|
"@id": ENTITY_IDS.organization,
|
|
423
471
|
name: brand.name
|
|
424
472
|
},
|
|
425
|
-
inLanguage: locale,
|
|
426
|
-
availableLanguage: [...supportedLanguages],
|
|
427
473
|
areaServed: "Worldwide",
|
|
428
474
|
...motion.price ? {
|
|
429
475
|
offers: {
|
|
@@ -436,8 +482,12 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
436
482
|
termsOfService: `${brand.url}/legal/terms`
|
|
437
483
|
};
|
|
438
484
|
},
|
|
439
|
-
/**
|
|
440
|
-
|
|
485
|
+
/**
|
|
486
|
+
* JobPosting schema — Career detail pages.
|
|
487
|
+
* `inLanguage` is NOT valid on JobPosting and is not emitted. The `locale`
|
|
488
|
+
* param is retained for call-site signature stability.
|
|
489
|
+
*/
|
|
490
|
+
jobPosting(job, _locale = "en") {
|
|
441
491
|
return {
|
|
442
492
|
"@context": "https://schema.org",
|
|
443
493
|
"@type": "JobPosting",
|
|
@@ -462,8 +512,7 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
462
512
|
}
|
|
463
513
|
} : {
|
|
464
514
|
jobLocationType: "TELECOMMUTE"
|
|
465
|
-
}
|
|
466
|
-
inLanguage: locale
|
|
515
|
+
}
|
|
467
516
|
};
|
|
468
517
|
},
|
|
469
518
|
/** ItemList schema — Hub/listing pages. */
|
|
@@ -499,9 +548,17 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
499
548
|
}))
|
|
500
549
|
};
|
|
501
550
|
},
|
|
502
|
-
/**
|
|
551
|
+
/**
|
|
552
|
+
* Speakable — marks content sections suitable for voice assistant reading.
|
|
553
|
+
*
|
|
554
|
+
* Includes its own `@context` so it is valid when rendered as a standalone
|
|
555
|
+
* top-level JSON-LD node. When embedded inside another schema (e.g. as the
|
|
556
|
+
* `speakable` value on WebPage/Article), the surrounding `buildPageGraph`
|
|
557
|
+
* strips the redundant `@context`, so the nested case is unaffected.
|
|
558
|
+
*/
|
|
503
559
|
speakable(cssSelectors) {
|
|
504
560
|
return {
|
|
561
|
+
"@context": "https://schema.org",
|
|
505
562
|
"@type": "SpeakableSpecification",
|
|
506
563
|
cssSelector: cssSelectors
|
|
507
564
|
};
|
|
@@ -569,4 +626,4 @@ exports.canonicalUrl = canonicalUrl;
|
|
|
569
626
|
exports.createEntityIds = createEntityIds;
|
|
570
627
|
exports.createSchemaGenerators = createSchemaGenerators;
|
|
571
628
|
//# sourceMappingURL=out.js.map
|
|
572
|
-
//# sourceMappingURL=chunk-
|
|
629
|
+
//# sourceMappingURL=chunk-M4MLGT4B.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/web/seo/schema-generators.ts","../src/web/seo/JsonLd.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * Schema.org Generator System\n *\n * Pure functions that generate structured data objects for SEO.\n * Each generator accepts a `BrandConfig` and an optional `locale`. `inLanguage`\n * is emitted ONLY on schema types where schema.org permits it (CreativeWork\n * subtypes: WebPage, WebSite, Article, FAQPage, VideoObject, DefinedTermSet,\n * HowTo, SoftwareApplication). Types that forbid it (Organization, Person,\n * BreadcrumbList, Product, Service, JobPosting) accept `locale` for signature\n * stability but do not emit it.\n *\n * Architecture:\n * - Each generator returns an object with its own `@context` (standalone-safe).\n * - `buildPageGraph()` strips individual `@context` and wraps all schemas\n * in a single `{\"@context\": \"...\", \"@graph\": [...]}` for unified output.\n * - Use `JsonLd` React component to render the @graph into a single <script> tag.\n *\n * @example\n * ```ts\n * import { createSchemaGenerators, buildPageGraph } from '@salesmind-ai/design-system/web';\n *\n * const seo = createSchemaGenerators({\n * name: 'SalesMind AI',\n * url: 'https://sales-mind.ai',\n * description: 'AI sales automation',\n * tagline: 'AI-powered sales',\n * founder: 'Julien Gadea',\n * });\n *\n * const graph = buildPageGraph(\n * seo.organization(),\n * seo.website(),\n * seo.webPage('/pricing', 'Pricing', '...'),\n * );\n * ```\n */\n\nimport type {\n BrandConfig,\n ArticleMeta,\n BreadcrumbItem,\n CareerForSchema,\n CustomerOrganizationMeta,\n FAQItem,\n GlossaryTermForSchema,\n HowToMeta,\n HowToStep,\n ItemForList,\n PersonMeta,\n PricingPlan,\n ServiceMotion,\n SoftwareApplicationSchemaOptions,\n TestimonialForSchema,\n TranscriptForSchema,\n VideoObjectMeta,\n} from './types';\n\n// ─── Internal Helpers ────────────────────────────────────────────────────────\n\n/** Convert \"MM:SS\" or \"HH:MM:SS\" to ISO 8601 duration \"PT…\" */\nfunction toISO8601Duration(duration: string): string {\n if (duration.startsWith('PT')) return duration;\n const parts = duration.split(':').map(Number);\n if (parts.some(isNaN)) return duration;\n if (parts.length === 3) return `PT${parts[0]}H${parts[1]}M${parts[2]}S`;\n if (parts.length === 2) return `PT${parts[0]}M${parts[1]}S`;\n return `PT${parts[0]}S`;\n}\n\n/** Convert YouTube watch URL to embed URL */\nfunction toEmbedUrl(url: string): string | undefined {\n try {\n const parsed = new URL(url);\n if (parsed.hostname.includes('youtube.com') && parsed.searchParams.has('v')) {\n return `https://www.youtube.com/embed/${parsed.searchParams.get('v')}`;\n }\n if (parsed.hostname === 'youtu.be') {\n return `https://www.youtube.com/embed${parsed.pathname}`;\n }\n return url;\n } catch {\n return undefined;\n }\n}\n\n/** Map career type string to Schema.org employmentType */\nfunction mapEmploymentType(type?: string | null): string {\n if (!type) return 'FULL_TIME';\n const lower = type.toLowerCase();\n if (lower.includes('part')) return 'PART_TIME';\n if (lower.includes('contract')) return 'CONTRACTOR';\n if (lower.includes('intern')) return 'INTERN';\n if (lower.includes('temporary') || lower.includes('temp')) return 'TEMPORARY';\n return 'FULL_TIME';\n}\n\n// ─── Entity ID Factory ──────────────────────────────────────────────────────\n\n/**\n * Create stable entity ID anchors for @graph cross-referencing.\n * Every entity in the knowledge graph gets a permanent @id.\n * Google resolves @id references across the entire site.\n */\n// Returns either `pathOrUrl` as-is (when it is an absolute http(s) URL) or\n// concatenated to `brand.url`. Defensive against callers that pass an absolute\n// URL where a relative path is expected — prevents the doubled-prefix bug\n// `https://brand.aihttps://brand.ai/page#anchor`.\nfunction normalizeEntityPath(brandUrl: string, pathOrUrl: string): string {\n if (/^https?:\\/\\//i.test(pathOrUrl)) return pathOrUrl;\n return `${brandUrl}${pathOrUrl}`;\n}\n\nexport function createEntityIds(brand: BrandConfig) {\n return {\n organization: `${brand.url}/#organization`,\n website: `${brand.url}/#website`,\n software: `${brand.url}/#software`,\n product: `${brand.url}/pricing#product`,\n webpage: (path: string) => `${normalizeEntityPath(brand.url, path)}#webpage`,\n article: (path: string) => `${normalizeEntityPath(brand.url, path)}#article`,\n faq: (path: string) => `${normalizeEntityPath(brand.url, path)}#faq`,\n breadcrumb: (path: string) => `${normalizeEntityPath(brand.url, path)}#breadcrumb`,\n person: (slug: string) => `${brand.url}/company/team#person-${slug}`,\n video: (path: string) => `${normalizeEntityPath(brand.url, path)}#video`,\n review: (id: string) => `${brand.url}/#review-${id}`,\n service: (slug: string) => `${brand.url}/#service-${slug}`,\n customerOrganization: (slug: string) => `${brand.url}/#customer-org-${slug}`,\n customerPerson: (slug: string) => `${brand.url}/#customer-person-${slug}`,\n } as const;\n}\n\n// ─── Schema Generator Factory ───────────────────────────────────────────────\n\n/**\n * Create all schema generators bound to a specific brand configuration.\n * Returns an object with methods for each schema type.\n */\nexport function createSchemaGenerators(\n brand: BrandConfig,\n supportedLanguages: readonly string[] = ['en', 'fr', 'es'],\n) {\n const ENTITY_IDS = createEntityIds(brand);\n\n return {\n /**\n * Organization schema — Homepage + About page.\n *\n * Note: schema.org does NOT allow `inLanguage` or `availableLanguage` on\n * Organization. The multilingual signal is carried by `knowsLanguage`\n * (valid on Organization, BCP-47 codes). The `locale` param is retained\n * for call-site signature stability but no longer emitted here.\n */\n organization(_locale: string = 'en') {\n void _locale;\n return {\n '@context': 'https://schema.org',\n '@type': 'Organization',\n '@id': ENTITY_IDS.organization,\n name: brand.name,\n url: brand.url,\n logo: {\n '@type': 'ImageObject',\n url: `${brand.url}/logo.svg`,\n },\n description: brand.description,\n knowsLanguage: [...supportedLanguages],\n founder: {\n '@type': 'Person',\n name: brand.founder,\n },\n ...(brand.sameAs && brand.sameAs.length > 0 ? { sameAs: brand.sameAs } : {}),\n contactPoint: [] as Record<string, unknown>[],\n areaServed: 'Worldwide',\n };\n },\n\n /** WebSite schema — Homepage only (with SearchAction). */\n website(locale: string = 'en') {\n return {\n '@context': 'https://schema.org',\n '@type': 'WebSite',\n '@id': ENTITY_IDS.website,\n name: brand.name,\n url: brand.url,\n description: brand.tagline,\n inLanguage: locale,\n publisher: {\n '@type': 'Organization',\n '@id': ENTITY_IDS.organization,\n name: brand.name,\n },\n potentialAction: [\n {\n '@type': 'SearchAction',\n target: {\n '@type': 'EntryPoint',\n urlTemplate: `${brand.url}/blog?q={search_term_string}`,\n },\n 'query-input': 'required name=search_term_string',\n },\n {\n '@type': 'ReadAction',\n target: brand.url,\n },\n ],\n };\n },\n\n /** WebPage schema — Every public page. Links to WebSite + Breadcrumb via @id. */\n webPage(path: string, title: string, description: string, locale: string = 'en', speakable?: Record<string, unknown>) {\n return {\n '@context': 'https://schema.org',\n '@type': 'WebPage',\n '@id': ENTITY_IDS.webpage(path),\n url: `${brand.url}${path}`,\n name: title,\n description,\n inLanguage: locale,\n // Reference stub to the site-wide WebSite node. `url`/`name` are\n // included (when the brand provides them) so the reference stands as a\n // complete WebSite on pages rendered independently of the WebSite node,\n // per schema.org @id-linking guidance. Guarded so a brand without\n // `url`/`name` never emits `undefined`.\n isPartOf: {\n '@type': 'WebSite',\n '@id': ENTITY_IDS.website,\n ...(brand.url ? { url: brand.url } : {}),\n ...(brand.name ? { name: brand.name } : {}),\n },\n breadcrumb: { '@id': ENTITY_IDS.breadcrumb(path) },\n potentialAction: {\n '@type': 'ReadAction',\n target: `${brand.url}${path}`,\n },\n ...(speakable ? { speakable } : {}),\n };\n },\n\n /** SoftwareApplication schema — Platform Hub, Platform Feature, Pricing. */\n softwareApplication(\n name?: string,\n description?: string,\n url?: string,\n locale: string = 'en',\n options: SoftwareApplicationSchemaOptions = {},\n ) {\n const aggregateRating = options.aggregateRating ?? brand.aggregateRating;\n const offers = options.offers ?? brand.softwareApplicationOffers;\n\n return {\n '@context': 'https://schema.org',\n '@type': 'SoftwareApplication',\n '@id': ENTITY_IDS.software,\n name: name || brand.name,\n description: description || brand.description,\n url: url || brand.url,\n applicationCategory: 'BusinessApplication',\n operatingSystem: 'Web',\n // `inLanguage` is valid — SoftwareApplication is a CreativeWork subtype.\n // `availableLanguage` is NOT valid on SoftwareApplication and is dropped.\n inLanguage: locale,\n // Google requires `offers` with a price. We expose only the price floor\n // via AggregateOffer so A/B-tested tier prices stay hidden.\n ...(offers\n ? {\n offers: {\n '@type': 'AggregateOffer',\n lowPrice: offers.lowPrice,\n priceCurrency: offers.priceCurrency,\n offerCount: offers.offerCount,\n url: offers.url ?? `${brand.url}/pricing`,\n availability: 'https://schema.org/InStock',\n },\n }\n : {}),\n ...(aggregateRating\n ? {\n aggregateRating: {\n '@type': 'AggregateRating',\n ratingValue: String(aggregateRating.ratingValue),\n ratingCount: String(aggregateRating.reviewCount),\n bestRating: String(aggregateRating.bestRating ?? 5),\n worstRating: String(aggregateRating.worstRating ?? 1),\n },\n }\n : {}),\n author: {\n '@type': 'Organization',\n '@id': ENTITY_IDS.organization,\n name: brand.name,\n },\n };\n },\n\n /** Article schema — Blog posts, Comparison pages. */\n article(meta: ArticleMeta, locale: string = 'en') {\n let path: string;\n try {\n path = new URL(meta.url).pathname;\n } catch {\n path = meta.url.startsWith('/') ? meta.url : `/${meta.url}`;\n }\n\n return {\n '@context': 'https://schema.org',\n '@type': 'Article',\n '@id': ENTITY_IDS.article(path),\n headline: meta.title,\n description: meta.description,\n url: meta.url.startsWith('http') ? meta.url : `${brand.url}${meta.url}`,\n image: meta.image || `${brand.url}/og-default.png`,\n datePublished: meta.publishedTime,\n dateModified: meta.modifiedTime,\n inLanguage: locale,\n author: meta.authorSlug\n ? { '@id': ENTITY_IDS.person(meta.authorSlug) }\n : {\n '@type': 'Person',\n name: meta.authorName,\n url: meta.authorUrl || `${brand.url}/company/team`,\n },\n publisher: {\n '@type': 'Organization',\n '@id': ENTITY_IDS.organization,\n name: brand.name,\n logo: {\n '@type': 'ImageObject',\n url: `${brand.url}/logo.svg`,\n },\n },\n isPartOf: { '@type': 'WebSite', '@id': ENTITY_IDS.website },\n mainEntityOfPage: { '@id': ENTITY_IDS.webpage(path) },\n articleSection: meta.section,\n keywords: meta.tags?.join(', '),\n speakable: {\n '@type': 'SpeakableSpecification',\n cssSelector: meta.speakableCssSelectors || ['article h1', 'article .summary', 'article .lead'],\n },\n ...(meta.about ? { about: meta.about } : {}),\n ...(meta.video ? { video: meta.video } : {}),\n };\n },\n\n /** FAQPage schema — FAQ hub, Solutions, Platform Features, Comparisons, Integrations. */\n faqPage(items: FAQItem[], pageUrl: string, locale: string = 'en') {\n return {\n '@context': 'https://schema.org',\n '@type': 'FAQPage',\n '@id': ENTITY_IDS.faq(pageUrl),\n inLanguage: locale,\n mainEntity: items.map((item) => ({\n '@type': 'Question',\n name: item.question,\n acceptedAnswer: {\n '@type': 'Answer',\n text: item.answer,\n inLanguage: locale,\n },\n })),\n };\n },\n\n /**\n * BreadcrumbList schema — Every public page.\n * `inLanguage` is NOT valid on BreadcrumbList and is not emitted. The\n * `locale` param is retained for call-site signature stability.\n */\n breadcrumb(items: BreadcrumbItem[], _locale: string = 'en') {\n void _locale;\n const lastUrl = items.length > 0 ? items[items.length - 1].url : '/';\n const path = lastUrl.startsWith('http') ? new URL(lastUrl).pathname : lastUrl;\n\n return {\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n '@id': ENTITY_IDS.breadcrumb(path),\n itemListElement: items.map((item, index) => ({\n '@type': 'ListItem',\n position: index + 1,\n name: item.name,\n item: item.url.startsWith('http') ? item.url : `${brand.url}${item.url}`,\n })),\n };\n },\n\n /**\n * Person schema — Team page, Blog author, Comparison author.\n * `inLanguage` is NOT valid on Person (Person is not a CreativeWork) and is\n * not emitted. The `locale` param is retained for signature stability.\n */\n person(person: PersonMeta, _locale: string = 'en') {\n void _locale;\n const slug = person.slug || person.name.toLowerCase().replace(/\\s+/g, '-');\n\n return {\n '@context': 'https://schema.org',\n '@type': 'Person',\n '@id': person.entityIdOverride || ENTITY_IDS.person(slug),\n name: person.name,\n jobTitle: person.jobTitle,\n url: person.url,\n image: person.image,\n worksFor: person.worksFor || {\n '@type': 'Organization',\n '@id': ENTITY_IDS.organization,\n name: brand.name,\n },\n sameAs: person.sameAs || [],\n };\n },\n\n /** Review schema — Generated from testimonials. */\n review(testimonial: TestimonialForSchema) {\n return {\n '@context': 'https://schema.org',\n '@type': 'Review',\n '@id': ENTITY_IDS.review(testimonial.id),\n author: {\n '@type': 'Person',\n ...(testimonial.authorEntityId ? { '@id': testimonial.authorEntityId } : {}),\n name: testimonial.customer_name,\n ...(testimonial.occupation ? { jobTitle: testimonial.occupation } : {}),\n },\n reviewBody: testimonial.quote || '',\n ...(testimonial.star_rating\n ? {\n reviewRating: {\n '@type': 'Rating',\n ratingValue: String(testimonial.star_rating),\n bestRating: '5',\n worstRating: '1',\n },\n }\n : {}),\n ...(testimonial.review_date ? { datePublished: testimonial.review_date } : {}),\n itemReviewed: {\n '@type': 'SoftwareApplication',\n '@id': ENTITY_IDS.software,\n name: brand.name,\n },\n ...(testimonial.review_source\n ? {\n publisher: {\n '@type': 'Organization',\n name: testimonial.review_source,\n },\n }\n : {}),\n };\n },\n\n /**\n * Product + multiple Offers schema — Pricing page.\n * `inLanguage` is NOT valid on Product and is not emitted. The `locale`\n * param is retained for call-site signature stability.\n */\n productWithOffers(\n plans: PricingPlan[],\n testimonials: TestimonialForSchema[] = [],\n _locale: string = 'en',\n ) {\n void _locale;\n return {\n '@context': 'https://schema.org',\n '@type': 'Product',\n '@id': ENTITY_IDS.product,\n name: brand.name,\n description: brand.description,\n brand: {\n '@type': 'Organization',\n '@id': ENTITY_IDS.organization,\n name: brand.name,\n },\n ...(testimonials.length > 0\n ? { aggregateRating: aggregateRatingFromTestimonials(testimonials) }\n : {}),\n offers: plans.map((plan) => ({\n '@type': 'Offer',\n name: plan.name,\n description: plan.description,\n price: plan.price.replace(/[^0-9.]/g, '') || '0',\n priceCurrency: plan.priceCurrency || 'USD',\n availability: 'https://schema.org/InStock',\n url: `${brand.url}/pricing`,\n ...(plan.billingPeriod\n ? {\n priceSpecification: {\n '@type': 'UnitPriceSpecification',\n price: plan.price.replace(/[^0-9.]/g, '') || '0',\n priceCurrency: plan.priceCurrency || 'USD',\n billingDuration: plan.billingPeriod,\n },\n }\n : {}),\n })),\n };\n },\n\n /** VideoObject schema — Transcript detail pages. */\n videoObject(transcript: TranscriptForSchema, locale: string = 'en') {\n const path = transcript.path || `/resources/transcripts/${transcript.slug}`;\n\n return {\n '@context': 'https://schema.org',\n '@type': 'VideoObject',\n '@id': ENTITY_IDS.video(path),\n name: transcript.title,\n description: transcript.summary || transcript.title,\n ...(transcript.video_link ? { contentUrl: transcript.video_link } : {}),\n ...(transcript.video_link ? { embedUrl: toEmbedUrl(transcript.video_link) } : {}),\n ...(transcript.duration\n ? { duration: toISO8601Duration(transcript.duration) }\n : {}),\n ...(transcript.published_at ? { uploadDate: transcript.published_at } : {}),\n ...(transcript.thumbnailUrl ? { thumbnailUrl: transcript.thumbnailUrl } : {}),\n inLanguage: locale,\n publisher: {\n '@type': 'Organization',\n '@id': ENTITY_IDS.organization,\n name: brand.name,\n },\n ...(transcript.transcript_text ? { transcript: transcript.transcript_text } : {}),\n };\n },\n\n /**\n * CustomerOrganization schema — Customer's company for Success Story pages.\n * `industry` is NOT valid on Organization (schema.org allows only the coded\n * `naics` / `isicV4`, plus free-text `keywords`). The free-text industry\n * value is carried by `keywords`.\n */\n customerOrganization(meta: CustomerOrganizationMeta) {\n return {\n '@context': 'https://schema.org',\n '@type': 'Organization',\n '@id': ENTITY_IDS.customerOrganization(meta.slug),\n name: meta.name,\n ...(meta.url ? { url: meta.url } : {}),\n ...(meta.logo ? { logo: meta.logo } : {}),\n ...(meta.description ? { description: meta.description } : {}),\n ...(meta.industry ? { keywords: meta.industry } : {}),\n ...(meta.sameAs && meta.sameAs.length > 0 ? { sameAs: meta.sameAs } : {}),\n };\n },\n\n /** Generic VideoObject — Success story main video and shorts. */\n videoObjectGeneric(meta: VideoObjectMeta, locale: string = 'en') {\n const videoId = meta.fragment\n ? `${brand.url}${meta.path}#${meta.fragment}`\n : ENTITY_IDS.video(meta.path);\n return {\n '@context': 'https://schema.org',\n '@type': 'VideoObject',\n '@id': videoId,\n name: meta.title,\n ...(meta.description ? { description: meta.description } : {}),\n ...(meta.videoUrl ? { contentUrl: meta.videoUrl } : {}),\n ...(meta.embedUrl ? { embedUrl: meta.embedUrl } : {}),\n ...(meta.thumbnailUrl ? { thumbnailUrl: meta.thumbnailUrl } : {}),\n ...(meta.duration ? { duration: meta.duration } : {}),\n ...(meta.uploadDate ? { uploadDate: meta.uploadDate } : {}),\n ...(meta.transcript ? { transcript: meta.transcript } : {}),\n inLanguage: locale,\n publisher: { '@id': ENTITY_IDS.organization },\n };\n },\n\n /** HowTo schema — Solution pages, tutorial blog posts. */\n howTo(steps: HowToStep[], meta: HowToMeta, locale: string = 'en') {\n return {\n '@context': 'https://schema.org',\n '@type': 'HowTo',\n name: meta.name,\n description: meta.description,\n inLanguage: locale,\n ...(meta.totalTime ? { totalTime: meta.totalTime } : {}),\n ...(meta.image ? { image: meta.image } : {}),\n step: steps.map((step, index) => ({\n '@type': 'HowToStep',\n position: index + 1,\n name: step.name,\n text: step.text,\n ...(step.url ? { url: step.url } : {}),\n ...(step.image ? { image: step.image } : {}),\n })),\n };\n },\n\n /**\n * Service schema — Growth motion service offerings.\n * Neither `inLanguage` nor `availableLanguage` is valid on Service, so both\n * are dropped. The `locale` param is retained for signature stability.\n */\n service(motion: ServiceMotion, _locale: string = 'en') {\n void _locale;\n return {\n '@context': 'https://schema.org',\n '@type': 'Service',\n '@id': ENTITY_IDS.service(motion.slug),\n name: motion.name,\n description: motion.description,\n url: motion.url.startsWith('http') ? motion.url : `${brand.url}${motion.url}`,\n provider: {\n '@type': 'Organization',\n '@id': ENTITY_IDS.organization,\n name: brand.name,\n },\n areaServed: 'Worldwide',\n ...(motion.price\n ? {\n offers: {\n '@type': 'Offer',\n price: motion.price.replace(/[^0-9.]/g, '') || '0',\n priceCurrency: motion.priceCurrency || 'USD',\n availability: 'https://schema.org/InStock',\n },\n }\n : {}),\n termsOfService: `${brand.url}/legal/terms`,\n };\n },\n\n /**\n * JobPosting schema — Career detail pages.\n * `inLanguage` is NOT valid on JobPosting and is not emitted. The `locale`\n * param is retained for call-site signature stability.\n */\n jobPosting(job: CareerForSchema, _locale: string = 'en') {\n void _locale;\n return {\n '@context': 'https://schema.org',\n '@type': 'JobPosting',\n '@id': `${brand.url}/careers/${job.slug}#jobposting`,\n title: job.title,\n description: job.description || '',\n datePosted: job.published_at || job.created_at,\n employmentType: mapEmploymentType(job.type),\n hiringOrganization: {\n '@type': 'Organization',\n '@id': ENTITY_IDS.organization,\n name: brand.name,\n sameAs: brand.url,\n },\n ...(job.location\n ? {\n jobLocation: {\n '@type': 'Place',\n address: {\n '@type': 'PostalAddress',\n addressLocality: job.location,\n },\n },\n }\n : {\n jobLocationType: 'TELECOMMUTE',\n }),\n };\n },\n\n /** ItemList schema — Hub/listing pages. */\n itemList(items: ItemForList[], listName: string) {\n return {\n '@context': 'https://schema.org',\n '@type': 'ItemList',\n name: listName,\n numberOfItems: items.length,\n itemListElement: items.map((item, index) => ({\n '@type': 'ListItem',\n position: item.position ?? index + 1,\n name: item.name,\n url: item.url.startsWith('http') ? item.url : `${brand.url}${item.url}`,\n ...(item.description ? { description: item.description } : {}),\n ...(item.image ? { image: item.image } : {}),\n })),\n };\n },\n\n /** DefinedTermSet schema — Glossary page. */\n definedTermSet(terms: GlossaryTermForSchema[], locale: string = 'en') {\n return {\n '@context': 'https://schema.org',\n '@type': 'DefinedTermSet',\n '@id': `${brand.url}/resources/glossary#termset`,\n name: 'AI Sales Glossary',\n inLanguage: locale,\n hasDefinedTerm: terms.map((term) => ({\n '@type': 'DefinedTerm',\n name: term.term,\n description: term.definition,\n url: term.url || `${brand.url}/resources/glossary#${term.slug}`,\n })),\n };\n },\n\n /**\n * Speakable — marks content sections suitable for voice assistant reading.\n *\n * Includes its own `@context` so it is valid when rendered as a standalone\n * top-level JSON-LD node. When embedded inside another schema (e.g. as the\n * `speakable` value on WebPage/Article), the surrounding `buildPageGraph`\n * strips the redundant `@context`, so the nested case is unaffected.\n */\n speakable(cssSelectors: string[]): Record<string, unknown> {\n return {\n '@context': 'https://schema.org',\n '@type': 'SpeakableSpecification',\n cssSelector: cssSelectors,\n };\n },\n\n /** Access the entity IDs for cross-referencing */\n entityIds: ENTITY_IDS,\n };\n}\n\n// ─── Standalone Utilities ───────────────────────────────────────────────────\n\n/**\n * Compute AggregateRating from real testimonial data.\n * Falls back to hardcoded 4.7/150 when no rated testimonials exist.\n * Returns a fragment (no @context) — meant to be embedded in Product/SoftwareApp.\n */\nexport function aggregateRatingFromTestimonials(testimonials: TestimonialForSchema[]) {\n const rated = testimonials.filter((t) => t.star_rating != null && t.star_rating > 0);\n\n if (rated.length === 0) {\n return {\n '@type': 'AggregateRating',\n ratingValue: '4.7',\n ratingCount: '150',\n bestRating: '5',\n worstRating: '1',\n };\n }\n\n const sum = rated.reduce((acc, t) => acc + (t.star_rating || 0), 0);\n const avg = (sum / rated.length).toFixed(1);\n\n return {\n '@type': 'AggregateRating',\n ratingValue: avg,\n ratingCount: String(rated.length),\n bestRating: '5',\n worstRating: '1',\n };\n}\n\n/**\n * Assemble multiple schema entities into a single @graph array.\n * Strips individual `@context` from each schema — the wrapper provides it once.\n *\n * @example\n * ```ts\n * const graph = buildPageGraph(\n * seo.organization(),\n * seo.website(),\n * seo.webPage('/pricing', 'Pricing', '...'),\n * seo.breadcrumb(crumbs),\n * );\n * ```\n */\nexport function buildPageGraph(\n ...schemas: Record<string, unknown>[]\n): Record<string, unknown> {\n const graph = schemas.map((schema) => {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { '@context': _, ...rest } = schema;\n return rest;\n });\n\n return {\n '@context': 'https://schema.org',\n '@graph': graph,\n };\n}\n\n/**\n * Build canonical URL from pathname.\n * Removes trailing slash (except root) and query params.\n *\n * @param baseUrl - The site's base URL (e.g. \"https://sales-mind.ai\")\n * @param pathname - The route path (e.g. \"/pricing\", \"/blog/post/foo\")\n * @param locale - BCP-47 locale code. 'en' = no prefix (default). Others get /{locale}/ prefix.\n */\nexport function canonicalUrl(baseUrl: string, pathname: string, locale?: string): string {\n const clean = pathname === '/' ? '/' : pathname.replace(/\\/+$/, '');\n\n if (locale && locale !== 'en') {\n const stripped = clean.replace(new RegExp(`^/${locale}(/|$)`), '$1') || '/';\n const path = stripped === '/' ? '' : stripped;\n return `${baseUrl}/${locale}${path}`;\n }\n\n return `${baseUrl}${clean}`;\n}\n","/**\n * JsonLd — Renders structured data as a `<script type=\"application/ld+json\">` tag.\n *\n * Framework-agnostic: works with any React-based framework (Next.js, Vite, Remix, etc.).\n * Safely serializes the data object and escapes `</script>` sequences.\n *\n * @example\n * ```tsx\n * import { JsonLd, buildPageGraph } from '@salesmind-ai/design-system/web';\n *\n * <JsonLd data={buildPageGraph(seo.organization(), seo.website())} />\n * ```\n */\nexport interface JsonLdProps {\n /** The structured data object (schema.org format) */\n data: Record<string, unknown>;\n /** Optional nonce for CSP headers */\n nonce?: string;\n}\n\nexport function JsonLd({ data, nonce }: JsonLdProps) {\n const json = JSON.stringify(data).replace(/<\\/script>/gi, '<\\\\/script>');\n\n return (\n <script\n type=\"application/ld+json\"\n nonce={nonce}\n dangerouslySetInnerHTML={{ __html: json }}\n />\n );\n}\n"]}
|
|
@@ -4,7 +4,16 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
4
4
|
|
|
5
5
|
// src/components/SectionShell/SectionShell.tsx
|
|
6
6
|
var SectionHeader = forwardRef(
|
|
7
|
-
({
|
|
7
|
+
({
|
|
8
|
+
title,
|
|
9
|
+
subtitle,
|
|
10
|
+
eyebrow,
|
|
11
|
+
align = "center",
|
|
12
|
+
size = "default",
|
|
13
|
+
titleAs: TitleElement = "h2",
|
|
14
|
+
className,
|
|
15
|
+
...props
|
|
16
|
+
}, ref) => {
|
|
8
17
|
if (!title && !subtitle && !eyebrow) return null;
|
|
9
18
|
return /* @__PURE__ */ jsxs(
|
|
10
19
|
"header",
|
|
@@ -20,7 +29,7 @@ var SectionHeader = forwardRef(
|
|
|
20
29
|
...props,
|
|
21
30
|
children: [
|
|
22
31
|
eyebrow && /* @__PURE__ */ jsx("span", { className: "ds-section-header__eyebrow", children: eyebrow }),
|
|
23
|
-
title && /* @__PURE__ */ jsx(
|
|
32
|
+
title && /* @__PURE__ */ jsx(TitleElement, { className: "ds-section-header__title", children: title }),
|
|
24
33
|
subtitle && /* @__PURE__ */ jsx("p", { className: "ds-section-header__subtitle", children: subtitle })
|
|
25
34
|
]
|
|
26
35
|
}
|
|
@@ -66,4 +75,4 @@ SectionShell.displayName = "SectionShell";
|
|
|
66
75
|
|
|
67
76
|
export { SectionHeader, SectionShell };
|
|
68
77
|
//# sourceMappingURL=out.js.map
|
|
69
|
-
//# sourceMappingURL=chunk-
|
|
78
|
+
//# sourceMappingURL=chunk-MPOYZNAA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/SectionShell/SectionShell.tsx"],"names":[],"mappings":";AAAA,SAAgB,kBAAkC;AAClD,OAAO,UAAU;AAwCX,SAWc,KAXd;AAjBC,IAAM,gBAAgB;AAAA,EAC3B,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,SAAS,eAAe;AAAA,IACxB;AAAA,IACA,GAAG;AAAA,EACL,GACA,QACG;AACH,QAAI,CAAC,SAAS,CAAC,YAAY,CAAC,QAAS,QAAO;AAE5C,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,sBAAsB,KAAK;AAAA,UAC3B,SAAS,aAAa;AAAA,UACtB,SAAS,WAAW;AAAA,UACpB;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEH;AAAA,qBAAW,oBAAC,UAAK,WAAU,8BAA8B,mBAAQ;AAAA,UACjE,SAAS,oBAAC,gBAAa,WAAU,4BAA4B,iBAAM;AAAA,UACnE,YAAY,oBAAC,OAAE,WAAU,+BAA+B,oBAAS;AAAA;AAAA;AAAA,IACpE;AAAA,EAEJ;AACF;AACA,cAAc,cAAc;AAcrB,IAAM,eAAe;AAAA,EAC1B,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,UAAU;AAAA,IACV;AAAA,IACA,iBAAiB;AAAA,IACjB,GAAG;AAAA,EACL,GACA,QACG;AACH,UAAM,uBAA+C;AAAA,MACnD,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,OAAO;AAAA,IACT;AACA,UAAM,WAAW,iBACb,SACA,gBACG,qBAAqB,aAAa,KAAK,uCACxC;AAEN,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,kBAAkB,UAAU;AAAA,UAC5B,uBAAuB,OAAO;AAAA,UAC9B;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEJ,8BAAC,SAAI,OAAO,EAAC,UAAU,cAAc,QAAQ,eAAe,kBAAkB,OAAO,OAAM,GACxF,UACH;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;AACA,aAAa,cAAc","sourcesContent":["import React, { forwardRef, HTMLAttributes } from 'react';\nimport clsx from 'clsx';\nimport './SectionShell.css';\n\n/* ============================================================================\n Section Header Component\n ============================================================================ */\n\nexport interface SectionHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n title?: React.ReactNode;\n subtitle?: React.ReactNode;\n eyebrow?: React.ReactNode;\n align?: 'left' | 'center' | 'right';\n size?: 'compact' | 'default' | 'large';\n /**\n * The heading element rendered for `title`. Defaults to `'h2'` so section\n * headers stay below the page `h1`. Set to `'h1'` when this header is the\n * primary heading of the page (one per page) to keep a valid document\n * outline. Styling is class-driven (`.ds-section-header__title`), so the\n * tag change is purely semantic — the visual size is unchanged.\n */\n titleAs?: React.ElementType;\n}\n\nexport const SectionHeader = forwardRef<HTMLDivElement, SectionHeaderProps>(\n (\n {\n title,\n subtitle,\n eyebrow,\n align = 'center',\n size = 'default',\n titleAs: TitleElement = 'h2',\n className,\n ...props\n },\n ref,\n ) => {\n if (!title && !subtitle && !eyebrow) return null;\n\n return (\n <header\n ref={ref}\n className={clsx(\n 'ds-section-header',\n `ds-section-header--${align}`,\n size === 'compact' && 'ds-section-header--compact',\n size === 'large' && 'ds-section-header--large',\n className,\n )}\n {...props}\n >\n {eyebrow && <span className=\"ds-section-header__eyebrow\">{eyebrow}</span>}\n {title && <TitleElement className=\"ds-section-header__title\">{title}</TitleElement>}\n {subtitle && <p className=\"ds-section-header__subtitle\">{subtitle}</p>}\n </header>\n );\n },\n);\nSectionHeader.displayName = 'SectionHeader';\n\n/* ============================================================================\n Section Shell Component\n ============================================================================ */\n\nexport interface SectionShellProps extends HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n background?: 'default' | 'muted' | 'brand' | 'transparent' | 'dark';\n padding?: 'none' | 'sm' | 'md' | 'lg';\n containerSize?: 'sm' | 'md' | 'lg' | 'xl' | 'fluid'; // Maps to Container max-width\n containerFluid?: boolean;\n}\n\nexport const SectionShell = forwardRef<HTMLDivElement, SectionShellProps>(\n (\n {\n className,\n children,\n background = 'default',\n padding = 'md',\n containerSize,\n containerFluid = false,\n ...props\n },\n ref,\n ) => {\n const containerMaxWidthMap: Record<string, string> = {\n sm: 'var(--container-max-width-sm, 640px)',\n md: 'var(--container-max-width-md, 768px)',\n lg: 'var(--container-max-width-lg, 1024px)',\n xl: 'var(--container-max-width-xl, 1280px)',\n fluid: 'none',\n };\n const maxWidth = containerFluid\n ? 'none'\n : containerSize\n ? (containerMaxWidthMap[containerSize] ?? 'var(--container-max-width, 1200px)')\n : 'var(--container-max-width, 1200px)';\n\n return (\n <section\n ref={ref}\n className={clsx(\n 'ds-section',\n `ds-section--bg-${background}`,\n `ds-section--padding-${padding}`,\n className,\n )}\n {...props}\n >\n <div style={{maxWidth, marginInline: 'auto', paddingInline: 'var(--space-4)', width: '100%'}}>\n {children}\n </div>\n </section>\n );\n },\n);\nSectionShell.displayName = 'SectionShell';\n"]}
|
|
@@ -57,8 +57,15 @@ function createEntityIds(brand) {
|
|
|
57
57
|
function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"]) {
|
|
58
58
|
const ENTITY_IDS = createEntityIds(brand);
|
|
59
59
|
return {
|
|
60
|
-
/**
|
|
61
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Organization schema — Homepage + About page.
|
|
62
|
+
*
|
|
63
|
+
* Note: schema.org does NOT allow `inLanguage` or `availableLanguage` on
|
|
64
|
+
* Organization. The multilingual signal is carried by `knowsLanguage`
|
|
65
|
+
* (valid on Organization, BCP-47 codes). The `locale` param is retained
|
|
66
|
+
* for call-site signature stability but no longer emitted here.
|
|
67
|
+
*/
|
|
68
|
+
organization(_locale = "en") {
|
|
62
69
|
return {
|
|
63
70
|
"@context": "https://schema.org",
|
|
64
71
|
"@type": "Organization",
|
|
@@ -70,8 +77,7 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
70
77
|
url: `${brand.url}/logo.svg`
|
|
71
78
|
},
|
|
72
79
|
description: brand.description,
|
|
73
|
-
|
|
74
|
-
availableLanguage: [...supportedLanguages],
|
|
80
|
+
knowsLanguage: [...supportedLanguages],
|
|
75
81
|
founder: {
|
|
76
82
|
"@type": "Person",
|
|
77
83
|
name: brand.founder
|
|
@@ -122,7 +128,17 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
122
128
|
name: title,
|
|
123
129
|
description,
|
|
124
130
|
inLanguage: locale,
|
|
125
|
-
|
|
131
|
+
// Reference stub to the site-wide WebSite node. `url`/`name` are
|
|
132
|
+
// included (when the brand provides them) so the reference stands as a
|
|
133
|
+
// complete WebSite on pages rendered independently of the WebSite node,
|
|
134
|
+
// per schema.org @id-linking guidance. Guarded so a brand without
|
|
135
|
+
// `url`/`name` never emits `undefined`.
|
|
136
|
+
isPartOf: {
|
|
137
|
+
"@type": "WebSite",
|
|
138
|
+
"@id": ENTITY_IDS.website,
|
|
139
|
+
...brand.url ? { url: brand.url } : {},
|
|
140
|
+
...brand.name ? { name: brand.name } : {}
|
|
141
|
+
},
|
|
126
142
|
breadcrumb: { "@id": ENTITY_IDS.breadcrumb(path) },
|
|
127
143
|
potentialAction: {
|
|
128
144
|
"@type": "ReadAction",
|
|
@@ -134,6 +150,7 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
134
150
|
/** SoftwareApplication schema — Platform Hub, Platform Feature, Pricing. */
|
|
135
151
|
softwareApplication(name, description, url, locale = "en", options = {}) {
|
|
136
152
|
const aggregateRating = options.aggregateRating ?? brand.aggregateRating;
|
|
153
|
+
const offers = options.offers ?? brand.softwareApplicationOffers;
|
|
137
154
|
return {
|
|
138
155
|
"@context": "https://schema.org",
|
|
139
156
|
"@type": "SoftwareApplication",
|
|
@@ -143,8 +160,21 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
143
160
|
url: url || brand.url,
|
|
144
161
|
applicationCategory: "BusinessApplication",
|
|
145
162
|
operatingSystem: "Web",
|
|
163
|
+
// `inLanguage` is valid — SoftwareApplication is a CreativeWork subtype.
|
|
164
|
+
// `availableLanguage` is NOT valid on SoftwareApplication and is dropped.
|
|
146
165
|
inLanguage: locale,
|
|
147
|
-
|
|
166
|
+
// Google requires `offers` with a price. We expose only the price floor
|
|
167
|
+
// via AggregateOffer so A/B-tested tier prices stay hidden.
|
|
168
|
+
...offers ? {
|
|
169
|
+
offers: {
|
|
170
|
+
"@type": "AggregateOffer",
|
|
171
|
+
lowPrice: offers.lowPrice,
|
|
172
|
+
priceCurrency: offers.priceCurrency,
|
|
173
|
+
offerCount: offers.offerCount,
|
|
174
|
+
url: offers.url ?? `${brand.url}/pricing`,
|
|
175
|
+
availability: "https://schema.org/InStock"
|
|
176
|
+
}
|
|
177
|
+
} : {},
|
|
148
178
|
...aggregateRating ? {
|
|
149
179
|
aggregateRating: {
|
|
150
180
|
"@type": "AggregateRating",
|
|
@@ -224,15 +254,18 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
224
254
|
}))
|
|
225
255
|
};
|
|
226
256
|
},
|
|
227
|
-
/**
|
|
228
|
-
|
|
257
|
+
/**
|
|
258
|
+
* BreadcrumbList schema — Every public page.
|
|
259
|
+
* `inLanguage` is NOT valid on BreadcrumbList and is not emitted. The
|
|
260
|
+
* `locale` param is retained for call-site signature stability.
|
|
261
|
+
*/
|
|
262
|
+
breadcrumb(items, _locale = "en") {
|
|
229
263
|
const lastUrl = items.length > 0 ? items[items.length - 1].url : "/";
|
|
230
264
|
const path = lastUrl.startsWith("http") ? new URL(lastUrl).pathname : lastUrl;
|
|
231
265
|
return {
|
|
232
266
|
"@context": "https://schema.org",
|
|
233
267
|
"@type": "BreadcrumbList",
|
|
234
268
|
"@id": ENTITY_IDS.breadcrumb(path),
|
|
235
|
-
inLanguage: locale,
|
|
236
269
|
itemListElement: items.map((item, index) => ({
|
|
237
270
|
"@type": "ListItem",
|
|
238
271
|
position: index + 1,
|
|
@@ -241,8 +274,12 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
241
274
|
}))
|
|
242
275
|
};
|
|
243
276
|
},
|
|
244
|
-
/**
|
|
245
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Person schema — Team page, Blog author, Comparison author.
|
|
279
|
+
* `inLanguage` is NOT valid on Person (Person is not a CreativeWork) and is
|
|
280
|
+
* not emitted. The `locale` param is retained for signature stability.
|
|
281
|
+
*/
|
|
282
|
+
person(person, _locale = "en") {
|
|
246
283
|
const slug = person.slug || person.name.toLowerCase().replace(/\s+/g, "-");
|
|
247
284
|
return {
|
|
248
285
|
"@context": "https://schema.org",
|
|
@@ -252,7 +289,6 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
252
289
|
jobTitle: person.jobTitle,
|
|
253
290
|
url: person.url,
|
|
254
291
|
image: person.image,
|
|
255
|
-
inLanguage: locale,
|
|
256
292
|
worksFor: person.worksFor || {
|
|
257
293
|
"@type": "Organization",
|
|
258
294
|
"@id": ENTITY_IDS.organization,
|
|
@@ -296,8 +332,12 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
296
332
|
} : {}
|
|
297
333
|
};
|
|
298
334
|
},
|
|
299
|
-
/**
|
|
300
|
-
|
|
335
|
+
/**
|
|
336
|
+
* Product + multiple Offers schema — Pricing page.
|
|
337
|
+
* `inLanguage` is NOT valid on Product and is not emitted. The `locale`
|
|
338
|
+
* param is retained for call-site signature stability.
|
|
339
|
+
*/
|
|
340
|
+
productWithOffers(plans, testimonials = [], _locale = "en") {
|
|
301
341
|
return {
|
|
302
342
|
"@context": "https://schema.org",
|
|
303
343
|
"@type": "Product",
|
|
@@ -309,7 +349,6 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
309
349
|
"@id": ENTITY_IDS.organization,
|
|
310
350
|
name: brand.name
|
|
311
351
|
},
|
|
312
|
-
inLanguage: locale,
|
|
313
352
|
...testimonials.length > 0 ? { aggregateRating: aggregateRatingFromTestimonials(testimonials) } : {},
|
|
314
353
|
offers: plans.map((plan) => ({
|
|
315
354
|
"@type": "Offer",
|
|
@@ -353,7 +392,12 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
353
392
|
...transcript.transcript_text ? { transcript: transcript.transcript_text } : {}
|
|
354
393
|
};
|
|
355
394
|
},
|
|
356
|
-
/**
|
|
395
|
+
/**
|
|
396
|
+
* CustomerOrganization schema — Customer's company for Success Story pages.
|
|
397
|
+
* `industry` is NOT valid on Organization (schema.org allows only the coded
|
|
398
|
+
* `naics` / `isicV4`, plus free-text `keywords`). The free-text industry
|
|
399
|
+
* value is carried by `keywords`.
|
|
400
|
+
*/
|
|
357
401
|
customerOrganization(meta) {
|
|
358
402
|
return {
|
|
359
403
|
"@context": "https://schema.org",
|
|
@@ -363,7 +407,7 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
363
407
|
...meta.url ? { url: meta.url } : {},
|
|
364
408
|
...meta.logo ? { logo: meta.logo } : {},
|
|
365
409
|
...meta.description ? { description: meta.description } : {},
|
|
366
|
-
...meta.industry ? {
|
|
410
|
+
...meta.industry ? { keywords: meta.industry } : {},
|
|
367
411
|
...meta.sameAs && meta.sameAs.length > 0 ? { sameAs: meta.sameAs } : {}
|
|
368
412
|
};
|
|
369
413
|
},
|
|
@@ -406,8 +450,12 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
406
450
|
}))
|
|
407
451
|
};
|
|
408
452
|
},
|
|
409
|
-
/**
|
|
410
|
-
|
|
453
|
+
/**
|
|
454
|
+
* Service schema — Growth motion service offerings.
|
|
455
|
+
* Neither `inLanguage` nor `availableLanguage` is valid on Service, so both
|
|
456
|
+
* are dropped. The `locale` param is retained for signature stability.
|
|
457
|
+
*/
|
|
458
|
+
service(motion, _locale = "en") {
|
|
411
459
|
return {
|
|
412
460
|
"@context": "https://schema.org",
|
|
413
461
|
"@type": "Service",
|
|
@@ -420,8 +468,6 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
420
468
|
"@id": ENTITY_IDS.organization,
|
|
421
469
|
name: brand.name
|
|
422
470
|
},
|
|
423
|
-
inLanguage: locale,
|
|
424
|
-
availableLanguage: [...supportedLanguages],
|
|
425
471
|
areaServed: "Worldwide",
|
|
426
472
|
...motion.price ? {
|
|
427
473
|
offers: {
|
|
@@ -434,8 +480,12 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
434
480
|
termsOfService: `${brand.url}/legal/terms`
|
|
435
481
|
};
|
|
436
482
|
},
|
|
437
|
-
/**
|
|
438
|
-
|
|
483
|
+
/**
|
|
484
|
+
* JobPosting schema — Career detail pages.
|
|
485
|
+
* `inLanguage` is NOT valid on JobPosting and is not emitted. The `locale`
|
|
486
|
+
* param is retained for call-site signature stability.
|
|
487
|
+
*/
|
|
488
|
+
jobPosting(job, _locale = "en") {
|
|
439
489
|
return {
|
|
440
490
|
"@context": "https://schema.org",
|
|
441
491
|
"@type": "JobPosting",
|
|
@@ -460,8 +510,7 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
460
510
|
}
|
|
461
511
|
} : {
|
|
462
512
|
jobLocationType: "TELECOMMUTE"
|
|
463
|
-
}
|
|
464
|
-
inLanguage: locale
|
|
513
|
+
}
|
|
465
514
|
};
|
|
466
515
|
},
|
|
467
516
|
/** ItemList schema — Hub/listing pages. */
|
|
@@ -497,9 +546,17 @@ function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"])
|
|
|
497
546
|
}))
|
|
498
547
|
};
|
|
499
548
|
},
|
|
500
|
-
/**
|
|
549
|
+
/**
|
|
550
|
+
* Speakable — marks content sections suitable for voice assistant reading.
|
|
551
|
+
*
|
|
552
|
+
* Includes its own `@context` so it is valid when rendered as a standalone
|
|
553
|
+
* top-level JSON-LD node. When embedded inside another schema (e.g. as the
|
|
554
|
+
* `speakable` value on WebPage/Article), the surrounding `buildPageGraph`
|
|
555
|
+
* strips the redundant `@context`, so the nested case is unaffected.
|
|
556
|
+
*/
|
|
501
557
|
speakable(cssSelectors) {
|
|
502
558
|
return {
|
|
559
|
+
"@context": "https://schema.org",
|
|
503
560
|
"@type": "SpeakableSpecification",
|
|
504
561
|
cssSelector: cssSelectors
|
|
505
562
|
};
|
|
@@ -562,4 +619,4 @@ function JsonLd({ data, nonce }) {
|
|
|
562
619
|
|
|
563
620
|
export { JsonLd, aggregateRatingFromTestimonials, buildPageGraph, canonicalUrl, createEntityIds, createSchemaGenerators };
|
|
564
621
|
//# sourceMappingURL=out.js.map
|
|
565
|
-
//# sourceMappingURL=chunk-
|
|
622
|
+
//# sourceMappingURL=chunk-QVGDMAZY.js.map
|