@salesmind-ai/design-system 0.3.0 → 0.3.2

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 (212) hide show
  1. package/README.md +32 -2
  2. package/dist/admin/index.cjs +68 -2928
  3. package/dist/admin/index.cjs.map +1 -1
  4. package/dist/admin/index.js +5 -2915
  5. package/dist/admin/index.js.map +1 -1
  6. package/dist/blog/index.cjs +53 -1064
  7. package/dist/blog/index.cjs.map +1 -1
  8. package/dist/blog/index.js +8 -1054
  9. package/dist/blog/index.js.map +1 -1
  10. package/dist/charts/index.cjs +46 -2694
  11. package/dist/charts/index.cjs.map +1 -1
  12. package/dist/charts/index.js +3 -2680
  13. package/dist/charts/index.js.map +1 -1
  14. package/dist/chunk-2GARWEJK.js +17 -0
  15. package/dist/chunk-2GARWEJK.js.map +1 -0
  16. package/dist/chunk-3NKRFUAR.js +37 -0
  17. package/dist/chunk-3NKRFUAR.js.map +1 -0
  18. package/dist/chunk-3TGSIILM.cjs +201 -0
  19. package/dist/chunk-3TGSIILM.cjs.map +1 -0
  20. package/dist/chunk-4GM5BGBN.cjs +801 -0
  21. package/dist/chunk-4GM5BGBN.cjs.map +1 -0
  22. package/dist/chunk-5LGDEZWY.cjs +2434 -0
  23. package/dist/chunk-5LGDEZWY.cjs.map +1 -0
  24. package/dist/chunk-6H4DSTXR.js +786 -0
  25. package/dist/chunk-6H4DSTXR.js.map +1 -0
  26. package/dist/chunk-6UNG76Y2.js +153 -0
  27. package/dist/chunk-6UNG76Y2.js.map +1 -0
  28. package/dist/chunk-7PX2AZ6Y.js +39 -0
  29. package/dist/chunk-7PX2AZ6Y.js.map +1 -0
  30. package/dist/chunk-B6AVAX4F.js +1415 -0
  31. package/dist/chunk-B6AVAX4F.js.map +1 -0
  32. package/dist/chunk-BILT5KD3.js +264 -0
  33. package/dist/chunk-BILT5KD3.js.map +1 -0
  34. package/dist/chunk-C2BCDNAV.js +24 -0
  35. package/dist/chunk-C2BCDNAV.js.map +1 -0
  36. package/dist/chunk-CH42VPWE.cjs +421 -0
  37. package/dist/chunk-CH42VPWE.cjs.map +1 -0
  38. package/dist/chunk-CJ2MKVAF.cjs +46 -0
  39. package/dist/chunk-CJ2MKVAF.cjs.map +1 -0
  40. package/dist/chunk-DP74LUXG.cjs +98 -0
  41. package/dist/chunk-DP74LUXG.cjs.map +1 -0
  42. package/dist/chunk-E7D6EKJ4.cjs +44 -0
  43. package/dist/chunk-E7D6EKJ4.cjs.map +1 -0
  44. package/dist/chunk-ECXBTUH6.cjs +584 -0
  45. package/dist/chunk-ECXBTUH6.cjs.map +1 -0
  46. package/dist/chunk-EFRAP5ES.js +157 -0
  47. package/dist/chunk-EFRAP5ES.js.map +1 -0
  48. package/dist/chunk-F6YYWMME.js +485 -0
  49. package/dist/chunk-F6YYWMME.js.map +1 -0
  50. package/dist/chunk-FAFAP4L5.js +183 -0
  51. package/dist/chunk-FAFAP4L5.js.map +1 -0
  52. package/dist/chunk-GUZIMHWS.js +1608 -0
  53. package/dist/chunk-GUZIMHWS.js.map +1 -0
  54. package/dist/chunk-H2Y6BSTL.cjs +69 -0
  55. package/dist/chunk-H2Y6BSTL.cjs.map +1 -0
  56. package/dist/chunk-HN4PHABT.js +126 -0
  57. package/dist/chunk-HN4PHABT.js.map +1 -0
  58. package/dist/chunk-HRENHNDJ.js +211 -0
  59. package/dist/chunk-HRENHNDJ.js.map +1 -0
  60. package/dist/chunk-I75BFEYT.cjs +2561 -0
  61. package/dist/chunk-I75BFEYT.cjs.map +1 -0
  62. package/dist/chunk-IFRATNLU.js +562 -0
  63. package/dist/chunk-IFRATNLU.js.map +1 -0
  64. package/dist/chunk-IYPXJ6YC.cjs +69 -0
  65. package/dist/chunk-IYPXJ6YC.cjs.map +1 -0
  66. package/dist/chunk-JPJN4YBC.js +409 -0
  67. package/dist/chunk-JPJN4YBC.js.map +1 -0
  68. package/dist/chunk-KBA2LFBG.js +62 -0
  69. package/dist/chunk-KBA2LFBG.js.map +1 -0
  70. package/dist/chunk-KCKUSU2M.cjs +166 -0
  71. package/dist/chunk-KCKUSU2M.cjs.map +1 -0
  72. package/dist/chunk-KJ2OXQF4.js +287 -0
  73. package/dist/chunk-KJ2OXQF4.js.map +1 -0
  74. package/dist/chunk-KNQEIU7O.cjs +1202 -0
  75. package/dist/chunk-KNQEIU7O.cjs.map +1 -0
  76. package/dist/chunk-KVGSVGRK.cjs +569 -0
  77. package/dist/chunk-KVGSVGRK.cjs.map +1 -0
  78. package/dist/chunk-L352JRV6.cjs +105 -0
  79. package/dist/chunk-L352JRV6.cjs.map +1 -0
  80. package/dist/chunk-LJADZITX.cjs +298 -0
  81. package/dist/chunk-LJADZITX.cjs.map +1 -0
  82. package/dist/chunk-LMJPWXTZ.cjs +194 -0
  83. package/dist/chunk-LMJPWXTZ.cjs.map +1 -0
  84. package/dist/chunk-LOWEAQST.js +701 -0
  85. package/dist/chunk-LOWEAQST.js.map +1 -0
  86. package/dist/chunk-MDB2WCRQ.cjs +137 -0
  87. package/dist/chunk-MDB2WCRQ.cjs.map +1 -0
  88. package/dist/chunk-MQDEE7HC.cjs +283 -0
  89. package/dist/chunk-MQDEE7HC.cjs.map +1 -0
  90. package/dist/chunk-MQRB634A.cjs +34 -0
  91. package/dist/chunk-MQRB634A.cjs.map +1 -0
  92. package/dist/chunk-MTI27RDV.js +185 -0
  93. package/dist/chunk-MTI27RDV.js.map +1 -0
  94. package/dist/chunk-MU6GW5ZV.js +2317 -0
  95. package/dist/chunk-MU6GW5ZV.js.map +1 -0
  96. package/dist/chunk-NN3TUHIH.js +28 -0
  97. package/dist/chunk-NN3TUHIH.js.map +1 -0
  98. package/dist/chunk-NT4LBP7D.cjs +111 -0
  99. package/dist/chunk-NT4LBP7D.cjs.map +1 -0
  100. package/dist/chunk-OLV7OD3X.cjs +502 -0
  101. package/dist/chunk-OLV7OD3X.cjs.map +1 -0
  102. package/dist/chunk-OXNXEQY7.js +2538 -0
  103. package/dist/chunk-OXNXEQY7.js.map +1 -0
  104. package/dist/chunk-P5BOFE5A.js +546 -0
  105. package/dist/chunk-P5BOFE5A.js.map +1 -0
  106. package/dist/chunk-Q2MFGYTE.cjs +1449 -0
  107. package/dist/chunk-Q2MFGYTE.cjs.map +1 -0
  108. package/dist/chunk-Q75DBVDY.cjs +68 -0
  109. package/dist/chunk-Q75DBVDY.cjs.map +1 -0
  110. package/dist/chunk-REQ5Q6ZI.js +1022 -0
  111. package/dist/chunk-REQ5Q6ZI.js.map +1 -0
  112. package/dist/chunk-SICKWUWB.js +62 -0
  113. package/dist/chunk-SICKWUWB.js.map +1 -0
  114. package/dist/chunk-T343CCH5.js +1190 -0
  115. package/dist/chunk-T343CCH5.js.map +1 -0
  116. package/dist/chunk-TEC62D4A.cjs +1624 -0
  117. package/dist/chunk-TEC62D4A.cjs.map +1 -0
  118. package/dist/chunk-TW5JB35D.js +2122 -0
  119. package/dist/chunk-TW5JB35D.js.map +1 -0
  120. package/dist/chunk-VC5LMUVQ.cjs +20 -0
  121. package/dist/chunk-VC5LMUVQ.cjs.map +1 -0
  122. package/dist/chunk-VM7WFMKI.cjs +76 -0
  123. package/dist/chunk-VM7WFMKI.cjs.map +1 -0
  124. package/dist/chunk-W2WTP6HS.cjs +233 -0
  125. package/dist/chunk-W2WTP6HS.cjs.map +1 -0
  126. package/dist/chunk-WH7PYHZY.cjs +35 -0
  127. package/dist/chunk-WH7PYHZY.cjs.map +1 -0
  128. package/dist/chunk-XQZVY7JJ.cjs +717 -0
  129. package/dist/chunk-XQZVY7JJ.cjs.map +1 -0
  130. package/dist/chunk-XU3OMQ7V.js +98 -0
  131. package/dist/chunk-XU3OMQ7V.js.map +1 -0
  132. package/dist/chunk-XWPDRMZG.js +62 -0
  133. package/dist/chunk-XWPDRMZG.js.map +1 -0
  134. package/dist/chunk-Y3CPKNB7.js +67 -0
  135. package/dist/chunk-Y3CPKNB7.js.map +1 -0
  136. package/dist/chunk-YNVRDD2P.js +98 -0
  137. package/dist/chunk-YNVRDD2P.js.map +1 -0
  138. package/dist/chunk-YSYR54XR.js +92 -0
  139. package/dist/chunk-YSYR54XR.js.map +1 -0
  140. package/dist/chunk-YTYDQBVY.cjs +162 -0
  141. package/dist/chunk-YTYDQBVY.cjs.map +1 -0
  142. package/dist/chunk-ZDLOA2UT.cjs +1042 -0
  143. package/dist/chunk-ZDLOA2UT.cjs.map +1 -0
  144. package/dist/chunk-ZWUKRCOJ.cjs +2162 -0
  145. package/dist/chunk-ZWUKRCOJ.cjs.map +1 -0
  146. package/dist/core/index.cjs +807 -4333
  147. package/dist/core/index.cjs.map +1 -1
  148. package/dist/core/index.js +14 -4130
  149. package/dist/core/index.js.map +1 -1
  150. package/dist/i18n/index.cjs +86 -558
  151. package/dist/i18n/index.cjs.map +1 -1
  152. package/dist/i18n/index.js +1 -544
  153. package/dist/i18n/index.js.map +1 -1
  154. package/dist/index.cjs +1432 -17139
  155. package/dist/index.cjs.map +1 -1
  156. package/dist/index.css +11 -7
  157. package/dist/index.css.map +1 -1
  158. package/dist/index.js +31 -16784
  159. package/dist/index.js.map +1 -1
  160. package/dist/marketing/index.cjs +142 -3072
  161. package/dist/marketing/index.cjs.map +1 -1
  162. package/dist/marketing/index.js +11 -3042
  163. package/dist/marketing/index.js.map +1 -1
  164. package/dist/motion/index.cjs +26 -1222
  165. package/dist/motion/index.cjs.map +1 -1
  166. package/dist/motion/index.js +2 -1215
  167. package/dist/motion/index.js.map +1 -1
  168. package/dist/nav/index.cjs +101 -1518
  169. package/dist/nav/index.cjs.map +1 -1
  170. package/dist/nav/index.js +4 -1498
  171. package/dist/nav/index.js.map +1 -1
  172. package/dist/report/index.cjs +171 -2403
  173. package/dist/report/index.cjs.map +1 -1
  174. package/dist/report/index.js +3 -2363
  175. package/dist/report/index.js.map +1 -1
  176. package/dist/sections/index.cjs +28 -378
  177. package/dist/sections/index.cjs.map +1 -1
  178. package/dist/sections/index.css +1 -4
  179. package/dist/sections/index.css.map +1 -1
  180. package/dist/sections/index.js +4 -372
  181. package/dist/sections/index.js.map +1 -1
  182. package/dist/social-proof/index.cjs +53 -1249
  183. package/dist/social-proof/index.cjs.map +1 -1
  184. package/dist/social-proof/index.css +10 -3
  185. package/dist/social-proof/index.css.map +1 -1
  186. package/dist/social-proof/index.js +6 -1234
  187. package/dist/social-proof/index.js.map +1 -1
  188. package/dist/theme/index.cjs +38 -565
  189. package/dist/theme/index.cjs.map +1 -1
  190. package/dist/theme/index.js +2 -555
  191. package/dist/theme/index.js.map +1 -1
  192. package/dist/web/client/index.cjs +48 -0
  193. package/dist/web/client/index.cjs.map +1 -0
  194. package/dist/web/client/index.css +456 -0
  195. package/dist/web/client/index.css.map +1 -0
  196. package/dist/web/client/index.d.cts +172 -0
  197. package/dist/web/client/index.d.ts +172 -0
  198. package/dist/web/client/index.js +7 -0
  199. package/dist/web/client/index.js.map +1 -0
  200. package/dist/web/index.cjs +158 -1346
  201. package/dist/web/index.cjs.map +1 -1
  202. package/dist/web/index.d.cts +5 -893
  203. package/dist/web/index.d.ts +5 -893
  204. package/dist/web/index.js +9 -1305
  205. package/dist/web/index.js.map +1 -1
  206. package/dist/web/server/index.cjs +32 -0
  207. package/dist/web/server/index.cjs.map +1 -0
  208. package/dist/web/server/index.d.cts +725 -0
  209. package/dist/web/server/index.d.ts +725 -0
  210. package/dist/web/server/index.js +3 -0
  211. package/dist/web/server/index.js.map +1 -0
  212. package/package.json +14 -1
