@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.
- package/INTEGRATION.md +76 -0
- package/LICENSE +74 -0
- package/README.md +102 -0
- package/astro/AdPreview.astro +64 -0
- package/astro/AdPreviewPair.astro +10 -0
- package/astro/AuditFindings.astro +29 -0
- package/astro/AuditScores.astro +60 -0
- package/astro/AuthorCard.astro +32 -0
- package/astro/BeforeAfter.astro +26 -0
- package/astro/BlogBehaviors.astro +15 -0
- package/astro/CTABanner.astro +28 -0
- package/astro/CalloutBox.astro +28 -0
- package/astro/CaseStudyHero.astro +45 -0
- package/astro/ChannelMixBars.astro +33 -0
- package/astro/Checklist.astro +24 -0
- package/astro/ChecklistItem.astro +15 -0
- package/astro/CodeSnippet.astro +20 -0
- package/astro/ComparisonTable.astro +103 -0
- package/astro/Definition.astro +30 -0
- package/astro/DeliveryComparison.astro +40 -0
- package/astro/FAQList.astro +43 -0
- package/astro/FurtherReading.astro +34 -0
- package/astro/ImageFeature.astro +22 -0
- package/astro/Infographic.astro +12 -0
- package/astro/KeyMetric.astro +40 -0
- package/astro/KeywordTable.astro +69 -0
- package/astro/List.astro +46 -0
- package/astro/MetricHighlight.astro +77 -0
- package/astro/NewsletterCTA.astro +40 -0
- package/astro/NumberedCard.astro +6 -0
- package/astro/ProConBlock.astro +38 -0
- package/astro/ProseList.astro +46 -0
- package/astro/QuoteBlock.astro +72 -0
- package/astro/RegionCallout.astro +24 -0
- package/astro/RelatedPosts.astro +47 -0
- package/astro/ResultsStrip.astro +59 -0
- package/astro/ScoreBar.astro +19 -0
- package/astro/SerpPreview.astro +35 -0
- package/astro/ServicePromoCard.astro +21 -0
- package/astro/StatCard.astro +48 -0
- package/astro/StepBlock.astro +5 -0
- package/astro/TableOfContents.astro +12 -0
- package/astro/TimelineBlock.astro +30 -0
- package/astro/TipBox.astro +14 -0
- package/astro/TrafficChart.astro +61 -0
- package/astro/VerdictCard.astro +48 -0
- package/astro/blogkit/Article.astro +63 -0
- package/astro/blogkit/BlogIndex.astro +144 -0
- package/core/behaviors/code.js +78 -0
- package/core/behaviors/comparison.js +52 -0
- package/core/behaviors/delivery-comparison.js +52 -0
- package/core/behaviors/faq.js +61 -0
- package/core/behaviors/index.d.ts +3 -0
- package/core/behaviors/index.js +35 -0
- package/core/behaviors/keyword-table.js +52 -0
- package/core/behaviors/toc.js +130 -0
- package/core/css/base.css +146 -0
- package/core/css/components.css +2632 -0
- package/core/css/index-listing.css +207 -0
- package/core/css/index.css +13 -0
- package/core/css/tokens.css +127 -0
- package/core/icons.ts +20 -0
- package/core/lib.ts +70 -0
- package/core/manifest/components.json +573 -0
- package/core/manifest/frontmatter.json +19 -0
- package/core/manifest/templates.json +77 -0
- package/dist/core/behaviors/code.js +78 -0
- package/dist/core/behaviors/comparison.js +52 -0
- package/dist/core/behaviors/delivery-comparison.js +52 -0
- package/dist/core/behaviors/faq.js +61 -0
- package/dist/core/behaviors/index.d.ts +3 -0
- package/dist/core/behaviors/index.js +35 -0
- package/dist/core/behaviors/keyword-table.js +52 -0
- package/dist/core/behaviors/toc.js +130 -0
- package/dist/core/css/base.css +146 -0
- package/dist/core/css/components.css +2632 -0
- package/dist/core/css/index-listing.css +207 -0
- package/dist/core/css/index.css +13 -0
- package/dist/core/css/tokens.css +127 -0
- package/dist/core/icons.d.ts +2 -0
- package/dist/core/icons.d.ts.map +1 -0
- package/dist/core/icons.js +20 -0
- package/dist/core/icons.js.map +1 -0
- package/dist/core/lib.d.ts +21 -0
- package/dist/core/lib.d.ts.map +1 -0
- package/dist/core/lib.js +57 -0
- package/dist/core/lib.js.map +1 -0
- package/dist/core/manifest/components.json +573 -0
- package/dist/core/manifest/frontmatter.json +19 -0
- package/dist/core/manifest/templates.json +77 -0
- package/dist/package/adapters/hjd-api.d.ts +14 -0
- package/dist/package/adapters/hjd-api.d.ts.map +1 -0
- package/dist/package/adapters/hjd-api.js +57 -0
- package/dist/package/adapters/hjd-api.js.map +1 -0
- package/dist/package/adapters/index.d.ts +13 -0
- package/dist/package/adapters/index.d.ts.map +1 -0
- package/dist/package/adapters/index.js +16 -0
- package/dist/package/adapters/index.js.map +1 -0
- package/dist/package/adapters/local.d.ts +13 -0
- package/dist/package/adapters/local.d.ts.map +1 -0
- package/dist/package/adapters/local.js +72 -0
- package/dist/package/adapters/local.js.map +1 -0
- package/dist/package/adapters/source.d.ts +39 -0
- package/dist/package/adapters/source.d.ts.map +1 -0
- package/dist/package/adapters/source.js +19 -0
- package/dist/package/adapters/source.js.map +1 -0
- package/dist/package/article.d.ts +17 -0
- package/dist/package/article.d.ts.map +1 -0
- package/dist/package/article.js +37 -0
- package/dist/package/article.js.map +1 -0
- package/dist/package/astro/data.d.ts +45 -0
- package/dist/package/astro/data.d.ts.map +1 -0
- package/dist/package/astro/data.js +81 -0
- package/dist/package/astro/data.js.map +1 -0
- package/dist/package/astro/freshness.d.ts +11 -0
- package/dist/package/astro/freshness.d.ts.map +1 -0
- package/dist/package/astro/freshness.js +48 -0
- package/dist/package/astro/freshness.js.map +1 -0
- package/dist/package/astro/index.d.ts +12 -0
- package/dist/package/astro/index.d.ts.map +1 -0
- package/dist/package/astro/index.js +31 -0
- package/dist/package/astro/index.js.map +1 -0
- package/dist/package/blog-index.d.ts +10 -0
- package/dist/package/blog-index.d.ts.map +1 -0
- package/dist/package/blog-index.js +27 -0
- package/dist/package/blog-index.js.map +1 -0
- package/dist/package/cli/exchange.d.ts +27 -0
- package/dist/package/cli/exchange.d.ts.map +1 -0
- package/dist/package/cli/exchange.js +94 -0
- package/dist/package/cli/exchange.js.map +1 -0
- package/dist/package/cli/index.d.ts +3 -0
- package/dist/package/cli/index.d.ts.map +1 -0
- package/dist/package/cli/index.js +301 -0
- package/dist/package/cli/index.js.map +1 -0
- package/dist/package/config/define.d.ts +13 -0
- package/dist/package/config/define.d.ts.map +1 -0
- package/dist/package/config/define.js +14 -0
- package/dist/package/config/define.js.map +1 -0
- package/dist/package/config/resolve.d.ts +11 -0
- package/dist/package/config/resolve.d.ts.map +1 -0
- package/dist/package/config/resolve.js +43 -0
- package/dist/package/config/resolve.js.map +1 -0
- package/dist/package/config/types.d.ts +74 -0
- package/dist/package/config/types.d.ts.map +1 -0
- package/dist/package/config/types.js +13 -0
- package/dist/package/config/types.js.map +1 -0
- package/dist/package/index-core.d.ts +28 -0
- package/dist/package/index-core.d.ts.map +1 -0
- package/dist/package/index-core.js +102 -0
- package/dist/package/index-core.js.map +1 -0
- package/dist/package/index.d.ts +13 -0
- package/dist/package/index.d.ts.map +1 -0
- package/dist/package/index.js +25 -0
- package/dist/package/index.js.map +1 -0
- package/dist/package/mdx/render-astro.d.ts +18 -0
- package/dist/package/mdx/render-astro.d.ts.map +1 -0
- package/dist/package/mdx/render-astro.js +75 -0
- package/dist/package/mdx/render-astro.js.map +1 -0
- package/dist/package/mdx/render.d.ts +13 -0
- package/dist/package/mdx/render.d.ts.map +1 -0
- package/dist/package/mdx/render.js +37 -0
- package/dist/package/mdx/render.js.map +1 -0
- package/dist/react/AdPreview.d.ts +26 -0
- package/dist/react/AdPreview.d.ts.map +1 -0
- package/dist/react/AdPreview.js +8 -0
- package/dist/react/AdPreview.js.map +1 -0
- package/dist/react/AdPreviewPair.d.ts +7 -0
- package/dist/react/AdPreviewPair.d.ts.map +1 -0
- package/dist/react/AdPreviewPair.js +5 -0
- package/dist/react/AdPreviewPair.js.map +1 -0
- package/dist/react/AuditFindings.d.ts +14 -0
- package/dist/react/AuditFindings.d.ts.map +1 -0
- package/dist/react/AuditFindings.js +5 -0
- package/dist/react/AuditFindings.js.map +1 -0
- package/dist/react/AuditScores.d.ts +12 -0
- package/dist/react/AuditScores.d.ts.map +1 -0
- package/dist/react/AuditScores.js +25 -0
- package/dist/react/AuditScores.js.map +1 -0
- package/dist/react/AuthorCard.d.ts +10 -0
- package/dist/react/AuthorCard.d.ts.map +1 -0
- package/dist/react/AuthorCard.js +6 -0
- package/dist/react/AuthorCard.js.map +1 -0
- package/dist/react/BeforeAfter.d.ts +12 -0
- package/dist/react/BeforeAfter.d.ts.map +1 -0
- package/dist/react/BeforeAfter.js +7 -0
- package/dist/react/BeforeAfter.js.map +1 -0
- package/dist/react/BlogBehaviors.d.ts +10 -0
- package/dist/react/BlogBehaviors.d.ts.map +1 -0
- package/dist/react/BlogBehaviors.js +20 -0
- package/dist/react/BlogBehaviors.js.map +1 -0
- package/dist/react/CTABanner.d.ts +8 -0
- package/dist/react/CTABanner.d.ts.map +1 -0
- package/dist/react/CTABanner.js +9 -0
- package/dist/react/CTABanner.js.map +1 -0
- package/dist/react/CalloutBox.d.ts +13 -0
- package/dist/react/CalloutBox.d.ts.map +1 -0
- package/dist/react/CalloutBox.js +9 -0
- package/dist/react/CalloutBox.js.map +1 -0
- package/dist/react/CaseStudyHero.d.ts +20 -0
- package/dist/react/CaseStudyHero.d.ts.map +1 -0
- package/dist/react/CaseStudyHero.js +7 -0
- package/dist/react/CaseStudyHero.js.map +1 -0
- package/dist/react/ChannelMixBars.d.ts +18 -0
- package/dist/react/ChannelMixBars.d.ts.map +1 -0
- package/dist/react/ChannelMixBars.js +6 -0
- package/dist/react/ChannelMixBars.js.map +1 -0
- package/dist/react/Checklist.d.ts +10 -0
- package/dist/react/Checklist.d.ts.map +1 -0
- package/dist/react/Checklist.js +7 -0
- package/dist/react/Checklist.js.map +1 -0
- package/dist/react/ChecklistItem.d.ts +7 -0
- package/dist/react/ChecklistItem.d.ts.map +1 -0
- package/dist/react/ChecklistItem.js +5 -0
- package/dist/react/ChecklistItem.js.map +1 -0
- package/dist/react/CodeSnippet.d.ts +17 -0
- package/dist/react/CodeSnippet.d.ts.map +1 -0
- package/dist/react/CodeSnippet.js +14 -0
- package/dist/react/CodeSnippet.js.map +1 -0
- package/dist/react/ComparisonTable.d.ts +22 -0
- package/dist/react/ComparisonTable.d.ts.map +1 -0
- package/dist/react/ComparisonTable.js +35 -0
- package/dist/react/ComparisonTable.js.map +1 -0
- package/dist/react/Definition.d.ts +9 -0
- package/dist/react/Definition.d.ts.map +1 -0
- package/dist/react/Definition.js +19 -0
- package/dist/react/Definition.js.map +1 -0
- package/dist/react/DeliveryComparison.d.ts +16 -0
- package/dist/react/DeliveryComparison.d.ts.map +1 -0
- package/dist/react/DeliveryComparison.js +7 -0
- package/dist/react/DeliveryComparison.js.map +1 -0
- package/dist/react/FAQList.d.ts +20 -0
- package/dist/react/FAQList.d.ts.map +1 -0
- package/dist/react/FAQList.js +19 -0
- package/dist/react/FAQList.js.map +1 -0
- package/dist/react/FurtherReading.d.ts +21 -0
- package/dist/react/FurtherReading.d.ts.map +1 -0
- package/dist/react/FurtherReading.js +13 -0
- package/dist/react/FurtherReading.js.map +1 -0
- package/dist/react/ImageFeature.d.ts +9 -0
- package/dist/react/ImageFeature.d.ts.map +1 -0
- package/dist/react/ImageFeature.js +6 -0
- package/dist/react/ImageFeature.js.map +1 -0
- package/dist/react/Infographic.d.ts +6 -0
- package/dist/react/Infographic.d.ts.map +1 -0
- package/dist/react/Infographic.js +7 -0
- package/dist/react/Infographic.js.map +1 -0
- package/dist/react/KeyMetric.d.ts +16 -0
- package/dist/react/KeyMetric.d.ts.map +1 -0
- package/dist/react/KeyMetric.js +15 -0
- package/dist/react/KeyMetric.js.map +1 -0
- package/dist/react/KeywordTable.d.ts +18 -0
- package/dist/react/KeywordTable.d.ts.map +1 -0
- package/dist/react/KeywordTable.js +23 -0
- package/dist/react/KeywordTable.js.map +1 -0
- package/dist/react/List.d.ts +11 -0
- package/dist/react/List.d.ts.map +1 -0
- package/dist/react/List.js +21 -0
- package/dist/react/List.js.map +1 -0
- package/dist/react/MetricHighlight.d.ts +15 -0
- package/dist/react/MetricHighlight.d.ts.map +1 -0
- package/dist/react/MetricHighlight.js +26 -0
- package/dist/react/MetricHighlight.js.map +1 -0
- package/dist/react/NewsletterCTA.d.ts +9 -0
- package/dist/react/NewsletterCTA.d.ts.map +1 -0
- package/dist/react/NewsletterCTA.js +5 -0
- package/dist/react/NewsletterCTA.js.map +1 -0
- package/dist/react/NumberedCard.d.ts +9 -0
- package/dist/react/NumberedCard.d.ts.map +1 -0
- package/dist/react/NumberedCard.js +7 -0
- package/dist/react/NumberedCard.js.map +1 -0
- package/dist/react/ProConBlock.d.ts +6 -0
- package/dist/react/ProConBlock.d.ts.map +1 -0
- package/dist/react/ProConBlock.js +7 -0
- package/dist/react/ProConBlock.js.map +1 -0
- package/dist/react/ProseList.d.ts +17 -0
- package/dist/react/ProseList.d.ts.map +1 -0
- package/dist/react/ProseList.js +26 -0
- package/dist/react/ProseList.js.map +1 -0
- package/dist/react/QuoteBlock.d.ts +17 -0
- package/dist/react/QuoteBlock.d.ts.map +1 -0
- package/dist/react/QuoteBlock.js +26 -0
- package/dist/react/QuoteBlock.js.map +1 -0
- package/dist/react/RegionCallout.d.ts +13 -0
- package/dist/react/RegionCallout.d.ts.map +1 -0
- package/dist/react/RegionCallout.js +5 -0
- package/dist/react/RegionCallout.js.map +1 -0
- package/dist/react/RelatedPosts.d.ts +20 -0
- package/dist/react/RelatedPosts.d.ts.map +1 -0
- package/dist/react/RelatedPosts.js +7 -0
- package/dist/react/RelatedPosts.js.map +1 -0
- package/dist/react/ResultsStrip.d.ts +18 -0
- package/dist/react/ResultsStrip.d.ts.map +1 -0
- package/dist/react/ResultsStrip.js +22 -0
- package/dist/react/ResultsStrip.js.map +1 -0
- package/dist/react/ScoreBar.d.ts +8 -0
- package/dist/react/ScoreBar.d.ts.map +1 -0
- package/dist/react/ScoreBar.js +6 -0
- package/dist/react/ScoreBar.js.map +1 -0
- package/dist/react/SerpPreview.d.ts +18 -0
- package/dist/react/SerpPreview.d.ts.map +1 -0
- package/dist/react/SerpPreview.js +13 -0
- package/dist/react/SerpPreview.js.map +1 -0
- package/dist/react/ServicePromoCard.d.ts +14 -0
- package/dist/react/ServicePromoCard.d.ts.map +1 -0
- package/dist/react/ServicePromoCard.js +12 -0
- package/dist/react/ServicePromoCard.js.map +1 -0
- package/dist/react/StatCard.d.ts +13 -0
- package/dist/react/StatCard.d.ts.map +1 -0
- package/dist/react/StatCard.js +20 -0
- package/dist/react/StatCard.js.map +1 -0
- package/dist/react/StepBlock.d.ts +8 -0
- package/dist/react/StepBlock.d.ts.map +1 -0
- package/dist/react/StepBlock.js +5 -0
- package/dist/react/StepBlock.js.map +1 -0
- package/dist/react/TableOfContents.d.ts +14 -0
- package/dist/react/TableOfContents.d.ts.map +1 -0
- package/dist/react/TableOfContents.js +12 -0
- package/dist/react/TableOfContents.js.map +1 -0
- package/dist/react/TimelineBlock.d.ts +14 -0
- package/dist/react/TimelineBlock.d.ts.map +1 -0
- package/dist/react/TimelineBlock.js +8 -0
- package/dist/react/TimelineBlock.js.map +1 -0
- package/dist/react/TipBox.d.ts +6 -0
- package/dist/react/TipBox.d.ts.map +1 -0
- package/dist/react/TipBox.js +5 -0
- package/dist/react/TipBox.js.map +1 -0
- package/dist/react/TrafficChart.d.ts +16 -0
- package/dist/react/TrafficChart.d.ts.map +1 -0
- package/dist/react/TrafficChart.js +14 -0
- package/dist/react/TrafficChart.js.map +1 -0
- package/dist/react/VerdictCard.d.ts +15 -0
- package/dist/react/VerdictCard.d.ts.map +1 -0
- package/dist/react/VerdictCard.js +5 -0
- package/dist/react/VerdictCard.js.map +1 -0
- package/dist/react/components-map.d.ts +133 -0
- package/dist/react/components-map.d.ts.map +1 -0
- package/dist/react/components-map.js +120 -0
- package/dist/react/components-map.js.map +1 -0
- package/dist/react/index.d.ts +5 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +13 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +116 -0
- package/react/AdPreview.tsx +94 -0
- package/react/AdPreviewPair.tsx +16 -0
- package/react/AuditFindings.tsx +43 -0
- package/react/AuditScores.tsx +73 -0
- package/react/AuthorCard.tsx +35 -0
- package/react/BeforeAfter.tsx +27 -0
- package/react/BlogBehaviors.tsx +21 -0
- package/react/CTABanner.tsx +32 -0
- package/react/CalloutBox.tsx +31 -0
- package/react/CaseStudyHero.tsx +71 -0
- package/react/ChannelMixBars.tsx +50 -0
- package/react/Checklist.tsx +31 -0
- package/react/ChecklistItem.tsx +19 -0
- package/react/CodeSnippet.tsx +36 -0
- package/react/ComparisonTable.tsx +114 -0
- package/react/Definition.tsx +36 -0
- package/react/DeliveryComparison.tsx +62 -0
- package/react/FAQList.tsx +61 -0
- package/react/FurtherReading.tsx +46 -0
- package/react/ImageFeature.tsx +26 -0
- package/react/Infographic.tsx +18 -0
- package/react/KeyMetric.tsx +61 -0
- package/react/KeywordTable.tsx +92 -0
- package/react/List.tsx +58 -0
- package/react/MetricHighlight.tsx +86 -0
- package/react/NewsletterCTA.tsx +48 -0
- package/react/NumberedCard.tsx +7 -0
- package/react/ProConBlock.tsx +42 -0
- package/react/ProseList.tsx +72 -0
- package/react/QuoteBlock.tsx +89 -0
- package/react/RegionCallout.tsx +38 -0
- package/react/RelatedPosts.tsx +58 -0
- package/react/ResultsStrip.tsx +77 -0
- package/react/ScoreBar.tsx +27 -0
- package/react/SerpPreview.tsx +59 -0
- package/react/ServicePromoCard.tsx +43 -0
- package/react/StatCard.tsx +62 -0
- package/react/StepBlock.tsx +5 -0
- package/react/TableOfContents.tsx +27 -0
- package/react/TimelineBlock.tsx +35 -0
- package/react/TipBox.tsx +16 -0
- package/react/TrafficChart.tsx +79 -0
- package/react/VerdictCard.tsx +60 -0
- package/react/components-map.ts +122 -0
- package/react/index.ts +13 -0
- package/templates/blogkit/app/api/blogkit/revalidate/route.ts.tmpl +32 -0
- package/templates/blogkit/app/blog/[slug]/page.tsx.tmpl +41 -0
- package/templates/blogkit/app/blog/page.tsx.tmpl +18 -0
- package/templates/blogkit/blogkit.config.ts.tmpl +23 -0
- package/templates/blogkit-astro/BLOGKIT_ASTRO_SETUP.md.tmpl +49 -0
- package/templates/blogkit-astro/src/blogkit.config.ts.tmpl +29 -0
- package/templates/blogkit-astro/src/pages/api/blogkit/revalidate.ts.tmpl +46 -0
- package/templates/blogkit-astro/src/pages/blog/[slug].astro.tmpl +39 -0
- package/templates/blogkit-astro/src/pages/blog/index.astro.tmpl +29 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
blog-kit — listing surface (<BlogIndex>) styles.
|
|
3
|
+
Namespaced bk-idx-*, scoped under .blog-root, driven entirely
|
|
4
|
+
by --blog-* tokens so the tenant theme recolours it for free.
|
|
5
|
+
Self-contained so a site gets a working /blog with no bespoke
|
|
6
|
+
listing chrome.
|
|
7
|
+
============================================================ */
|
|
8
|
+
.blog-root.bk-idx {
|
|
9
|
+
max-width: var(--blog-max-page, 960px);
|
|
10
|
+
margin: 0 auto;
|
|
11
|
+
padding: 48px 20px 80px;
|
|
12
|
+
font-family: var(--blog-font-body);
|
|
13
|
+
color: var(--blog-text);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.bk-idx-head {
|
|
17
|
+
margin-bottom: 28px;
|
|
18
|
+
}
|
|
19
|
+
.bk-idx-eyebrow {
|
|
20
|
+
margin: 0 0 6px;
|
|
21
|
+
font-size: var(--blog-fs-eyebrow, 0.75rem);
|
|
22
|
+
letter-spacing: var(--blog-tracking-eyebrow, 0.12em);
|
|
23
|
+
text-transform: uppercase;
|
|
24
|
+
font-weight: 700;
|
|
25
|
+
color: var(--blog-brand-dark, var(--blog-brand));
|
|
26
|
+
}
|
|
27
|
+
.bk-idx-h1 {
|
|
28
|
+
margin: 0;
|
|
29
|
+
font-family: var(--blog-font-display);
|
|
30
|
+
font-size: var(--blog-fs-display-1, 2.5rem);
|
|
31
|
+
font-weight: var(--blog-heading-weight, 800);
|
|
32
|
+
text-transform: var(--blog-heading-transform, none);
|
|
33
|
+
letter-spacing: var(--blog-tracking-tight, -0.01em);
|
|
34
|
+
color: var(--blog-ink);
|
|
35
|
+
line-height: 1.05;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* category nav */
|
|
39
|
+
.bk-idx-nav {
|
|
40
|
+
display: flex;
|
|
41
|
+
flex-wrap: wrap;
|
|
42
|
+
gap: 8px;
|
|
43
|
+
margin: 0 0 32px;
|
|
44
|
+
}
|
|
45
|
+
.bk-idx-pill {
|
|
46
|
+
display: inline-flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
gap: 6px;
|
|
49
|
+
padding: 6px 14px;
|
|
50
|
+
border-radius: var(--blog-radius-pill, 999px);
|
|
51
|
+
border: 1px solid var(--blog-border);
|
|
52
|
+
background: var(--blog-paper);
|
|
53
|
+
color: var(--blog-mute);
|
|
54
|
+
font-size: 0.85rem;
|
|
55
|
+
font-weight: 600;
|
|
56
|
+
text-decoration: none;
|
|
57
|
+
transition: all 0.15s ease;
|
|
58
|
+
}
|
|
59
|
+
.bk-idx-pill:hover {
|
|
60
|
+
border-color: var(--blog-brand);
|
|
61
|
+
color: var(--blog-ink);
|
|
62
|
+
}
|
|
63
|
+
.bk-idx-pill.is-active {
|
|
64
|
+
background: var(--blog-brand);
|
|
65
|
+
border-color: var(--blog-brand);
|
|
66
|
+
color: var(--blog-on-brand, #fff);
|
|
67
|
+
}
|
|
68
|
+
.bk-idx-pill-count {
|
|
69
|
+
opacity: 0.6;
|
|
70
|
+
font-variant-numeric: tabular-nums;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* grid */
|
|
74
|
+
.bk-idx-grid {
|
|
75
|
+
display: grid;
|
|
76
|
+
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
77
|
+
gap: 24px;
|
|
78
|
+
}
|
|
79
|
+
.bk-idx-featured {
|
|
80
|
+
margin-bottom: 32px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* cards */
|
|
84
|
+
.bk-idx-card {
|
|
85
|
+
display: flex;
|
|
86
|
+
flex-direction: column;
|
|
87
|
+
border-radius: var(--blog-radius-lg, 16px);
|
|
88
|
+
overflow: hidden;
|
|
89
|
+
background: var(--blog-paper);
|
|
90
|
+
border: 1px solid var(--blog-border);
|
|
91
|
+
box-shadow: var(--blog-shadow-card, 0 1px 3px rgba(0, 0, 0, 0.06));
|
|
92
|
+
text-decoration: none;
|
|
93
|
+
color: inherit;
|
|
94
|
+
transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
|
|
95
|
+
}
|
|
96
|
+
.bk-idx-card:hover {
|
|
97
|
+
transform: translateY(-3px);
|
|
98
|
+
box-shadow: var(--blog-shadow-lg, 0 12px 30px rgba(0, 0, 0, 0.12));
|
|
99
|
+
border-color: var(--blog-brand-soft, var(--blog-brand));
|
|
100
|
+
}
|
|
101
|
+
.bk-idx-card--featured {
|
|
102
|
+
flex-direction: row;
|
|
103
|
+
align-items: stretch;
|
|
104
|
+
}
|
|
105
|
+
.bk-idx-card--featured .bk-idx-thumb {
|
|
106
|
+
flex: 0 0 48%;
|
|
107
|
+
min-height: 280px;
|
|
108
|
+
}
|
|
109
|
+
.bk-idx-card--featured .bk-idx-title {
|
|
110
|
+
font-size: var(--blog-fs-h2, 1.6rem);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.bk-idx-thumb {
|
|
114
|
+
position: relative;
|
|
115
|
+
aspect-ratio: 16 / 9;
|
|
116
|
+
overflow: hidden;
|
|
117
|
+
background: var(--blog-bg-secondary, #f1f3f5);
|
|
118
|
+
}
|
|
119
|
+
.bk-idx-thumb--ph {
|
|
120
|
+
background: linear-gradient(135deg, var(--blog-brand-tint, #eef) 0%, var(--blog-brand-soft, #dde) 100%);
|
|
121
|
+
}
|
|
122
|
+
.bk-idx-img {
|
|
123
|
+
width: 100%;
|
|
124
|
+
height: 100%;
|
|
125
|
+
object-fit: cover;
|
|
126
|
+
display: block;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.bk-idx-body {
|
|
130
|
+
padding: 18px 20px 22px;
|
|
131
|
+
display: flex;
|
|
132
|
+
flex-direction: column;
|
|
133
|
+
gap: 8px;
|
|
134
|
+
}
|
|
135
|
+
.bk-idx-cat {
|
|
136
|
+
font-size: 0.72rem;
|
|
137
|
+
font-weight: 700;
|
|
138
|
+
letter-spacing: 0.06em;
|
|
139
|
+
text-transform: uppercase;
|
|
140
|
+
color: var(--blog-brand-dark, var(--blog-brand));
|
|
141
|
+
}
|
|
142
|
+
.bk-idx-title {
|
|
143
|
+
margin: 0;
|
|
144
|
+
font-family: var(--blog-font-display);
|
|
145
|
+
font-size: var(--blog-fs-h3, 1.25rem);
|
|
146
|
+
font-weight: 700;
|
|
147
|
+
line-height: 1.2;
|
|
148
|
+
color: var(--blog-ink);
|
|
149
|
+
}
|
|
150
|
+
.bk-idx-desc {
|
|
151
|
+
margin: 0;
|
|
152
|
+
font-size: 0.95rem;
|
|
153
|
+
line-height: 1.5;
|
|
154
|
+
color: var(--blog-mute);
|
|
155
|
+
display: -webkit-box;
|
|
156
|
+
-webkit-line-clamp: 3;
|
|
157
|
+
-webkit-box-orient: vertical;
|
|
158
|
+
overflow: hidden;
|
|
159
|
+
}
|
|
160
|
+
.bk-idx-meta {
|
|
161
|
+
margin: 4px 0 0;
|
|
162
|
+
font-size: 0.8rem;
|
|
163
|
+
color: var(--blog-faint, var(--blog-mute-2));
|
|
164
|
+
font-variant-numeric: tabular-nums;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.bk-idx-empty {
|
|
168
|
+
padding: 60px 0;
|
|
169
|
+
text-align: center;
|
|
170
|
+
color: var(--blog-mute);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* pager */
|
|
174
|
+
.bk-idx-pager {
|
|
175
|
+
display: flex;
|
|
176
|
+
align-items: center;
|
|
177
|
+
justify-content: center;
|
|
178
|
+
gap: 20px;
|
|
179
|
+
margin-top: 48px;
|
|
180
|
+
}
|
|
181
|
+
.bk-idx-pagelink {
|
|
182
|
+
padding: 8px 18px;
|
|
183
|
+
border-radius: var(--blog-radius-pill, 999px);
|
|
184
|
+
border: 1px solid var(--blog-border);
|
|
185
|
+
background: var(--blog-paper);
|
|
186
|
+
color: var(--blog-ink);
|
|
187
|
+
font-weight: 600;
|
|
188
|
+
font-size: 0.9rem;
|
|
189
|
+
text-decoration: none;
|
|
190
|
+
}
|
|
191
|
+
.bk-idx-pagelink:hover {
|
|
192
|
+
border-color: var(--blog-brand);
|
|
193
|
+
}
|
|
194
|
+
.bk-idx-pageinfo {
|
|
195
|
+
font-size: 0.85rem;
|
|
196
|
+
color: var(--blog-mute);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
@media (max-width: 640px) {
|
|
200
|
+
.bk-idx-card--featured {
|
|
201
|
+
flex-direction: column;
|
|
202
|
+
}
|
|
203
|
+
.bk-idx-card--featured .bk-idx-thumb {
|
|
204
|
+
flex: none;
|
|
205
|
+
min-height: 0;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
blog-kit — CSS entrypoint
|
|
3
|
+
Import this once per site (the /blog route imports it).
|
|
4
|
+
Order matters: tokens → base → components.
|
|
5
|
+
A tenant theme is layered AFTER this (it overrides --blog-*
|
|
6
|
+
tokens on .blog-root) — see the generated theme stylesheet.
|
|
7
|
+
============================================================ */
|
|
8
|
+
@import "./tokens.css";
|
|
9
|
+
@import "./base.css";
|
|
10
|
+
@import "./components.css";
|
|
11
|
+
/* Listing surface (<BlogIndex>) — namespaced bk-idx-*, token-driven. Additive:
|
|
12
|
+
only renders if a site uses the package's <BlogIndex> route. */
|
|
13
|
+
@import "./index-listing.css";
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
blog-kit — Design Tokens (default theme)
|
|
3
|
+
------------------------------------------------------------
|
|
4
|
+
Every token is declared on the .blog-root wrapper, NOT :root.
|
|
5
|
+
This is deliberate: it keeps the blog's styling out of the
|
|
6
|
+
host page entirely, and lets a per-tenant theme re-skin the
|
|
7
|
+
blog by overriding ONLY these variables on .blog-root.
|
|
8
|
+
|
|
9
|
+
A tenant theme (generated from the content repo's theme.json)
|
|
10
|
+
overrides only the brand + font tokens. Everything structural
|
|
11
|
+
below stays shared across every site.
|
|
12
|
+
|
|
13
|
+
Naming: all tokens are --blog-* to avoid any collision with a
|
|
14
|
+
host site's own custom properties.
|
|
15
|
+
============================================================ */
|
|
16
|
+
|
|
17
|
+
.blog-root {
|
|
18
|
+
/* --- Brand (tenant overrides these) --------------------- */
|
|
19
|
+
--blog-brand: #2563EB; /* primary accent */
|
|
20
|
+
--blog-brand-dark: #1D4ED8; /* hover / pressed */
|
|
21
|
+
--blog-brand-bright: #3B82F6; /* lifted accent */
|
|
22
|
+
--blog-brand-soft: #DBEAFE; /* soft fill */
|
|
23
|
+
--blog-brand-tint: #EFF6FF; /* faint wash / callout bg */
|
|
24
|
+
--blog-on-brand: #FFFFFF; /* text on a brand fill */
|
|
25
|
+
|
|
26
|
+
/* --- Semantic state colours ----------------------------- */
|
|
27
|
+
--blog-success: #15803D;
|
|
28
|
+
--blog-success-bg: #F0FDF4;
|
|
29
|
+
--blog-warn: #B45309;
|
|
30
|
+
--blog-warn-bg: #FFFBEB;
|
|
31
|
+
--blog-danger: #DC2626;
|
|
32
|
+
--blog-danger-bg: #FEF2F2;
|
|
33
|
+
--blog-info: #0369A1;
|
|
34
|
+
--blog-info-bg: #EFF6FF;
|
|
35
|
+
|
|
36
|
+
/* --- Text / ink (5-layer ramp) -------------------------- */
|
|
37
|
+
--blog-ink: #0A0E13; /* headings / strongest */
|
|
38
|
+
--blog-text: #1F2937; /* body */
|
|
39
|
+
--blog-mute: #4B5563; /* secondary */
|
|
40
|
+
--blog-mute-2: #6B7280; /* captions / labels */
|
|
41
|
+
--blog-faint: #9CA3AF; /* faintest meta */
|
|
42
|
+
|
|
43
|
+
/* --- Surfaces ------------------------------------------- */
|
|
44
|
+
--blog-paper: #FFFFFF; /* main surface */
|
|
45
|
+
--blog-bg-secondary: #F9FAFB; /* grouped panels */
|
|
46
|
+
--blog-bg-tertiary: #F2F5F7; /* deepest light fill */
|
|
47
|
+
--blog-dark: #0B0F14; /* dark panel */
|
|
48
|
+
--blog-dark-2: #141A21;
|
|
49
|
+
--blog-dark-3: #1F2730;
|
|
50
|
+
--blog-on-dark: #F3F4F6; /* text on a dark panel */
|
|
51
|
+
--blog-on-dark-mute: rgba(255, 255, 255, 0.62);
|
|
52
|
+
|
|
53
|
+
/* --- Borders -------------------------------------------- */
|
|
54
|
+
--blog-border: #D7DBE0;
|
|
55
|
+
--blog-border-light: #E4E7EA;
|
|
56
|
+
--blog-border-subtle: #EEF1F4;
|
|
57
|
+
--blog-border-dark: rgba(255, 255, 255, 0.12);
|
|
58
|
+
|
|
59
|
+
/* --- Shadows (tokenised — never inline a box-shadow) ----- */
|
|
60
|
+
--blog-shadow-sm: 0 1px 2px rgba(10, 14, 19, 0.06);
|
|
61
|
+
--blog-shadow-md: 0 4px 12px rgba(10, 14, 19, 0.08);
|
|
62
|
+
--blog-shadow-lg: 0 12px 32px rgba(10, 14, 19, 0.12);
|
|
63
|
+
--blog-shadow-card: 0 1px 3px rgba(10, 14, 19, 0.08), 0 1px 2px rgba(10, 14, 19, 0.04);
|
|
64
|
+
/* resolves the using component's local --_accent (falls back to brand) */
|
|
65
|
+
--blog-shadow-verdict: 0 5px 30px color-mix(in srgb, var(--_accent, var(--blog-brand)) 15%, transparent);
|
|
66
|
+
--blog-shadow-ring: 0 0 0 1px var(--blog-brand); /* 1px brand outline (e.g. timeline dot) */
|
|
67
|
+
--blog-shadow-focus-ring: 0 0 0 2px color-mix(in srgb, var(--blog-brand) 40%, transparent);
|
|
68
|
+
|
|
69
|
+
/* --- Radii ---------------------------------------------- */
|
|
70
|
+
--blog-radius-xs: 4px;
|
|
71
|
+
--blog-radius-sm: 8px;
|
|
72
|
+
--blog-radius-md: 12px;
|
|
73
|
+
--blog-radius-lg: 16px;
|
|
74
|
+
--blog-radius-xl: 20px;
|
|
75
|
+
--blog-radius-2xl: 24px;
|
|
76
|
+
--blog-radius-pill: 999px;
|
|
77
|
+
|
|
78
|
+
/* --- Spacing scale -------------------------------------- */
|
|
79
|
+
--blog-sp-1: 0.25rem;
|
|
80
|
+
--blog-sp-2: 0.5rem;
|
|
81
|
+
--blog-sp-3: 0.75rem;
|
|
82
|
+
--blog-sp-4: 1rem;
|
|
83
|
+
--blog-sp-5: 1.25rem;
|
|
84
|
+
--blog-sp-6: 1.5rem;
|
|
85
|
+
--blog-sp-7: 1.75rem;
|
|
86
|
+
--blog-sp-8: 2rem;
|
|
87
|
+
--blog-sp-10: 2.5rem;
|
|
88
|
+
--blog-sp-12: 3rem;
|
|
89
|
+
--blog-sp-16: 4rem;
|
|
90
|
+
|
|
91
|
+
/* --- Typography (tenant overrides the families) --------- */
|
|
92
|
+
--blog-font-display: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
93
|
+
--blog-font-body: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
94
|
+
--blog-font-mono: ui-monospace, "SF Mono", Menlo, Monaco, "Cascadia Code", monospace;
|
|
95
|
+
--blog-tracking-tight: -0.01em;
|
|
96
|
+
--blog-tracking-wide: 0.04em;
|
|
97
|
+
--blog-tracking-eyebrow: 0.08em;
|
|
98
|
+
--blog-heading-transform: none; /* tenants can set uppercase */
|
|
99
|
+
--blog-heading-weight: 700;
|
|
100
|
+
|
|
101
|
+
/* --- Type scale ----------------------------------------------
|
|
102
|
+
One canonical ramp every component points at, so the same role
|
|
103
|
+
(eyebrow, body, caption, display number) is the same size kit-
|
|
104
|
+
wide. Reconciled from the kit's prevailing sizes; all rem on a
|
|
105
|
+
16px base. Components must not hardcode font-size — use these. */
|
|
106
|
+
--blog-fs-eyebrow-sm: 0.625rem; /* 10px — tiny kickers / badges / pill labels */
|
|
107
|
+
--blog-fs-eyebrow: 0.6875rem; /* 11px — standard uppercase eyebrow */
|
|
108
|
+
--blog-fs-xs: 0.75rem; /* 12px — counters, mono meta, small labels */
|
|
109
|
+
--blog-fs-sm: 0.8125rem; /* 13px — captions, secondary body */
|
|
110
|
+
--blog-fs-base: 0.875rem; /* 14px — default body */
|
|
111
|
+
--blog-fs-md: 0.9375rem; /* 15px — comfortable body */
|
|
112
|
+
--blog-fs-lg: 1rem; /* 16px — large body / strong labels */
|
|
113
|
+
--blog-fs-xl: 1.125rem; /* 18px — lead / sub-headings */
|
|
114
|
+
--blog-fs-2xl: 1.375rem; /* 22px */
|
|
115
|
+
--blog-fs-3xl: 1.625rem; /* 26px */
|
|
116
|
+
--blog-fs-4xl: 1.75rem; /* 28px */
|
|
117
|
+
--blog-fs-5xl: 2rem; /* 32px */
|
|
118
|
+
--blog-fs-6xl: 2.25rem; /* 36px */
|
|
119
|
+
--blog-fs-7xl: 2.75rem; /* 44px — large metric numbers */
|
|
120
|
+
--blog-fs-8xl: 3.5rem; /* 56px — largest stepped metric number */
|
|
121
|
+
--blog-fs-display: clamp(56px, 14vw, 130px); /* metric hero value */
|
|
122
|
+
--blog-fs-display-2: clamp(80px, 11vw, 150px); /* KeyMetric headline number */
|
|
123
|
+
|
|
124
|
+
/* --- Layout --------------------------------------------- */
|
|
125
|
+
--blog-max-content: 720px; /* article body measure */
|
|
126
|
+
--blog-max-page: 960px; /* full breakout width */
|
|
127
|
+
}
|
package/core/icons.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
blog-kit — shared inline SVG icons
|
|
3
|
+
Framework-neutral raw SVG strings. React renders them via
|
|
4
|
+
dangerouslySetInnerHTML; Astro via set:html. Defining them
|
|
5
|
+
once here keeps the two adapters byte-identical.
|
|
6
|
+
1.75px stroke, currentColor, 24px viewbox.
|
|
7
|
+
============================================================ */
|
|
8
|
+
|
|
9
|
+
export const ICONS: Record<string, string> = {
|
|
10
|
+
info: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>',
|
|
11
|
+
tip: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1.3.5 2.6 1.5 3.5.8.8 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></svg>',
|
|
12
|
+
success: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/></svg>',
|
|
13
|
+
warn: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>',
|
|
14
|
+
danger: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 8v4"/><path d="M12 16h.01"/></svg>',
|
|
15
|
+
external: '<svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 2h6v6"/><path d="M10 2 3 9"/></svg>',
|
|
16
|
+
"check-tick": '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 13 10 17 18 7"/></svg>',
|
|
17
|
+
copy: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>',
|
|
18
|
+
arrowRight: '<svg viewBox="0 0 18 16" fill="none"><path d="M9.34 15.71L15.15 9.04H0.77V7.62H15.17L9.34 0.95H11.19L17.79 8.32L11.19 15.71H9.34Z" fill="currentColor"/></svg>',
|
|
19
|
+
"search": '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.35-4.35"/></svg>',
|
|
20
|
+
};
|
package/core/lib.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
blog-kit — shared component logic
|
|
3
|
+
Framework-neutral helpers reused by both the React and Astro
|
|
4
|
+
adapters so prop-handling never diverges between frameworks.
|
|
5
|
+
============================================================ */
|
|
6
|
+
|
|
7
|
+
export type CalloutTone = "info" | "tip" | "success" | "warn" | "danger";
|
|
8
|
+
|
|
9
|
+
const CALLOUT_TONE_ALIASES: Record<string, CalloutTone> = {
|
|
10
|
+
info: "info",
|
|
11
|
+
note: "info",
|
|
12
|
+
default: "info",
|
|
13
|
+
tip: "tip",
|
|
14
|
+
idea: "tip",
|
|
15
|
+
success: "success",
|
|
16
|
+
ok: "success",
|
|
17
|
+
positive: "success",
|
|
18
|
+
warn: "warn",
|
|
19
|
+
warning: "warn",
|
|
20
|
+
caution: "warn",
|
|
21
|
+
danger: "danger",
|
|
22
|
+
error: "danger",
|
|
23
|
+
important: "danger",
|
|
24
|
+
alert: "danger",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Normalise the callout tone from any of the accepted prop names.
|
|
29
|
+
* hjd authored `type`, capture authored `variant`; canonical is `tone`.
|
|
30
|
+
* Falls back to "info" for anything unrecognised.
|
|
31
|
+
*/
|
|
32
|
+
export function resolveCalloutTone(input?: string): CalloutTone {
|
|
33
|
+
if (!input) return "info";
|
|
34
|
+
return CALLOUT_TONE_ALIASES[input.toLowerCase().trim()] ?? "info";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const CALLOUT_DEFAULT_TITLE: Record<CalloutTone, string> = {
|
|
38
|
+
info: "Note",
|
|
39
|
+
tip: "Tip",
|
|
40
|
+
success: "Success",
|
|
41
|
+
warn: "Warning",
|
|
42
|
+
danger: "Important",
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** Tiny classnames joiner (skips falsy). */
|
|
46
|
+
export function cx(...parts: Array<string | false | null | undefined>): string {
|
|
47
|
+
return parts.filter(Boolean).join(" ");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ── AuthorCard helpers ───────────────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
/** A labelled link shown in an AuthorCard (e.g. profile / site). */
|
|
53
|
+
export interface AuthorLink {
|
|
54
|
+
label: string;
|
|
55
|
+
href: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Derive up-to-two-letter initials from an author name for the avatar
|
|
60
|
+
* fallback. "Jane Doe" → "JD"; "capture ai" → "CA"; "" → "".
|
|
61
|
+
*/
|
|
62
|
+
export function authorInitials(name: string): string {
|
|
63
|
+
return (name || "")
|
|
64
|
+
.trim()
|
|
65
|
+
.split(/\s+/)
|
|
66
|
+
.filter(Boolean)
|
|
67
|
+
.slice(0, 2)
|
|
68
|
+
.map((w) => w[0]!.toUpperCase())
|
|
69
|
+
.join("");
|
|
70
|
+
}
|