@shipsite.dev/components 0.2.13 → 0.2.14

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 (68) hide show
  1. package/components.json +1 -75
  2. package/dist/blog/BlogArticle.d.ts +9 -1
  3. package/dist/blog/BlogArticle.d.ts.map +1 -1
  4. package/dist/blog/BlogArticle.js +3 -2
  5. package/dist/blog/BlogArticle.js.map +1 -1
  6. package/dist/blog/BlogArticleClient.d.ts +15 -0
  7. package/dist/blog/BlogArticleClient.d.ts.map +1 -0
  8. package/dist/blog/BlogArticleClient.js +106 -0
  9. package/dist/blog/BlogArticleClient.js.map +1 -0
  10. package/dist/index.d.ts +1 -7
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -7
  13. package/dist/index.js.map +1 -1
  14. package/dist/marketing/CalloutCard.d.ts.map +1 -1
  15. package/dist/marketing/CalloutCard.js +4 -4
  16. package/dist/marketing/CalloutCard.js.map +1 -1
  17. package/dist/marketing/CardGrid.d.ts.map +1 -1
  18. package/dist/marketing/CardGrid.js +2 -2
  19. package/dist/marketing/CardGrid.js.map +1 -1
  20. package/dist/ui/prose.d.ts +16 -0
  21. package/dist/ui/prose.d.ts.map +1 -0
  22. package/dist/ui/prose.js +44 -0
  23. package/dist/ui/prose.js.map +1 -0
  24. package/dist/ui/table.js +1 -1
  25. package/dist/ui/table.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/blog/BlogArticle.tsx +14 -4
  28. package/src/blog/BlogArticleClient.tsx +212 -0
  29. package/src/index.ts +3 -7
  30. package/src/marketing/CalloutCard.tsx +6 -4
  31. package/src/marketing/CardGrid.tsx +7 -3
  32. package/src/ui/prose.tsx +201 -0
  33. package/src/ui/table.tsx +1 -1
  34. package/dist/blog/BlogCTA.d.ts +0 -8
  35. package/dist/blog/BlogCTA.d.ts.map +0 -1
  36. package/dist/blog/BlogCTA.js +0 -6
  37. package/dist/blog/BlogCTA.js.map +0 -1
  38. package/dist/blog/BlogCTABanner.d.ts +0 -9
  39. package/dist/blog/BlogCTABanner.d.ts.map +0 -1
  40. package/dist/blog/BlogCTABanner.js +0 -7
  41. package/dist/blog/BlogCTABanner.js.map +0 -1
  42. package/dist/blog/BlogFAQ.d.ts +0 -10
  43. package/dist/blog/BlogFAQ.d.ts.map +0 -1
  44. package/dist/blog/BlogFAQ.js +0 -7
  45. package/dist/blog/BlogFAQ.js.map +0 -1
  46. package/dist/blog/BlogIntro.d.ts +0 -5
  47. package/dist/blog/BlogIntro.d.ts.map +0 -1
  48. package/dist/blog/BlogIntro.js +0 -5
  49. package/dist/blog/BlogIntro.js.map +0 -1
  50. package/dist/blog/BlogTable.d.ts +0 -7
  51. package/dist/blog/BlogTable.d.ts.map +0 -1
  52. package/dist/blog/BlogTable.js +0 -5
  53. package/dist/blog/BlogTable.js.map +0 -1
  54. package/dist/blog/BlogTip.d.ts +0 -8
  55. package/dist/blog/BlogTip.d.ts.map +0 -1
  56. package/dist/blog/BlogTip.js +0 -5
  57. package/dist/blog/BlogTip.js.map +0 -1
  58. package/dist/blog/StartFreeNowCTA.d.ts +0 -9
  59. package/dist/blog/StartFreeNowCTA.d.ts.map +0 -1
  60. package/dist/blog/StartFreeNowCTA.js +0 -7
  61. package/dist/blog/StartFreeNowCTA.js.map +0 -1
  62. package/src/blog/BlogCTA.tsx +0 -19
  63. package/src/blog/BlogCTABanner.tsx +0 -25
  64. package/src/blog/BlogFAQ.tsx +0 -32
  65. package/src/blog/BlogIntro.tsx +0 -9
  66. package/src/blog/BlogTable.tsx +0 -27
  67. package/src/blog/BlogTip.tsx +0 -15
  68. package/src/blog/StartFreeNowCTA.tsx +0 -29
