@olwiba/ui 0.0.38 → 0.0.42
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/dist/email/index.d.ts +35 -0
- package/dist/email/index.js +135 -0
- package/dist/email/index.js.map +1 -0
- package/dist/index.d.ts +64 -2
- package/dist/index.js +149 -13
- package/dist/index.js.map +1 -1
- package/package.json +9 -4
- package/src/app/AppShell.tsx +5 -1
- package/src/email/ActionEmail.tsx +43 -0
- package/src/email/EmailLayout.tsx +96 -0
- package/src/email/EmailLinkFallback.tsx +26 -0
- package/src/email/NoticeEmail.tsx +31 -0
- package/src/email/index.ts +3 -0
- package/src/index.ts +3 -0
- package/src/layout/Grid.tsx +72 -0
- package/src/layout/Section.tsx +29 -0
- package/src/layout/Stack.tsx +62 -0
- package/src/layout/index.ts +6 -0
- package/src/marketing/ContactSection.tsx +13 -4
- package/src/marketing/Footer.tsx +7 -7
- package/src/marketing/Navbar.tsx +1 -1
- package/src/marketing/NewsletterSection.tsx +8 -0
- package/src/types/external-packages.d.ts +28 -76
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olwiba/ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.42",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -9,7 +9,12 @@
|
|
|
9
9
|
"module": "./dist/index.js",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
-
"import": "./dist/index.js"
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
},
|
|
15
|
+
"./email": {
|
|
16
|
+
"import": "./dist/email/index.js",
|
|
17
|
+
"types": "./dist/email/index.d.ts"
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
"files": [
|
|
@@ -44,7 +49,7 @@
|
|
|
44
49
|
},
|
|
45
50
|
"peerDependencies": {
|
|
46
51
|
"@content-collections/mdx": ">=0.2.0",
|
|
47
|
-
"@olwiba/cn": ">=0.1.
|
|
52
|
+
"@olwiba/cn": ">=0.1.16",
|
|
48
53
|
"react": ">=18.0.0",
|
|
49
54
|
"react-dom": ">=18.0.0"
|
|
50
55
|
},
|
|
@@ -55,7 +60,7 @@
|
|
|
55
60
|
},
|
|
56
61
|
"devDependencies": {
|
|
57
62
|
"@content-collections/mdx": "^0.2.2",
|
|
58
|
-
"@olwiba/cn": "
|
|
63
|
+
"@olwiba/cn": "0.1.17",
|
|
59
64
|
"@tailwindcss/vite": "^4.1.18",
|
|
60
65
|
"@tanstack/react-router": "1.154.8",
|
|
61
66
|
"@tanstack/react-router-devtools": "1.154.8",
|
package/src/app/AppShell.tsx
CHANGED
|
@@ -219,7 +219,11 @@ function ShellSidebar({
|
|
|
219
219
|
href: brand.href ?? '#',
|
|
220
220
|
children: (
|
|
221
221
|
<>
|
|
222
|
-
{brand.logo
|
|
222
|
+
{brand.logo ? (
|
|
223
|
+
<span className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-primary text-primary-foreground">
|
|
224
|
+
{brand.logo}
|
|
225
|
+
</span>
|
|
226
|
+
) : (
|
|
223
227
|
<span className="flex size-4 shrink-0 items-center justify-center text-sm font-semibold">
|
|
224
228
|
{fallbackLogo}
|
|
225
229
|
</span>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EmailButton,
|
|
3
|
+
EmailHeading,
|
|
4
|
+
EmailText,
|
|
5
|
+
emailTheme,
|
|
6
|
+
} from '@olwiba/cn/email';
|
|
7
|
+
import { EmailLayout } from './EmailLayout';
|
|
8
|
+
import { EmailLinkFallback } from './EmailLinkFallback';
|
|
9
|
+
|
|
10
|
+
export interface ActionEmailProps {
|
|
11
|
+
appName: string;
|
|
12
|
+
preview: string;
|
|
13
|
+
heading: string;
|
|
14
|
+
description: string;
|
|
15
|
+
actionLabel: string;
|
|
16
|
+
actionUrl: string;
|
|
17
|
+
brandColor?: string;
|
|
18
|
+
showLinkFallback?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function ActionEmail({
|
|
22
|
+
appName,
|
|
23
|
+
preview,
|
|
24
|
+
heading,
|
|
25
|
+
description,
|
|
26
|
+
actionLabel,
|
|
27
|
+
actionUrl,
|
|
28
|
+
brandColor = emailTheme.defaultBrandColor,
|
|
29
|
+
showLinkFallback = true,
|
|
30
|
+
}: ActionEmailProps) {
|
|
31
|
+
return (
|
|
32
|
+
<EmailLayout preview={preview} appName={appName} brandColor={brandColor}>
|
|
33
|
+
<EmailHeading>{heading}</EmailHeading>
|
|
34
|
+
<EmailText variant="muted" style={{ margin: '0 0 24px' }}>
|
|
35
|
+
{description}
|
|
36
|
+
</EmailText>
|
|
37
|
+
<EmailButton href={actionUrl} label={actionLabel} brandColor={brandColor} />
|
|
38
|
+
{showLinkFallback ? (
|
|
39
|
+
<EmailLinkFallback actionUrl={actionUrl} brandColor={brandColor} />
|
|
40
|
+
) : null}
|
|
41
|
+
</EmailLayout>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
EmailBody,
|
|
4
|
+
EmailContainer,
|
|
5
|
+
EmailHead,
|
|
6
|
+
EmailPreview,
|
|
7
|
+
EmailRoot,
|
|
8
|
+
EmailSection,
|
|
9
|
+
EmailText,
|
|
10
|
+
emailTheme,
|
|
11
|
+
} from '@olwiba/cn/email';
|
|
12
|
+
|
|
13
|
+
export interface EmailLayoutProps {
|
|
14
|
+
preview?: string;
|
|
15
|
+
appName: string;
|
|
16
|
+
brandColor?: string;
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
footer?: ReactNode;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Branded email shell — UI block composed from CN primitives. */
|
|
22
|
+
export function EmailLayout({
|
|
23
|
+
preview,
|
|
24
|
+
appName,
|
|
25
|
+
brandColor = emailTheme.defaultBrandColor,
|
|
26
|
+
children,
|
|
27
|
+
footer,
|
|
28
|
+
}: EmailLayoutProps) {
|
|
29
|
+
const year = new Date().getFullYear();
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<EmailRoot>
|
|
33
|
+
<EmailHead />
|
|
34
|
+
{preview ? <EmailPreview>{preview}</EmailPreview> : null}
|
|
35
|
+
<EmailBody
|
|
36
|
+
style={{
|
|
37
|
+
backgroundColor: emailTheme.pageBackground,
|
|
38
|
+
fontFamily: emailTheme.fontFamily,
|
|
39
|
+
margin: 0,
|
|
40
|
+
padding: '24px 0',
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
<EmailContainer
|
|
44
|
+
style={{
|
|
45
|
+
maxWidth: '560px',
|
|
46
|
+
margin: '0 auto',
|
|
47
|
+
backgroundColor: emailTheme.cardBackground,
|
|
48
|
+
borderRadius: '16px',
|
|
49
|
+
overflow: 'hidden',
|
|
50
|
+
border: `1px solid ${emailTheme.cardBorder}`,
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<EmailSection
|
|
54
|
+
style={{
|
|
55
|
+
padding: '24px 32px',
|
|
56
|
+
borderBottom: `1px solid ${emailTheme.cardBorder}`,
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
<EmailText
|
|
60
|
+
style={{
|
|
61
|
+
margin: 0,
|
|
62
|
+
fontSize: '18px',
|
|
63
|
+
fontWeight: 600,
|
|
64
|
+
color: brandColor,
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
{appName}
|
|
68
|
+
</EmailText>
|
|
69
|
+
</EmailSection>
|
|
70
|
+
|
|
71
|
+
<EmailSection style={{ padding: '32px' }}>{children}</EmailSection>
|
|
72
|
+
|
|
73
|
+
{footer ?? (
|
|
74
|
+
<EmailSection
|
|
75
|
+
style={{
|
|
76
|
+
padding: '20px 32px',
|
|
77
|
+
borderTop: `1px solid ${emailTheme.cardBorder}`,
|
|
78
|
+
backgroundColor: emailTheme.mutedBackground,
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
<EmailText
|
|
82
|
+
variant="caption"
|
|
83
|
+
style={{
|
|
84
|
+
margin: 0,
|
|
85
|
+
textAlign: 'center',
|
|
86
|
+
}}
|
|
87
|
+
>
|
|
88
|
+
© {year} {appName}. All rights reserved.
|
|
89
|
+
</EmailText>
|
|
90
|
+
</EmailSection>
|
|
91
|
+
)}
|
|
92
|
+
</EmailContainer>
|
|
93
|
+
</EmailBody>
|
|
94
|
+
</EmailRoot>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { EmailLink, EmailText } from '@olwiba/cn/email';
|
|
2
|
+
|
|
3
|
+
export interface EmailLinkFallbackProps {
|
|
4
|
+
actionUrl: string;
|
|
5
|
+
label?: string;
|
|
6
|
+
brandColor?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function EmailLinkFallback({
|
|
10
|
+
actionUrl,
|
|
11
|
+
label = 'Or copy and paste this link into your browser:',
|
|
12
|
+
brandColor,
|
|
13
|
+
}: EmailLinkFallbackProps) {
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
<EmailText variant="caption" style={{ margin: '24px 0 8px' }}>
|
|
17
|
+
{label}
|
|
18
|
+
</EmailText>
|
|
19
|
+
<EmailText style={{ margin: 0 }}>
|
|
20
|
+
<EmailLink href={actionUrl} brandColor={brandColor}>
|
|
21
|
+
{actionUrl}
|
|
22
|
+
</EmailLink>
|
|
23
|
+
</EmailText>
|
|
24
|
+
</>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EmailHeading,
|
|
3
|
+
EmailText,
|
|
4
|
+
emailTheme,
|
|
5
|
+
} from '@olwiba/cn/email';
|
|
6
|
+
import { EmailLayout } from './EmailLayout';
|
|
7
|
+
|
|
8
|
+
export interface NoticeEmailProps {
|
|
9
|
+
appName: string;
|
|
10
|
+
preview: string;
|
|
11
|
+
heading: string;
|
|
12
|
+
body: string;
|
|
13
|
+
brandColor?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function NoticeEmail({
|
|
17
|
+
appName,
|
|
18
|
+
preview,
|
|
19
|
+
heading,
|
|
20
|
+
body,
|
|
21
|
+
brandColor = emailTheme.defaultBrandColor,
|
|
22
|
+
}: NoticeEmailProps) {
|
|
23
|
+
return (
|
|
24
|
+
<EmailLayout preview={preview} appName={appName} brandColor={brandColor}>
|
|
25
|
+
<EmailHeading>{heading}</EmailHeading>
|
|
26
|
+
<EmailText variant="muted" style={{ margin: 0, whiteSpace: 'pre-wrap' }}>
|
|
27
|
+
{body}
|
|
28
|
+
</EmailText>
|
|
29
|
+
</EmailLayout>
|
|
30
|
+
);
|
|
31
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,9 @@ export {
|
|
|
14
14
|
// ─── Primitives — mode-aware re-exports of @olwiba/cn components ─────────────
|
|
15
15
|
export * from './primitives';
|
|
16
16
|
|
|
17
|
+
// ─── Layout — grid, stack, section primitives ────────────────────────────────
|
|
18
|
+
export * from './layout';
|
|
19
|
+
|
|
17
20
|
// ─── App — shells, auth, feedback ────────────────────────────────────────────
|
|
18
21
|
export {
|
|
19
22
|
AppShell,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { cn } from '../lib/utils'
|
|
3
|
+
|
|
4
|
+
const colsMap: Record<number, string> = {
|
|
5
|
+
1: 'grid-cols-1',
|
|
6
|
+
2: 'grid-cols-2',
|
|
7
|
+
3: 'grid-cols-3',
|
|
8
|
+
4: 'grid-cols-4',
|
|
9
|
+
5: 'grid-cols-5',
|
|
10
|
+
6: 'grid-cols-6',
|
|
11
|
+
12: 'grid-cols-12',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const gapMap = {
|
|
15
|
+
none: 'gap-0',
|
|
16
|
+
xs: 'gap-2',
|
|
17
|
+
sm: 'gap-3',
|
|
18
|
+
md: 'gap-4',
|
|
19
|
+
lg: 'gap-6',
|
|
20
|
+
xl: 'gap-8',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const spanMap: Record<number, string> = {
|
|
24
|
+
1: 'col-span-1',
|
|
25
|
+
2: 'col-span-2',
|
|
26
|
+
3: 'col-span-3',
|
|
27
|
+
4: 'col-span-4',
|
|
28
|
+
5: 'col-span-5',
|
|
29
|
+
6: 'col-span-6',
|
|
30
|
+
7: 'col-span-7',
|
|
31
|
+
8: 'col-span-8',
|
|
32
|
+
9: 'col-span-9',
|
|
33
|
+
10: 'col-span-10',
|
|
34
|
+
11: 'col-span-11',
|
|
35
|
+
12: 'col-span-12',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const rowSpanMap: Record<number, string> = {
|
|
39
|
+
1: 'row-span-1',
|
|
40
|
+
2: 'row-span-2',
|
|
41
|
+
3: 'row-span-3',
|
|
42
|
+
4: 'row-span-4',
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface GridProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
46
|
+
columns?: 1 | 2 | 3 | 4 | 5 | 6 | 12
|
|
47
|
+
gap?: keyof typeof gapMap
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function Grid({ columns = 3, gap = 'md', className, children, ...props }: GridProps) {
|
|
51
|
+
return (
|
|
52
|
+
<div className={cn('grid', colsMap[columns], gapMap[gap], className)} {...props}>
|
|
53
|
+
{children}
|
|
54
|
+
</div>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface GridItemProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
59
|
+
span?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
|
|
60
|
+
rowSpan?: 1 | 2 | 3 | 4
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function GridItem({ span = 1, rowSpan, className, children, ...props }: GridItemProps) {
|
|
64
|
+
return (
|
|
65
|
+
<div
|
|
66
|
+
className={cn(spanMap[span], rowSpan != null && rowSpanMap[rowSpan], className)}
|
|
67
|
+
{...props}
|
|
68
|
+
>
|
|
69
|
+
{children}
|
|
70
|
+
</div>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { cn } from '../lib/utils'
|
|
3
|
+
|
|
4
|
+
const paddingMap = {
|
|
5
|
+
none: '',
|
|
6
|
+
sm: 'py-4',
|
|
7
|
+
md: 'py-8',
|
|
8
|
+
lg: 'py-16',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SectionProps extends React.HTMLAttributes<HTMLElement> {
|
|
12
|
+
title?: string
|
|
13
|
+
description?: string
|
|
14
|
+
padding?: keyof typeof paddingMap
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function Section({ title, description, padding = 'md', className, children, ...props }: SectionProps) {
|
|
18
|
+
return (
|
|
19
|
+
<section className={cn('w-full', paddingMap[padding], className)} {...props}>
|
|
20
|
+
{(title || description) && (
|
|
21
|
+
<div className="mb-6">
|
|
22
|
+
{title && <h2 className="text-xl font-semibold text-foreground">{title}</h2>}
|
|
23
|
+
{description && <p className="mt-1 text-sm text-muted-foreground">{description}</p>}
|
|
24
|
+
</div>
|
|
25
|
+
)}
|
|
26
|
+
{children}
|
|
27
|
+
</section>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { cn } from '../lib/utils'
|
|
3
|
+
|
|
4
|
+
const gapMap = {
|
|
5
|
+
none: 'gap-0',
|
|
6
|
+
xs: 'gap-2',
|
|
7
|
+
sm: 'gap-3',
|
|
8
|
+
md: 'gap-4',
|
|
9
|
+
lg: 'gap-6',
|
|
10
|
+
xl: 'gap-8',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const alignMap = {
|
|
14
|
+
start: 'items-start',
|
|
15
|
+
center: 'items-center',
|
|
16
|
+
end: 'items-end',
|
|
17
|
+
stretch: 'items-stretch',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const justifyMap = {
|
|
21
|
+
start: 'justify-start',
|
|
22
|
+
center: 'justify-center',
|
|
23
|
+
end: 'justify-end',
|
|
24
|
+
between: 'justify-between',
|
|
25
|
+
around: 'justify-around',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface StackProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
29
|
+
direction?: 'col' | 'row'
|
|
30
|
+
gap?: keyof typeof gapMap
|
|
31
|
+
align?: keyof typeof alignMap
|
|
32
|
+
justify?: keyof typeof justifyMap
|
|
33
|
+
wrap?: boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function Stack({
|
|
37
|
+
direction = 'col',
|
|
38
|
+
gap = 'md',
|
|
39
|
+
align = 'stretch',
|
|
40
|
+
justify = 'start',
|
|
41
|
+
wrap = false,
|
|
42
|
+
className,
|
|
43
|
+
children,
|
|
44
|
+
...props
|
|
45
|
+
}: StackProps) {
|
|
46
|
+
return (
|
|
47
|
+
<div
|
|
48
|
+
className={cn(
|
|
49
|
+
'flex',
|
|
50
|
+
direction === 'col' ? 'flex-col' : 'flex-row',
|
|
51
|
+
gapMap[gap],
|
|
52
|
+
alignMap[align],
|
|
53
|
+
justifyMap[justify],
|
|
54
|
+
wrap && 'flex-wrap',
|
|
55
|
+
className,
|
|
56
|
+
)}
|
|
57
|
+
{...props}
|
|
58
|
+
>
|
|
59
|
+
{children}
|
|
60
|
+
</div>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
@@ -106,28 +106,37 @@ export function ContactSection({
|
|
|
106
106
|
</div>
|
|
107
107
|
) : (
|
|
108
108
|
<form onSubmit={handleSubmit} className="space-y-5">
|
|
109
|
+
<input
|
|
110
|
+
type="text"
|
|
111
|
+
name="company"
|
|
112
|
+
tabIndex={-1}
|
|
113
|
+
autoComplete="off"
|
|
114
|
+
aria-hidden="true"
|
|
115
|
+
className="hidden"
|
|
116
|
+
/>
|
|
109
117
|
<div className="grid gap-4 sm:grid-cols-2">
|
|
110
118
|
<div className="space-y-1.5">
|
|
111
119
|
<Label htmlFor="contact-first">First name</Label>
|
|
112
|
-
<Input id="contact-first" placeholder="Olivia" required />
|
|
120
|
+
<Input id="contact-first" name="firstName" placeholder="Olivia" required />
|
|
113
121
|
</div>
|
|
114
122
|
<div className="space-y-1.5">
|
|
115
123
|
<Label htmlFor="contact-last">Last name</Label>
|
|
116
|
-
<Input id="contact-last" placeholder="Reed" required />
|
|
124
|
+
<Input id="contact-last" name="lastName" placeholder="Reed" required />
|
|
117
125
|
</div>
|
|
118
126
|
</div>
|
|
119
127
|
<div className="space-y-1.5">
|
|
120
128
|
<Label htmlFor="contact-email">Email</Label>
|
|
121
|
-
<Input id="contact-email" type="email" placeholder="olivia@company.com" required />
|
|
129
|
+
<Input id="contact-email" name="email" type="email" placeholder="olivia@company.com" required />
|
|
122
130
|
</div>
|
|
123
131
|
<div className="space-y-1.5">
|
|
124
132
|
<Label htmlFor="contact-subject">Subject</Label>
|
|
125
|
-
<Input id="contact-subject" placeholder="How can we help?" required />
|
|
133
|
+
<Input id="contact-subject" name="subject" placeholder="How can we help?" required />
|
|
126
134
|
</div>
|
|
127
135
|
<div className="space-y-1.5">
|
|
128
136
|
<Label htmlFor="contact-message">Message</Label>
|
|
129
137
|
<Textarea
|
|
130
138
|
id="contact-message"
|
|
139
|
+
name="message"
|
|
131
140
|
placeholder="Tell us what you're working on..."
|
|
132
141
|
className="min-h-28 resize-none"
|
|
133
142
|
required
|
package/src/marketing/Footer.tsx
CHANGED
|
@@ -26,8 +26,8 @@ export function Footer({
|
|
|
26
26
|
const copyrightText = legal ?? `\u00A9 ${new Date().getFullYear()} ${brand.name}. All rights reserved.`;
|
|
27
27
|
|
|
28
28
|
return (
|
|
29
|
-
<footer className="bg-
|
|
30
|
-
<div className="mx-auto max-w-7xl
|
|
29
|
+
<footer className="overflow-hidden rounded-2xl border bg-foreground text-background">
|
|
30
|
+
<div className="mx-auto max-w-7xl px-6 py-20 sm:py-24 lg:px-8">
|
|
31
31
|
{/* Brand */}
|
|
32
32
|
<div className="flex justify-center">
|
|
33
33
|
{renderLink({
|
|
@@ -36,11 +36,11 @@ export function Footer({
|
|
|
36
36
|
children: (
|
|
37
37
|
<>
|
|
38
38
|
{brand.logo && (
|
|
39
|
-
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-
|
|
39
|
+
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-background/10 text-background">
|
|
40
40
|
{brand.logo}
|
|
41
41
|
</span>
|
|
42
42
|
)}
|
|
43
|
-
<span className="text-lg font-semibold text-
|
|
43
|
+
<span className="text-lg font-semibold text-background">{brand.name}</span>
|
|
44
44
|
</>
|
|
45
45
|
),
|
|
46
46
|
})}
|
|
@@ -53,7 +53,7 @@ export function Footer({
|
|
|
53
53
|
<div key={label}>
|
|
54
54
|
{renderLink({
|
|
55
55
|
href,
|
|
56
|
-
className: 'text-sm/6 text-
|
|
56
|
+
className: 'text-sm/6 text-background/70 transition-colors hover:text-background',
|
|
57
57
|
children: label,
|
|
58
58
|
})}
|
|
59
59
|
</div>
|
|
@@ -69,7 +69,7 @@ export function Footer({
|
|
|
69
69
|
key={label}
|
|
70
70
|
href={href}
|
|
71
71
|
aria-label={label}
|
|
72
|
-
className="text-
|
|
72
|
+
className="text-background/70 transition-colors hover:text-background"
|
|
73
73
|
>
|
|
74
74
|
{icon}
|
|
75
75
|
</a>
|
|
@@ -78,7 +78,7 @@ export function Footer({
|
|
|
78
78
|
)}
|
|
79
79
|
|
|
80
80
|
{/* Copyright */}
|
|
81
|
-
<p className="mt-10 text-center text-sm/6 text-
|
|
81
|
+
<p className="mt-10 text-center text-sm/6 text-background/50">
|
|
82
82
|
{copyrightText}
|
|
83
83
|
</p>
|
|
84
84
|
</div>
|
package/src/marketing/Navbar.tsx
CHANGED
|
@@ -40,7 +40,7 @@ export function Navbar({
|
|
|
40
40
|
children: (
|
|
41
41
|
<span className="flex items-center gap-2 font-semibold">
|
|
42
42
|
{brand.logo && (
|
|
43
|
-
<span className="flex h-
|
|
43
|
+
<span className="flex h-9 w-9 items-center justify-center rounded-xl bg-primary text-primary-foreground">
|
|
44
44
|
{brand.logo}
|
|
45
45
|
</span>
|
|
46
46
|
)}
|
|
@@ -74,6 +74,14 @@ export function NewsletterSection({
|
|
|
74
74
|
</div>
|
|
75
75
|
) : (
|
|
76
76
|
<form onSubmit={handleSubmit} className="mt-8 flex flex-col gap-3 sm:flex-row">
|
|
77
|
+
<input
|
|
78
|
+
type="text"
|
|
79
|
+
name="company"
|
|
80
|
+
tabIndex={-1}
|
|
81
|
+
autoComplete="off"
|
|
82
|
+
aria-hidden="true"
|
|
83
|
+
className="hidden"
|
|
84
|
+
/>
|
|
77
85
|
<Input
|
|
78
86
|
type="email"
|
|
79
87
|
placeholder={placeholder}
|
|
@@ -1,79 +1,31 @@
|
|
|
1
|
-
declare module '@olwiba/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
declare module '@olwiba/cn/email' {
|
|
2
|
+
export const emailTheme: {
|
|
3
|
+
pageBackground: string;
|
|
4
|
+
cardBackground: string;
|
|
5
|
+
cardBorder: string;
|
|
6
|
+
mutedBackground: string;
|
|
7
|
+
text: string;
|
|
8
|
+
mutedText: string;
|
|
9
|
+
link: string;
|
|
10
|
+
buttonText: string;
|
|
11
|
+
defaultBrandColor: string;
|
|
12
|
+
fontFamily: string;
|
|
7
13
|
};
|
|
8
14
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
export
|
|
12
|
-
export
|
|
13
|
-
export
|
|
14
|
-
export
|
|
15
|
-
export
|
|
16
|
-
export
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
export
|
|
25
|
-
id: string;
|
|
26
|
-
defaultViewport?: 'desktop' | 'tablet' | 'mobile' | 'custom';
|
|
27
|
-
files: Array<{ path: string; language: string; code: string }>;
|
|
28
|
-
preview: React.LazyExoticComponent<React.FC>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export type SandboxRegistryInput =
|
|
32
|
-
| SandboxDefinition[]
|
|
33
|
-
| Record<string, SandboxDefinition>;
|
|
34
|
-
|
|
35
|
-
export function registerSandboxes(input: SandboxRegistryInput): void;
|
|
36
|
-
export function getSandboxDefinition(id: string): SandboxDefinition | undefined;
|
|
37
|
-
|
|
38
|
-
export interface UIModeOption {
|
|
39
|
-
value: string;
|
|
40
|
-
label: string;
|
|
41
|
-
}
|
|
42
|
-
export interface UIModeDropdownProps {
|
|
43
|
-
modes: UIModeOption[];
|
|
44
|
-
}
|
|
45
|
-
export const UIModeDropdown: React.ComponentType<UIModeDropdownProps>;
|
|
46
|
-
export function getUIMode(): string;
|
|
47
|
-
export function setUIMode(mode: string): void;
|
|
48
|
-
export function subscribeUIMode(fn: (mode: string) => void): () => void;
|
|
49
|
-
|
|
50
|
-
export interface SidebarSection {
|
|
51
|
-
name: string;
|
|
52
|
-
href: string;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface TocItem {
|
|
56
|
-
title: string;
|
|
57
|
-
url: string;
|
|
58
|
-
depth: number;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export interface PageLoaderData {
|
|
62
|
-
path: string;
|
|
63
|
-
url: string;
|
|
64
|
-
pageTree: unknown;
|
|
65
|
-
frontmatter: { title?: string; description?: string };
|
|
66
|
-
toc: TocItem[];
|
|
67
|
-
rawContent: string;
|
|
68
|
-
neighbours: {
|
|
69
|
-
previous: { url: string; name: string } | null;
|
|
70
|
-
next: { url: string; name: string } | null;
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
declare module '@olwiba/docs/server' {
|
|
76
|
-
export function createServer(): unknown;
|
|
15
|
+
export type EmailTheme = typeof emailTheme;
|
|
16
|
+
|
|
17
|
+
export function EmailRoot(props: { children?: React.ReactNode }): JSX.Element;
|
|
18
|
+
export function EmailHead(props: { children?: React.ReactNode }): JSX.Element;
|
|
19
|
+
export function EmailBody(props: { children?: React.ReactNode; style?: React.CSSProperties }): JSX.Element;
|
|
20
|
+
export function EmailPreview(props: { children?: string }): JSX.Element;
|
|
21
|
+
export function EmailContainer(props: { children?: React.ReactNode; style?: React.CSSProperties }): JSX.Element;
|
|
22
|
+
export function EmailSection(props: { children?: React.ReactNode; style?: React.CSSProperties }): JSX.Element;
|
|
23
|
+
export function EmailText(props: {
|
|
24
|
+
children?: React.ReactNode;
|
|
25
|
+
variant?: 'default' | 'muted' | 'caption';
|
|
26
|
+
style?: React.CSSProperties;
|
|
27
|
+
}): JSX.Element;
|
|
28
|
+
export function EmailHeading(props: { children?: React.ReactNode; style?: React.CSSProperties }): JSX.Element;
|
|
29
|
+
export function EmailLink(props: { href: string; children?: React.ReactNode; style?: React.CSSProperties }): JSX.Element;
|
|
30
|
+
export function EmailButton(props: { href: string; label: string; brandColor?: string }): JSX.Element;
|
|
77
31
|
}
|
|
78
|
-
|
|
79
|
-
|