@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.
- package/components.json +1 -75
- package/dist/blog/BlogArticle.d.ts +9 -1
- package/dist/blog/BlogArticle.d.ts.map +1 -1
- package/dist/blog/BlogArticle.js +3 -2
- package/dist/blog/BlogArticle.js.map +1 -1
- package/dist/blog/BlogArticleClient.d.ts +15 -0
- package/dist/blog/BlogArticleClient.d.ts.map +1 -0
- package/dist/blog/BlogArticleClient.js +106 -0
- package/dist/blog/BlogArticleClient.js.map +1 -0
- package/dist/index.d.ts +1 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -7
- package/dist/index.js.map +1 -1
- package/dist/marketing/CalloutCard.d.ts.map +1 -1
- package/dist/marketing/CalloutCard.js +4 -4
- package/dist/marketing/CalloutCard.js.map +1 -1
- package/dist/marketing/CardGrid.d.ts.map +1 -1
- package/dist/marketing/CardGrid.js +2 -2
- package/dist/marketing/CardGrid.js.map +1 -1
- package/dist/ui/prose.d.ts +16 -0
- package/dist/ui/prose.d.ts.map +1 -0
- package/dist/ui/prose.js +44 -0
- package/dist/ui/prose.js.map +1 -0
- package/dist/ui/table.js +1 -1
- package/dist/ui/table.js.map +1 -1
- package/package.json +1 -1
- package/src/blog/BlogArticle.tsx +14 -4
- package/src/blog/BlogArticleClient.tsx +212 -0
- package/src/index.ts +3 -7
- package/src/marketing/CalloutCard.tsx +6 -4
- package/src/marketing/CardGrid.tsx +7 -3
- package/src/ui/prose.tsx +201 -0
- package/src/ui/table.tsx +1 -1
- package/dist/blog/BlogCTA.d.ts +0 -8
- package/dist/blog/BlogCTA.d.ts.map +0 -1
- package/dist/blog/BlogCTA.js +0 -6
- package/dist/blog/BlogCTA.js.map +0 -1
- package/dist/blog/BlogCTABanner.d.ts +0 -9
- package/dist/blog/BlogCTABanner.d.ts.map +0 -1
- package/dist/blog/BlogCTABanner.js +0 -7
- package/dist/blog/BlogCTABanner.js.map +0 -1
- package/dist/blog/BlogFAQ.d.ts +0 -10
- package/dist/blog/BlogFAQ.d.ts.map +0 -1
- package/dist/blog/BlogFAQ.js +0 -7
- package/dist/blog/BlogFAQ.js.map +0 -1
- package/dist/blog/BlogIntro.d.ts +0 -5
- package/dist/blog/BlogIntro.d.ts.map +0 -1
- package/dist/blog/BlogIntro.js +0 -5
- package/dist/blog/BlogIntro.js.map +0 -1
- package/dist/blog/BlogTable.d.ts +0 -7
- package/dist/blog/BlogTable.d.ts.map +0 -1
- package/dist/blog/BlogTable.js +0 -5
- package/dist/blog/BlogTable.js.map +0 -1
- package/dist/blog/BlogTip.d.ts +0 -8
- package/dist/blog/BlogTip.d.ts.map +0 -1
- package/dist/blog/BlogTip.js +0 -5
- package/dist/blog/BlogTip.js.map +0 -1
- package/dist/blog/StartFreeNowCTA.d.ts +0 -9
- package/dist/blog/StartFreeNowCTA.d.ts.map +0 -1
- package/dist/blog/StartFreeNowCTA.js +0 -7
- package/dist/blog/StartFreeNowCTA.js.map +0 -1
- package/src/blog/BlogCTA.tsx +0 -19
- package/src/blog/BlogCTABanner.tsx +0 -25
- package/src/blog/BlogFAQ.tsx +0 -32
- package/src/blog/BlogIntro.tsx +0 -9
- package/src/blog/BlogTable.tsx +0 -27
- package/src/blog/BlogTip.tsx +0 -15
- 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-
|
|
15
|
-
warning: 'bg-amber-
|
|
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('
|
|
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
|
|
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
|
}
|
package/src/ui/prose.tsx
ADDED
|
@@ -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"
|
package/dist/blog/BlogCTA.d.ts
DELETED
|
@@ -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"}
|
package/dist/blog/BlogCTA.js
DELETED
|
@@ -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
|
package/dist/blog/BlogCTA.js.map
DELETED
|
@@ -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"}
|
package/dist/blog/BlogFAQ.d.ts
DELETED
|
@@ -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"}
|
package/dist/blog/BlogFAQ.js
DELETED
|
@@ -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
|
package/dist/blog/BlogFAQ.js.map
DELETED
|
@@ -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"}
|
package/dist/blog/BlogIntro.d.ts
DELETED
|
@@ -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"}
|
package/dist/blog/BlogIntro.js
DELETED
|
@@ -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"}
|
package/dist/blog/BlogTable.d.ts
DELETED
|
@@ -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"}
|
package/dist/blog/BlogTable.js
DELETED
|
@@ -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"}
|
package/dist/blog/BlogTip.d.ts
DELETED
|
@@ -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"}
|
package/dist/blog/BlogTip.js
DELETED
|
@@ -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
|
package/dist/blog/BlogTip.js.map
DELETED
|
@@ -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"}
|