@olwiba/cn 0.1.14 → 0.1.17
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/README.md +8 -4
- package/dist/email/index.d.ts +52 -0
- package/dist/email/index.js +122 -0
- package/dist/email/index.js.map +1 -0
- package/dist/index.js +25 -6
- package/dist/index.js.map +1 -1
- package/package.json +16 -3
package/README.md
CHANGED
|
@@ -27,15 +27,19 @@
|
|
|
27
27
|
|
|
28
28
|
## What This Is
|
|
29
29
|
|
|
30
|
-
`@olwiba/cn` is a custom shadcn component registry.
|
|
30
|
+
`@olwiba/cn` is a custom shadcn component registry.
|
|
31
|
+
It contains beautifully designed, copy-paste ready primitive components built on React 19 and Tailwind CSS v4.
|
|
31
32
|
|
|
32
33
|
Primitives are the individual lego pieces for building on the web.
|
|
33
34
|
|
|
34
35
|
If you're interested in composite components, these are prebuilt, opinionated combinations of primitives that solve specific UI problems. They're coming soon in `@olwiba/ui`.
|
|
35
36
|
|
|
36
|
-
The project introduces the idea of a `mode` prop, this lets you dial in the visual personality without touching variants or structure.
|
|
37
|
+
The project introduces the idea of a `mode` prop, this lets you dial in the visual personality without touching variants or structure.
|
|
38
|
+
Pair that with seven built-in color themes and you get a design system that can conform to your project.
|
|
37
39
|
|
|
38
|
-
It ships two ways
|
|
40
|
+
It ships two ways:
|
|
41
|
+
1. As an installable package
|
|
42
|
+
2. As a shadcn registry you can copy directly into your project
|
|
39
43
|
|
|
40
44
|
## Installation
|
|
41
45
|
|
|
@@ -114,4 +118,4 @@ Open an issue first for anything beyond a small fix.
|
|
|
114
118
|
|
|
115
119
|
<p align="center">
|
|
116
120
|
<a href="https://buymeacoffee.com/olwiba"><img src="https://img.shields.io/badge/Buy%20Me%20A%20Coffee-FFDD00?logo=buymeacoffee&logoColor=black" alt="Buy Me A Coffee" /></a>
|
|
117
|
-
</p>
|
|
121
|
+
</p>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { BodyProps, HeadProps, PreviewProps, HtmlProps, ContainerProps, SectionProps, TextProps, HeadingProps, LinkProps, ButtonProps } from '@react-email/components';
|
|
3
|
+
|
|
4
|
+
declare const emailTheme: {
|
|
5
|
+
readonly pageBackground: "#f4f4f5";
|
|
6
|
+
readonly cardBackground: "#ffffff";
|
|
7
|
+
readonly cardBorder: "#e4e4e7";
|
|
8
|
+
readonly mutedBackground: "#fafafa";
|
|
9
|
+
readonly text: "#18181b";
|
|
10
|
+
readonly mutedText: "#71717a";
|
|
11
|
+
readonly link: "#10b981";
|
|
12
|
+
readonly buttonText: "#ffffff";
|
|
13
|
+
readonly defaultBrandColor: "#10b981";
|
|
14
|
+
readonly fontFamily: "-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif";
|
|
15
|
+
};
|
|
16
|
+
type EmailTheme = typeof emailTheme;
|
|
17
|
+
|
|
18
|
+
type EmailRootProps = HtmlProps;
|
|
19
|
+
type EmailHeadProps = HeadProps;
|
|
20
|
+
type EmailBodyProps = BodyProps;
|
|
21
|
+
type EmailPreviewProps = PreviewProps;
|
|
22
|
+
declare function EmailRoot(props: EmailRootProps): react_jsx_runtime.JSX.Element;
|
|
23
|
+
declare function EmailHead(props: EmailHeadProps): react_jsx_runtime.JSX.Element;
|
|
24
|
+
declare function EmailBody(props: EmailBodyProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
declare function EmailPreview(props: EmailPreviewProps): react_jsx_runtime.JSX.Element;
|
|
26
|
+
|
|
27
|
+
type EmailContainerProps = ContainerProps;
|
|
28
|
+
declare function EmailContainer(props: EmailContainerProps): react_jsx_runtime.JSX.Element;
|
|
29
|
+
|
|
30
|
+
type EmailSectionProps = SectionProps;
|
|
31
|
+
declare function EmailSection(props: EmailSectionProps): react_jsx_runtime.JSX.Element;
|
|
32
|
+
|
|
33
|
+
type EmailTextProps = TextProps & {
|
|
34
|
+
variant?: 'default' | 'muted' | 'caption';
|
|
35
|
+
};
|
|
36
|
+
declare function EmailText({ variant, style, ...props }: EmailTextProps): react_jsx_runtime.JSX.Element;
|
|
37
|
+
|
|
38
|
+
type EmailHeadingProps = HeadingProps;
|
|
39
|
+
declare function EmailHeading({ style, ...props }: EmailHeadingProps): react_jsx_runtime.JSX.Element;
|
|
40
|
+
|
|
41
|
+
type EmailLinkProps = LinkProps & {
|
|
42
|
+
brandColor?: string;
|
|
43
|
+
};
|
|
44
|
+
declare function EmailLink({ brandColor, style, ...props }: EmailLinkProps): react_jsx_runtime.JSX.Element;
|
|
45
|
+
|
|
46
|
+
interface EmailButtonProps extends Omit<ButtonProps, 'children'> {
|
|
47
|
+
label: string;
|
|
48
|
+
brandColor?: string;
|
|
49
|
+
}
|
|
50
|
+
declare function EmailButton({ label, brandColor, style, ...props }: EmailButtonProps): react_jsx_runtime.JSX.Element;
|
|
51
|
+
|
|
52
|
+
export { EmailBody, type EmailBodyProps, EmailButton, type EmailButtonProps, EmailContainer, type EmailContainerProps, EmailHead, type EmailHeadProps, EmailHeading, type EmailHeadingProps, EmailLink, type EmailLinkProps, EmailPreview, type EmailPreviewProps, EmailRoot, type EmailRootProps, EmailSection, type EmailSectionProps, EmailText, type EmailTextProps, type EmailTheme, emailTheme };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Html, Head, Body, Preview, Container, Section, Text, Heading, Link, Button } from '@react-email/components';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
// src/email/theme.ts
|
|
5
|
+
var emailTheme = {
|
|
6
|
+
pageBackground: "#f4f4f5",
|
|
7
|
+
cardBackground: "#ffffff",
|
|
8
|
+
cardBorder: "#e4e4e7",
|
|
9
|
+
mutedBackground: "#fafafa",
|
|
10
|
+
text: "#18181b",
|
|
11
|
+
mutedText: "#71717a",
|
|
12
|
+
link: "#10b981",
|
|
13
|
+
buttonText: "#ffffff",
|
|
14
|
+
defaultBrandColor: "#10b981",
|
|
15
|
+
fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif'
|
|
16
|
+
};
|
|
17
|
+
function EmailRoot(props) {
|
|
18
|
+
return /* @__PURE__ */ jsx(Html, { ...props });
|
|
19
|
+
}
|
|
20
|
+
function EmailHead(props) {
|
|
21
|
+
return /* @__PURE__ */ jsx(Head, { ...props });
|
|
22
|
+
}
|
|
23
|
+
function EmailBody(props) {
|
|
24
|
+
return /* @__PURE__ */ jsx(Body, { ...props });
|
|
25
|
+
}
|
|
26
|
+
function EmailPreview(props) {
|
|
27
|
+
return /* @__PURE__ */ jsx(Preview, { ...props });
|
|
28
|
+
}
|
|
29
|
+
function EmailContainer(props) {
|
|
30
|
+
return /* @__PURE__ */ jsx(Container, { ...props });
|
|
31
|
+
}
|
|
32
|
+
function EmailSection(props) {
|
|
33
|
+
return /* @__PURE__ */ jsx(Section, { ...props });
|
|
34
|
+
}
|
|
35
|
+
var variantStyles = {
|
|
36
|
+
default: {
|
|
37
|
+
color: emailTheme.text,
|
|
38
|
+
fontSize: "15px",
|
|
39
|
+
lineHeight: "24px"
|
|
40
|
+
},
|
|
41
|
+
muted: {
|
|
42
|
+
color: emailTheme.mutedText,
|
|
43
|
+
fontSize: "15px",
|
|
44
|
+
lineHeight: "24px"
|
|
45
|
+
},
|
|
46
|
+
caption: {
|
|
47
|
+
color: emailTheme.mutedText,
|
|
48
|
+
fontSize: "13px",
|
|
49
|
+
lineHeight: "20px"
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
function EmailText({
|
|
53
|
+
variant = "default",
|
|
54
|
+
style,
|
|
55
|
+
...props
|
|
56
|
+
}) {
|
|
57
|
+
return /* @__PURE__ */ jsx(Text, { style: { ...variantStyles[variant], ...style }, ...props });
|
|
58
|
+
}
|
|
59
|
+
function EmailHeading({ style, ...props }) {
|
|
60
|
+
return /* @__PURE__ */ jsx(
|
|
61
|
+
Heading,
|
|
62
|
+
{
|
|
63
|
+
style: {
|
|
64
|
+
margin: "0 0 12px",
|
|
65
|
+
fontSize: "24px",
|
|
66
|
+
fontWeight: 600,
|
|
67
|
+
lineHeight: "32px",
|
|
68
|
+
color: emailTheme.text,
|
|
69
|
+
...style
|
|
70
|
+
},
|
|
71
|
+
...props
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
function EmailLink({
|
|
76
|
+
brandColor = emailTheme.link,
|
|
77
|
+
style,
|
|
78
|
+
...props
|
|
79
|
+
}) {
|
|
80
|
+
return /* @__PURE__ */ jsx(
|
|
81
|
+
Link,
|
|
82
|
+
{
|
|
83
|
+
style: {
|
|
84
|
+
color: brandColor,
|
|
85
|
+
wordBreak: "break-all",
|
|
86
|
+
...style
|
|
87
|
+
},
|
|
88
|
+
...props
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
function EmailButton({
|
|
93
|
+
label,
|
|
94
|
+
brandColor = emailTheme.defaultBrandColor,
|
|
95
|
+
style,
|
|
96
|
+
...props
|
|
97
|
+
}) {
|
|
98
|
+
return /* @__PURE__ */ jsx(
|
|
99
|
+
Button,
|
|
100
|
+
{
|
|
101
|
+
style: {
|
|
102
|
+
backgroundColor: brandColor,
|
|
103
|
+
borderRadius: "8px",
|
|
104
|
+
color: emailTheme.buttonText,
|
|
105
|
+
display: "inline-block",
|
|
106
|
+
fontSize: "14px",
|
|
107
|
+
fontWeight: 600,
|
|
108
|
+
lineHeight: "1",
|
|
109
|
+
padding: "12px 20px",
|
|
110
|
+
textDecoration: "none",
|
|
111
|
+
textAlign: "center",
|
|
112
|
+
...style
|
|
113
|
+
},
|
|
114
|
+
...props,
|
|
115
|
+
children: label
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { EmailBody, EmailButton, EmailContainer, EmailHead, EmailHeading, EmailLink, EmailPreview, EmailRoot, EmailSection, EmailText, emailTheme };
|
|
121
|
+
//# sourceMappingURL=index.js.map
|
|
122
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/email/theme.ts","../../src/email/root.tsx","../../src/email/container.tsx","../../src/email/section.tsx","../../src/email/text.tsx","../../src/email/heading.tsx","../../src/email/link.tsx","../../src/email/button.tsx"],"names":["jsx"],"mappings":"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","file":"index.js","sourcesContent":["export const emailTheme = {\n pageBackground: '#f4f4f5',\n cardBackground: '#ffffff',\n cardBorder: '#e4e4e7',\n mutedBackground: '#fafafa',\n text: '#18181b',\n mutedText: '#71717a',\n link: '#10b981',\n buttonText: '#ffffff',\n defaultBrandColor: '#10b981',\n fontFamily:\n '-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif',\n} as const;\n\nexport type EmailTheme = typeof emailTheme;\n","import {\n Body,\n Head,\n Html,\n Preview,\n type BodyProps,\n type HeadProps,\n type HtmlProps,\n type PreviewProps,\n} from '@react-email/components';\n\nexport type EmailRootProps = HtmlProps;\nexport type EmailHeadProps = HeadProps;\nexport type EmailBodyProps = BodyProps;\nexport type EmailPreviewProps = PreviewProps;\n\nexport function EmailRoot(props: EmailRootProps) {\n return <Html {...props} />;\n}\n\nexport function EmailHead(props: EmailHeadProps) {\n return <Head {...props} />;\n}\n\nexport function EmailBody(props: EmailBodyProps) {\n return <Body {...props} />;\n}\n\nexport function EmailPreview(props: EmailPreviewProps) {\n return <Preview {...props} />;\n}\n","import { Container, type ContainerProps } from '@react-email/components';\n\nexport type EmailContainerProps = ContainerProps;\n\nexport function EmailContainer(props: EmailContainerProps) {\n return <Container {...props} />;\n}\n","import { Section, type SectionProps } from '@react-email/components';\n\nexport type EmailSectionProps = SectionProps;\n\nexport function EmailSection(props: EmailSectionProps) {\n return <Section {...props} />;\n}\n","import { Text, type TextProps } from '@react-email/components';\nimport { emailTheme } from './theme';\n\nexport type EmailTextProps = TextProps & {\n variant?: 'default' | 'muted' | 'caption';\n};\n\nconst variantStyles = {\n default: {\n color: emailTheme.text,\n fontSize: '15px',\n lineHeight: '24px',\n },\n muted: {\n color: emailTheme.mutedText,\n fontSize: '15px',\n lineHeight: '24px',\n },\n caption: {\n color: emailTheme.mutedText,\n fontSize: '13px',\n lineHeight: '20px',\n },\n} as const;\n\nexport function EmailText({\n variant = 'default',\n style,\n ...props\n}: EmailTextProps) {\n return <Text style={{ ...variantStyles[variant], ...style }} {...props} />;\n}\n","import { Heading, type HeadingProps } from '@react-email/components';\nimport { emailTheme } from './theme';\n\nexport type EmailHeadingProps = HeadingProps;\n\nexport function EmailHeading({ style, ...props }: EmailHeadingProps) {\n return (\n <Heading\n style={{\n margin: '0 0 12px',\n fontSize: '24px',\n fontWeight: 600,\n lineHeight: '32px',\n color: emailTheme.text,\n ...style,\n }}\n {...props}\n />\n );\n}\n","import { Link, type LinkProps } from '@react-email/components';\nimport { emailTheme } from './theme';\n\nexport type EmailLinkProps = LinkProps & {\n brandColor?: string;\n};\n\nexport function EmailLink({\n brandColor = emailTheme.link,\n style,\n ...props\n}: EmailLinkProps) {\n return (\n <Link\n style={{\n color: brandColor,\n wordBreak: 'break-all',\n ...style,\n }}\n {...props}\n />\n );\n}\n","import { Button, type ButtonProps } from '@react-email/components';\nimport { emailTheme } from './theme';\n\nexport interface EmailButtonProps extends Omit<ButtonProps, 'children'> {\n label: string;\n brandColor?: string;\n}\n\nexport function EmailButton({\n label,\n brandColor = emailTheme.defaultBrandColor,\n style,\n ...props\n}: EmailButtonProps) {\n return (\n <Button\n style={{\n backgroundColor: brandColor,\n borderRadius: '8px',\n color: emailTheme.buttonText,\n display: 'inline-block',\n fontSize: '14px',\n fontWeight: 600,\n lineHeight: '1',\n padding: '12px 20px',\n textDecoration: 'none',\n textAlign: 'center',\n ...style,\n }}\n {...props}\n >\n {label}\n </Button>\n );\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -6534,13 +6534,10 @@ function AsciiText({
|
|
|
6534
6534
|
active: false
|
|
6535
6535
|
});
|
|
6536
6536
|
const wavesRef = useRef([]);
|
|
6537
|
-
const
|
|
6537
|
+
const colorsRef = useRef({ base: "#a3a3a3", accent: "#a3a3a3" });
|
|
6538
|
+
const resolveColors = useCallback(() => {
|
|
6538
6539
|
const canvas = canvasRef.current;
|
|
6539
6540
|
if (!canvas) return;
|
|
6540
|
-
const ctx = canvas.getContext("2d");
|
|
6541
|
-
if (!ctx) return;
|
|
6542
|
-
const time = timeRef.current;
|
|
6543
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
6544
6541
|
const root = document.documentElement;
|
|
6545
6542
|
const rootStyle = getComputedStyle(root);
|
|
6546
6543
|
const style = getComputedStyle(canvas);
|
|
@@ -6554,6 +6551,28 @@ function AsciiText({
|
|
|
6554
6551
|
highlightColor = accentColor;
|
|
6555
6552
|
}
|
|
6556
6553
|
}
|
|
6554
|
+
colorsRef.current = { base: baseColor, accent: highlightColor };
|
|
6555
|
+
}, [color, accentColor]);
|
|
6556
|
+
useEffect(() => {
|
|
6557
|
+
resolveColors();
|
|
6558
|
+
}, [resolveColors]);
|
|
6559
|
+
useEffect(() => {
|
|
6560
|
+
if (typeof MutationObserver === "undefined") return;
|
|
6561
|
+
const observer = new MutationObserver(() => resolveColors());
|
|
6562
|
+
observer.observe(document.documentElement, {
|
|
6563
|
+
attributes: true,
|
|
6564
|
+
attributeFilter: ["class", "data-theme", "style"]
|
|
6565
|
+
});
|
|
6566
|
+
return () => observer.disconnect();
|
|
6567
|
+
}, [resolveColors]);
|
|
6568
|
+
const render = useCallback(() => {
|
|
6569
|
+
const canvas = canvasRef.current;
|
|
6570
|
+
if (!canvas) return;
|
|
6571
|
+
const ctx = canvas.getContext("2d");
|
|
6572
|
+
if (!ctx) return;
|
|
6573
|
+
const time = timeRef.current;
|
|
6574
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
6575
|
+
const { base: baseColor, accent: highlightColor } = colorsRef.current;
|
|
6557
6576
|
renderAsciiFrameToContext(ctx, { cells, cols, rows }, {
|
|
6558
6577
|
accentColumns: accentCols,
|
|
6559
6578
|
color: baseColor,
|
|
@@ -6567,7 +6586,7 @@ function AsciiText({
|
|
|
6567
6586
|
setIsCanvasReady(true);
|
|
6568
6587
|
}
|
|
6569
6588
|
wavesRef.current = wavesRef.current.filter((w) => time - w.t < 3);
|
|
6570
|
-
}, [cells, accentCols,
|
|
6589
|
+
}, [cells, accentCols, cols, rows]);
|
|
6571
6590
|
useEffect(() => {
|
|
6572
6591
|
hasPaintedRef.current = false;
|
|
6573
6592
|
setIsCanvasReady(false);
|