@shipsite.dev/components 0.2.13 → 0.2.15

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 (76) hide show
  1. package/components.json +11 -85
  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/content/ContentPage.d.ts +14 -0
  11. package/dist/content/ContentPage.d.ts.map +1 -0
  12. package/dist/{legal/LegalPage.js → content/ContentPage.js} +3 -3
  13. package/dist/content/ContentPage.js.map +1 -0
  14. package/dist/index.d.ts +2 -8
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +4 -9
  17. package/dist/index.js.map +1 -1
  18. package/dist/marketing/CalloutCard.d.ts.map +1 -1
  19. package/dist/marketing/CalloutCard.js +4 -4
  20. package/dist/marketing/CalloutCard.js.map +1 -1
  21. package/dist/marketing/CardGrid.d.ts.map +1 -1
  22. package/dist/marketing/CardGrid.js +2 -2
  23. package/dist/marketing/CardGrid.js.map +1 -1
  24. package/dist/ui/prose.d.ts +16 -0
  25. package/dist/ui/prose.d.ts.map +1 -0
  26. package/dist/ui/prose.js +44 -0
  27. package/dist/ui/prose.js.map +1 -0
  28. package/dist/ui/table.js +1 -1
  29. package/dist/ui/table.js.map +1 -1
  30. package/package.json +1 -1
  31. package/src/blog/BlogArticle.tsx +14 -4
  32. package/src/blog/BlogArticleClient.tsx +212 -0
  33. package/src/{legal/LegalPage.tsx → content/ContentPage.tsx} +4 -4
  34. package/src/index.ts +5 -9
  35. package/src/marketing/CalloutCard.tsx +6 -4
  36. package/src/marketing/CardGrid.tsx +7 -3
  37. package/src/ui/prose.tsx +201 -0
  38. package/src/ui/table.tsx +1 -1
  39. package/dist/blog/BlogCTA.d.ts +0 -8
  40. package/dist/blog/BlogCTA.d.ts.map +0 -1
  41. package/dist/blog/BlogCTA.js +0 -6
  42. package/dist/blog/BlogCTA.js.map +0 -1
  43. package/dist/blog/BlogCTABanner.d.ts +0 -9
  44. package/dist/blog/BlogCTABanner.d.ts.map +0 -1
  45. package/dist/blog/BlogCTABanner.js +0 -7
  46. package/dist/blog/BlogCTABanner.js.map +0 -1
  47. package/dist/blog/BlogFAQ.d.ts +0 -10
  48. package/dist/blog/BlogFAQ.d.ts.map +0 -1
  49. package/dist/blog/BlogFAQ.js +0 -7
  50. package/dist/blog/BlogFAQ.js.map +0 -1
  51. package/dist/blog/BlogIntro.d.ts +0 -5
  52. package/dist/blog/BlogIntro.d.ts.map +0 -1
  53. package/dist/blog/BlogIntro.js +0 -5
  54. package/dist/blog/BlogIntro.js.map +0 -1
  55. package/dist/blog/BlogTable.d.ts +0 -7
  56. package/dist/blog/BlogTable.d.ts.map +0 -1
  57. package/dist/blog/BlogTable.js +0 -5
  58. package/dist/blog/BlogTable.js.map +0 -1
  59. package/dist/blog/BlogTip.d.ts +0 -8
  60. package/dist/blog/BlogTip.d.ts.map +0 -1
  61. package/dist/blog/BlogTip.js +0 -5
  62. package/dist/blog/BlogTip.js.map +0 -1
  63. package/dist/blog/StartFreeNowCTA.d.ts +0 -9
  64. package/dist/blog/StartFreeNowCTA.d.ts.map +0 -1
  65. package/dist/blog/StartFreeNowCTA.js +0 -7
  66. package/dist/blog/StartFreeNowCTA.js.map +0 -1
  67. package/dist/legal/LegalPage.d.ts +0 -14
  68. package/dist/legal/LegalPage.d.ts.map +0 -1
  69. package/dist/legal/LegalPage.js.map +0 -1
  70. package/src/blog/BlogCTA.tsx +0 -19
  71. package/src/blog/BlogCTABanner.tsx +0 -25
  72. package/src/blog/BlogFAQ.tsx +0 -32
  73. package/src/blog/BlogIntro.tsx +0 -9
  74. package/src/blog/BlogTable.tsx +0 -27
  75. package/src/blog/BlogTip.tsx +0 -15
  76. package/src/blog/StartFreeNowCTA.tsx +0 -29
@@ -1,14 +1,24 @@
1
1
  import React from 'react';
2
+ import { BlogArticleClient } from './BlogArticleClient';
3
+
4
+ interface BlogArticleAuthor {
5
+ name: string;
6
+ role: string;
7
+ image: string;
8
+ }
2
9
 
3
10
  interface BlogArticleProps {
4
11
  children: React.ReactNode;
5
12
  contentFolder?: string;
13
+ date?: string;
14
+ readingTime?: number;
15
+ author?: BlogArticleAuthor;
6
16
  }
7
17
 
8
- export function BlogArticle({ children }: BlogArticleProps) {
18
+ export function BlogArticle({ children, author, date, readingTime }: BlogArticleProps) {
9
19
  return (
10
- <article className="py-12 md:py-20">
11
- <div className="container-main max-w-3xl">{children}</div>
12
- </article>
20
+ <BlogArticleClient author={author} date={date} readingTime={readingTime}>
21
+ {children}
22
+ </BlogArticleClient>
13
23
  );
14
24
  }
@@ -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
+ }
@@ -1,11 +1,11 @@
1
1
  import React from 'react';
2
2
 
3
- interface LegalSectionProps {
3
+ interface ContentSectionProps {
4
4
  title: string;
5
5
  children: React.ReactNode;
6
6
  }
7
7
 
8
- export function LegalSection({ title, children }: LegalSectionProps) {
8
+ export function ContentSection({ title, children }: ContentSectionProps) {
9
9
  return (
10
10
  <div className="mb-8">
11
11
  <h2 className="text-xl font-bold text-foreground mb-4">{title}</h2>
@@ -16,13 +16,13 @@ export function LegalSection({ title, children }: LegalSectionProps) {
16
16
  );
17
17
  }
18
18
 
19
- interface LegalPageProps {
19
+ interface ContentPageProps {
20
20
  title: string;
21
21
  lastUpdated?: string;
22
22
  children: React.ReactNode;
23
23
  }
24
24
 
25
- export function LegalPage({ title, lastUpdated, children }: LegalPageProps) {
25
+ export function ContentPage({ title, lastUpdated, children }: ContentPageProps) {
26
26
  return (
27
27
  <section className="py-12 md:py-20">
28
28
  <div className="container-main max-w-3xl">
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
 
74
- // Legal
75
- export { LegalPage, LegalSection } from './legal/LegalPage';
67
+ // Prose (Markdown element overrides)
68
+ export { ProseH2, ProseH3, ProseH4, ProseP, ProseA, ProseUl, ProseOl, ProseLi, ProseBlockquote, ProsePre, ProseCode, ProseHr, ProseImg } from './ui/prose';
69
+
70
+ // Content
71
+ export { ContentPage, ContentSection } from './content/ContentPage';
@@ -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"}