doom-design-system 0.1.0
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 +50 -0
- package/dist/DesignSystemProvider.d.ts +7 -0
- package/dist/DesignSystemProvider.js +13 -0
- package/dist/components/ActionRow/ActionRow.d.ts +9 -0
- package/dist/components/ActionRow/ActionRow.js +47 -0
- package/dist/components/ActionRow/index.d.ts +1 -0
- package/dist/components/ActionRow/index.js +1 -0
- package/dist/components/Badge/Badge.d.ts +8 -0
- package/dist/components/Badge/Badge.js +57 -0
- package/dist/components/Badge/index.d.ts +1 -0
- package/dist/components/Badge/index.js +1 -0
- package/dist/components/Button/Button.d.ts +9 -0
- package/dist/components/Button/Button.js +110 -0
- package/dist/components/Button/index.d.ts +1 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/Card/Card.d.ts +8 -0
- package/dist/components/Card/Card.js +28 -0
- package/dist/components/Card/index.d.ts +1 -0
- package/dist/components/Card/index.js +1 -0
- package/dist/components/Dropdown/Dropdown.d.ts +11 -0
- package/dist/components/Dropdown/Dropdown.js +47 -0
- package/dist/components/Dropdown/index.d.ts +1 -0
- package/dist/components/Dropdown/index.js +1 -0
- package/dist/components/Form/Form.d.ts +14 -0
- package/dist/components/Form/Form.js +24 -0
- package/dist/components/Form/index.d.ts +1 -0
- package/dist/components/Form/index.js +1 -0
- package/dist/components/Icon/index.d.ts +25 -0
- package/dist/components/Icon/index.js +41 -0
- package/dist/components/Input/Input.d.ts +12 -0
- package/dist/components/Input/Input.js +129 -0
- package/dist/components/Input/index.d.ts +1 -0
- package/dist/components/Input/index.js +1 -0
- package/dist/components/Layout/Layout.d.ts +17 -0
- package/dist/components/Layout/Layout.js +37 -0
- package/dist/components/Layout/index.d.ts +1 -0
- package/dist/components/Layout/index.js +1 -0
- package/dist/components/Link/Link.d.ts +11 -0
- package/dist/components/Link/Link.js +78 -0
- package/dist/components/Link/index.d.ts +1 -0
- package/dist/components/Link/index.js +1 -0
- package/dist/components/Modal/Modal.d.ts +22 -0
- package/dist/components/Modal/Modal.js +89 -0
- package/dist/components/Modal/index.d.ts +1 -0
- package/dist/components/Modal/index.js +1 -0
- package/dist/components/Page/Page.d.ts +13 -0
- package/dist/components/Page/Page.js +27 -0
- package/dist/components/Page/index.d.ts +1 -0
- package/dist/components/Page/index.js +1 -0
- package/dist/components/Popover/Popover.d.ts +11 -0
- package/dist/components/Popover/Popover.js +91 -0
- package/dist/components/Popover/index.d.ts +1 -0
- package/dist/components/Popover/index.js +1 -0
- package/dist/components/ProgressBar/ProgressBar.d.ts +12 -0
- package/dist/components/ProgressBar/ProgressBar.js +42 -0
- package/dist/components/ProgressBar/index.d.ts +1 -0
- package/dist/components/ProgressBar/index.js +1 -0
- package/dist/components/Select/Select.d.ts +12 -0
- package/dist/components/Select/Select.js +202 -0
- package/dist/components/Select/index.d.ts +1 -0
- package/dist/components/Select/index.js +1 -0
- package/dist/components/Skeleton/Skeleton.d.ts +8 -0
- package/dist/components/Skeleton/Skeleton.js +65 -0
- package/dist/components/Skeleton/index.d.ts +1 -0
- package/dist/components/Skeleton/index.js +1 -0
- package/dist/components/SplitButton/SplitButton.d.ts +12 -0
- package/dist/components/SplitButton/SplitButton.js +90 -0
- package/dist/components/SplitButton/index.d.ts +1 -0
- package/dist/components/SplitButton/index.js +1 -0
- package/dist/components/Table/Table.d.ts +19 -0
- package/dist/components/Table/Table.js +176 -0
- package/dist/components/Table/index.d.ts +1 -0
- package/dist/components/Table/index.js +1 -0
- package/dist/components/Tabs/Tabs.d.ts +34 -0
- package/dist/components/Tabs/Tabs.js +94 -0
- package/dist/components/Tabs/index.d.ts +1 -0
- package/dist/components/Tabs/index.js +1 -0
- package/dist/components/Text/Text.d.ts +14 -0
- package/dist/components/Text/Text.js +123 -0
- package/dist/components/Text/index.d.ts +1 -0
- package/dist/components/Text/index.js +1 -0
- package/dist/components/Textarea/Textarea.d.ts +3 -0
- package/dist/components/Textarea/Textarea.js +30 -0
- package/dist/components/Textarea/index.d.ts +1 -0
- package/dist/components/Textarea/index.js +1 -0
- package/dist/components/Toast/Toast.d.ts +14 -0
- package/dist/components/Toast/Toast.js +109 -0
- package/dist/components/Toast/index.d.ts +1 -0
- package/dist/components/Toast/index.js +1 -0
- package/dist/fonts.d.ts +1 -0
- package/dist/fonts.js +6 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +24 -0
- package/dist/styles/index.d.ts +3 -0
- package/dist/styles/index.js +3 -0
- package/dist/styles/reset.d.ts +1 -0
- package/dist/styles/reset.js +29 -0
- package/dist/styles/theme.d.ts +1 -0
- package/dist/styles/theme.js +11 -0
- package/dist/styles/themes/ThemeProvider.d.ts +13 -0
- package/dist/styles/themes/ThemeProvider.js +37 -0
- package/dist/styles/themes/actions.d.ts +3 -0
- package/dist/styles/themes/actions.js +16 -0
- package/dist/styles/themes/definitions.d.ts +211 -0
- package/dist/styles/themes/definitions.js +48 -0
- package/dist/styles/themes/index.d.ts +3 -0
- package/dist/styles/themes/index.js +3 -0
- package/dist/styles/utilities.d.ts +1 -0
- package/dist/styles/utilities.js +184 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useState } from 'react';
|
|
4
|
+
import styled from '@emotion/styled';
|
|
5
|
+
import { keyframes } from '@emotion/react';
|
|
6
|
+
const TabsContext = createContext(null);
|
|
7
|
+
// --- Styled Components ---
|
|
8
|
+
const fadeIn = keyframes `
|
|
9
|
+
from { opacity: 0; transform: translateY(5px); }
|
|
10
|
+
to { opacity: 1; transform: translateY(0); }
|
|
11
|
+
`;
|
|
12
|
+
const StyledTabsList = styled.div `
|
|
13
|
+
display: flex;
|
|
14
|
+
gap: 0.5rem;
|
|
15
|
+
margin-bottom: 0;
|
|
16
|
+
padding-left: 1rem;
|
|
17
|
+
position: relative;
|
|
18
|
+
/* z-index is managed by triggers */
|
|
19
|
+
`;
|
|
20
|
+
const StyledTabsTrigger = styled.button `
|
|
21
|
+
padding: 0.75rem 1.5rem;
|
|
22
|
+
font-size: 0.9rem;
|
|
23
|
+
font-weight: 700;
|
|
24
|
+
text-transform: uppercase;
|
|
25
|
+
letter-spacing: 0.05em;
|
|
26
|
+
background-color: var(--primary);
|
|
27
|
+
color: var(--primary-foreground);
|
|
28
|
+
opacity: ${props => props.isActive ? '1' : '0.6'};
|
|
29
|
+
border: var(--border-width) solid var(--card-border);
|
|
30
|
+
border-bottom: var(--border-width) solid var(--card-border);
|
|
31
|
+
border-radius: var(--radius) var(--radius) 0 0;
|
|
32
|
+
cursor: pointer;
|
|
33
|
+
position: relative;
|
|
34
|
+
z-index: ${props => props.isActive ? 'var(--z-elevated)' : 1};
|
|
35
|
+
transition: all 0.2s ease;
|
|
36
|
+
transform: ${props => props.isActive ? 'translateY(0)' : 'translateY(4px)'};
|
|
37
|
+
|
|
38
|
+
&:hover {
|
|
39
|
+
${props => !props.isActive && `
|
|
40
|
+
opacity: 0.8;
|
|
41
|
+
transform: translateY(2px);
|
|
42
|
+
`}
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
45
|
+
const StyledTabsBody = styled.div `
|
|
46
|
+
background: var(--card-bg);
|
|
47
|
+
border: var(--border-width) solid var(--card-border);
|
|
48
|
+
border-radius: var(--radius);
|
|
49
|
+
padding: 2.5rem;
|
|
50
|
+
box-shadow: var(--shadow-hard);
|
|
51
|
+
position: relative;
|
|
52
|
+
z-index: 5;
|
|
53
|
+
min-height: 600px;
|
|
54
|
+
margin-top: -3px;
|
|
55
|
+
`;
|
|
56
|
+
const StyledTabsContent = styled.div `
|
|
57
|
+
animation: ${fadeIn} 0.3s ease-out forwards;
|
|
58
|
+
`;
|
|
59
|
+
export function Tabs({ defaultValue, value, onValueChange, children, className }) {
|
|
60
|
+
const [internalActiveTab, setInternalActiveTab] = useState(defaultValue || '');
|
|
61
|
+
const isControlled = value !== undefined;
|
|
62
|
+
const activeTab = isControlled ? value : internalActiveTab;
|
|
63
|
+
const setActiveTab = (newValue) => {
|
|
64
|
+
if (!isControlled) {
|
|
65
|
+
setInternalActiveTab(newValue);
|
|
66
|
+
}
|
|
67
|
+
onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(newValue);
|
|
68
|
+
};
|
|
69
|
+
return (_jsx(TabsContext.Provider, { value: { activeTab, setActiveTab }, children: _jsx("div", { className: className, children: children }) }));
|
|
70
|
+
}
|
|
71
|
+
export function TabsList({ children, className }) {
|
|
72
|
+
return _jsx(StyledTabsList, { className: className, children: children });
|
|
73
|
+
}
|
|
74
|
+
export function TabsTrigger({ value, children, className, onClick }) {
|
|
75
|
+
const context = useContext(TabsContext);
|
|
76
|
+
if (!context)
|
|
77
|
+
throw new Error('TabsTrigger must be used within Tabs');
|
|
78
|
+
const isActive = context.activeTab === value;
|
|
79
|
+
return (_jsx(StyledTabsTrigger, { isActive: isActive, onClick: () => {
|
|
80
|
+
context.setActiveTab(value);
|
|
81
|
+
onClick === null || onClick === void 0 ? void 0 : onClick();
|
|
82
|
+
}, className: className, children: children }));
|
|
83
|
+
}
|
|
84
|
+
export function TabsBody({ children, className, style }) {
|
|
85
|
+
return _jsx(StyledTabsBody, { className: className, style: style, children: children });
|
|
86
|
+
}
|
|
87
|
+
export function TabsContent({ value, children, className }) {
|
|
88
|
+
const context = useContext(TabsContext);
|
|
89
|
+
if (!context)
|
|
90
|
+
throw new Error('TabsContent must be used within Tabs');
|
|
91
|
+
if (context.activeTab !== value)
|
|
92
|
+
return null;
|
|
93
|
+
return _jsx(StyledTabsContent, { className: className, children: children });
|
|
94
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Tabs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Tabs';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type BaseProps = Omit<React.ComponentPropsWithoutRef<'span'>, 'color'>;
|
|
3
|
+
interface CustomTextProps {
|
|
4
|
+
variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body' | 'small' | 'caption';
|
|
5
|
+
weight?: 'normal' | 'medium' | 'semibold' | 'bold' | 'black';
|
|
6
|
+
color?: 'primary' | 'secondary' | 'muted' | 'error' | 'success' | 'warning';
|
|
7
|
+
align?: 'left' | 'center' | 'right';
|
|
8
|
+
as?: React.ElementType;
|
|
9
|
+
htmlFor?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface TextProps extends BaseProps, CustomTextProps {
|
|
12
|
+
}
|
|
13
|
+
export declare function Text({ variant, weight, color, align, className, style, children, as, ...props }: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
|
+
import styled from '@emotion/styled';
|
|
15
|
+
const StyledText = styled.span `
|
|
16
|
+
/* Variant styles */
|
|
17
|
+
${props => {
|
|
18
|
+
switch (props.$variant) {
|
|
19
|
+
case 'h1':
|
|
20
|
+
return `
|
|
21
|
+
font-size: var(--text-5xl);
|
|
22
|
+
font-weight: var(--font-black);
|
|
23
|
+
line-height: 1.1;
|
|
24
|
+
letter-spacing: -0.02em;
|
|
25
|
+
`;
|
|
26
|
+
case 'h2':
|
|
27
|
+
return `
|
|
28
|
+
font-size: var(--text-4xl);
|
|
29
|
+
font-weight: var(--font-black);
|
|
30
|
+
line-height: 1.1;
|
|
31
|
+
letter-spacing: -0.02em;
|
|
32
|
+
`;
|
|
33
|
+
case 'h3':
|
|
34
|
+
return `
|
|
35
|
+
font-size: var(--text-3xl);
|
|
36
|
+
font-weight: var(--font-black);
|
|
37
|
+
line-height: 1.1;
|
|
38
|
+
`;
|
|
39
|
+
case 'h4':
|
|
40
|
+
return `
|
|
41
|
+
font-size: var(--text-2xl);
|
|
42
|
+
font-weight: var(--font-bold);
|
|
43
|
+
line-height: 1.2;
|
|
44
|
+
`;
|
|
45
|
+
case 'h5':
|
|
46
|
+
return `
|
|
47
|
+
font-size: var(--text-xl);
|
|
48
|
+
font-weight: var(--font-bold);
|
|
49
|
+
line-height: 1.3;
|
|
50
|
+
`;
|
|
51
|
+
case 'h6':
|
|
52
|
+
return `
|
|
53
|
+
font-size: var(--text-lg);
|
|
54
|
+
font-weight: var(--font-bold);
|
|
55
|
+
line-height: 1.4;
|
|
56
|
+
`;
|
|
57
|
+
case 'small':
|
|
58
|
+
return `
|
|
59
|
+
font-size: var(--text-xs);
|
|
60
|
+
line-height: 1.5;
|
|
61
|
+
`;
|
|
62
|
+
case 'caption':
|
|
63
|
+
return `
|
|
64
|
+
font-size: var(--text-xs);
|
|
65
|
+
line-height: 1.5;
|
|
66
|
+
color: var(--muted-foreground);
|
|
67
|
+
`;
|
|
68
|
+
case 'body':
|
|
69
|
+
default:
|
|
70
|
+
return `
|
|
71
|
+
font-size: var(--text-base);
|
|
72
|
+
line-height: 1.6;
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
}}
|
|
76
|
+
|
|
77
|
+
/* Weight styles */
|
|
78
|
+
${props => {
|
|
79
|
+
switch (props.$weight) {
|
|
80
|
+
case 'normal':
|
|
81
|
+
return 'font-weight: var(--font-regular);';
|
|
82
|
+
case 'medium':
|
|
83
|
+
return 'font-weight: var(--font-medium);';
|
|
84
|
+
case 'semibold':
|
|
85
|
+
return 'font-weight: var(--font-bold);'; // Mapping semibold to bold
|
|
86
|
+
case 'bold':
|
|
87
|
+
return 'font-weight: var(--font-bold);';
|
|
88
|
+
case 'black':
|
|
89
|
+
return 'font-weight: var(--font-black);';
|
|
90
|
+
default:
|
|
91
|
+
return '';
|
|
92
|
+
}
|
|
93
|
+
}}
|
|
94
|
+
|
|
95
|
+
/* Color styles */
|
|
96
|
+
${props => {
|
|
97
|
+
switch (props.$color) {
|
|
98
|
+
case 'primary':
|
|
99
|
+
return 'color: var(--primary);';
|
|
100
|
+
case 'secondary':
|
|
101
|
+
return 'color: var(--secondary);';
|
|
102
|
+
case 'muted':
|
|
103
|
+
return 'color: var(--muted-foreground);';
|
|
104
|
+
case 'error':
|
|
105
|
+
return 'color: var(--error);';
|
|
106
|
+
case 'success':
|
|
107
|
+
return 'color: var(--success);';
|
|
108
|
+
case 'warning':
|
|
109
|
+
return 'color: var(--warning);';
|
|
110
|
+
default:
|
|
111
|
+
return 'color: var(--foreground);';
|
|
112
|
+
}
|
|
113
|
+
}}
|
|
114
|
+
|
|
115
|
+
/* Alignment */
|
|
116
|
+
text-align: ${props => props.$align || 'left'};
|
|
117
|
+
`;
|
|
118
|
+
export function Text(_a) {
|
|
119
|
+
var { variant = 'body', weight, color, align, className, style, children, as } = _a, props = __rest(_a, ["variant", "weight", "color", "align", "className", "style", "children", "as"]);
|
|
120
|
+
// Determine the HTML element to use
|
|
121
|
+
const element = as || ((variant === null || variant === void 0 ? void 0 : variant.startsWith('h')) ? variant : 'span');
|
|
122
|
+
return (_jsx(StyledText, Object.assign({ as: element, "$variant": variant, "$weight": weight, "$color": color, "$align": align, className: className, style: style }, props, { children: children })));
|
|
123
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Text';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Text';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import styled from '@emotion/styled';
|
|
4
|
+
const StyledTextarea = styled.textarea `
|
|
5
|
+
width: 100%;
|
|
6
|
+
padding: 0.75rem 1rem;
|
|
7
|
+
font-size: var(--text-base);
|
|
8
|
+
background: var(--card-bg);
|
|
9
|
+
color: var(--foreground);
|
|
10
|
+
border: var(--border-width) solid var(--card-border);
|
|
11
|
+
border-radius: var(--radius);
|
|
12
|
+
box-shadow: var(--shadow-hard);
|
|
13
|
+
outline: none;
|
|
14
|
+
transition: all 0.1s ease;
|
|
15
|
+
font-family: inherit;
|
|
16
|
+
resize: vertical;
|
|
17
|
+
|
|
18
|
+
&:focus {
|
|
19
|
+
box-shadow: var(--shadow-hover);
|
|
20
|
+
transform: translate(-2px, -2px);
|
|
21
|
+
border-color: var(--primary);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&::placeholder {
|
|
25
|
+
color: var(--muted);
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
export function Textarea(props) {
|
|
29
|
+
return _jsx(StyledTextarea, Object.assign({}, props));
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Textarea';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Textarea';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type ToastType = 'success' | 'error' | 'warning' | 'info';
|
|
3
|
+
interface ToastContextType {
|
|
4
|
+
toast: (message: string, type?: ToastType) => void;
|
|
5
|
+
toastSuccess: (message: string) => void;
|
|
6
|
+
toastError: (message: string) => void;
|
|
7
|
+
toastWarning: (message: string) => void;
|
|
8
|
+
toastInfo: (message: string) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function ToastProvider({ children }: {
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function useToast(): ToastContextType;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useState, useCallback, useEffect } from 'react';
|
|
4
|
+
import styled from '@emotion/styled';
|
|
5
|
+
import { createPortal } from 'react-dom';
|
|
6
|
+
import { CheckCircle2, XCircle, AlertTriangle, Info, X } from 'lucide-react';
|
|
7
|
+
// Context
|
|
8
|
+
const ToastContext = createContext(undefined);
|
|
9
|
+
// Styled Components
|
|
10
|
+
const ToastContainer = styled.div `
|
|
11
|
+
position: fixed;
|
|
12
|
+
bottom: 2rem;
|
|
13
|
+
right: 2rem;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
gap: 1rem;
|
|
17
|
+
z-index: var(--z-tooltip);
|
|
18
|
+
pointer-events: none; /* Allow clicking through the container area */
|
|
19
|
+
`;
|
|
20
|
+
const ToastItem = styled.div `
|
|
21
|
+
min-width: 300px;
|
|
22
|
+
background: var(--card-bg);
|
|
23
|
+
border: var(--border-width) solid var(--card-border);
|
|
24
|
+
color: var(--foreground);
|
|
25
|
+
box-shadow: var(--shadow-hard);
|
|
26
|
+
padding: 1rem;
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
gap: 0.75rem;
|
|
30
|
+
animation: ${props => props.isExiting ? 'slideOut 0.3s ease-in forwards' : 'slideIn 0.3s ease-out forwards'};
|
|
31
|
+
position: relative;
|
|
32
|
+
overflow: hidden;
|
|
33
|
+
pointer-events: auto; /* Re-enable pointer events for the toast itself */
|
|
34
|
+
border-radius: var(--radius);
|
|
35
|
+
|
|
36
|
+
&::before {
|
|
37
|
+
content: '';
|
|
38
|
+
position: absolute;
|
|
39
|
+
left: 0;
|
|
40
|
+
top: 0;
|
|
41
|
+
bottom: 0;
|
|
42
|
+
width: 6px;
|
|
43
|
+
background-color: ${props => {
|
|
44
|
+
switch (props.type) {
|
|
45
|
+
case 'success': return 'var(--success)';
|
|
46
|
+
case 'error': return 'var(--error)';
|
|
47
|
+
case 'warning': return 'var(--warning)';
|
|
48
|
+
default: return 'var(--primary)';
|
|
49
|
+
}
|
|
50
|
+
}};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@keyframes slideIn {
|
|
54
|
+
from { transform: translateX(100%); opacity: 0; }
|
|
55
|
+
to { transform: translateX(0); opacity: 1; }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@keyframes slideOut {
|
|
59
|
+
from { transform: translateX(0); opacity: 1; }
|
|
60
|
+
to { transform: translateX(100%); opacity: 0; }
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
const CloseButton = styled.button `
|
|
64
|
+
background: none;
|
|
65
|
+
border: none;
|
|
66
|
+
margin-left: auto;
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
font-size: 1.25rem;
|
|
69
|
+
color: var(--foreground);
|
|
70
|
+
opacity: 0.5;
|
|
71
|
+
transition: opacity 0.2s;
|
|
72
|
+
&:hover { opacity: 1; }
|
|
73
|
+
`;
|
|
74
|
+
// Provider
|
|
75
|
+
export function ToastProvider({ children }) {
|
|
76
|
+
const [toasts, setToasts] = useState([]);
|
|
77
|
+
const [isMounted, setIsMounted] = useState(false);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
setIsMounted(true);
|
|
80
|
+
}, []);
|
|
81
|
+
const removeToast = useCallback((id) => {
|
|
82
|
+
setToasts(prev => prev.map(t => t.id === id ? Object.assign(Object.assign({}, t), { isExiting: true }) : t));
|
|
83
|
+
setTimeout(() => {
|
|
84
|
+
setToasts(prev => prev.filter(t => t.id !== id));
|
|
85
|
+
}, 300); // Match animation duration
|
|
86
|
+
}, []);
|
|
87
|
+
const addToast = useCallback((message, type = 'info') => {
|
|
88
|
+
const id = Math.random().toString(36).substring(2, 9);
|
|
89
|
+
setToasts(prev => [...prev, { id, message, type }]);
|
|
90
|
+
// Auto remove after 5 seconds
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
removeToast(id);
|
|
93
|
+
}, 5000);
|
|
94
|
+
}, [removeToast]);
|
|
95
|
+
const toast = useCallback((message, type = 'info') => addToast(message, type), [addToast]);
|
|
96
|
+
const toastSuccess = useCallback((message) => addToast(message, 'success'), [addToast]);
|
|
97
|
+
const toastError = useCallback((message) => addToast(message, 'error'), [addToast]);
|
|
98
|
+
const toastWarning = useCallback((message) => addToast(message, 'warning'), [addToast]);
|
|
99
|
+
const toastInfo = useCallback((message) => addToast(message, 'info'), [addToast]);
|
|
100
|
+
return (_jsxs(ToastContext.Provider, { value: { toast, toastSuccess, toastError, toastWarning, toastInfo }, children: [children, isMounted && createPortal(_jsx(ToastContainer, { children: toasts.map(t => (_jsxs(ToastItem, { type: t.type, isExiting: t.isExiting, children: [t.type === 'success' && _jsx(CheckCircle2, { size: 20, strokeWidth: 2.5, color: "var(--success)" }), t.type === 'error' && _jsx(XCircle, { size: 20, strokeWidth: 2.5, color: "var(--error)" }), t.type === 'warning' && _jsx(AlertTriangle, { size: 20, strokeWidth: 2.5, color: "var(--warning)" }), t.type === 'info' && _jsx(Info, { size: 20, strokeWidth: 2.5, color: "var(--primary)" }), _jsx("span", { className: "font-semibold", children: t.message }), _jsx(CloseButton, { onClick: () => removeToast(t.id), children: _jsx(X, { size: 16, strokeWidth: 2.5 }) })] }, t.id))) }), document.body)] }));
|
|
101
|
+
}
|
|
102
|
+
// Hook
|
|
103
|
+
export function useToast() {
|
|
104
|
+
const context = useContext(ToastContext);
|
|
105
|
+
if (!context) {
|
|
106
|
+
throw new Error('useToast must be used within a ToastProvider');
|
|
107
|
+
}
|
|
108
|
+
return context;
|
|
109
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Toast';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Toast';
|
package/dist/fonts.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const defaultFont: import("next/dist/compiled/@next/font").NextFontWithVariable;
|
package/dist/fonts.js
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export * from './components/Badge';
|
|
2
|
+
export * from './components/Button';
|
|
3
|
+
export * from './components/Card';
|
|
4
|
+
export * from './components/Dropdown';
|
|
5
|
+
export * from './components/Form';
|
|
6
|
+
export * from './components/Input';
|
|
7
|
+
export * from './components/Layout';
|
|
8
|
+
export * from './components/Link';
|
|
9
|
+
export * from './components/Modal';
|
|
10
|
+
export * from './components/Page';
|
|
11
|
+
export * from './components/Popover';
|
|
12
|
+
export * from './components/ProgressBar';
|
|
13
|
+
export * from './components/Select';
|
|
14
|
+
export * from './components/SplitButton';
|
|
15
|
+
export * from './components/Table';
|
|
16
|
+
export * from './components/Tabs';
|
|
17
|
+
export * from './components/Text';
|
|
18
|
+
export * from './components/Textarea';
|
|
19
|
+
export * from './components/Toast';
|
|
20
|
+
export * from './components/ActionRow';
|
|
21
|
+
export * from './components/Skeleton';
|
|
22
|
+
export * from './DesignSystemProvider';
|
|
23
|
+
export * from './styles/themes';
|
|
24
|
+
export * from './fonts';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export * from './components/Badge';
|
|
2
|
+
export * from './components/Button';
|
|
3
|
+
export * from './components/Card';
|
|
4
|
+
export * from './components/Dropdown';
|
|
5
|
+
export * from './components/Form';
|
|
6
|
+
export * from './components/Input';
|
|
7
|
+
export * from './components/Layout';
|
|
8
|
+
export * from './components/Link';
|
|
9
|
+
export * from './components/Modal';
|
|
10
|
+
export * from './components/Page';
|
|
11
|
+
export * from './components/Popover';
|
|
12
|
+
export * from './components/ProgressBar';
|
|
13
|
+
export * from './components/Select';
|
|
14
|
+
export * from './components/SplitButton';
|
|
15
|
+
export * from './components/Table';
|
|
16
|
+
export * from './components/Tabs';
|
|
17
|
+
export * from './components/Text';
|
|
18
|
+
export * from './components/Textarea';
|
|
19
|
+
export * from './components/Toast';
|
|
20
|
+
export * from './components/ActionRow';
|
|
21
|
+
export * from './components/Skeleton';
|
|
22
|
+
export * from './DesignSystemProvider';
|
|
23
|
+
export * from './styles/themes';
|
|
24
|
+
export * from './fonts';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const resetStyles: import("@emotion/utils").SerializedStyles;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { css } from '@emotion/react';
|
|
2
|
+
export const resetStyles = css `
|
|
3
|
+
* {
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
padding: 0;
|
|
6
|
+
margin: 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
html {
|
|
10
|
+
overflow-y: scroll; /* Force scrollbar to prevent layout shift */
|
|
11
|
+
overflow-x: hidden;
|
|
12
|
+
background-color: var(--background);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
body {
|
|
16
|
+
min-height: 100vh;
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
background-color: var(--background);
|
|
20
|
+
color: var(--foreground);
|
|
21
|
+
font-family: var(--font-montserrat), system-ui, sans-serif;
|
|
22
|
+
-webkit-font-smoothing: antialiased;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
a {
|
|
26
|
+
color: inherit;
|
|
27
|
+
text-decoration: none;
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const themeDefaults: import("@emotion/utils").SerializedStyles;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { css } from '@emotion/react';
|
|
2
|
+
import { themes } from './themes';
|
|
3
|
+
// Use the default theme as the baseline for the design system
|
|
4
|
+
const defaultTheme = themes.default.variables;
|
|
5
|
+
export const themeDefaults = css `
|
|
6
|
+
:root {
|
|
7
|
+
${Object.entries(defaultTheme)
|
|
8
|
+
.map(([key, value]) => `${key}: ${value};`)
|
|
9
|
+
.join('\n ')}
|
|
10
|
+
}
|
|
11
|
+
`;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { themes, ThemeKey } from './definitions';
|
|
3
|
+
interface ThemeContextType {
|
|
4
|
+
theme: ThemeKey;
|
|
5
|
+
setTheme: (theme: ThemeKey) => void;
|
|
6
|
+
availableThemes: typeof themes;
|
|
7
|
+
}
|
|
8
|
+
export declare function ThemeProvider({ children, initialTheme }: {
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
initialTheme: ThemeKey;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function useTheme(): ThemeContextType;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useState } from 'react';
|
|
4
|
+
import { Global, css } from '@emotion/react';
|
|
5
|
+
import { themes } from './definitions';
|
|
6
|
+
import { setThemePreference } from './actions';
|
|
7
|
+
const ThemeContext = createContext(undefined);
|
|
8
|
+
export function ThemeProvider({ children, initialTheme }) {
|
|
9
|
+
var _a;
|
|
10
|
+
const [currentTheme, setCurrentTheme] = useState(initialTheme);
|
|
11
|
+
const handleSetTheme = async (newTheme) => {
|
|
12
|
+
setCurrentTheme(newTheme);
|
|
13
|
+
await setThemePreference(newTheme);
|
|
14
|
+
};
|
|
15
|
+
// Get the variables for the current theme
|
|
16
|
+
const themeVars = ((_a = themes[currentTheme]) === null || _a === void 0 ? void 0 : _a.variables) || themes.default.variables;
|
|
17
|
+
// Generate CSS variables block
|
|
18
|
+
const themeStyles = css `
|
|
19
|
+
:root {
|
|
20
|
+
${Object.entries(themeVars)
|
|
21
|
+
.map(([key, value]) => `${key}: ${value};`)
|
|
22
|
+
.join('\n ')}
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
return (_jsxs(ThemeContext.Provider, { value: {
|
|
26
|
+
theme: currentTheme,
|
|
27
|
+
setTheme: handleSetTheme,
|
|
28
|
+
availableThemes: themes
|
|
29
|
+
}, children: [_jsx(Global, { styles: themeStyles }), children] }));
|
|
30
|
+
}
|
|
31
|
+
export function useTheme() {
|
|
32
|
+
const context = useContext(ThemeContext);
|
|
33
|
+
if (context === undefined) {
|
|
34
|
+
throw new Error('useTheme must be used within a ThemeProvider');
|
|
35
|
+
}
|
|
36
|
+
return context;
|
|
37
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
import { cookies } from 'next/headers';
|
|
3
|
+
const THEME_COOKIE_NAME = 'theme-preference';
|
|
4
|
+
export async function getThemePreference() {
|
|
5
|
+
const cookieStore = await cookies();
|
|
6
|
+
const theme = cookieStore.get(THEME_COOKIE_NAME);
|
|
7
|
+
return (theme === null || theme === void 0 ? void 0 : theme.value) || 'doom';
|
|
8
|
+
}
|
|
9
|
+
export async function setThemePreference(theme) {
|
|
10
|
+
const cookieStore = await cookies();
|
|
11
|
+
cookieStore.set(THEME_COOKIE_NAME, theme, {
|
|
12
|
+
path: '/',
|
|
13
|
+
maxAge: 60 * 60 * 24 * 365, // 1 year
|
|
14
|
+
sameSite: 'lax',
|
|
15
|
+
});
|
|
16
|
+
}
|