@highjumpdigitalsoftware/blog-kit 0.6.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.
Files changed (397) hide show
  1. package/INTEGRATION.md +76 -0
  2. package/LICENSE +74 -0
  3. package/README.md +102 -0
  4. package/astro/AdPreview.astro +64 -0
  5. package/astro/AdPreviewPair.astro +10 -0
  6. package/astro/AuditFindings.astro +29 -0
  7. package/astro/AuditScores.astro +60 -0
  8. package/astro/AuthorCard.astro +32 -0
  9. package/astro/BeforeAfter.astro +26 -0
  10. package/astro/BlogBehaviors.astro +15 -0
  11. package/astro/CTABanner.astro +28 -0
  12. package/astro/CalloutBox.astro +28 -0
  13. package/astro/CaseStudyHero.astro +45 -0
  14. package/astro/ChannelMixBars.astro +33 -0
  15. package/astro/Checklist.astro +24 -0
  16. package/astro/ChecklistItem.astro +15 -0
  17. package/astro/CodeSnippet.astro +20 -0
  18. package/astro/ComparisonTable.astro +103 -0
  19. package/astro/Definition.astro +30 -0
  20. package/astro/DeliveryComparison.astro +40 -0
  21. package/astro/FAQList.astro +43 -0
  22. package/astro/FurtherReading.astro +34 -0
  23. package/astro/ImageFeature.astro +22 -0
  24. package/astro/Infographic.astro +12 -0
  25. package/astro/KeyMetric.astro +40 -0
  26. package/astro/KeywordTable.astro +69 -0
  27. package/astro/List.astro +46 -0
  28. package/astro/MetricHighlight.astro +77 -0
  29. package/astro/NewsletterCTA.astro +40 -0
  30. package/astro/NumberedCard.astro +6 -0
  31. package/astro/ProConBlock.astro +38 -0
  32. package/astro/ProseList.astro +46 -0
  33. package/astro/QuoteBlock.astro +72 -0
  34. package/astro/RegionCallout.astro +24 -0
  35. package/astro/RelatedPosts.astro +47 -0
  36. package/astro/ResultsStrip.astro +59 -0
  37. package/astro/ScoreBar.astro +19 -0
  38. package/astro/SerpPreview.astro +35 -0
  39. package/astro/ServicePromoCard.astro +21 -0
  40. package/astro/StatCard.astro +48 -0
  41. package/astro/StepBlock.astro +5 -0
  42. package/astro/TableOfContents.astro +12 -0
  43. package/astro/TimelineBlock.astro +30 -0
  44. package/astro/TipBox.astro +14 -0
  45. package/astro/TrafficChart.astro +61 -0
  46. package/astro/VerdictCard.astro +48 -0
  47. package/astro/blogkit/Article.astro +63 -0
  48. package/astro/blogkit/BlogIndex.astro +144 -0
  49. package/core/behaviors/code.js +78 -0
  50. package/core/behaviors/comparison.js +52 -0
  51. package/core/behaviors/delivery-comparison.js +52 -0
  52. package/core/behaviors/faq.js +61 -0
  53. package/core/behaviors/index.d.ts +3 -0
  54. package/core/behaviors/index.js +35 -0
  55. package/core/behaviors/keyword-table.js +52 -0
  56. package/core/behaviors/toc.js +130 -0
  57. package/core/css/base.css +146 -0
  58. package/core/css/components.css +2632 -0
  59. package/core/css/index-listing.css +207 -0
  60. package/core/css/index.css +13 -0
  61. package/core/css/tokens.css +127 -0
  62. package/core/icons.ts +20 -0
  63. package/core/lib.ts +70 -0
  64. package/core/manifest/components.json +573 -0
  65. package/core/manifest/frontmatter.json +19 -0
  66. package/core/manifest/templates.json +77 -0
  67. package/dist/core/behaviors/code.js +78 -0
  68. package/dist/core/behaviors/comparison.js +52 -0
  69. package/dist/core/behaviors/delivery-comparison.js +52 -0
  70. package/dist/core/behaviors/faq.js +61 -0
  71. package/dist/core/behaviors/index.d.ts +3 -0
  72. package/dist/core/behaviors/index.js +35 -0
  73. package/dist/core/behaviors/keyword-table.js +52 -0
  74. package/dist/core/behaviors/toc.js +130 -0
  75. package/dist/core/css/base.css +146 -0
  76. package/dist/core/css/components.css +2632 -0
  77. package/dist/core/css/index-listing.css +207 -0
  78. package/dist/core/css/index.css +13 -0
  79. package/dist/core/css/tokens.css +127 -0
  80. package/dist/core/icons.d.ts +2 -0
  81. package/dist/core/icons.d.ts.map +1 -0
  82. package/dist/core/icons.js +20 -0
  83. package/dist/core/icons.js.map +1 -0
  84. package/dist/core/lib.d.ts +21 -0
  85. package/dist/core/lib.d.ts.map +1 -0
  86. package/dist/core/lib.js +57 -0
  87. package/dist/core/lib.js.map +1 -0
  88. package/dist/core/manifest/components.json +573 -0
  89. package/dist/core/manifest/frontmatter.json +19 -0
  90. package/dist/core/manifest/templates.json +77 -0
  91. package/dist/package/adapters/hjd-api.d.ts +14 -0
  92. package/dist/package/adapters/hjd-api.d.ts.map +1 -0
  93. package/dist/package/adapters/hjd-api.js +57 -0
  94. package/dist/package/adapters/hjd-api.js.map +1 -0
  95. package/dist/package/adapters/index.d.ts +13 -0
  96. package/dist/package/adapters/index.d.ts.map +1 -0
  97. package/dist/package/adapters/index.js +16 -0
  98. package/dist/package/adapters/index.js.map +1 -0
  99. package/dist/package/adapters/local.d.ts +13 -0
  100. package/dist/package/adapters/local.d.ts.map +1 -0
  101. package/dist/package/adapters/local.js +72 -0
  102. package/dist/package/adapters/local.js.map +1 -0
  103. package/dist/package/adapters/source.d.ts +39 -0
  104. package/dist/package/adapters/source.d.ts.map +1 -0
  105. package/dist/package/adapters/source.js +19 -0
  106. package/dist/package/adapters/source.js.map +1 -0
  107. package/dist/package/article.d.ts +17 -0
  108. package/dist/package/article.d.ts.map +1 -0
  109. package/dist/package/article.js +37 -0
  110. package/dist/package/article.js.map +1 -0
  111. package/dist/package/astro/data.d.ts +45 -0
  112. package/dist/package/astro/data.d.ts.map +1 -0
  113. package/dist/package/astro/data.js +81 -0
  114. package/dist/package/astro/data.js.map +1 -0
  115. package/dist/package/astro/freshness.d.ts +11 -0
  116. package/dist/package/astro/freshness.d.ts.map +1 -0
  117. package/dist/package/astro/freshness.js +48 -0
  118. package/dist/package/astro/freshness.js.map +1 -0
  119. package/dist/package/astro/index.d.ts +12 -0
  120. package/dist/package/astro/index.d.ts.map +1 -0
  121. package/dist/package/astro/index.js +31 -0
  122. package/dist/package/astro/index.js.map +1 -0
  123. package/dist/package/blog-index.d.ts +10 -0
  124. package/dist/package/blog-index.d.ts.map +1 -0
  125. package/dist/package/blog-index.js +27 -0
  126. package/dist/package/blog-index.js.map +1 -0
  127. package/dist/package/cli/exchange.d.ts +27 -0
  128. package/dist/package/cli/exchange.d.ts.map +1 -0
  129. package/dist/package/cli/exchange.js +94 -0
  130. package/dist/package/cli/exchange.js.map +1 -0
  131. package/dist/package/cli/index.d.ts +3 -0
  132. package/dist/package/cli/index.d.ts.map +1 -0
  133. package/dist/package/cli/index.js +301 -0
  134. package/dist/package/cli/index.js.map +1 -0
  135. package/dist/package/config/define.d.ts +13 -0
  136. package/dist/package/config/define.d.ts.map +1 -0
  137. package/dist/package/config/define.js +14 -0
  138. package/dist/package/config/define.js.map +1 -0
  139. package/dist/package/config/resolve.d.ts +11 -0
  140. package/dist/package/config/resolve.d.ts.map +1 -0
  141. package/dist/package/config/resolve.js +43 -0
  142. package/dist/package/config/resolve.js.map +1 -0
  143. package/dist/package/config/types.d.ts +74 -0
  144. package/dist/package/config/types.d.ts.map +1 -0
  145. package/dist/package/config/types.js +13 -0
  146. package/dist/package/config/types.js.map +1 -0
  147. package/dist/package/index-core.d.ts +28 -0
  148. package/dist/package/index-core.d.ts.map +1 -0
  149. package/dist/package/index-core.js +102 -0
  150. package/dist/package/index-core.js.map +1 -0
  151. package/dist/package/index.d.ts +13 -0
  152. package/dist/package/index.d.ts.map +1 -0
  153. package/dist/package/index.js +25 -0
  154. package/dist/package/index.js.map +1 -0
  155. package/dist/package/mdx/render-astro.d.ts +18 -0
  156. package/dist/package/mdx/render-astro.d.ts.map +1 -0
  157. package/dist/package/mdx/render-astro.js +75 -0
  158. package/dist/package/mdx/render-astro.js.map +1 -0
  159. package/dist/package/mdx/render.d.ts +13 -0
  160. package/dist/package/mdx/render.d.ts.map +1 -0
  161. package/dist/package/mdx/render.js +37 -0
  162. package/dist/package/mdx/render.js.map +1 -0
  163. package/dist/react/AdPreview.d.ts +26 -0
  164. package/dist/react/AdPreview.d.ts.map +1 -0
  165. package/dist/react/AdPreview.js +8 -0
  166. package/dist/react/AdPreview.js.map +1 -0
  167. package/dist/react/AdPreviewPair.d.ts +7 -0
  168. package/dist/react/AdPreviewPair.d.ts.map +1 -0
  169. package/dist/react/AdPreviewPair.js +5 -0
  170. package/dist/react/AdPreviewPair.js.map +1 -0
  171. package/dist/react/AuditFindings.d.ts +14 -0
  172. package/dist/react/AuditFindings.d.ts.map +1 -0
  173. package/dist/react/AuditFindings.js +5 -0
  174. package/dist/react/AuditFindings.js.map +1 -0
  175. package/dist/react/AuditScores.d.ts +12 -0
  176. package/dist/react/AuditScores.d.ts.map +1 -0
  177. package/dist/react/AuditScores.js +25 -0
  178. package/dist/react/AuditScores.js.map +1 -0
  179. package/dist/react/AuthorCard.d.ts +10 -0
  180. package/dist/react/AuthorCard.d.ts.map +1 -0
  181. package/dist/react/AuthorCard.js +6 -0
  182. package/dist/react/AuthorCard.js.map +1 -0
  183. package/dist/react/BeforeAfter.d.ts +12 -0
  184. package/dist/react/BeforeAfter.d.ts.map +1 -0
  185. package/dist/react/BeforeAfter.js +7 -0
  186. package/dist/react/BeforeAfter.js.map +1 -0
  187. package/dist/react/BlogBehaviors.d.ts +10 -0
  188. package/dist/react/BlogBehaviors.d.ts.map +1 -0
  189. package/dist/react/BlogBehaviors.js +20 -0
  190. package/dist/react/BlogBehaviors.js.map +1 -0
  191. package/dist/react/CTABanner.d.ts +8 -0
  192. package/dist/react/CTABanner.d.ts.map +1 -0
  193. package/dist/react/CTABanner.js +9 -0
  194. package/dist/react/CTABanner.js.map +1 -0
  195. package/dist/react/CalloutBox.d.ts +13 -0
  196. package/dist/react/CalloutBox.d.ts.map +1 -0
  197. package/dist/react/CalloutBox.js +9 -0
  198. package/dist/react/CalloutBox.js.map +1 -0
  199. package/dist/react/CaseStudyHero.d.ts +20 -0
  200. package/dist/react/CaseStudyHero.d.ts.map +1 -0
  201. package/dist/react/CaseStudyHero.js +7 -0
  202. package/dist/react/CaseStudyHero.js.map +1 -0
  203. package/dist/react/ChannelMixBars.d.ts +18 -0
  204. package/dist/react/ChannelMixBars.d.ts.map +1 -0
  205. package/dist/react/ChannelMixBars.js +6 -0
  206. package/dist/react/ChannelMixBars.js.map +1 -0
  207. package/dist/react/Checklist.d.ts +10 -0
  208. package/dist/react/Checklist.d.ts.map +1 -0
  209. package/dist/react/Checklist.js +7 -0
  210. package/dist/react/Checklist.js.map +1 -0
  211. package/dist/react/ChecklistItem.d.ts +7 -0
  212. package/dist/react/ChecklistItem.d.ts.map +1 -0
  213. package/dist/react/ChecklistItem.js +5 -0
  214. package/dist/react/ChecklistItem.js.map +1 -0
  215. package/dist/react/CodeSnippet.d.ts +17 -0
  216. package/dist/react/CodeSnippet.d.ts.map +1 -0
  217. package/dist/react/CodeSnippet.js +14 -0
  218. package/dist/react/CodeSnippet.js.map +1 -0
  219. package/dist/react/ComparisonTable.d.ts +22 -0
  220. package/dist/react/ComparisonTable.d.ts.map +1 -0
  221. package/dist/react/ComparisonTable.js +35 -0
  222. package/dist/react/ComparisonTable.js.map +1 -0
  223. package/dist/react/Definition.d.ts +9 -0
  224. package/dist/react/Definition.d.ts.map +1 -0
  225. package/dist/react/Definition.js +19 -0
  226. package/dist/react/Definition.js.map +1 -0
  227. package/dist/react/DeliveryComparison.d.ts +16 -0
  228. package/dist/react/DeliveryComparison.d.ts.map +1 -0
  229. package/dist/react/DeliveryComparison.js +7 -0
  230. package/dist/react/DeliveryComparison.js.map +1 -0
  231. package/dist/react/FAQList.d.ts +20 -0
  232. package/dist/react/FAQList.d.ts.map +1 -0
  233. package/dist/react/FAQList.js +19 -0
  234. package/dist/react/FAQList.js.map +1 -0
  235. package/dist/react/FurtherReading.d.ts +21 -0
  236. package/dist/react/FurtherReading.d.ts.map +1 -0
  237. package/dist/react/FurtherReading.js +13 -0
  238. package/dist/react/FurtherReading.js.map +1 -0
  239. package/dist/react/ImageFeature.d.ts +9 -0
  240. package/dist/react/ImageFeature.d.ts.map +1 -0
  241. package/dist/react/ImageFeature.js +6 -0
  242. package/dist/react/ImageFeature.js.map +1 -0
  243. package/dist/react/Infographic.d.ts +6 -0
  244. package/dist/react/Infographic.d.ts.map +1 -0
  245. package/dist/react/Infographic.js +7 -0
  246. package/dist/react/Infographic.js.map +1 -0
  247. package/dist/react/KeyMetric.d.ts +16 -0
  248. package/dist/react/KeyMetric.d.ts.map +1 -0
  249. package/dist/react/KeyMetric.js +15 -0
  250. package/dist/react/KeyMetric.js.map +1 -0
  251. package/dist/react/KeywordTable.d.ts +18 -0
  252. package/dist/react/KeywordTable.d.ts.map +1 -0
  253. package/dist/react/KeywordTable.js +23 -0
  254. package/dist/react/KeywordTable.js.map +1 -0
  255. package/dist/react/List.d.ts +11 -0
  256. package/dist/react/List.d.ts.map +1 -0
  257. package/dist/react/List.js +21 -0
  258. package/dist/react/List.js.map +1 -0
  259. package/dist/react/MetricHighlight.d.ts +15 -0
  260. package/dist/react/MetricHighlight.d.ts.map +1 -0
  261. package/dist/react/MetricHighlight.js +26 -0
  262. package/dist/react/MetricHighlight.js.map +1 -0
  263. package/dist/react/NewsletterCTA.d.ts +9 -0
  264. package/dist/react/NewsletterCTA.d.ts.map +1 -0
  265. package/dist/react/NewsletterCTA.js +5 -0
  266. package/dist/react/NewsletterCTA.js.map +1 -0
  267. package/dist/react/NumberedCard.d.ts +9 -0
  268. package/dist/react/NumberedCard.d.ts.map +1 -0
  269. package/dist/react/NumberedCard.js +7 -0
  270. package/dist/react/NumberedCard.js.map +1 -0
  271. package/dist/react/ProConBlock.d.ts +6 -0
  272. package/dist/react/ProConBlock.d.ts.map +1 -0
  273. package/dist/react/ProConBlock.js +7 -0
  274. package/dist/react/ProConBlock.js.map +1 -0
  275. package/dist/react/ProseList.d.ts +17 -0
  276. package/dist/react/ProseList.d.ts.map +1 -0
  277. package/dist/react/ProseList.js +26 -0
  278. package/dist/react/ProseList.js.map +1 -0
  279. package/dist/react/QuoteBlock.d.ts +17 -0
  280. package/dist/react/QuoteBlock.d.ts.map +1 -0
  281. package/dist/react/QuoteBlock.js +26 -0
  282. package/dist/react/QuoteBlock.js.map +1 -0
  283. package/dist/react/RegionCallout.d.ts +13 -0
  284. package/dist/react/RegionCallout.d.ts.map +1 -0
  285. package/dist/react/RegionCallout.js +5 -0
  286. package/dist/react/RegionCallout.js.map +1 -0
  287. package/dist/react/RelatedPosts.d.ts +20 -0
  288. package/dist/react/RelatedPosts.d.ts.map +1 -0
  289. package/dist/react/RelatedPosts.js +7 -0
  290. package/dist/react/RelatedPosts.js.map +1 -0
  291. package/dist/react/ResultsStrip.d.ts +18 -0
  292. package/dist/react/ResultsStrip.d.ts.map +1 -0
  293. package/dist/react/ResultsStrip.js +22 -0
  294. package/dist/react/ResultsStrip.js.map +1 -0
  295. package/dist/react/ScoreBar.d.ts +8 -0
  296. package/dist/react/ScoreBar.d.ts.map +1 -0
  297. package/dist/react/ScoreBar.js +6 -0
  298. package/dist/react/ScoreBar.js.map +1 -0
  299. package/dist/react/SerpPreview.d.ts +18 -0
  300. package/dist/react/SerpPreview.d.ts.map +1 -0
  301. package/dist/react/SerpPreview.js +13 -0
  302. package/dist/react/SerpPreview.js.map +1 -0
  303. package/dist/react/ServicePromoCard.d.ts +14 -0
  304. package/dist/react/ServicePromoCard.d.ts.map +1 -0
  305. package/dist/react/ServicePromoCard.js +12 -0
  306. package/dist/react/ServicePromoCard.js.map +1 -0
  307. package/dist/react/StatCard.d.ts +13 -0
  308. package/dist/react/StatCard.d.ts.map +1 -0
  309. package/dist/react/StatCard.js +20 -0
  310. package/dist/react/StatCard.js.map +1 -0
  311. package/dist/react/StepBlock.d.ts +8 -0
  312. package/dist/react/StepBlock.d.ts.map +1 -0
  313. package/dist/react/StepBlock.js +5 -0
  314. package/dist/react/StepBlock.js.map +1 -0
  315. package/dist/react/TableOfContents.d.ts +14 -0
  316. package/dist/react/TableOfContents.d.ts.map +1 -0
  317. package/dist/react/TableOfContents.js +12 -0
  318. package/dist/react/TableOfContents.js.map +1 -0
  319. package/dist/react/TimelineBlock.d.ts +14 -0
  320. package/dist/react/TimelineBlock.d.ts.map +1 -0
  321. package/dist/react/TimelineBlock.js +8 -0
  322. package/dist/react/TimelineBlock.js.map +1 -0
  323. package/dist/react/TipBox.d.ts +6 -0
  324. package/dist/react/TipBox.d.ts.map +1 -0
  325. package/dist/react/TipBox.js +5 -0
  326. package/dist/react/TipBox.js.map +1 -0
  327. package/dist/react/TrafficChart.d.ts +16 -0
  328. package/dist/react/TrafficChart.d.ts.map +1 -0
  329. package/dist/react/TrafficChart.js +14 -0
  330. package/dist/react/TrafficChart.js.map +1 -0
  331. package/dist/react/VerdictCard.d.ts +15 -0
  332. package/dist/react/VerdictCard.d.ts.map +1 -0
  333. package/dist/react/VerdictCard.js +5 -0
  334. package/dist/react/VerdictCard.js.map +1 -0
  335. package/dist/react/components-map.d.ts +133 -0
  336. package/dist/react/components-map.d.ts.map +1 -0
  337. package/dist/react/components-map.js +120 -0
  338. package/dist/react/components-map.js.map +1 -0
  339. package/dist/react/index.d.ts +5 -0
  340. package/dist/react/index.d.ts.map +1 -0
  341. package/dist/react/index.js +13 -0
  342. package/dist/react/index.js.map +1 -0
  343. package/package.json +116 -0
  344. package/react/AdPreview.tsx +94 -0
  345. package/react/AdPreviewPair.tsx +16 -0
  346. package/react/AuditFindings.tsx +43 -0
  347. package/react/AuditScores.tsx +73 -0
  348. package/react/AuthorCard.tsx +35 -0
  349. package/react/BeforeAfter.tsx +27 -0
  350. package/react/BlogBehaviors.tsx +21 -0
  351. package/react/CTABanner.tsx +32 -0
  352. package/react/CalloutBox.tsx +31 -0
  353. package/react/CaseStudyHero.tsx +71 -0
  354. package/react/ChannelMixBars.tsx +50 -0
  355. package/react/Checklist.tsx +31 -0
  356. package/react/ChecklistItem.tsx +19 -0
  357. package/react/CodeSnippet.tsx +36 -0
  358. package/react/ComparisonTable.tsx +114 -0
  359. package/react/Definition.tsx +36 -0
  360. package/react/DeliveryComparison.tsx +62 -0
  361. package/react/FAQList.tsx +61 -0
  362. package/react/FurtherReading.tsx +46 -0
  363. package/react/ImageFeature.tsx +26 -0
  364. package/react/Infographic.tsx +18 -0
  365. package/react/KeyMetric.tsx +61 -0
  366. package/react/KeywordTable.tsx +92 -0
  367. package/react/List.tsx +58 -0
  368. package/react/MetricHighlight.tsx +86 -0
  369. package/react/NewsletterCTA.tsx +48 -0
  370. package/react/NumberedCard.tsx +7 -0
  371. package/react/ProConBlock.tsx +42 -0
  372. package/react/ProseList.tsx +72 -0
  373. package/react/QuoteBlock.tsx +89 -0
  374. package/react/RegionCallout.tsx +38 -0
  375. package/react/RelatedPosts.tsx +58 -0
  376. package/react/ResultsStrip.tsx +77 -0
  377. package/react/ScoreBar.tsx +27 -0
  378. package/react/SerpPreview.tsx +59 -0
  379. package/react/ServicePromoCard.tsx +43 -0
  380. package/react/StatCard.tsx +62 -0
  381. package/react/StepBlock.tsx +5 -0
  382. package/react/TableOfContents.tsx +27 -0
  383. package/react/TimelineBlock.tsx +35 -0
  384. package/react/TipBox.tsx +16 -0
  385. package/react/TrafficChart.tsx +79 -0
  386. package/react/VerdictCard.tsx +60 -0
  387. package/react/components-map.ts +122 -0
  388. package/react/index.ts +13 -0
  389. package/templates/blogkit/app/api/blogkit/revalidate/route.ts.tmpl +32 -0
  390. package/templates/blogkit/app/blog/[slug]/page.tsx.tmpl +41 -0
  391. package/templates/blogkit/app/blog/page.tsx.tmpl +18 -0
  392. package/templates/blogkit/blogkit.config.ts.tmpl +23 -0
  393. package/templates/blogkit-astro/BLOGKIT_ASTRO_SETUP.md.tmpl +49 -0
  394. package/templates/blogkit-astro/src/blogkit.config.ts.tmpl +29 -0
  395. package/templates/blogkit-astro/src/pages/api/blogkit/revalidate.ts.tmpl +46 -0
  396. package/templates/blogkit-astro/src/pages/blog/[slug].astro.tmpl +39 -0
  397. package/templates/blogkit-astro/src/pages/blog/index.astro.tmpl +29 -0