package/dist/web/index.js CHANGED
@@ -1,1313 +1,17 @@
1
1
  "use client";
2
- import { jsx, jsxs } from 'react/jsx-runtime';
3
- import React, { createContext, forwardRef, useState, useEffect, useContext, useCallback, useMemo } from 'react';
4
- import { Slot } from '@radix-ui/react-slot';
5
- import clsx from 'clsx';
6
- import { X } from 'lucide-react';
2
+ export { JsonLd, aggregateRatingFromTestimonials, buildPageGraph, canonicalUrl, createEntityIds, createSchemaGenerators } from '../chunk-IFRATNLU.js';
3
+ export { AnalyticsProvider, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, CookieConsent, createAnalyticsLoader, loadClarity, loadGoogleAnalytics, useCookieConsent } from '../chunk-6UNG76Y2.js';
4
+ export { UTM_CAMPAIGNS, UTM_CONTENTS, UTM_MEDIUMS_ALL, UTM_MEDIUMS_APP, UTM_MEDIUMS_MESSAGING, UTM_MEDIUMS_WEB, UTM_SOURCES, UTM_SOURCES_REQUIRING_SELLER, UTM_TERMS, buildBlockedError, classifyAndEnforce, createAuditEntry, isValidUtmParams, parseUtmParams, requiresSellerAttribution, toFirstTouchAttribution, validateCompliance, validateUtmField } from '../chunk-BILT5KD3.js';
5
+ import '../chunk-SICKWUWB.js';
6
+ export { useAnalytics } from '../chunk-2GARWEJK.js';
7
+ import { UtmContext } from '../chunk-KJ2OXQF4.js';
8
+ export { buildUtmUrl, classifyUrl, isUtmExempt, requiresUtm, useUtmDefaults } from '../chunk-KJ2OXQF4.js';
9
+ import { jsx } from 'react/jsx-runtime';
7
10
 