@@ -0,0 +1,212 @@
1
+ 'use client';
2
+
3
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
4
+ import { cn } from '../lib/utils';
5
+
6
+ interface TocItem {
7
+ id: string;
8
+ title: string;
9
+ level: number;
10
+ }
11
+
12
+ interface BlogArticleAuthor {
13
+ name: string;
14
+ role: string;
15
+ image: string;
16
+ }
17
+
18
+ interface BlogArticleClientProps {
19
+ children: React.ReactNode;
20
+ author?: BlogArticleAuthor;
21
+ date?: string;
22
+ readingTime?: number;
23
+ }
24
+
25
+ export function BlogArticleClient({
26
+ children,
27
+ author,
28
+ date,
29
+ readingTime,
30
+ }: BlogArticleClientProps) {
31
+ const contentRef = useRef<HTMLDivElement>(null);
32
+ const [tocItems, setTocItems] = useState<TocItem[]>([]);
33
+ const [activeId, setActiveId] = useState('');
34
+ const [activeH2Id, setActiveH2Id] = useState('');
35
+
36
+ // Extract headings from rendered content
37
+ useEffect(() => {
38
+ const el = contentRef.current;
39
+ if (!el) return;
40
+ const rafId = requestAnimationFrame(() => {
41
+ const headings = el.querySelectorAll('h2, h3');
42
+ const items: TocItem[] = [];
43
+ headings.forEach((heading) => {
44
+ const title = heading.textContent?.trim() || '';
45
+ if (!title || heading.hasAttribute('data-toc-exclude')) return;
46
+ if (!heading.id) {
47
+ heading.id =
48
+ title
49
+ .toLowerCase()
50
+ .replace(/[^a-z0-9]+/g, '-')
51
+ .replace(/(^-|-$)/g, '') || '';
52
+ }
53
+ items.push({
54
+ id: heading.id,
55
+ title,
56
+ level: heading.tagName === 'H2' ? 2 : 3,
57
+ });
58
+ });
59
+ setTocItems(items);
60
+ });
61
+ return () => cancelAnimationFrame(rafId);
62
+ }, [children]);
63
+
64
+ // IntersectionObserver for active heading tracking
65
+ useEffect(() => {
66
+ const el = contentRef.current;
67
+ if (!el || tocItems.length === 0) return;
68
+ const observer = new IntersectionObserver(
69
+ (entries) => {
70
+ for (const entry of entries) {
71
+ if (entry.isIntersecting) {
72
+ const id = entry.target.id;
73
+ setActiveId(id);
74
+ const tocItem = tocItems.find((t) => t.id === id);
75
+ if (tocItem?.level === 2) {
76
+ setActiveH2Id(id);
77
+ } else if (tocItem?.level === 3) {
78
+ const idx = tocItems.indexOf(tocItem);
79
+ for (let i = idx - 1; i >= 0; i--) {
80
+ if (tocItems[i].level === 2) {
81
+ setActiveH2Id(tocItems[i].id);
82
+ break;
83
+ }
84
+ }
85
+ }
86
+ }
87
+ }
88
+ },
89
+ { rootMargin: '-80px 0px -60% 0px', threshold: 0.1 },
90
+ );
91
+ tocItems.forEach((item) => {
92
+ const h = document.getElementById(item.id);
93
+ if (h) observer.observe(h);
94
+ });
95
+ return () => observer.disconnect();
96
+ }, [tocItems]);
97
+
98
+ // Smooth scroll to heading
99
+ const scrollToHeading = useCallback((id: string) => {
100
+ const el = document.getElementById(id);
101
+ if (el) {
102
+ const top = el.getBoundingClientRect().top + window.scrollY - 100;
103
+ window.scrollTo({ top, behavior: 'smooth' });
104
+ }
105
+ }, []);
106
+
107
+ const formattedDate = date
108
+ ? new Date(date + 'T00:00:00').toLocaleDateString(undefined, {
109
+ year: 'numeric',
110
+ month: 'long',
111
+ day: 'numeric',
112
+ })
113
+ : '';
114
+
115
+ return (
116
+ <article className="py-12 md:py-20">
117
+ <div className="mx-auto w-full max-w-[76rem] px-[clamp(1rem,3vw,3rem)]">
118
+ <div className="flex gap-10 lg:gap-16">
119
+ {/* Main content */}
120
+ <div ref={contentRef} className="blog-content min-w-0 flex-1 max-w-3xl">
121
+ {children}
122
+ </div>
123
+
124
+ {/* Sidebar */}
125
+ <aside className="hidden lg:block w-64 shrink-0">
126
+ <div className="sticky top-24 flex flex-col gap-6">
127
+ {/* TOC */}
128
+ {tocItems.length > 0 && (
129
+ <nav>
130
+ <ul className="flex flex-col">
131
+ {tocItems.map((item) => {
132
+ const isActive = activeId === item.id;
133
+ if (item.level === 3) {
134
+ const idx = tocItems.indexOf(item);
135
+ let parentH2Id = '';
136
+ for (let i = idx - 1; i >= 0; i--) {
137
+ if (tocItems[i].level === 2) {
138
+ parentH2Id = tocItems[i].id;
139
+ break;
140
+ }
141
+ }
142
+ if (parentH2Id !== activeH2Id) return null;
143
+ }
144
+ return (
145
+ <li key={item.id} className={item.level === 3 ? 'pl-3' : ''}>
146
+ <button
147
+ onClick={() => scrollToHeading(item.id)}
148
+ className={cn(
149
+ 'my-0.5 flex items-center gap-2 w-full cursor-pointer text-left',
150
+ isActive
151
+ ? 'text-foreground font-medium'
152
+ : 'text-muted-foreground hover:text-foreground',
153
+ )}
154
+ >
155
+ <span
156
+ className={cn(
157
+ 'w-3 h-px shrink-0 transition-colors',
158
+ isActive ? 'bg-primary' : 'bg-border',
159
+ )}
160
+ />
161
+ <span className="text-sm leading-snug line-clamp-1">
162
+ {item.title}
163
+ </span>
164
+ </button>
165
+ </li>
166
+ );
167
+ })}
168
+ </ul>
169
+ </nav>
170
+ )}
171
+
172
+ {/* Author */}
173
+ {author && (
174
+ <>
175
+ {tocItems.length > 0 && <hr className="border-border" />}
176
+ <div className="flex flex-col gap-3">
177
+ {author.image && (
178
+ <img
179
+ src={author.image}
180
+ alt={author.name}
181
+ className="w-12 h-12 rounded-full object-cover"
182
+ />
183
+ )}
184
+ <div>
185
+ <p className="text-sm font-medium text-foreground">{author.name}</p>
186
+ {author.role && (
187
+ <p className="text-xs text-muted-foreground">{author.role}</p>
188
+ )}
189
+ </div>
190
+ </div>
191
+ </>
192
+ )}
193
+
194
+ {/* Meta */}
195
+ {(formattedDate || readingTime) && (
196
+ <>
197
+ {(tocItems.length > 0 || author) && !author && (
198
+ <hr className="border-border" />
199
+ )}
200
+ <div className="flex flex-col gap-1 text-xs text-muted-foreground">
201
+ {formattedDate && <span>{formattedDate}</span>}
202
+ {readingTime ? <span>{readingTime} min read</span> : null}
203
+ </div>
204
+ </>
205
+ )}
206
+ </div>
207
+ </aside>
208
+ </div>
209
+ </div>
210
+ </article>
211
+ );
212
+ }
package/src/index.ts CHANGED
@@ -51,13 +51,6 @@ export { TabsSection, TabItem } from './marketing/TabsSection';
51
51
  // Blog