@@ -0,0 +1,24 @@
1
+ ---
2
+ interface ChecklistEntry {
3
+ title: string;
4
+ sub?: string;
5
+ done?: boolean;
6
+ }
7
+ interface Props {
8
+ items: ChecklistEntry[];
9
+ }
10
+ const { items } = Astro.props;
11
+ ---
12
+ {items && items.length > 0 && (
13
+ <ul class="bk-checklist">
14
+ {items.map((it) => (
15
+ <li class={`bk-checklist__item${it.done ? " bk-checklist__item--done" : ""}`}>
16
+ <span class="bk-checklist__box" aria-hidden="true">{it.done ? "✓" : ""}</span>
17
+ <span class="bk-checklist__text">
18
+ <span class="bk-checklist__title">{it.title}</span>
19
+ {it.sub && <span class="bk-checklist__sub">{it.sub}</span>}
20
+ </span>
21
+ </li>
22
+ ))}
23
+ </ul>
24
+ )}
@@ -0,0 +1,15 @@
1
+ ---
2
+ interface Props {
3
+ checked: boolean;
4
+ label: string;
5
+ description?: string;
6
+ }
7
+ const { checked, label, description } = Astro.props;
8
+ ---
9
+ <div class={`bk-checklist-item${checked ? " bk-checklist-item--checked" : ""}`}>
10
+ <span class="bk-checklist-item__box" aria-hidden={!checked}>{checked ? "✓" : ""}</span>
11
+ <span class="bk-checklist-item__text">
12
+ <span class="bk-checklist-item__label">{label}</span>
13
+ {description && <span class="bk-checklist-item__desc">{description}</span>}
14
+ </span>
15
+ </div>
@@ -0,0 +1,20 @@
1
+ ---
2
+ import { ICONS } from "../core/icons";
3
+ interface Props {
4
+ code: string;
5
+ language?: string;
6
+ filename?: string;
7
+ }
8
+ const { code, language = "text", filename } = Astro.props;
9
+ const label = filename || (language !== "text" ? language : "code");
10
+ ---
11
+ <div class="bk-code" data-bk-code>
12
+ <div class="bk-code__bar">
13
+ <span class="bk-code__label">{label}</span>
14
+ <button type="button" class="bk-code__copy" data-bk-code-copy>
15
+ <span class="bk-code__copy-icon" set:html={ICONS.copy} />
16
+ <span class="bk-code__copy-label">Copy</span>
17
+ </button>
18
+ </div>
19
+ <pre class="bk-code__pre"><code class={`bk-code__code language-${language}`}>{code}</code></pre>
20
+ </div>
@@ -0,0 +1,103 @@
1
+ ---
2
+ interface ComparisonItem {
3
+ feature: string;
4
+ optionA: string;
5
+ optionB: string;
6
+ winner?: "a" | "b" | "tie";
7
+ }
8
+ interface Props {
9
+ title?: string;
10
+ optionALabel: string;
11
+ optionBLabel: string;
12
+ items?: ComparisonItem[];
13
+ }
14
+
15
+ const TICK = "✓";
16
+ const CROSS = "✕";
17
+
18
+ type Cell = { kind: "yes" | "no" | "text"; text: string };
19
+
20
+ /** Normalise a cell value: tick/"yes" and cross/"no" become glyph marks. */
21
+ function resolveCell(text: string): Cell {
22
+ const v = String(text ?? "").trim();
23
+ const lower = v.toLowerCase();
24
+ if (v === TICK || lower === "yes") return { kind: "yes", text: TICK };
25
+ if (v === CROSS || lower === "no") return { kind: "no", text: CROSS };
26
+ return { kind: "text", text: v };
27
+ }
28
+
29
+ const { title, optionALabel, optionBLabel, items = [] } = Astro.props;
30
+ const list = items ?? [];
31
+ ---
32
+ {list.length > 0 && (
33
+ <div class="bk-comparison">
34
+ {title && <h3 class="bk-comparison__title">{title}</h3>}
35
+
36
+ <div class="bk-comparison__cards">
37
+ {list.map((item) => {
38
+ const a = resolveCell(item.optionA);
39
+ const b = resolveCell(item.optionB);
40
+ return (
41
+ <div class="bk-comparison__card">
42
+ <div class="bk-comparison__card-feature">{item.feature}</div>
43
+ <div class={`bk-comparison__card-row${item.winner === "a" ? " bk-comparison__card-row--best" : ""}`}>
44
+ <span class="bk-comparison__card-label">{optionALabel}</span>
45
+ {a.kind === "yes"
46
+ ? <span class="bk-comparison__mark bk-comparison__mark--yes">{a.text}</span>
47
+ : a.kind === "no"
48
+ ? <span class="bk-comparison__mark bk-comparison__mark--no">{a.text}</span>
49
+ : <span class={item.winner === "a" ? "bk-comparison__value--best" : undefined}>{a.text}</span>}
50
+ </div>
51
+ <div class={`bk-comparison__card-row${item.winner === "b" ? " bk-comparison__card-row--best" : ""}`}>
52
+ <span class="bk-comparison__card-label">{optionBLabel}</span>
53
+ {b.kind === "yes"
54
+ ? <span class="bk-comparison__mark bk-comparison__mark--yes">{b.text}</span>
55
+ : b.kind === "no"
56
+ ? <span class="bk-comparison__mark bk-comparison__mark--no">{b.text}</span>
57
+ : <span class={item.winner === "b" ? "bk-comparison__value--best" : undefined}>{b.text}</span>}
58
+ </div>
59
+ </div>
60
+ );
61
+ })}
62
+ </div>
63
+
64
+ <div class="bk-comparison__table-wrap" data-bk-comparison>
65
+ <div class="bk-comparison__scroll">
66
+ <table class="bk-comparison__table">
67
+ <thead>
68
+ <tr>
69
+ <th class="bk-comparison__th">Feature</th>
70
+ <th class="bk-comparison__th">{optionALabel}</th>
71
+ <th class="bk-comparison__th">{optionBLabel}</th>
72
+ </tr>
73
+ </thead>
74
+ <tbody>
75
+ {list.map((item) => {
76
+ const a = resolveCell(item.optionA);
77
+ const b = resolveCell(item.optionB);
78
+ return (
79
+ <tr class="bk-comparison__tr">
80
+ <td class="bk-comparison__td bk-comparison__td--feature">{item.feature}</td>
81
+ <td class={`bk-comparison__td${item.winner === "a" ? " bk-comparison__td--best" : ""}`}>
82
+ {a.kind === "yes"
83
+ ? <span class="bk-comparison__mark bk-comparison__mark--yes">{a.text}</span>
84
+ : a.kind === "no"
85
+ ? <span class="bk-comparison__mark bk-comparison__mark--no">{a.text}</span>
86
+ : <span class={item.winner === "a" ? "bk-comparison__value--best" : undefined}>{a.text}</span>}
87
+ </td>
88
+ <td class={`bk-comparison__td${item.winner === "b" ? " bk-comparison__td--best" : ""}`}>
89
+ {b.kind === "yes"
90
+ ? <span class="bk-comparison__mark bk-comparison__mark--yes">{b.text}</span>
91
+ : b.kind === "no"
92
+ ? <span class="bk-comparison__mark bk-comparison__mark--no">{b.text}</span>
93
+ : <span class={item.winner === "b" ? "bk-comparison__value--best" : undefined}>{b.text}</span>}
94
+ </td>
95
+ </tr>
96
+ );
97
+ })}
98
+ </tbody>
99
+ </table>
100
+ </div>
101
+ </div>
102
+ </div>
103
+ )}
@@ -0,0 +1,30 @@
1
+ ---
2
+ interface Props {
3
+ term: string;
4
+ name?: string;
5
+ pronunciation?: string;
6
+ }
7
+ const { term, name, pronunciation } = Astro.props;
8
+ // `term` is meant to be a 2-3 char monogram. If an author passes a full
9
+ // phrase, derive initials so the tile doesn't overflow.
10
+ const rawTerm = String(term ?? "").trim();
11
+ const looksLikePhrase = rawTerm.length > 4 || /\s|-/.test(rawTerm);
12
+ const monogram = looksLikePhrase
13
+ ? rawTerm
14
+ .split(/[\s-]+/)
15
+ .map((w) => w[0])
16
+ .filter(Boolean)
17
+ .join("")
18
+ .slice(0, 3)
19
+ .toUpperCase()
20
+ : rawTerm.toUpperCase();
21
+ const resolvedName = name ?? (looksLikePhrase ? rawTerm : undefined);
22
+ ---
23
+ <div class="bk-definition">
24
+ <div class="bk-definition__monogram" aria-hidden="true">{monogram}</div>
25
+ <div class="bk-definition__content">
26
+ {resolvedName && <p class="bk-definition__name">{resolvedName}</p>}
27
+ {pronunciation && <p class="bk-definition__pronunciation">{pronunciation}</p>}
28
+ <p class="bk-definition__body"><slot /></p>
29
+ </div>
30
+ </div>
@@ -0,0 +1,40 @@
1
+ ---
2
+ interface DeliveryComparisonRow {
3
+ label: string;
4
+ sub?: string;
5
+ values: string[];
6
+ }
7
+ interface Props {
8
+ columns?: string[];
9
+ rows?: DeliveryComparisonRow[];
10
+ }
11
+
12
+ const { columns = [], rows = [] } = Astro.props;
13
+ const cols = columns ?? [];
14
+ const list = rows ?? [];
15
+ ---
16
+ {list.length > 0 && (
17
+ <div class="bk-delivery-comparison" data-bk-delivery-comparison>
18
+ <div class="bk-delivery-comparison__scroll">
19
+ <table class="bk-delivery-comparison__table">
20
+ <thead>
21
+ <tr>
22
+ <th class="bk-delivery-comparison__th" />
23
+ {cols.map((c) => <th class="bk-delivery-comparison__th">{c}</th>)}
24
+ </tr>
25
+ </thead>
26
+ <tbody>
27
+ {list.map((r) => (
28
+ <tr class="bk-delivery-comparison__tr">
29
+ <td class="bk-delivery-comparison__td bk-delivery-comparison__td--label">
30
+ <strong class="bk-delivery-comparison__label">{r.label}</strong>
31
+ {r.sub}
32
+ </td>
33
+ {r.values.map((v) => <td class="bk-delivery-comparison__td">{v}</td>)}
34
+ </tr>
35
+ ))}
36
+ </tbody>
37
+ </table>
38
+ </div>
39
+ </div>
40
+ )}
@@ -0,0 +1,43 @@
1
+ ---
2
+ interface FAQItem {
3
+ q: string;
4
+ a: string;
5
+ }
6
+ interface Props {
7
+ items?: FAQItem[];
8
+ heading?: string;
9
+ }
10
+
11
+ /** Split an answer body into paragraphs on blank lines. */
12
+ function toParagraphs(a: string): string[] {
13
+ return String(a ?? "")
14
+ .split(/\n{2,}/)
15
+ .filter(Boolean);
16
+ }
17
+
18
+ const { items, heading } = Astro.props;
19
+ const list = items ?? [];
20
+ ---
21
+ <div class="bk-faq" data-bk-faq>
22
+ {heading && <p class="bk-faq__heading">{heading}</p>}
23
+ <div class="bk-faq__list">
24
+ {list.length > 0
25
+ ? list.map((it, i) => (
26
+ <details class="bk-faq__item" open={i === 0}>
27
+ <summary class="bk-faq__summary">
28
+ <span class="bk-faq__question">{it.q}</span>
29
+ <span class="bk-faq__toggle" aria-hidden="true">
30
+ <span class="bk-faq__bar bk-faq__bar--h" />
31
+ <span class="bk-faq__bar bk-faq__bar--v" />
32
+ </span>
33
+ </summary>
34
+ <div class="bk-faq__answer">
35
+ {toParagraphs(it.a).map((p) => (
36
+ <p class="bk-faq__para" set:html={p} />
37
+ ))}
38
+ </div>
39
+ </details>
40
+ ))
41
+ : <slot />}
42
+ </div>
43
+ </div>
@@ -0,0 +1,34 @@
1
+ ---
2
+ interface FurtherReadingSource {
3
+ title: string;
4
+ source: string;
5
+ url: string;
6
+ }
7
+ interface Props {
8
+ sources?: FurtherReadingSource[];
9
+ heading?: string;
10
+ }
11
+
12
+ const { sources, heading } = Astro.props;
13
+ const list = sources ?? [];
14
+ ---
15
+ {list.length > 0 && (
16
+ <div class="bk-further-reading">
17
+ <p class="bk-further-reading__title">{heading ?? "Further reading"}</p>
18
+ <ul class="bk-further-reading__list">
19
+ {list.map((s) => (
20
+ <li class="bk-further-reading__item">
21
+ <a
22
+ class="bk-further-reading__link"
23
+ href={s.url}
24
+ target="_blank"
25
+ rel="nofollow noopener noreferrer"
26
+ >
27
+ {s.title}
28
+ </a>
29
+ <span class="bk-further-reading__source">{s.source}</span>
30
+ </li>
31
+ ))}
32
+ </ul>
33
+ </div>
34
+ )}
@@ -0,0 +1,22 @@
1
+ ---
2
+ interface Props {
3
+ src: string;
4
+ alt: string;
5
+ caption?: string;
6
+ credit?: string;
7
+ position?: "left" | "right" | "full";
8
+ }
9
+ const { src, alt, caption, credit, position = "full" } = Astro.props;
10
+ const pos = position === "left" || position === "right" ? position : "full";
11
+ ---
12
+ <figure class={`bk-image-feature bk-image-feature--${pos}`}>
13
+ <div class="bk-image-feature__frame">
14
+ <img class="bk-image-feature__img" src={src} alt={alt} loading="lazy" decoding="async" />
15
+ </div>
16
+ {(caption || credit) && (
17
+ <figcaption class="bk-image-feature__caption">
18
+ {caption && <span class="bk-image-feature__text">{caption}</span>}
19
+ {credit && <span class="bk-image-feature__credit">{credit}</span>}
20
+ </figcaption>
21
+ )}
22
+ </figure>
@@ -0,0 +1,12 @@
1
+ ---
2
+ interface Props {
3
+ src: string;
4
+ alt: string;
5
+ }
6
+ const { src, alt } = Astro.props;
7
+ ---
8
+ {src && (
9
+ <figure class="bk-infographic">
10
+ <img class="bk-infographic__img" src={src} alt={alt} loading="lazy" decoding="async" />
11
+ </figure>
12
+ )}
@@ -0,0 +1,40 @@
1
+ ---
2
+ import { ICONS } from "../core/icons";
3
+
4
+ interface Props {
5
+ number: string;
6
+ label?: string;
7
+ title?: string;
8
+ sub?: string;
9
+ source?: string;
10
+ sourceUrl?: string;
11
+ }
12
+
13
+ const { number, label, title, sub, source, sourceUrl } = Astro.props;
14
+ ---
15
+ <div class="bk-key-metric">
16
+ <div class="bk-key-metric__num">{number}</div>
17
+ <div class="bk-key-metric__copy">
18
+ {label && <div class="bk-key-metric__label">{label}</div>}
19
+ {title && <p class="bk-key-metric__title" set:html={title} />}
20
+ {sub && <p class="bk-key-metric__sub">{sub}</p>}
21
+ {source &&
22
+ (sourceUrl ? (
23
+ <a
24
+ class="bk-key-metric__source bk-key-metric__source--link"
25
+ href={sourceUrl}
26
+ target="_blank"
27
+ rel="nofollow noopener noreferrer"
28
+ >
29
+ <span class="bk-key-metric__source-kicker">Source</span>
30
+ {source}
31
+ <span class="bk-key-metric__source-icon" aria-hidden="true" set:html={ICONS["external"]} />
32
+ </a>
33
+ ) : (
34
+ <div class="bk-key-metric__source">
35
+ <span class="bk-key-metric__source-kicker">Source</span>
36
+ {source}
37
+ </div>
38
+ ))}
39
+ </div>
40
+ </div>
@@ -0,0 +1,69 @@
1
+ ---
2
+ interface KeywordRow {
3
+ keyword: string;
4
+ volume: string;
5
+ difficulty: number;
6
+ was?: number | string;
7
+ now: number | string;
8
+ delta: number | string;
9
+ }
10
+ interface Props {
11
+ rows?: KeywordRow[];
12
+ }
13
+
14
+ /** Bucket a 0–100 difficulty score into low / med / high. */
15
+ function difficultyBucket(difficulty: number): "low" | "med" | "high" {
16
+ return difficulty < 40 ? "low" : difficulty < 60 ? "med" : "high";
17
+ }
18
+
19
+ /** A negative delta means the rank dropped (down); anything else is up. */
20
+ function deltaDirection(delta: number | string): "up" | "down" {
21
+ return delta && String(delta).startsWith("-") ? "down" : "up";
22
+ }
23
+
24
+ /** Show the magnitude when numeric, else the raw value. */
25
+ function deltaDisplay(delta: number | string): number | string {
26
+ return Math.abs(Number(delta)) || delta;
27
+ }
28
+
29
+ const { rows = [] } = Astro.props;
30
+ const list = rows ?? [];
31
+ ---
32
+ {list.length > 0 && (
33
+ <div class="bk-keyword-table" data-bk-keyword-table>
34
+ <div class="bk-keyword-table__scroll">
35
+ <table class="bk-keyword-table__table">
36
+ <thead>
37
+ <tr>
38
+ <th class="bk-keyword-table__th">Keyword</th>
39
+ <th class="bk-keyword-table__th bk-keyword-table__th--r">Volume</th>
40
+ <th class="bk-keyword-table__th">Difficulty</th>
41
+ <th class="bk-keyword-table__th bk-keyword-table__th--r">Was</th>
42
+ <th class="bk-keyword-table__th bk-keyword-table__th--r">Now</th>
43
+ <th class="bk-keyword-table__th bk-keyword-table__th--r">Δ</th>
44
+ </tr>
45
+ </thead>
46
+ <tbody>
47
+ {list.map((r) => {
48
+ const diff = difficultyBucket(r.difficulty);
49
+ const direction = deltaDirection(r.delta);
50
+ return (
51
+ <tr class="bk-keyword-table__tr">
52
+ <td class="bk-keyword-table__td bk-keyword-table__td--kw">{r.keyword}</td>
53
+ <td class="bk-keyword-table__td bk-keyword-table__td--r">{r.volume}</td>
54
+ <td class="bk-keyword-table__td">
55
+ <span class={`bk-keyword-table__diff bk-keyword-table__diff--${diff}`}>{r.difficulty}</span>
56
+ </td>
57
+ <td class="bk-keyword-table__td bk-keyword-table__td--r bk-keyword-table__rank">{r.was ?? "—"}</td>
58
+ <td class="bk-keyword-table__td bk-keyword-table__td--r bk-keyword-table__rank">{r.now}</td>
59
+ <td class="bk-keyword-table__td bk-keyword-table__td--r">
60
+ <span class={`bk-keyword-table__delta bk-keyword-table__delta--${direction}`}>{deltaDisplay(r.delta)}</span>
61
+ </td>
62
+ </tr>
63
+ );
64
+ })}
65
+ </tbody>
66
+ </table>
67
+ </div>
68
+ </div>
69
+ )}
@@ -0,0 +1,46 @@
1
+ ---
2
+ import { ICONS } from "../core/icons";
3
+
4
+ type ListVariant = "ordered" | "bullet" | "check";
5
+ interface Props {
6
+ variant?: ListVariant | string;
7
+ items: string[];
8
+ heading?: string;
9
+ }
10
+
11
+ const VARIANTS: Record<string, ListVariant> = {
12
+ ordered: "ordered",
13
+ numbered: "ordered",
14
+ number: "ordered",
15
+ bullet: "bullet",
16
+ bulleted: "bullet",
17
+ dot: "bullet",
18
+ check: "check",
19
+ checked: "check",
20
+ checklist: "check",
21
+ };
22
+
23
+ const { variant, items, heading } = Astro.props;
24
+ const v = VARIANTS[(variant ?? "bullet").toLowerCase().trim()] ?? "bullet";
25
+ const Tag = v === "ordered" ? "ol" : "ul";
26
+ const hasItems = Array.isArray(items) && items.length > 0;
27
+ ---
28
+ {hasItems && (
29
+ <div class={`bk-list bk-list--${v}`}>
30
+ {heading && <p class="bk-list__heading">{heading}</p>}
31
+ <Tag class="bk-list__items">
32
+ {items.map((item, i) => (
33
+ <li class="bk-list__item">
34
+ {v === "ordered" ? (
35
+ <span class="bk-list__marker" aria-hidden="true">{String(i + 1).padStart(2, "0")}</span>
36
+ ) : v === "check" ? (
37
+ <span class="bk-list__marker" aria-hidden="true" set:html={ICONS["check-tick"]} />
38
+ ) : (
39
+ <span class="bk-list__marker" aria-hidden="true" />
40
+ )}
41
+ <span class="bk-list__text" set:html={item} />
42
+ </li>
43
+ ))}
44
+ </Tag>
45
+ </div>
46
+ )}
@@ -0,0 +1,77 @@
1
+ ---
2
+ import { ICONS } from "../core/icons";
3
+
4
+ interface Metric {
5
+ value: string;
6
+ label: string;
7
+ change?: string;
8
+ source?: string;
9
+ sourceUrl?: string;
10
+ }
11
+
12
+ interface Props {
13
+ metrics?: Metric[];
14
+ }
15
+
16
+ const { metrics = [] } = Astro.props;
17
+ const single = metrics.length === 1 ? metrics[0] : null;
18
+ const cols = metrics.length === 2 ? 2 : metrics.length === 3 ? 3 : 4;
19
+ ---
20
+ {metrics.length === 0 ? null : single ? (
21
+ <div class="bk-metric-highlight bk-metric-highlight--hero">
22
+ <div class="bk-metric-highlight__hero-value">{single.value}</div>
23
+ <div class="bk-metric-highlight__hero-body">
24
+ {single.change && <div class="bk-metric-highlight__hero-change">{single.change}</div>}
25
+ <div class="bk-metric-highlight__hero-label">{single.label}</div>
26
+ {single.source &&
27
+ (single.sourceUrl ? (
28
+ <a
29
+ class="bk-metric-highlight__source bk-metric-highlight__source--dark bk-metric-highlight__source--link"
30
+ href={single.sourceUrl}
31
+ target="_blank"
32
+ rel="nofollow noopener noreferrer"
33
+ >
34
+ <span class="bk-metric-highlight__source-kicker">Source</span>
35
+ {single.source}
36
+ <span class="bk-metric-highlight__source-icon" aria-hidden="true" set:html={ICONS["external"]} />
37
+ </a>
38
+ ) : (
39
+ <div class="bk-metric-highlight__source bk-metric-highlight__source--dark">
40
+ <span class="bk-metric-highlight__source-kicker">Source</span>
41
+ {single.source}
42
+ </div>
43
+ ))}
44
+ </div>
45
+ </div>
46
+ ) : (
47
+ <div class={`bk-metric-highlight bk-metric-highlight--grid bk-metric-highlight--${cols}`}>
48
+ {metrics.map((metric) => (
49
+ <div class="bk-metric-highlight__card">
50
+ <div class="bk-metric-highlight__value">{metric.value}</div>
51
+ <div class="bk-metric-highlight__label">{metric.label}</div>
52
+ {metric.change && <div class="bk-metric-highlight__change">{metric.change}</div>}
53
+ {metric.source && (
54
+ <div class="bk-metric-highlight__source-wrap">
55
+ {metric.sourceUrl ? (
56
+ <a
57
+ class="bk-metric-highlight__source bk-metric-highlight__source--link"
58
+ href={metric.sourceUrl}
59
+ target="_blank"
60
+ rel="nofollow noopener noreferrer"
61
+ >
62
+ <span class="bk-metric-highlight__source-kicker">Source</span>
63
+ {metric.source}
64
+ <span class="bk-metric-highlight__source-icon" aria-hidden="true" set:html={ICONS["external"]} />
65
+ </a>
66
+ ) : (
67
+ <div class="bk-metric-highlight__source">
68
+ <span class="bk-metric-highlight__source-kicker">Source</span>
69
+ {metric.source}
70
+ </div>
71
+ )}
72
+ </div>
73
+ )}
74
+ </div>
75
+ ))}
76
+ </div>
77
+ )}
@@ -0,0 +1,40 @@
1
+ ---
2
+ interface Props {
3
+ heading?: string;
4
+ description?: string;
5
+ action?: string;
6
+ placeholder?: string;
7
+ buttonText?: string;
8
+ }
9
+ const {
10
+ heading = "One email, once a week.",
11
+ description = "Field-tested ideas for turning chat traffic into revenue. No filler.",
12
+ action = "/api/newsletter",
13
+ placeholder = "you@studio.com",
14
+ buttonText = "Subscribe",
15
+ } = Astro.props;
16
+ ---
17
+ <div class="bk-newsletter">
18
+ <span class="bk-newsletter__glow" aria-hidden="true"></span>
19
+ <div class="bk-newsletter__copy">
20
+ <h3 class="bk-newsletter__heading">{heading}</h3>
21
+ <p class="bk-newsletter__desc">{description}</p>
22
+ </div>
23
+ <div class="bk-newsletter__action">
24
+ <form class="bk-newsletter__form" action={action} method="post">
25
+ <label class="bk-newsletter__honeypot" aria-hidden="true">
26
+ Leave this field empty
27
+ <input type="text" name="website" tabindex="-1" autocomplete="off" />
28
+ </label>
29
+ <input
30
+ class="bk-newsletter__input"
31
+ type="email"
32
+ name="email"
33
+ required
34
+ placeholder={placeholder}
35
+ autocomplete="email"
36
+ />
37
+ <button class="bk-newsletter__button" type="submit">{buttonText}</button>
38
+ </form>
39
+ </div>
40
+ </div>
@@ -0,0 +1,6 @@
1
+ ---
2
+ interface Props { number?: number | string; title?: string; description?: string; }
3
+ const { number, title, description } = Astro.props;
4
+ const n = String(number ?? "").padStart(2, "0");
5
+ ---
6
+ <div class="bk-numbered-card"><span class="bk-numbered-card__badge">{n}</span>{title ? <h4 class="bk-numbered-card__title">{title}</h4> : null}<p class="bk-numbered-card__body">{description}<slot /></p></div>