8
- // src/web/seo/schema-generators.ts
9
- function toISO8601Duration(duration) {
10
- if (duration.startsWith("PT")) return duration;
11
- const parts = duration.split(":").map(Number);
12
- if (parts.some(isNaN)) return duration;
13
- if (parts.length === 3) return `PT${parts[0]}H${parts[1]}M${parts[2]}S`;
14
- if (parts.length === 2) return `PT${parts[0]}M${parts[1]}S`;
15
- return `PT${parts[0]}S`;
16
- }
17
- function toEmbedUrl(url) {
18
- try {
19
- const parsed = new URL(url);
20
- if (parsed.hostname.includes("youtube.com") && parsed.searchParams.has("v")) {
21
- return `https://www.youtube.com/embed/${parsed.searchParams.get("v")}`;
22
- }
23
- if (parsed.hostname === "youtu.be") {
24
- return `https://www.youtube.com/embed${parsed.pathname}`;
25
- }
26
- return url;
27
- } catch {
28
- return void 0;
29
- }
30
- }
31
- function mapEmploymentType(type) {
32
- if (!type) return "FULL_TIME";
33
- const lower = type.toLowerCase();
34
- if (lower.includes("part")) return "PART_TIME";
35
- if (lower.includes("contract")) return "CONTRACTOR";
36
- if (lower.includes("intern")) return "INTERN";
37
- if (lower.includes("temporary") || lower.includes("temp")) return "TEMPORARY";
38
- return "FULL_TIME";
39
- }
40
- function createEntityIds(brand) {
41
- return {
42
- organization: `${brand.url}/#organization`,
43
- website: `${brand.url}/#website`,
44
- software: `${brand.url}/#software`,
45
- product: `${brand.url}/pricing#product`,
46
- webpage: (path) => `${brand.url}${path}#webpage`,
47
- article: (path) => `${brand.url}${path}#article`,
48
- faq: (path) => `${brand.url}${path}#faq`,
49
- breadcrumb: (path) => `${brand.url}${path}#breadcrumb`,
50
- person: (slug) => `${brand.url}/company/team#person-${slug}`,
51
- video: (path) => `${brand.url}${path}#video`,
52
- review: (id) => `${brand.url}/#review-${id}`,
53
- service: (slug) => `${brand.url}/#service-${slug}`,
54
- customerOrganization: (slug) => `${brand.url}/#customer-org-${slug}`,
55
- customerPerson: (slug) => `${brand.url}/#customer-person-${slug}`
56
- };
57
- }
58
- function createSchemaGenerators(brand, supportedLanguages = ["en", "fr", "es"]) {
59
- const ENTITY_IDS = createEntityIds(brand);
60
- return {
61
- /** Organization schema — Homepage + About page. */
62
- organization(locale = "en") {
63
- return {
64
- "@context": "https://schema.org",
65
- "@type": "Organization",
66
- "@id": ENTITY_IDS.organization,
67
- name: brand.name,
68
- url: brand.url,
69
- logo: {
70
- "@type": "ImageObject",
71
- url: `${brand.url}/logo.svg`
72
- },
73
- description: brand.description,
74
- inLanguage: locale,
75
- availableLanguage: [...supportedLanguages],
76
- founder: {
77
- "@type": "Person",
78
- name: brand.founder
79
- },
80
- sameAs: [],
81
- contactPoint: [],
82
- areaServed: "Worldwide"
83
- };
84
- },
85
- /** WebSite schema — Homepage only (with SearchAction). */
86
- website(locale = "en") {
87
- return {
88
- "@context": "https://schema.org",
89
- "@type": "WebSite",
90
- "@id": ENTITY_IDS.website,
91
- name: brand.name,
92
- url: brand.url,
93
- description: brand.tagline,
94
- inLanguage: locale,
95
- publisher: {
96
- "@type": "Organization",
97
- "@id": ENTITY_IDS.organization,
98
- name: brand.name
99
- },
100
- potentialAction: [
101
- {
102
- "@type": "SearchAction",
103
- target: {
104
- "@type": "EntryPoint",
105
- urlTemplate: `${brand.url}/blog?q={search_term_string}`
106
- },
107
- "query-input": "required name=search_term_string"
108
- },
109
- {
110
- "@type": "ReadAction",
111
- target: brand.url
112
- }
113
- ]
114
- };
115
- },
116
- /** WebPage schema — Every public page. Links to WebSite + Breadcrumb via @id. */
117
- webPage(path, title, description, locale = "en", speakable) {
118
- return {
119
- "@context": "https://schema.org",
120
- "@type": "WebPage",
121
- "@id": ENTITY_IDS.webpage(path),
122
- url: `${brand.url}${path}`,
123
- name: title,
124
- description,
125
- inLanguage: locale,
126
- isPartOf: { "@type": "WebSite", "@id": ENTITY_IDS.website },
127
- breadcrumb: { "@id": ENTITY_IDS.breadcrumb(path) },
128
- potentialAction: {
129
- "@type": "ReadAction",
130
- target: `${brand.url}${path}`
131
- },
132
- ...speakable ? { speakable } : {}
133
- };
134
- },
135
- /** SoftwareApplication schema — Platform Hub, Platform Feature, Pricing. */
136
- softwareApplication(name, description, url, locale = "en") {
137
- return {
138
- "@context": "https://schema.org",
139
- "@type": "SoftwareApplication",
140
- "@id": ENTITY_IDS.software,
141
- name: name || brand.name,
142
- description: description || brand.description,
143
- url: url || brand.url,
144
- applicationCategory: "BusinessApplication",
145
- operatingSystem: "Web",
146
- inLanguage: locale,
147
- availableLanguage: [...supportedLanguages],
148
- offers: {
149
- "@type": "AggregateOffer",
150
- priceCurrency: "USD",
151
- lowPrice: "0",
152
- highPrice: "0",
153
- offerCount: "2",
154
- priceSpecification: {
155
- "@type": "PriceSpecification",
156
- description: "Custom pricing \u2014 contact sales for a tailored quote"
157
- }
158
- },
159
- author: {
160
- "@type": "Organization",
161
- "@id": ENTITY_IDS.organization,
162
- name: brand.name
163
- }
164
- };
165
- },
166
- /** Article schema — Blog posts, Comparison pages. */
167
- article(meta, locale = "en") {
168
- let path;
169
- try {
170
- path = new URL(meta.url).pathname;
171
- } catch {
172
- path = meta.url.startsWith("/") ? meta.url : `/${meta.url}`;
173
- }
174
- return {
175
- "@context": "https://schema.org",
176
- "@type": "Article",
177
- "@id": ENTITY_IDS.article(path),
178
- headline: meta.title,
179
- description: meta.description,
180
- url: meta.url.startsWith("http") ? meta.url : `${brand.url}${meta.url}`,
181
- image: meta.image || `${brand.url}/og-default.png`,
182
- datePublished: meta.publishedTime,
183
- dateModified: meta.modifiedTime,
184
- inLanguage: locale,
185
- author: meta.authorSlug ? { "@id": ENTITY_IDS.person(meta.authorSlug) } : {
186
- "@type": "Person",
187
- name: meta.authorName,
188
- url: meta.authorUrl || `${brand.url}/company/team`
189
- },
190
- publisher: {
191
- "@type": "Organization",
192
- "@id": ENTITY_IDS.organization,
193
- name: brand.name,
194
- logo: {
195
- "@type": "ImageObject",
196
- url: `${brand.url}/logo.svg`
197
- }
198
- },
199
- isPartOf: { "@type": "WebSite", "@id": ENTITY_IDS.website },
200
- mainEntityOfPage: { "@id": ENTITY_IDS.webpage(path) },
201
- articleSection: meta.section,
202
- keywords: meta.tags?.join(", "),
203
- speakable: {
204
- "@type": "SpeakableSpecification",
205
- cssSelector: meta.speakableCssSelectors || ["article h1", "article .summary", "article .lead"]
206
- },
207
- ...meta.about ? { about: meta.about } : {},
208
- ...meta.video ? { video: meta.video } : {}
209
- };
210
- },
211
- /** FAQPage schema — FAQ hub, Solutions, Platform Features, Comparisons, Integrations. */
212
- faqPage(items, pageUrl, locale = "en") {
213
- return {
214
- "@context": "https://schema.org",
215
- "@type": "FAQPage",
216
- "@id": ENTITY_IDS.faq(pageUrl),
217
- inLanguage: locale,
218
- mainEntity: items.map((item) => ({
219
- "@type": "Question",
220
- name: item.question,
221
- acceptedAnswer: {
222
- "@type": "Answer",
223
- text: item.answer,
224
- inLanguage: locale
225
- }
226
- }))
227
- };
228
- },
229
- /** BreadcrumbList schema — Every public page. */
230
- breadcrumb(items, locale = "en") {
231
- const lastUrl = items.length > 0 ? items[items.length - 1].url : "/";
232
- const path = lastUrl.startsWith("http") ? new URL(lastUrl).pathname : lastUrl;
233
- return {
234
- "@context": "https://schema.org",
235
- "@type": "BreadcrumbList",
236
- "@id": ENTITY_IDS.breadcrumb(path),
237
- inLanguage: locale,
238
- itemListElement: items.map((item, index) => ({
239
- "@type": "ListItem",
240
- position: index + 1,
241
- name: item.name,
242
- item: item.url.startsWith("http") ? item.url : `${brand.url}${item.url}`
243
- }))
244
- };
245
- },
246
- /** Person schema — Team page, Blog author, Comparison author. */
247
- person(person, locale = "en") {
248
- const slug = person.slug || person.name.toLowerCase().replace(/\s+/g, "-");
249
- return {
250
- "@context": "https://schema.org",
251
- "@type": "Person",
252
- "@id": person.entityIdOverride || ENTITY_IDS.person(slug),
253
- name: person.name,
254
- jobTitle: person.jobTitle,
255
- url: person.url,
256
- image: person.image,
257
- inLanguage: locale,
258
- worksFor: person.worksFor || {
259
- "@type": "Organization",
260
- "@id": ENTITY_IDS.organization,
261
- name: brand.name
262
- },
263
- sameAs: person.sameAs || []
264
- };
265
- },
266
- /** Review schema — Generated from testimonials. */
267
- review(testimonial) {
268
- return {
269
- "@context": "https://schema.org",
270
- "@type": "Review",
271
- "@id": ENTITY_IDS.review(testimonial.id),
272
- author: {
273
- "@type": "Person",
274
- ...testimonial.authorEntityId ? { "@id": testimonial.authorEntityId } : {},
275
- name: testimonial.customer_name,
276
- ...testimonial.occupation ? { jobTitle: testimonial.occupation } : {}
277
- },
278
- reviewBody: testimonial.quote || "",
279
- ...testimonial.star_rating ? {
280
- reviewRating: {
281
- "@type": "Rating",
282
- ratingValue: String(testimonial.star_rating),
283
- bestRating: "5",
284
- worstRating: "1"
285
- }
286
- } : {},
287
- ...testimonial.review_date ? { datePublished: testimonial.review_date } : {},
288
- itemReviewed: {
289
- "@type": "SoftwareApplication",
290
- "@id": ENTITY_IDS.software,
291
- name: brand.name
292
- },
293
- ...testimonial.review_source ? {
294
- publisher: {
295
- "@type": "Organization",
296
- name: testimonial.review_source
297
- }
298
- } : {}
299
- };
300
- },
301
- /** Product + multiple Offers schema — Pricing page. */
302
- productWithOffers(plans, testimonials = [], locale = "en") {
303
- return {
304
- "@context": "https://schema.org",
305
- "@type": "Product",
306
- "@id": ENTITY_IDS.product,
307
- name: brand.name,
308
- description: brand.description,
309
- brand: {
310
- "@type": "Organization",
311
- "@id": ENTITY_IDS.organization,
312
- name: brand.name
313
- },
314
- inLanguage: locale,
315
- ...testimonials.length > 0 ? { aggregateRating: aggregateRatingFromTestimonials(testimonials) } : {},
316
- offers: plans.map((plan) => ({
317
- "@type": "Offer",
318
- name: plan.name,
319
- description: plan.description,
320
- price: plan.price.replace(/[^0-9.]/g, "") || "0",
321
- priceCurrency: plan.priceCurrency || "USD",
322
- availability: "https://schema.org/InStock",
323
- url: `${brand.url}/pricing`,
324
- ...plan.billingPeriod ? {
325
- priceSpecification: {
326
- "@type": "UnitPriceSpecification",
327
- price: plan.price.replace(/[^0-9.]/g, "") || "0",
328
- priceCurrency: plan.priceCurrency || "USD",
329
- billingDuration: plan.billingPeriod
330
- }
331
- } : {}
332
- }))
333
- };
334
- },
335
- /** VideoObject schema — Transcript detail pages. */
336
- videoObject(transcript, locale = "en") {
337
- const path = transcript.path || `/resources/transcripts/${transcript.slug}`;
338
- return {
339
- "@context": "https://schema.org",
340
- "@type": "VideoObject",
341
- "@id": ENTITY_IDS.video(path),
342
- name: transcript.title,
343
- description: transcript.summary || transcript.title,
344
- ...transcript.video_link ? { contentUrl: transcript.video_link } : {},
345
- ...transcript.video_link ? { embedUrl: toEmbedUrl(transcript.video_link) } : {},
346
- ...transcript.duration ? { duration: toISO8601Duration(transcript.duration) } : {},
347
- ...transcript.published_at ? { uploadDate: transcript.published_at } : {},
348
- ...transcript.thumbnailUrl ? { thumbnailUrl: transcript.thumbnailUrl } : {},
349
- inLanguage: locale,
350
- publisher: {
351
- "@type": "Organization",
352
- "@id": ENTITY_IDS.organization,
353
- name: brand.name
354
- },
355
- ...transcript.transcript_text ? { transcript: transcript.transcript_text } : {}
356
- };
357
- },
358
- /** CustomerOrganization schema — Customer's company for Success Story pages. */
359
- customerOrganization(meta) {
360
- return {
361
- "@context": "https://schema.org",
362
- "@type": "Organization",
363
- "@id": ENTITY_IDS.customerOrganization(meta.slug),
364
- name: meta.name,
365
- ...meta.url ? { url: meta.url } : {},
366
- ...meta.logo ? { logo: meta.logo } : {},
367
- ...meta.description ? { description: meta.description } : {},
368
- ...meta.industry ? { industry: meta.industry } : {},
369
- ...meta.sameAs && meta.sameAs.length > 0 ? { sameAs: meta.sameAs } : {}
370
- };
371
- },
372
- /** Generic VideoObject — Success story main video and shorts. */
373
- videoObjectGeneric(meta, locale = "en") {
374
- const videoId = meta.fragment ? `${brand.url}${meta.path}#${meta.fragment}` : ENTITY_IDS.video(meta.path);
375
- return {
376
- "@context": "https://schema.org",
377
- "@type": "VideoObject",
378
- "@id": videoId,
379
- name: meta.title,
380
- ...meta.description ? { description: meta.description } : {},
381
- ...meta.videoUrl ? { contentUrl: meta.videoUrl } : {},
382
- ...meta.embedUrl ? { embedUrl: meta.embedUrl } : {},
383
- ...meta.thumbnailUrl ? { thumbnailUrl: meta.thumbnailUrl } : {},
384
- ...meta.duration ? { duration: meta.duration } : {},
385
- ...meta.uploadDate ? { uploadDate: meta.uploadDate } : {},
386
- ...meta.transcript ? { transcript: meta.transcript } : {},
387
- inLanguage: locale,
388
- publisher: { "@id": ENTITY_IDS.organization }
389
- };
390
- },
391
- /** HowTo schema — Solution pages, tutorial blog posts. */
392
- howTo(steps, meta, locale = "en") {
393
- return {
394
- "@context": "https://schema.org",
395
- "@type": "HowTo",
396
- name: meta.name,
397
- description: meta.description,
398
- inLanguage: locale,
399
- ...meta.totalTime ? { totalTime: meta.totalTime } : {},
400
- ...meta.image ? { image: meta.image } : {},
401
- step: steps.map((step, index) => ({
402
- "@type": "HowToStep",
403
- position: index + 1,
404
- name: step.name,
405
- text: step.text,
406
- ...step.url ? { url: step.url } : {},
407
- ...step.image ? { image: step.image } : {}
408
- }))
409
- };
410
- },
411
- /** Service schema — Growth motion service offerings. */
412
- service(motion, locale = "en") {
413
- return {
414
- "@context": "https://schema.org",
415
- "@type": "Service",
416
- "@id": ENTITY_IDS.service(motion.slug),
417
- name: motion.name,
418
- description: motion.description,
419
- url: motion.url.startsWith("http") ? motion.url : `${brand.url}${motion.url}`,
420
- provider: {
421
- "@type": "Organization",
422
- "@id": ENTITY_IDS.organization,
423
- name: brand.name
424
- },
425
- inLanguage: locale,
426
- availableLanguage: [...supportedLanguages],
427
- areaServed: "Worldwide",
428
- ...motion.price ? {
429
- offers: {
430
- "@type": "Offer",
431
- price: motion.price.replace(/[^0-9.]/g, "") || "0",
432
- priceCurrency: motion.priceCurrency || "USD",
433
- availability: "https://schema.org/InStock"
434
- }
435
- } : {},
436
- termsOfService: `${brand.url}/legal/terms`
437
- };
438
- },
439
- /** JobPosting schema — Career detail pages. */
440
- jobPosting(job, locale = "en") {
441
- return {
442
- "@context": "https://schema.org",
443
- "@type": "JobPosting",
444
- "@id": `${brand.url}/careers/${job.slug}#jobposting`,
445
- title: job.title,
446
- description: job.description || "",
447
- datePosted: job.published_at || job.created_at,
448
- employmentType: mapEmploymentType(job.type),
449
- hiringOrganization: {
450
- "@type": "Organization",
451
- "@id": ENTITY_IDS.organization,
452
- name: brand.name,
453
- sameAs: brand.url
454
- },
455
- ...job.location ? {
456
- jobLocation: {
457
- "@type": "Place",
458
- address: {
459
- "@type": "PostalAddress",
460
- addressLocality: job.location
461
- }
462
- }
463
- } : {
464
- jobLocationType: "TELECOMMUTE"
465
- },
466
- inLanguage: locale
467
- };
468
- },
469
- /** ItemList schema — Hub/listing pages. */
470
- itemList(items, listName) {
471
- return {
472
- "@context": "https://schema.org",
473
- "@type": "ItemList",
474
- name: listName,
475
- numberOfItems: items.length,
476
- itemListElement: items.map((item, index) => ({
477
- "@type": "ListItem",
478
- position: item.position ?? index + 1,
479
- name: item.name,
480
- url: item.url.startsWith("http") ? item.url : `${brand.url}${item.url}`,
481
- ...item.description ? { description: item.description } : {},
482
- ...item.image ? { image: item.image } : {}
483
- }))
484
- };
485
- },
486
- /** DefinedTermSet schema — Glossary page. */
487
- definedTermSet(terms, locale = "en") {
488
- return {
489
- "@context": "https://schema.org",
490
- "@type": "DefinedTermSet",
491
- "@id": `${brand.url}/resources/glossary#termset`,
492
- name: "AI Sales Glossary",
493
- inLanguage: locale,
494
- hasDefinedTerm: terms.map((term) => ({
495
- "@type": "DefinedTerm",
496
- name: term.term,
497
- description: term.definition,
498
- url: term.url || `${brand.url}/resources/glossary#${term.slug}`
499
- }))
500
- };
501
- },
502
- /** Speakable — marks content sections suitable for voice assistant reading. */
503
- speakable(cssSelectors) {
504
- return {
505
- "@type": "SpeakableSpecification",
506
- cssSelector: cssSelectors
507
- };
508
- },
509
- /** Access the entity IDs for cross-referencing */
510
- entityIds: ENTITY_IDS
511
- };
512
- }
513
- function aggregateRatingFromTestimonials(testimonials) {
514
- const rated = testimonials.filter((t) => t.star_rating != null && t.star_rating > 0);
515
- if (rated.length === 0) {
516
- return {
517
- "@type": "AggregateRating",
518
- ratingValue: "4.7",
519
- ratingCount: "150",
520
- bestRating: "5",
521
- worstRating: "1"
522
- };
523
- }
524
- const sum = rated.reduce((acc, t) => acc + (t.star_rating || 0), 0);
525
- const avg = (sum / rated.length).toFixed(1);
526
- return {
527
- "@type": "AggregateRating",
528
- ratingValue: avg,
529
- ratingCount: String(rated.length),
530
- bestRating: "5",
531
- worstRating: "1"
532
- };
533
- }
534
- function buildPageGraph(...schemas) {
535
- const graph = schemas.map((schema) => {
536
- const { "@context": _, ...rest } = schema;
537
- return rest;
538
- });
539
- return {
540
- "@context": "https://schema.org",
541
- "@graph": graph
542
- };
543
- }
544
- function canonicalUrl(baseUrl, pathname, locale) {
545
- const clean = pathname === "/" ? "/" : pathname.replace(/\/+$/, "");
546
- if (locale && locale !== "en") {
547
- const stripped = clean.replace(new RegExp(`^/${locale}(/|$)`), "$1") || "/";
548
- const path = stripped === "/" ? "" : stripped;
549
- return `${baseUrl}/${locale}${path}`;
550
- }
551
- return `${baseUrl}${clean}`;
552
- }
553
- function JsonLd({ data, nonce }) {
554
- const json = JSON.stringify(data).replace(/<\/script>/gi, "<\\/script>");
555
- return /* @__PURE__ */ jsx(
556
- "script",
557
- {
558
- type: "application/ld+json",
559
- nonce,
560
- dangerouslySetInnerHTML: { __html: json }
561
- }
562
- );
563
- }
564
-
565
- // src/web/analytics/create-analytics-loader.ts
566
- function createAnalyticsLoader(config) {
567
- return (trackingId) => {
568
- if (typeof document === "undefined") return;
569
- if (document.getElementById(config.id)) return;
570
- const script = document.createElement("script");
571
- script.id = config.id;
572
- if (config.inlineScript) {
573
- script.textContent = config.inlineScript(trackingId);
574
- } else {
575
- script.async = config.async ?? true;
576
- script.src = config.src(trackingId);
577
- }
578
- document.head.appendChild(script);
579
- config.onLoad?.(trackingId);
580
- };
581
- }
582
- var loadGoogleAnalytics = createAnalyticsLoader({
583
- id: "ga-script",
584
- src: (gaId) => `https://www.googletagmanager.com/gtag/js?id=${gaId}`,
585
- onLoad: (gaId) => {
586
- window.dataLayer = window.dataLayer || [];
587
- window.dataLayer.push(["js", /* @__PURE__ */ new Date()]);
588
- window.dataLayer.push(["config", gaId]);
589
- }
590
- });
591
- var loadClarity = createAnalyticsLoader({
592
- id: "clarity-script",
593
- src: (clarityId) => `https://www.clarity.ms/tag/${clarityId}`,
594
- onLoad: () => {
595
- if (!window.clarity) {
596
- const queue = [];
597
- window.clarity = (...args) => {
598
- queue.push(args);
599
- };
600
- window.clarity.q = queue;
601
- }
602
- }
603
- });
604
- var Button = React.forwardRef(
605
- ({ className, variant = "primary", size = "md", asChild = false, isLoading = false, children, disabled, ...props }, ref) => {
606
- const buttonClass = clsx(
607
- "ds-button",
608
- `ds-button--${variant}`,
609
- size === "icon" ? "ds-button--icon ds-button--md" : `ds-button--${size}`,
610
- isLoading && "ds-button--loading",
611
- className
612
- );
613
- if (asChild) {
614
- return /* @__PURE__ */ jsx(
615
- Slot,
616
- {
617
- ref,
618
- "aria-disabled": isLoading || disabled || void 0,
619
- className: buttonClass,
620
- ...props,
621
- children
622
- }
623
- );
624
- }
625
- return /* @__PURE__ */ jsxs(
626
- "button",
627
- {
628
- ref,
629
- disabled: isLoading || disabled,
630
- className: buttonClass,
631
- ...props,
632
- children: [
633
- isLoading && /* @__PURE__ */ jsx(
634
- "svg",
635
- {
636
- className: "ds-button__spinner",
637
- xmlns: "http://www.w3.org/2000/svg",
638
- width: "1em",
639
- height: "1em",
640
- viewBox: "0 0 24 24",
641
- fill: "none",
642
- stroke: "currentColor",
643
- strokeWidth: "2",
644
- strokeLinecap: "round",
645
- strokeLinejoin: "round",
646
- children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
647
- }
648
- ),
649
- /* @__PURE__ */ jsx("span", { className: clsx("ds-button__content", isLoading && "ds-button__content--hidden"), children })
650
- ]
651
- }
652
- );
653
- }
654
- );
655
- Button.displayName = "Button";
656
- var UtmContext = createContext(null);
657
-
658
- // src/web/utm/useUtmDefaults.ts
659
- function useUtmDefaults() {
660
- return useContext(UtmContext);
661
- }
662
-
663
- // src/web/utm/builders.ts
664
- var PLACEHOLDER_ORIGIN = "https://__placeholder__.internal";
665
- function buildUtmUrl(baseUrl, params) {
666
- const isRelative = baseUrl.startsWith("/");
667
- let url;
668
- try {
669
- url = isRelative ? new URL(baseUrl, PLACEHOLDER_ORIGIN) : new URL(baseUrl);
670
- } catch {
671
- return baseUrl;
672
- }
673
- const existingParams = [];
674
- url.searchParams.forEach((value, key) => {
675
- existingParams.push([key, value]);
676
- });
677
- for (const [key] of existingParams) {
678
- url.searchParams.delete(key);
679
- }
680
- for (const [key, value] of existingParams) {
681
- if (!key.startsWith("utm_")) {
682
- url.searchParams.set(key, value);
683
- }
684
- }
685
- url.searchParams.set("utm_source", params.source);
686
- url.searchParams.set("utm_medium", params.medium);
687
- url.searchParams.set("utm_campaign", params.campaign);
688
- if (params.term !== void 0) {
689
- url.searchParams.set("utm_term", params.term);
690
- }
691
- if (params.content !== void 0) {
692
- url.searchParams.set("utm_content", params.content);
693
- }
694
- if (isRelative) {
695
- return url.href.replace(PLACEHOLDER_ORIGIN, "");
696
- }
697
- return url.href;
698
- }
699
-
700
- // src/web/utm/classifiers.ts
701
- var INTERNAL_PATTERNS = [
702
- /^\/(?!\/)/,
703
- // Relative paths
704
- /^https?:\/\/(www\.)?sales-mind\.ai/i,
705
- // Marketing site
706
- /^https?:\/\/app\.sales-mind\.ai/i,
707
- // Web app
708
- /^https?:\/\/apps\.sales-mind\.ai/i,
709
- // Web app (legacy)
710
- /^https?:\/\/meet\.sales-mind\.ai/i,
711
- // Booking
712
- /^https?:\/\/docs\.sales-mind\.ai/i
713
- // Docs
714
- ];
715
- var SYSTEM_PATTERNS = [
716
- /^https?:\/\/.*\/api\//i,
717
- // API endpoints
718
- /^https?:\/\/.*\/webhook/i,
719
- // Webhooks
720
- /^https?:\/\/.*\/oauth/i,
721
- // OAuth callbacks
722
- /^https?:\/\/.*\/callback/i,
723
- // Callbacks
724
- /^https?:\/\/.*\.supabase\.(co|com)/i,
725
- // Supabase
726
- /^https?:\/\/.*\.firebaseapp\.com/i,
727
- // Firebase
728
- /^https?:\/\/.*\.cloudfunctions\.net/i
729
- // Cloud Functions
730
- ];
731
- var ASSET_PATTERNS = [
732
- /\.(css|js|mjs|map|woff2?|ttf|eot|svg|png|jpe?g|gif|webp|avif|ico|pdf)(\?.*)?$/i
733
- ];
734
- var CONVERSION_PATTERNS = [
735
- /^https?:\/\/(www\.)?calendly\.com/i,
736
- /^https?:\/\/(checkout\.)?stripe\.com/i,
737
- /^https?:\/\/buy\.stripe\.com/i,
738
- /^https?:\/\/chromewebstore\.google\.com/i,
739
- /^https?:\/\/meet\.sales-mind\.ai/i
740
- ];
741
- var PROTOCOL_EXEMPT = [
742
- /^mailto:/i,
743
- /^tel:/i,
744
- /^#/,
745
- /^javascript:/i
746
- ];
747
- function classifyUrl(url) {
748
- if (PROTOCOL_EXEMPT.some((p) => p.test(url))) return "protocol";
749
- if (ASSET_PATTERNS.some((p) => p.test(url))) return "asset";
750
- if (SYSTEM_PATTERNS.some((p) => p.test(url))) return "system";
751
- if (CONVERSION_PATTERNS.some((p) => p.test(url))) return "conversion";
752
- if (INTERNAL_PATTERNS.some((p) => p.test(url))) return "internal";
753
- return "external";
754
- }
755
- function requiresUtm(url) {
756
- const classification = classifyUrl(url);
757
- return classification === "external" || classification === "conversion";
758
- }
759
- function isUtmExempt(url) {
760
- const classification = classifyUrl(url);
761
- return classification === "protocol" || classification === "asset" || classification === "system" || classification === "internal";
762
- }
763
-
764
- // src/components/OutboundLink/outbound-link-utils.ts
765
- var LEGACY_UTM_SOURCE = "salesmind";
766
- var EXEMPT_PATTERNS = [
767
- /^https?:\/\/(www\.)?(stripe\.com|checkout\.stripe\.com|paypal\.com)/i,
768
- /^https?:\/\/(www\.)?github\.com\/login\/oauth/i
769
- ];
770
- var isExemptUrl = (urlStr) => {
771
- if (urlStr.startsWith("mailto:") || urlStr.startsWith("tel:")) return true;
772
- const classification = classifyUrl(urlStr);
773
- if (classification === "system" || classification === "protocol" || classification === "asset") {
774
- return true;
775
- }
776
- return EXEMPT_PATTERNS.some((pattern) => pattern.test(urlStr));
777
- };
778
- var appendGovernedUTMs = (href, params, preserveExisting = true) => {
779
- try {
780
- const url = new URL(href);
781
- if (preserveExisting) {
782
- const hasAll = url.searchParams.has("utm_source") && url.searchParams.has("utm_medium") && url.searchParams.has("utm_campaign");
783
- if (hasAll) return href;
784
- }
785
- return buildUtmUrl(href, params);
786
- } catch {
787
- return href;
788
- }
789
- };
790
- var appendUTMs = (href, context, pageSlug, options) => {
791
- try {
792
- const url = new URL(href);
793
- const { mediumOverride = "outbound_link", campaignOverride, preserveExisting = true } = options;
794
- const utms = {
795
- utm_source: LEGACY_UTM_SOURCE,
796
- utm_medium: mediumOverride,
797
- utm_campaign: campaignOverride || pageSlug,
798
- utm_content: context
799
- };
800
- Object.entries(utms).forEach(([key, value]) => {
801
- if (value) {
802
- if (preserveExisting && url.searchParams.has(key)) {
803
- return;
804
- }
805
- url.searchParams.set(key, value);
806
- }
807
- });
808
- return url.toString();
809
- } catch {
810
- return href;
811
- }
812
- };
813
- var OutboundLink = forwardRef(
814
- ({
815
- href,
816
- context,
817
- campaignOverride,
818
- mediumOverride = "outbound_link",
819
- preserveExistingUTM = true,
820
- openInNewTab = true,
821
- disableTracking = false,
822
- utmParams,
823
- onClick,
824
- children,
825
- ...props
826
- }, ref) => {
827
- const contextParams = useUtmDefaults();
828
- const resolvedUtmParams = utmParams ?? contextParams;
829
- let hostname = "";
830
- try {
831
- const url = new URL(href);
832
- hostname = url.hostname;
833
- } catch {
834
- }
835
- const [finalHref, setFinalHref] = useState(href);
836
- useEffect(() => {
837
- let isExternal = false;
838
- let currentMedium = mediumOverride;
839
- try {
840
- const url = new URL(href);
841
- const currentHost = window.location.hostname;
842
- isExternal = url.hostname !== currentHost;
843
- if (isExternal && currentHost.includes("sales-mind.ai") && url.hostname.includes("sales-mind.ai")) {
844
- if (currentMedium === "outbound_link") {
845
- currentMedium = "cross_subdomain";
846
- }
847
- }
848
- } catch {
849
- isExternal = false;
850
- }
851
- const isExempt = isExemptUrl(href) || disableTracking;
852
- if (isExternal && !isExempt) {
853
- if (resolvedUtmParams) {
854
- setFinalHref(appendGovernedUTMs(href, resolvedUtmParams, preserveExistingUTM));
855
- } else {
856
- const pageSlug = window.location.pathname.replace(/^\/|\/$/g, "") || "home";
857
- setFinalHref(appendUTMs(href, context, pageSlug, {
858
- mediumOverride: currentMedium,
859
- campaignOverride,
860
- preserveExisting: preserveExistingUTM
861
- }));
862
- }
863
- } else {
864
- setFinalHref(href);
865
- }
866
- }, [href, context, mediumOverride, campaignOverride, preserveExistingUTM, disableTracking, resolvedUtmParams]);
867
- const handleClick = (e) => {
868
- if (typeof window === "undefined" || disableTracking) {
869
- onClick?.(e);
870
- return;
871
- }
872
- let clickExternal = false;
873
- let clickCrossSubdomain = false;
874
- let clickMedium = mediumOverride;
875
- try {
876
- const url = new URL(href);
877
- const currentHost = window.location.hostname;
878
- clickExternal = url.hostname !== currentHost;
879
- if (clickExternal && currentHost.includes("sales-mind.ai") && url.hostname.includes("sales-mind.ai")) {
880
- clickCrossSubdomain = true;
881
- if (clickMedium === "outbound_link") {
882
- clickMedium = "cross_subdomain";
883
- }
884
- }
885
- } catch {
886
- }
887
- if (clickExternal) {
888
- const detail = {
889
- destination_domain: hostname,
890
- destination_url: finalHref,
891
- utm_medium_type: clickMedium,
892
- page_slug: window.location.pathname,
893
- component_location: context,
894
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
895
- is_cross_subdomain: clickCrossSubdomain
896
- };
897
- const event = new CustomEvent("outbound_click", { detail });
898
- window.dispatchEvent(event);
899
- }
900
- onClick?.(e);
901
- };
902
- const relParts = [];
903
- let shouldOpenNewTab = openInNewTab;
904
- try {
905
- const url = new URL(href);
906
- if (typeof window !== "undefined") {
907
- const currentHost = window.location.hostname;
908
- if (url.hostname !== currentHost && currentHost.includes("sales-mind.ai") && url.hostname.includes("sales-mind.ai")) {
909
- shouldOpenNewTab = false;
910
- }
911
- }
912
- } catch {
913
- }
914
- if (shouldOpenNewTab) relParts.push("noopener", "noreferrer");
915
- if (mediumOverride === "citation") relParts.push("nofollow");
916
- const rel = relParts.length > 0 ? relParts.join(" ") : void 0;
917
- return (
918
- // eslint-disable-next-line no-restricted-syntax
919
- /* @__PURE__ */ jsx(
920
- "a",
921
- {
922
- ref,
923
- href: finalHref,
924
- target: shouldOpenNewTab ? "_blank" : void 0,
925
- rel,
926
- onClick: handleClick,
927
- ...props,
928
- children
929
- }
930
- )
931
- );
932
- }
933
- );
934
- OutboundLink.displayName = "OutboundLink";
935
- var COOKIE_CONSENT_EVENT = "cookie_consent_granted";
936
- var COOKIE_CONSENT_KEY = "cookie_consent";
937
- function CookieConsent({
938
- delay = 1e3,
939
- privacyUrl = "/legal/privacy",
940
- onAccept,
941
- onDecline,
942
- labels,
943
- className
944
- }) {
945
- const [state, setState] = useState("idle");
946
- useEffect(() => {
947
- const consent = localStorage.getItem(COOKIE_CONSENT_KEY);
948
- if (!consent) {
949
- const timer = setTimeout(() => setState("open"), delay);
950
- return () => clearTimeout(timer);
951
- } else {
952
- setState("closed");
953
- }
954
- }, [delay]);
955
- const handleDismiss = useCallback(() => {
956
- setState("closing");
957
- }, []);
958
- const handleAccept = useCallback(() => {
959
- localStorage.setItem(COOKIE_CONSENT_KEY, "granted");
960
- handleDismiss();
961
- if (typeof window !== "undefined") {
962
- window.dispatchEvent(new Event(COOKIE_CONSENT_EVENT));
963
- }
964
- onAccept?.();
965
- }, [onAccept, handleDismiss]);
966
- const handleDecline = useCallback(() => {
967
- localStorage.setItem(COOKIE_CONSENT_KEY, "denied");
968
- handleDismiss();
969
- onDecline?.();
970
- }, [onDecline, handleDismiss]);
971
- const handleTransitionEnd = useCallback(() => {
972
- if (state === "closing") {
973
- setState("closed");
974
- }
975
- }, [state]);
976
- if (state === "idle" || state === "closed") return null;
977
- return /* @__PURE__ */ jsx(
978
- "div",
979
- {
980
- className: `ds-cookie-consent ${className ?? ""}`,
981
- "data-state": state === "open" ? "open" : "closed",
982
- onTransitionEnd: handleTransitionEnd,
983
- role: "dialog",
984
- "aria-label": labels?.title ?? "Cookie consent",
985
- children: /* @__PURE__ */ jsxs("div", { className: "ds-cookie-consent__inner", children: [
986
- /* @__PURE__ */ jsxs("div", { className: "ds-cookie-consent__content", children: [
987
- /* @__PURE__ */ jsx("h3", { className: "ds-cookie-consent__title", children: labels?.title ?? "We use cookies" }),
988
- /* @__PURE__ */ jsxs("p", { className: "ds-cookie-consent__description", children: [
989
- labels?.description ?? "We use tracking cookies to understand how you use the product and help us improve it.",
990
- /* @__PURE__ */ jsx(OutboundLink, { href: privacyUrl, context: "cookie-consent-privacy", className: "ds-cookie-consent__link", children: labels?.privacyLinkText ?? "Privacy Policy" })
991
- ] })
992
- ] }),
993
- /* @__PURE__ */ jsxs("div", { className: "ds-cookie-consent__actions", children: [
994
- /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: handleDecline, children: labels?.declineLabel ?? "Decline" }),
995
- /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: handleAccept, children: labels?.acceptLabel ?? "Accept" })
996
- ] }),
997
- /* @__PURE__ */ jsx(
998
- "button",
999
- {
1000
- onClick: handleDecline,
1001
- className: "ds-cookie-consent__close",
1002
- "aria-label": "Close",
1003
- children: /* @__PURE__ */ jsx(X, { size: 16 })
1004
- }
1005
- )
1006
- ] })
1007
- }
1008
- );
1009
- }
1010
-
1011
- // src/web/analytics/use-cookie-consent.ts
1012
- function useCookieConsent() {
1013
- const [status, setStatus] = useState(() => {
1014
- if (typeof window === "undefined") return null;
1015
- const stored = localStorage.getItem(COOKIE_CONSENT_KEY);
1016
- if (stored === "granted") return "granted";
1017
- if (stored === "denied") return "denied";
1018
- return null;
1019
- });
1020
- useEffect(() => {
1021
- const handleConsent = () => setStatus("granted");
1022
- window.addEventListener(COOKIE_CONSENT_EVENT, handleConsent);
1023
- return () => window.removeEventListener(COOKIE_CONSENT_EVENT, handleConsent);
1024
- }, []);
1025
- return status;
1026
- }
1027
- var AnalyticsContext = createContext(null);
1028
- function AnalyticsProvider({ onTrack, debug = false, children }) {
1029
- const track = useCallback(
1030
- (event, props) => {
1031
- if (debug && typeof console !== "undefined") {
1032
- console.log("[DS Analytics]", event, props);
1033
- }
1034
- onTrack(event, props);
1035
- },
1036
- [onTrack, debug]
1037
- );
1038
- const value = useMemo(() => ({ track }), [track]);
1039
- return /* @__PURE__ */ jsx(AnalyticsContext.Provider, { value, children });
1040
- }
1041
- var NOOP_VALUE = {
1042
- track: () => {
1043
- }
1044
- };
1045
- function useAnalytics() {
1046
- return useContext(AnalyticsContext) ?? NOOP_VALUE;
1047
- }
1048
-
1049
- // src/web/utm/constants.ts
1050
- var UTM_SOURCES = [
1051
- "linkedin",
1052
- "whatsapp",
1053
- "intercom",
1054
- "email",
1055
- "website",
1056
- "app",
1057
- "chromeStore",
1058
- "stripe",
1059
- "direct"
1060
- ];
1061
- var UTM_MEDIUMS_MESSAGING = [
1062
- "dm",
1063
- "group",
1064
- "email",
1065
- "inAppChat",
1066
- "organicPost",
1067
- "paidAd",
1068
- "qrCode",
1069
- "redirect",
1070
- "storeListing"
1071
- ];
1072
- var UTM_MEDIUMS_APP = [
1073
- "appHome",
1074
- "appDashboard",
1075
- "appInbox",
1076
- "appContacts",
1077
- "appCampaigns",
1078
- "appSettings",
1079
- "appBilling",
1080
- "appCheckout",
1081
- "appOnboarding",
1082
- "appSupport",
1083
- "appCalendar"
1084
- ];
1085
- var UTM_MEDIUMS_WEB = [
1086
- "webHome",
1087
- "webDemo",
1088
- "webPricing",
1089
- "webFeatures",
1090
- "webUseCase",
1091
- "webSolution",
1092
- "webIndustry",
1093
- "webIntegrations",
1094
- "webBlog",
1095
- "webBlogPost",
1096
- "webLanding",
1097
- "webComparison",
1098
- "webCaseStudy",
1099
- "webAbout",
1100
- "webContact",
1101
- "webCareers",
1102
- "webLegal",
1103
- "webDocs",
1104
- "webAffiliate"
1105
- ];
1106
- var UTM_MEDIUMS_ALL = [
1107
- ...UTM_MEDIUMS_MESSAGING,
1108
- ...UTM_MEDIUMS_APP,
1109
- ...UTM_MEDIUMS_WEB
1110
- ];
1111
- var UTM_CAMPAIGNS = [
1112
- "discoveryCall",
1113
- "demo",
1114
- "trial",
1115
- "onboarding",
1116
- "upgrade",
1117
- "renewal",
1118
- "retention",
1119
- "accountSupport",
1120
- "supportCall",
1121
- "partnerCall",
1122
- "hiring",
1123
- "interviewCall"
1124
- ];
1125
- var UTM_TERMS = [
1126
- "julienGadea",
1127
- "bramSmith",
1128
- "florentDupont",
1129
- "sawLin",
1130
- "evaSupport",
1131
- "team",
1132
- "auto"
1133
- ];
1134
- var UTM_CONTENTS = [
1135
- "ctaPrimary",
1136
- "ctaSecondary",
1137
- "ctaHeader",
1138
- "ctaFooter",
1139
- "ctaInline",
1140
- "buttonPrimary",
1141
- "buttonSecondary",
1142
- "banner",
1143
- "popup",
1144
- "variantA",
1145
- "variantB",
1146
- "variantC"
1147
- ];
1148
- var UTM_SOURCES_REQUIRING_SELLER = [
1149
- "linkedin",
1150
- "whatsapp",
1151
- "intercom",
1152
- "email"
1153
- ];
1154
-
1155
- // src/web/utm/validators.ts
1156
- function validateUtmField(field, value) {
1157
- switch (field) {
1158
- case "source":
1159
- return UTM_SOURCES.includes(value);
1160
- case "medium":
1161
- return UTM_MEDIUMS_ALL.includes(value);
1162
- case "campaign":
1163
- return UTM_CAMPAIGNS.includes(value);
1164
- case "term":
1165
- return UTM_TERMS.includes(value);
1166
- case "content":
1167
- return UTM_CONTENTS.includes(value);
1168
- default:
1169
- return false;
1170
- }
1171
- }
1172
- function isValidUtmParams(params) {
1173
- if (!params.source || !params.medium || !params.campaign) {
1174
- return false;
1175
- }
1176
- if (!validateUtmField("source", params.source)) return false;
1177
- if (!validateUtmField("medium", params.medium)) return false;
1178
- if (!validateUtmField("campaign", params.campaign)) return false;
1179
- if (params.term !== void 0 && !validateUtmField("term", params.term)) return false;
1180
- if (params.content !== void 0 && !validateUtmField("content", params.content)) return false;
1181
- return true;
1182
- }
1183
- function validateCompliance(url, params) {
1184
- const errors = [];
1185
- const classification = classifyUrl(url);
1186
- const needsUtm = requiresUtm(url);
1187
- if (!needsUtm) {
1188
- return {
1189
- status: "compliant",
1190
- url,
1191
- params: params ?? null,
1192
- errors: []
1193
- };
1194
- }
1195
- if (!params) {
1196
- return {
1197
- status: "blocked",
1198
- url,
1199
- params: null,
1200
- errors: [`URL classified as '${classification}' requires UTM parameters but none provided`]
1201
- };
1202
- }
1203
- if (!params.source) errors.push("Missing required field: utm_source");
1204
- if (!params.medium) errors.push("Missing required field: utm_medium");
1205
- if (!params.campaign) errors.push("Missing required field: utm_campaign");
1206
- if (params.source && !validateUtmField("source", params.source)) {
1207
- errors.push(`Invalid utm_source: '${params.source}'. Must be one of: ${UTM_SOURCES.join(", ")}`);
1208
- }
1209
- if (params.medium && !validateUtmField("medium", params.medium)) {
1210
- errors.push(`Invalid utm_medium: '${params.medium}'. Must be one of governed enum values`);
1211
- }
1212
- if (params.campaign && !validateUtmField("campaign", params.campaign)) {
1213
- errors.push(`Invalid utm_campaign: '${params.campaign}'. Must be one of: ${UTM_CAMPAIGNS.join(", ")}`);
1214
- }
1215
- if (params.term !== void 0 && params.term && !validateUtmField("term", params.term)) {
1216
- errors.push(`Invalid utm_term: '${params.term}'. Must be one of: ${UTM_TERMS.join(", ")}`);
1217
- }
1218
- if (params.content !== void 0 && params.content && !validateUtmField("content", params.content)) {
1219
- errors.push(`Invalid utm_content: '${params.content}'. Must be one of: ${UTM_CONTENTS.join(", ")}`);
1220
- }
1221
- const allValues = [];
1222
- if (params.source) allValues.push(params.source);
1223
- if (params.medium) allValues.push(params.medium);
1224
- if (params.campaign) allValues.push(params.campaign);
1225
- if (params.term) allValues.push(params.term);
1226
- if (params.content) allValues.push(params.content);
1227
- for (const value of allValues) {
1228
- if (/\s/.test(value)) errors.push(`Value '${value}' contains spaces`);
1229
- if (/_/.test(value)) errors.push(`Value '${value}' contains underscores`);
1230
- if (/-/.test(value)) errors.push(`Value '${value}' contains hyphens`);
1231
- if (/[^\x20-\x7E]/.test(value)) errors.push(`Value '${value}' contains non-ASCII characters`);
1232
- if (value === value.toUpperCase() && value.length > 1) errors.push(`Value '${value}' is ALL CAPS`);
1233
- }
1234
- const status = errors.length === 0 ? "compliant" : "blocked";
1235
- return { status, url, params, errors };
1236
- }
1237
- function classifyAndEnforce(url, params) {
1238
- return validateCompliance(url, params);
1239
- }
1240
- function buildBlockedError(reason, url) {
1241
- return {
1242
- status: "UTM_COMPLIANCE_BLOCKED",
1243
- reason,
1244
- requiredFix: reason,
1245
- correctedExample: url ?? null
1246
- };
1247
- }
1248
-
1249
- // src/web/utm/attribution.ts
1250
- function parseUtmParams(search) {
1251
- if (!search) return {};
1252
- const params = new URLSearchParams(search);
1253
- const result = {};
1254
- const source = params.get("utm_source");
1255
- if (source && UTM_SOURCES.includes(source)) {
1256
- result.source = source;
1257
- }
1258
- const medium = params.get("utm_medium");
1259
- if (medium) {
1260
- result.medium = medium;
1261
- }
1262
- const campaign = params.get("utm_campaign");
1263
- if (campaign && UTM_CAMPAIGNS.includes(campaign)) {
1264
- result.campaign = campaign;
1265
- }
1266
- const term = params.get("utm_term");
1267
- if (term && UTM_TERMS.includes(term)) {
1268
- result.term = term;
1269
- }
1270
- const content = params.get("utm_content");
1271
- if (content && UTM_CONTENTS.includes(content)) {
1272
- result.content = content;
1273
- }
1274
- return result;
1275
- }
1276
- function toFirstTouchAttribution(params) {
1277
- return {
1278
- firstTouchSource: params.source,
1279
- firstTouchMedium: params.medium,
1280
- firstTouchCampaign: params.campaign,
1281
- firstTouchSeller: params.term ?? null
1282
- };
1283
- }
1284
- function requiresSellerAttribution(source) {
1285
- return UTM_SOURCES_REQUIRING_SELLER.includes(source);
1286
- }
1287
-
1288
- // src/web/utm/audit.ts
1289
- function createAuditEntry(url, params, generatorContext, confidence) {
1290
- const utmParts = [];
1291
- if (params) {
1292
- if (params.source) utmParts.push(`utm_source=${params.source}`);
1293
- if (params.medium) utmParts.push(`utm_medium=${params.medium}`);
1294
- if (params.campaign) utmParts.push(`utm_campaign=${params.campaign}`);
1295
- if (params.term) utmParts.push(`utm_term=${params.term}`);
1296
- if (params.content) utmParts.push(`utm_content=${params.content}`);
1297
- }
1298
- return {
1299
- url,
1300
- utmString: utmParts.join("&"),
1301
- generatorContext,
1302
- sellerAttribution: params?.term ?? null,
1303
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1304
- confidence
1305
- };
1306
- }
1307
11
  function UtmProvider({ params, children }) {
1308
12
  return /* @__PURE__ */ jsx(UtmContext.Provider, { value: params, children });
1309
13
  }
1310
14
 
1311
- export { AnalyticsProvider, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, CookieConsent, JsonLd, UTM_CAMPAIGNS, UTM_CONTENTS, UTM_MEDIUMS_ALL, UTM_MEDIUMS_APP, UTM_MEDIUMS_MESSAGING, UTM_MEDIUMS_WEB, UTM_SOURCES, UTM_SOURCES_REQUIRING_SELLER, UTM_TERMS, UtmProvider, aggregateRatingFromTestimonials, buildBlockedError, buildPageGraph, buildUtmUrl, canonicalUrl, classifyAndEnforce, classifyUrl, createAnalyticsLoader, createAuditEntry, createEntityIds, createSchemaGenerators, isUtmExempt, isValidUtmParams, loadClarity, loadGoogleAnalytics, parseUtmParams, requiresSellerAttribution, requiresUtm, toFirstTouchAttribution, useAnalytics, useCookieConsent, useUtmDefaults, validateCompliance, validateUtmField };
15
+ export { UtmProvider };
1312
16
  //# sourceMappingURL=out.js.map
1313
17
  //# sourceMappingURL=index.js.map