52
52
  export { BlogArticle } from './blog/BlogArticle';
53
53
  export { BlogIndex } from './blog/BlogIndex';
54
- export { BlogCTA } from './blog/BlogCTA';
55
- export { BlogCTABanner } from './blog/BlogCTABanner';
56
- export { BlogFAQ } from './blog/BlogFAQ';
57
- export { BlogIntro } from './blog/BlogIntro';
58
- export { BlogTable } from './blog/BlogTable';
59
- export { BlogTip } from './blog/BlogTip';
60
- export { StartFreeNowCTA } from './blog/StartFreeNowCTA';
61
54
 
62
55
  // UI primitives
63
56
  export {
@@ -71,5 +64,8 @@ export {
71
64
  TableCaption,
72
65
  } from './ui/table';
73
66
 
67
+ // Prose (Markdown element overrides)
68
+ export { ProseH2, ProseH3, ProseH4, ProseP, ProseA, ProseUl, ProseOl, ProseLi, ProseBlockquote, ProsePre, ProseCode, ProseHr, ProseImg } from './ui/prose';
69
+
74
70
  // Legal
75
71
  export { LegalPage, LegalSection } from './legal/LegalPage';
@@ -10,16 +10,18 @@ interface CalloutCardProps {
10
10
 
11
11
  export function CalloutCard({ title, description, variant = 'info', children }: CalloutCardProps) {
12
12
  const variantStyles = {
13
- info: 'bg-primary/5 border-primary/20',
14
- success: 'bg-emerald-50 border-emerald-200',
15
- warning: 'bg-amber-50 border-amber-200',
13
+ info: 'bg-primary/5 border-primary/20 dark:bg-primary/10',
14
+ success: 'bg-emerald-500/10 border-emerald-500/20',
15
+ warning: 'bg-amber-500/10 border-amber-500/20',
16
16
  };
17
17
 
18
18
  return (
19
- <div className={cn('rounded-xl border p-6 my-8', variantStyles[variant])}>
19
+ <div className={cn('mx-auto w-full max-w-[76rem] px-[clamp(1rem,3vw,3rem)] my-8')}>
20
+ <div className={cn('rounded-xl border p-6', variantStyles[variant])}>
20
21
  <h3 className="font-semibold text-foreground mb-2">{title}</h3>
21
22
  <p className="text-sm text-muted-foreground">{description}</p>
22
23
  {children}
23
24
  </div>
25
+ </div>
24
26
  );
25
27
  }
@@ -10,9 +10,9 @@ interface CardGridItemProps {
10
10
  export function CardGridItem({ title, description, icon, href }: CardGridItemProps) {
11
11
  const Wrapper = href ? 'a' : 'div';
12
12
  return (
13
- <Wrapper {...(href ? { href } : {})} className="block p-6 rounded-xl glass-1 hover:glass-2 transition-all">
13
+ <Wrapper {...(href ? { href } : {})} className="block p-6 rounded-xl glass-1 hover:glass-2 transition-all focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring">
14
14
  {icon && <div className="mb-3 text-primary">{icon}</div>}
15
- <h3 className="font-semibold text-foreground mb-2">{title}</h3>
15
+ <h3 className="font-semibold tracking-tight text-foreground mb-2">{title}</h3>
16
16
  <p className="text-sm text-muted-foreground">{description}</p>
17
17
  </Wrapper>
18
18
  );
@@ -25,5 +25,9 @@ interface CardGridProps {
25
25
 
26
26
  export function CardGrid({ columns = 3, children }: CardGridProps) {
27
27
  const gridCols = { 2: 'md:grid-cols-2', 3: 'md:grid-cols-3', 4: 'md:grid-cols-2 lg:grid-cols-4' };
28
- return <div className={`grid grid-cols-1 ${gridCols[columns]} gap-6 py-8`}>{children}</div>;
28
+ return (
29
+ <div className="mx-auto w-full max-w-[76rem] px-[clamp(1rem,3vw,3rem)] py-8">
30
+ <div className={`grid grid-cols-1 ${gridCols[columns]} gap-6`}>{children}</div>
31
+ </div>
32
+ );
29
33
  }
@@ -0,0 +1,201 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "../lib/utils";
4
+
5
+ const container = "prose-container mx-auto w-full max-w-[76rem] px-[clamp(1rem,3vw,3rem)]";
6
+
7
+ function ProseH2({ className, ...props }: React.ComponentProps<"h2">) {
8
+ return (
9
+ <h2
10
+ data-slot="prose-h2"
11
+ className={cn(
12
+ container,
13
+ "mt-10 mb-4 text-[clamp(1.375rem,1.1rem+1.2vw,2.25rem)] font-semibold tracking-tight",
14
+ className,
15
+ )}
16
+ {...props}
17
+ />
18
+ );
19
+ }
20
+
21
+ function ProseH3({ className, ...props }: React.ComponentProps<"h3">) {
22
+ return (
23
+ <h3
24
+ data-slot="prose-h3"
25
+ className={cn(
26
+ container,
27
+ "mt-6 mb-3 text-[clamp(1.125rem,1rem+0.6vw,1.5rem)] font-semibold tracking-tight",
28
+ className,
29
+ )}
30
+ {...props}
31
+ />
32
+ );
33
+ }
34
+
35
+ function ProseH4({ className, ...props }: React.ComponentProps<"h4">) {
36
+ return (
37
+ <h4
38
+ data-slot="prose-h4"
39
+ className={cn(
40
+ container,
41
+ "mt-4 mb-2 text-lg font-semibold",
42
+ className,
43
+ )}
44
+ {...props}
45
+ />
46
+ );
47
+ }
48
+
49
+ function ProseP({ className, ...props }: React.ComponentProps<"p">) {
50
+ return (
51
+ <p
52
+ data-slot="prose-p"
53
+ className={cn(
54
+ container,
55
+ "my-2 text-base leading-relaxed",
56
+ className,
57
+ )}
58
+ {...props}
59
+ />
60
+ );
61
+ }
62
+
63
+ function ProseA({ className, ...props }: React.ComponentProps<"a">) {
64
+ return (
65
+ <a
66
+ data-slot="prose-a"
67
+ className={cn(
68
+ "text-primary font-medium underline hover:no-underline",
69
+ className,
70
+ )}
71
+ {...props}
72
+ />
73
+ );
74
+ }
75
+
76
+ function ProseUl({ className, ...props }: React.ComponentProps<"ul">) {
77
+ return (
78
+ <ul
79
+ data-slot="prose-ul"
80
+ className={cn(
81
+ container,
82
+ "my-3 list-disc pl-7 [&_ul]:my-1 [&_ul]:max-w-none [&_ul]:px-0 [&_ol]:my-1 [&_ol]:max-w-none [&_ol]:px-0",
83
+ className,
84
+ )}
85
+ {...props}
86
+ />
87
+ );
88
+ }
89
+
90
+ function ProseOl({ className, ...props }: React.ComponentProps<"ol">) {
91
+ return (
92
+ <ol
93
+ data-slot="prose-ol"
94
+ className={cn(
95
+ container,
96
+ "my-3 list-decimal pl-7 [&_ul]:my-1 [&_ul]:max-w-none [&_ul]:px-0 [&_ol]:my-1 [&_ol]:max-w-none [&_ol]:px-0",
97
+ className,
98
+ )}
99
+ {...props}
100
+ />
101
+ );
102
+ }
103
+
104
+ function ProseLi({ className, ...props }: React.ComponentProps<"li">) {
105
+ return (
106
+ <li
107
+ data-slot="prose-li"
108
+ className={cn("mt-1 leading-relaxed", className)}
109
+ {...props}
110
+ />
111
+ );
112
+ }
113
+
114
+ function ProseBlockquote({ className, ...props }: React.ComponentProps<"blockquote">) {
115
+ return (
116
+ <div className={container}>
117
+ <blockquote
118
+ data-slot="prose-blockquote"
119
+ className={cn(
120
+ "my-6 rounded-xl border-l-4 border-primary bg-muted/50 px-6 py-4 [&>p]:max-w-none [&>p]:px-0 [&>p]:my-1",
121
+ className,
122
+ )}
123
+ {...props}
124
+ />
125
+ </div>
126
+ );
127
+ }
128
+
129
+ function ProsePre({ className, ...props }: React.ComponentProps<"pre">) {
130
+ return (
131
+ <div className={container}>
132
+ <pre
133
+ data-slot="prose-pre"
134
+ className={cn(
135
+ "my-6 overflow-x-auto rounded-xl border border-border bg-card p-4 shadow-sm",
136
+ className,
137
+ )}
138
+ {...props}
139
+ />
140
+ </div>
141
+ );
142
+ }
143
+
144
+ function ProseCode({ className, ...props }: React.ComponentProps<"code">) {
145
+ return (
146
+ <code
147
+ data-slot="prose-code"
148
+ className={cn(
149
+ "rounded-md bg-muted px-1.5 py-0.5 font-mono text-[0.875em] [[data-slot=prose-pre]_&]:bg-transparent [[data-slot=prose-pre]_&]:p-0",
150
+ className,
151
+ )}
152
+ {...props}
153
+ />
154
+ );
155
+ }
156
+
157
+ function ProseHr({ className, ...props }: React.ComponentProps<"hr">) {
158
+ return (
159
+ <hr
160
+ data-slot="prose-hr"
161
+ className={cn(
162
+ container,
163
+ "my-8 border-border",
164
+ className,
165
+ )}
166
+ {...props}
167
+ />
168
+ );
169
+ }
170
+
171
+ function ProseImg({ className, alt, ...props }: React.ComponentProps<"img">) {
172
+ return (
173
+ <div className={container}>
174
+ <img
175
+ data-slot="prose-img"
176
+ className={cn(
177
+ "my-6 rounded-xl border border-border shadow-sm",
178
+ className,
179
+ )}
180
+ alt={alt}
181
+ {...props}
182
+ />
183
+ </div>
184
+ );
185
+ }
186
+
187
+ export {
188
+ ProseH2,
189
+ ProseH3,
190
+ ProseH4,
191
+ ProseP,
192
+ ProseA,
193
+ ProseUl,
194
+ ProseOl,
195
+ ProseLi,
196
+ ProseBlockquote,
197
+ ProsePre,
198
+ ProseCode,
199
+ ProseHr,
200
+ ProseImg,
201
+ };
package/src/ui/table.tsx CHANGED
@@ -4,7 +4,7 @@ import { cn } from "../lib/utils";
4
4
 
5
5
  function Table({ className, ...props }: React.ComponentProps<"table">) {
6
6
  return (
7
- <div data-slot="table-container" className="my-8 mx-auto w-full max-w-[76rem] px-[clamp(1rem,3vw,3rem)] overflow-x-auto">
7
+ <div data-slot="table-container" className="prose-container my-8 mx-auto w-full max-w-[76rem] px-[clamp(1rem,3vw,3rem)] overflow-x-auto">
8
8
  <div className="rounded-xl border border-border bg-card shadow-sm">
9
9
  <table
10
10
  data-slot="table"
@@ -1,8 +0,0 @@
1
- interface BlogCTAProps {
2
- title: string;
3
- buttonText: string;
4
- buttonHref: string;
5
- }
6
- export declare function BlogCTA({ title, buttonText, buttonHref }: BlogCTAProps): import("react/jsx-runtime").JSX.Element;
7
- export {};
8
- //# sourceMappingURL=BlogCTA.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogCTA.d.ts","sourceRoot":"","sources":["../../src/blog/BlogCTA.tsx"],"names":[],"mappings":"AAGA,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,YAAY,2CAStE"}
@@ -1,6 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button } from '../ui/button';
3
- export function BlogCTA({ title, buttonText, buttonHref }) {
4
- return (_jsxs("div", { className: "my-10 p-8 rounded-2xl glass-1 text-center", children: [_jsx("h3", { className: "text-xl font-bold text-foreground mb-4", children: title }), _jsx(Button, { asChild: true, children: _jsx("a", { href: buttonHref, children: buttonText }) })] }));
5
- }
6
- //# sourceMappingURL=BlogCTA.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogCTA.js","sourceRoot":"","sources":["../../src/blog/BlogCTA.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAQtC,MAAM,UAAU,OAAO,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAgB;IACrE,OAAO,CACL,eAAK,SAAS,EAAC,2CAA2C,aACxD,aAAI,SAAS,EAAC,wCAAwC,YAAE,KAAK,GAAM,EACnE,KAAC,MAAM,IAAC,OAAO,kBACb,YAAG,IAAI,EAAE,UAAU,YAAG,UAAU,GAAK,GAC9B,IACL,CACP,CAAC;AACJ,CAAC"}
@@ -1,9 +0,0 @@
1
- interface BlogCTABannerProps {
2
- title: string;
3
- description: string;
4
- buttonText: string;
5
- buttonLink: string;
6
- }
7
- export declare function BlogCTABanner({ title, description, buttonText, buttonLink }: BlogCTABannerProps): import("react/jsx-runtime").JSX.Element;
8
- export {};
9
- //# sourceMappingURL=BlogCTABanner.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogCTABanner.d.ts","sourceRoot":"","sources":["../../src/blog/BlogCTABanner.tsx"],"names":[],"mappings":"AAIA,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,kBAAkB,2CAa/F"}
@@ -1,7 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button } from '../ui/button';
3
- import Glow from '../ui/glow';
4
- export function BlogCTABanner({ title, description, buttonText, buttonLink }) {
5
- return (_jsxs("div", { className: "my-12 rounded-2xl glass-4 p-10 text-center relative overflow-hidden", children: [_jsx(Glow, { variant: "center" }), _jsxs("div", { className: "relative z-10", children: [_jsx("h3", { className: "text-2xl font-bold text-foreground mb-3", children: title }), _jsx("p", { className: "text-muted-foreground mb-6 max-w-lg mx-auto", children: description }), _jsx(Button, { asChild: true, children: _jsx("a", { href: buttonLink, children: buttonText }) })] })] }));
6
- }
7
- //# sourceMappingURL=BlogCTABanner.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogCTABanner.js","sourceRoot":"","sources":["../../src/blog/BlogCTABanner.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,IAAI,MAAM,YAAY,CAAC;AAS9B,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAsB;IAC9F,OAAO,CACL,eAAK,SAAS,EAAC,qEAAqE,aAClF,KAAC,IAAI,IAAC,OAAO,EAAC,QAAQ,GAAG,EACzB,eAAK,SAAS,EAAC,eAAe,aAC5B,aAAI,SAAS,EAAC,yCAAyC,YAAE,KAAK,GAAM,EACpE,YAAG,SAAS,EAAC,6CAA6C,YAAE,WAAW,GAAK,EAC5E,KAAC,MAAM,IAAC,OAAO,kBACb,YAAG,IAAI,EAAE,UAAU,YAAG,UAAU,GAAK,GAC9B,IACL,IACF,CACP,CAAC;AACJ,CAAC"}
@@ -1,10 +0,0 @@
1
- interface BlogFAQProps {
2
- title: string;
3
- items: Array<{
4
- question: string;
5
- answer: string;
6
- }>;
7
- }
8
- export declare function BlogFAQ({ title, items }: BlogFAQProps): import("react/jsx-runtime").JSX.Element;
9
- export {};
10
- //# sourceMappingURL=BlogFAQ.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogFAQ.d.ts","sourceRoot":"","sources":["../../src/blog/BlogFAQ.tsx"],"names":[],"mappings":"AAUA,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,YAAY,2CAgBrD"}
@@ -1,7 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Accordion, AccordionItem, AccordionTrigger, AccordionContent, } from '../ui/accordion';
4
- export function BlogFAQ({ title, items }) {
5
- return (_jsxs("div", { className: "my-12", children: [_jsx("h2", { className: "text-2xl font-bold text-foreground mb-6", children: title }), _jsx(Accordion, { type: "single", collapsible: true, children: items.map((item, i) => (_jsxs(AccordionItem, { value: `faq-${i}`, children: [_jsx(AccordionTrigger, { children: item.question }), _jsx(AccordionContent, { children: _jsx("div", { className: "text-muted-foreground leading-relaxed", children: item.answer }) })] }, i))) })] }));
6
- }
7
- //# sourceMappingURL=BlogFAQ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogFAQ.js","sourceRoot":"","sources":["../../src/blog/BlogFAQ.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EACL,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAOzB,MAAM,UAAU,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAgB;IACpD,OAAO,CACL,eAAK,SAAS,EAAC,OAAO,aACpB,aAAI,SAAS,EAAC,yCAAyC,YAAE,KAAK,GAAM,EACpE,KAAC,SAAS,IAAC,IAAI,EAAC,QAAQ,EAAC,WAAW,kBACjC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CACtB,MAAC,aAAa,IAAS,KAAK,EAAE,OAAO,CAAC,EAAE,aACtC,KAAC,gBAAgB,cAAE,IAAI,CAAC,QAAQ,GAAoB,EACpD,KAAC,gBAAgB,cACf,cAAK,SAAS,EAAC,uCAAuC,YAAE,IAAI,CAAC,MAAM,GAAO,GACzD,KAJD,CAAC,CAKL,CACjB,CAAC,GACQ,IACR,CACP,CAAC;AACJ,CAAC"}
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
- export declare function BlogIntro({ children }: {
3
- children: React.ReactNode;
4
- }): import("react/jsx-runtime").JSX.Element;
5
- //# sourceMappingURL=BlogIntro.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogIntro.d.ts","sourceRoot":"","sources":["../../src/blog/BlogIntro.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAMpE"}
@@ -1,5 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- export function BlogIntro({ children }) {
3
- return (_jsx("div", { className: "text-lg text-muted-foreground leading-relaxed mb-8 [&>p]:mb-4", children: children }));
4
- }
5
- //# sourceMappingURL=BlogIntro.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogIntro.js","sourceRoot":"","sources":["../../src/blog/BlogIntro.tsx"],"names":[],"mappings":";AAEA,MAAM,UAAU,SAAS,CAAC,EAAE,QAAQ,EAAiC;IACnE,OAAO,CACL,cAAK,SAAS,EAAC,+DAA+D,YAC3E,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
@@ -1,7 +0,0 @@
1
- interface BlogTableProps {
2
- headers: string[];
3
- rows: string[][];
4
- }
5
- export declare function BlogTable({ headers, rows }: BlogTableProps): import("react/jsx-runtime").JSX.Element;
6
- export {};
7
- //# sourceMappingURL=BlogTable.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogTable.d.ts","sourceRoot":"","sources":["../../src/blog/BlogTable.tsx"],"names":[],"mappings":"AAEA,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;CAClB;AAED,wBAAgB,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,cAAc,2CAmB1D"}
@@ -1,5 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export function BlogTable({ headers, rows }) {
3
- return (_jsx("div", { className: "my-8 overflow-x-auto rounded-lg border border-border", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { children: _jsx("tr", { className: "bg-muted", children: headers.map((h, i) => _jsx("th", { className: "text-left py-3 px-4 font-semibold text-foreground", children: h }, i)) }) }), _jsx("tbody", { children: rows.map((row, i) => (_jsx("tr", { className: "border-t border-border", children: row.map((cell, j) => _jsx("td", { className: "py-3 px-4 text-muted-foreground", children: cell }, j)) }, i))) })] }) }));
4
- }
5
- //# sourceMappingURL=BlogTable.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogTable.js","sourceRoot":"","sources":["../../src/blog/BlogTable.tsx"],"names":[],"mappings":";AAOA,MAAM,UAAU,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAkB;IACzD,OAAO,CACL,cAAK,SAAS,EAAC,sDAAsD,YACnE,iBAAO,SAAS,EAAC,gBAAgB,aAC/B,0BACE,aAAI,SAAS,EAAC,UAAU,YACrB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,aAAY,SAAS,EAAC,mDAAmD,YAAE,CAAC,IAAnE,CAAC,CAAwE,CAAC,GACvG,GACC,EACR,0BACG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CACpB,aAAY,SAAS,EAAC,wBAAwB,YAC3C,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,aAAY,SAAS,EAAC,iCAAiC,YAAE,IAAI,IAApD,CAAC,CAAyD,CAAC,IADnF,CAAC,CAEL,CACN,CAAC,GACI,IACF,GACJ,CACP,CAAC;AACJ,CAAC"}
@@ -1,8 +0,0 @@
1
- import React from 'react';
2
- interface BlogTipProps {
3
- title?: string;
4
- children: React.ReactNode;
5
- }
6
- export declare function BlogTip({ title, children }: BlogTipProps): import("react/jsx-runtime").JSX.Element;
7
- export {};
8
- //# sourceMappingURL=BlogTip.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogTip.d.ts","sourceRoot":"","sources":["../../src/blog/BlogTip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,UAAU,YAAY;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAa,EAAE,QAAQ,EAAE,EAAE,YAAY,2CAOhE"}
@@ -1,5 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export function BlogTip({ title = 'Tip', children }) {
3
- return (_jsxs("div", { className: "my-6 p-5 rounded-lg bg-emerald-50 border border-emerald-200", children: [_jsx("p", { className: "font-semibold text-emerald-700 text-sm mb-1", children: title }), _jsx("div", { className: "text-sm text-muted-foreground", children: children })] }));
4
- }
5
- //# sourceMappingURL=BlogTip.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogTip.js","sourceRoot":"","sources":["../../src/blog/BlogTip.tsx"],"names":[],"mappings":";AAOA,MAAM,UAAU,OAAO,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,QAAQ,EAAgB;IAC/D,OAAO,CACL,eAAK,SAAS,EAAC,6DAA6D,aAC1E,YAAG,SAAS,EAAC,6CAA6C,YAAE,KAAK,GAAK,EACtE,cAAK,SAAS,EAAC,+BAA+B,YAAE,QAAQ,GAAO,IAC3D,CACP,CAAC;AACJ,CAAC"}
@@ -1,9 +0,0 @@
1
- interface StartFreeNowCTAProps {
2
- title: string;
3
- bullets: string[];
4
- buttonText: string;
5
- buttonHref: string;
6
- }
7
- export declare function StartFreeNowCTA({ title, bullets, buttonText, buttonHref }: StartFreeNowCTAProps): import("react/jsx-runtime").JSX.Element;
8
- export {};
9
- //# sourceMappingURL=StartFreeNowCTA.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"StartFreeNowCTA.d.ts","sourceRoot":"","sources":["../../src/blog/StartFreeNowCTA.tsx"],"names":[],"mappings":"AAIA,UAAU,oBAAoB;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,oBAAoB,2CAiB/F"}