@danielthurau/atlas-labs-codex 0.1.0 → 0.2.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.
Files changed (41) hide show
  1. package/README.md +11 -10
  2. package/components/react/Badge/Badge.module.css +0 -1
  3. package/components/react/Badge/Badge.stories.tsx +0 -1
  4. package/components/react/Badge/Badge.tsx +2 -8
  5. package/components/react/Badge/index.ts +0 -1
  6. package/components/react/Button/Button.module.css +0 -1
  7. package/components/react/Button/Button.stories.tsx +0 -1
  8. package/components/react/Button/Button.tsx +2 -16
  9. package/components/react/Button/index.ts +0 -1
  10. package/components/react/Card/Card.module.css +0 -1
  11. package/components/react/Card/Card.stories.tsx +3 -11
  12. package/components/react/Card/Card.tsx +0 -1
  13. package/components/react/Card/index.ts +0 -1
  14. package/components/react/Input/Input.module.css +3 -2
  15. package/components/react/Input/Input.stories.tsx +2 -11
  16. package/components/react/Input/Input.tsx +0 -1
  17. package/components/react/Input/index.ts +0 -1
  18. package/components/react/Modal/Modal.module.css +3 -2
  19. package/components/react/Modal/Modal.stories.tsx +4 -6
  20. package/components/react/Modal/Modal.tsx +4 -23
  21. package/components/react/Modal/index.ts +0 -1
  22. package/components/react/RefreshButton/RefreshButton.module.css +11 -6
  23. package/components/react/RefreshButton/RefreshButton.stories.tsx +0 -1
  24. package/components/react/RefreshButton/RefreshButton.tsx +10 -18
  25. package/components/react/RefreshButton/index.ts +0 -1
  26. package/components/react/Tabs/Tabs.module.css +3 -2
  27. package/components/react/Tabs/Tabs.stories.tsx +4 -11
  28. package/components/react/Tabs/Tabs.tsx +1 -6
  29. package/components/react/Tabs/index.ts +0 -1
  30. package/components/react/Toast/Toast.module.css +3 -2
  31. package/components/react/Toast/Toast.stories.tsx +1 -4
  32. package/components/react/Toast/Toast.tsx +3 -23
  33. package/components/react/Toast/index.ts +0 -1
  34. package/components/react/index.ts +1 -8
  35. package/lib/index.ts +0 -1
  36. package/lib/utils.ts +4 -5
  37. package/package.json +8 -2
  38. package/themes/css/base.css +10 -5
  39. package/themes/css/reset.css +140 -0
  40. package/themes/css/theme-dark.css +0 -1
  41. package/themes/css/theme-light.css +0 -1
package/README.md CHANGED
@@ -20,15 +20,15 @@ Then import components, styles, and utilities:
20
20
 
21
21
  ```tsx
22
22
  // Import components
23
- import { Button, Card, Input, Badge, RefreshButton } from '@atlas-labs/design-codex';
23
+ import { Button, Card, Input, Badge, RefreshButton } from "@atlas-labs/design-codex";
24
24
 
25
25
  // Import utilities
26
- import { formatRelativeTime, clsx } from '@atlas-labs/design-codex/lib';
26
+ import { formatRelativeTime, clsx } from "@atlas-labs/design-codex/lib";
27
27
 
28
28
  // Import CSS (in your layout.tsx or entry point)
29
- import '@atlas-labs/design-codex/themes/css/base.css';
30
- import '@atlas-labs/design-codex/themes/css/theme-light.css';
31
- import '@atlas-labs/design-codex/themes/css/theme-dark.css';
29
+ import "@atlas-labs/design-codex/themes/css/base.css";
30
+ import "@atlas-labs/design-codex/themes/css/theme-light.css";
31
+ import "@atlas-labs/design-codex/themes/css/theme-dark.css";
32
32
  ```
33
33
 
34
34
  ### Font Setup
@@ -37,8 +37,8 @@ Copy the Martian Mono font to your project's public folder, or load it in your C
37
37
 
38
38
  ```css
39
39
  @font-face {
40
- font-family: 'Martian Mono';
41
- src: url('/fonts/MartianMono-VariableFont_wdth,wght.ttf') format('truetype');
40
+ font-family: "Martian Mono";
41
+ src: url("/fonts/MartianMono-VariableFont_wdth,wght.ttf") format("truetype");
42
42
  font-weight: 100 800;
43
43
  font-display: swap;
44
44
  }
@@ -121,13 +121,15 @@ The codex supports light and dark themes via CSS custom properties. Theme switch
121
121
 
122
122
  ```html
123
123
  <html data-theme="light">
124
- <!-- or -->
125
- <html data-theme="dark">
124
+ <!-- or -->
125
+ <html data-theme="dark"></html>
126
+ </html>
126
127
  ```
127
128
 
128
129
  ## Components
129
130
 
130
131
  All components:
132
+
131
133
  - Use tokens exclusively (no hardcoded values)
132
134
  - Are built on Radix UI primitives for accessibility
133
135
  - Encode taste, not flexibility
@@ -135,4 +137,3 @@ All components:
135
137
  ## License
136
138
 
137
139
  Private repository. Personal use only.
138
-
@@ -35,4 +35,3 @@
35
35
  background-color: var(--color-intent-danger-bg);
36
36
  color: var(--color-intent-danger);
37
37
  }
38
-
@@ -76,4 +76,3 @@ export const StatusBadges: Story = {
76
76
  </div>
77
77
  ),
78
78
  };
79
-
@@ -19,19 +19,14 @@ const badgeVariants = cva(styles.badge, {
19
19
  });
20
20
 
21
21
  export interface BadgeProps
22
- extends HTMLAttributes<HTMLSpanElement>,
23
- VariantProps<typeof badgeVariants> {
22
+ extends HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {
24
23
  children: ReactNode;
25
24
  }
26
25
 
27
26
  export const Badge = forwardRef<HTMLSpanElement, BadgeProps>(
28
27
  ({ className, variant, children, ...props }, ref) => {
29
28
  return (
30
- <span
31
- ref={ref}
32
- className={clsx(badgeVariants({ variant }), className)}
33
- {...props}
34
- >
29
+ <span ref={ref} className={clsx(badgeVariants({ variant }), className)} {...props}>
35
30
  {children}
36
31
  </span>
37
32
  );
@@ -39,4 +34,3 @@ export const Badge = forwardRef<HTMLSpanElement, BadgeProps>(
39
34
  );
40
35
 
41
36
  Badge.displayName = "Badge";
42
-
@@ -1,2 +1 @@
1
1
  export { Badge, type BadgeProps } from "./Badge";
2
-
@@ -115,4 +115,3 @@
115
115
  transform: rotate(360deg);
116
116
  }
117
117
  }
118
-
@@ -105,4 +105,3 @@ export const AllSizes: Story = {
105
105
  </div>
106
106
  ),
107
107
  };
108
-
@@ -25,27 +25,14 @@ const buttonVariants = cva(styles.button, {
25
25
  });
26
26
 
27
27
  export interface ButtonProps
28
- extends ButtonHTMLAttributes<HTMLButtonElement>,
29
- VariantProps<typeof buttonVariants> {
28
+ extends ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
30
29
  children: ReactNode;
31
30
  loading?: boolean;
32
31
  asChild?: boolean;
33
32
  }
34
33
 
35
34
  export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
36
- (
37
- {
38
- className,
39
- variant,
40
- size,
41
- loading,
42
- disabled,
43
- asChild = false,
44
- children,
45
- ...props
46
- },
47
- ref
48
- ) => {
35
+ ({ className, variant, size, loading, disabled, asChild = false, children, ...props }, ref) => {
49
36
  const Comp = asChild ? Slot : "button";
50
37
 
51
38
  return (
@@ -70,4 +57,3 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
70
57
  );
71
58
 
72
59
  Button.displayName = "Button";
73
-
@@ -1,2 +1 @@
1
1
  export { Button, type ButtonProps } from "./Button";
2
-
@@ -56,4 +56,3 @@
56
56
  .card:has(.header, .content, .footer) {
57
57
  padding: 0;
58
58
  }
59
-
@@ -25,8 +25,7 @@ export const Default: Story = {
25
25
  args: {
26
26
  children: (
27
27
  <p>
28
- This is a basic card with some content. Cards are used to group related
29
- content together.
28
+ This is a basic card with some content. Cards are used to group related content together.
30
29
  </p>
31
30
  ),
32
31
  },
@@ -35,11 +34,7 @@ export const Default: Story = {
35
34
  export const Elevated: Story = {
36
35
  args: {
37
36
  elevated: true,
38
- children: (
39
- <p>
40
- This card has elevation (shadow) for a more prominent appearance.
41
- </p>
42
- ),
37
+ children: <p>This card has elevation (shadow) for a more prominent appearance.</p>,
43
38
  },
44
39
  };
45
40
 
@@ -82,9 +77,7 @@ export const Complete: Story = {
82
77
  <p style={{ marginBottom: "16px" }}>
83
78
  Configure your project settings here. Changes will be saved automatically.
84
79
  </p>
85
- <p>
86
- Last updated: January 1, 2024
87
- </p>
80
+ <p>Last updated: January 1, 2024</p>
88
81
  </CardContent>
89
82
  <CardFooter>
90
83
  <div style={{ display: "flex", gap: "8px", justifyContent: "flex-end" }}>
@@ -111,4 +104,3 @@ export const PaddingVariants: Story = {
111
104
  </div>
112
105
  ),
113
106
  };
114
-
@@ -76,4 +76,3 @@ export const CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(
76
76
  );
77
77
 
78
78
  CardFooter.displayName = "CardFooter";
79
-
@@ -8,4 +8,3 @@ export {
8
8
  type CardContentProps,
9
9
  type CardFooterProps,
10
10
  } from "./Card";
11
-
@@ -18,7 +18,9 @@
18
18
  border-radius: var(--input-radius);
19
19
  background-color: var(--color-bg-surface);
20
20
  color: var(--color-text-primary);
21
- transition: border-color 150ms ease, box-shadow 150ms ease;
21
+ transition:
22
+ border-color 150ms ease,
23
+ box-shadow 150ms ease;
22
24
  }
23
25
 
24
26
  .input::placeholder {
@@ -60,4 +62,3 @@
60
62
  font-size: var(--text-sm);
61
63
  color: var(--color-text-secondary);
62
64
  }
63
-
@@ -71,18 +71,9 @@ export const AllStates: Story = {
71
71
  render: () => (
72
72
  <div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
73
73
  <Input label="Default" placeholder="Enter text" />
74
- <Input
75
- label="With Helper"
76
- placeholder="Enter text"
77
- helperText="This is helper text"
78
- />
79
- <Input
80
- label="With Error"
81
- placeholder="Enter text"
82
- error="This field is required"
83
- />
74
+ <Input label="With Helper" placeholder="Enter text" helperText="This is helper text" />
75
+ <Input label="With Error" placeholder="Enter text" error="This field is required" />
84
76
  <Input label="Disabled" placeholder="Enter text" disabled />
85
77
  </div>
86
78
  ),
87
79
  };
88
-
@@ -47,4 +47,3 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
47
47
  );
48
48
 
49
49
  Input.displayName = "Input";
50
-
@@ -1,2 +1 @@
1
1
  export { Input, type InputProps } from "./Input";
2
-
@@ -68,7 +68,9 @@
68
68
  background: transparent;
69
69
  border: none;
70
70
  cursor: pointer;
71
- transition: background-color 150ms ease, color 150ms ease;
71
+ transition:
72
+ background-color 150ms ease,
73
+ color 150ms ease;
72
74
  }
73
75
 
74
76
  .close:hover {
@@ -100,4 +102,3 @@
100
102
  transform: translate(-50%, -50%) scale(1);
101
103
  }
102
104
  }
103
-
@@ -71,12 +71,11 @@ export const LargeModal: Story = {
71
71
  children: (
72
72
  <div>
73
73
  <p style={{ marginBottom: "16px" }}>
74
- Large modals are suitable for complex content that needs more space,
75
- such as detailed forms or previews.
74
+ Large modals are suitable for complex content that needs more space, such as detailed
75
+ forms or previews.
76
76
  </p>
77
77
  <p style={{ marginBottom: "16px" }}>
78
- However, if your modal content is very complex, consider using a
79
- dedicated page instead.
78
+ However, if your modal content is very complex, consider using a dedicated page instead.
80
79
  </p>
81
80
  <div style={{ display: "flex", gap: "8px", justifyContent: "flex-end" }}>
82
81
  <Button variant="secondary">Cancel</Button>
@@ -101,7 +100,7 @@ const ControlledExample = () => {
101
100
  description="This modal is controlled via state."
102
101
  >
103
102
  <p style={{ marginBottom: "16px" }}>
104
- This modal's open state is controlled by the parent component.
103
+ This modal&apos;s open state is controlled by the parent component.
105
104
  </p>
106
105
  <div style={{ display: "flex", gap: "8px", justifyContent: "flex-end" }}>
107
106
  <Button variant="secondary" onClick={() => setOpen(false)}>
@@ -116,4 +115,3 @@ const ControlledExample = () => {
116
115
  export const Controlled: Story = {
117
116
  render: () => <ControlledExample />,
118
117
  };
119
-
@@ -16,34 +16,16 @@ export interface ModalProps {
16
16
  }
17
17
 
18
18
  export const Modal = forwardRef<HTMLDivElement, ModalProps>(
19
- (
20
- {
21
- open,
22
- onOpenChange,
23
- trigger,
24
- title,
25
- description,
26
- children,
27
- size = "md",
28
- },
29
- ref
30
- ) => {
19
+ ({ open, onOpenChange, trigger, title, description, children, size = "md" }, ref) => {
31
20
  return (
32
21
  <Dialog.Root open={open} onOpenChange={onOpenChange}>
33
22
  {trigger && <Dialog.Trigger asChild>{trigger}</Dialog.Trigger>}
34
23
  <Dialog.Portal>
35
24
  <Dialog.Overlay className={styles.overlay} />
36
- <Dialog.Content
37
- ref={ref}
38
- className={clsx(styles.content, styles[size])}
39
- >
40
- {title && (
41
- <Dialog.Title className={styles.title}>{title}</Dialog.Title>
42
- )}
25
+ <Dialog.Content ref={ref} className={clsx(styles.content, styles[size])}>
26
+ {title && <Dialog.Title className={styles.title}>{title}</Dialog.Title>}
43
27
  {description && (
44
- <Dialog.Description className={styles.description}>
45
- {description}
46
- </Dialog.Description>
28
+ <Dialog.Description className={styles.description}>{description}</Dialog.Description>
47
29
  )}
48
30
  {children}
49
31
  <Dialog.Close asChild>
@@ -72,4 +54,3 @@ export const Modal = forwardRef<HTMLDivElement, ModalProps>(
72
54
  );
73
55
 
74
56
  Modal.displayName = "Modal";
75
-
@@ -1,2 +1 @@
1
1
  export { Modal, type ModalProps } from "./Modal";
2
-
@@ -28,7 +28,9 @@
28
28
  font-size: var(--text-sm);
29
29
  color: var(--color-text-primary);
30
30
  cursor: pointer;
31
- transition: background 150ms, color 150ms;
31
+ transition:
32
+ background 150ms,
33
+ color 150ms;
32
34
  }
33
35
 
34
36
  /* When progress bar is shown, remove bottom radius */
@@ -55,8 +57,12 @@
55
57
  }
56
58
 
57
59
  @keyframes spin {
58
- from { transform: rotate(0deg); }
59
- to { transform: rotate(360deg); }
60
+ from {
61
+ transform: rotate(0deg);
62
+ }
63
+ to {
64
+ transform: rotate(360deg);
65
+ }
60
66
  }
61
67
 
62
68
  /* Dropdown trigger */
@@ -190,13 +196,12 @@
190
196
  .refreshButton span:not(.icon) {
191
197
  display: none;
192
198
  }
193
-
199
+
194
200
  .refreshButton {
195
201
  padding: var(--space-2);
196
202
  }
197
-
203
+
198
204
  .dropdownTrigger {
199
205
  min-width: 50px;
200
206
  }
201
207
  }
202
-
@@ -40,4 +40,3 @@ export const Disabled: Story = {
40
40
  disabled: true,
41
41
  },
42
42
  };
43
-
@@ -28,14 +28,14 @@ export function RefreshButton({ onRefresh, onForceCheck, disabled }: RefreshButt
28
28
  const [isChecking, setIsChecking] = useState(false);
29
29
  const [selectedInterval, setSelectedInterval] = useState<IntervalOption>(INTERVAL_OPTIONS[0]);
30
30
  const [progress, setProgress] = useState(0);
31
- const [timeLeft, setTimeLeft] = useState<number | null>(null);
32
-
31
+ const [_timeLeft, setTimeLeft] = useState<number | null>(null);
32
+
33
33
  const intervalRef = useRef<NodeJS.Timeout | null>(null);
34
34
  const progressRef = useRef<NodeJS.Timeout | null>(null);
35
35
  const dropdownRef = useRef<HTMLDivElement>(null);
36
36
  const onRefreshRef = useRef(onRefresh);
37
37
  const onForceCheckRef = useRef(onForceCheck);
38
-
38
+
39
39
  // Keep refs updated
40
40
  useEffect(() => {
41
41
  onRefreshRef.current = onRefresh;
@@ -45,10 +45,10 @@ export function RefreshButton({ onRefresh, onForceCheck, disabled }: RefreshButt
45
45
  // Handle manual refresh
46
46
  const handleRefresh = useCallback(async () => {
47
47
  if (isRefreshing || disabled) return;
48
-
48
+
49
49
  setIsRefreshing(true);
50
50
  setProgress(0);
51
-
51
+
52
52
  try {
53
53
  await onRefreshRef.current();
54
54
  } finally {
@@ -72,10 +72,10 @@ export function RefreshButton({ onRefresh, onForceCheck, disabled }: RefreshButt
72
72
  // Handle force check (runs actual health checks)
73
73
  const handleForceCheck = useCallback(async () => {
74
74
  if (isChecking || disabled || !onForceCheckRef.current) return;
75
-
75
+
76
76
  setIsChecking(true);
77
77
  setIsOpen(false);
78
-
78
+
79
79
  try {
80
80
  await onForceCheckRef.current();
81
81
  } finally {
@@ -154,9 +154,7 @@ export function RefreshButton({ onRefresh, onForceCheck, disabled }: RefreshButt
154
154
  disabled={isRefreshing || disabled}
155
155
  title="Refresh now"
156
156
  >
157
- <span className={`${styles.icon} ${isRefreshing ? styles.spinning : ""}`}>
158
-
159
- </span>
157
+ <span className={`${styles.icon} ${isRefreshing ? styles.spinning : ""}`}>↻</span>
160
158
  {isRefreshing ? "Refreshing..." : "Refresh"}
161
159
  </button>
162
160
 
@@ -167,9 +165,7 @@ export function RefreshButton({ onRefresh, onForceCheck, disabled }: RefreshButt
167
165
  disabled={disabled}
168
166
  title="Set auto-refresh interval"
169
167
  >
170
- <span className={styles.intervalLabel}>
171
- {selectedInterval.label}
172
- </span>
168
+ <span className={styles.intervalLabel}>{selectedInterval.label}</span>
173
169
  <span className={styles.chevron}>{isOpen ? "▲" : "▼"}</span>
174
170
  </button>
175
171
  </div>
@@ -177,10 +173,7 @@ export function RefreshButton({ onRefresh, onForceCheck, disabled }: RefreshButt
177
173
  {/* Progress bar - only shows when auto-refresh is active */}
178
174
  {isAutoRefresh && (
179
175
  <div className={styles.progressBar}>
180
- <div
181
- className={styles.progressFill}
182
- style={{ width: `${progress}%` }}
183
- />
176
+ <div className={styles.progressFill} style={{ width: `${progress}%` }} />
184
177
  </div>
185
178
  )}
186
179
  </div>
@@ -219,4 +212,3 @@ export function RefreshButton({ onRefresh, onForceCheck, disabled }: RefreshButt
219
212
  </div>
220
213
  );
221
214
  }
222
-
@@ -1,2 +1 @@
1
1
  export { RefreshButton } from "./RefreshButton";
2
-
@@ -20,7 +20,9 @@
20
20
  border-bottom: 2px solid transparent;
21
21
  margin-bottom: -1px;
22
22
  cursor: pointer;
23
- transition: color 150ms ease, border-color 150ms ease;
23
+ transition:
24
+ color 150ms ease,
25
+ border-color 150ms ease;
24
26
  }
25
27
 
26
28
  .trigger:hover:not(:disabled) {
@@ -55,4 +57,3 @@
55
57
  .content[data-state="inactive"] {
56
58
  display: none;
57
59
  }
58
-
@@ -30,9 +30,7 @@ export const Default: Story = {
30
30
  content: (
31
31
  <Card>
32
32
  <h3>Account Settings</h3>
33
- <p style={{ marginTop: "8px" }}>
34
- Manage your account settings and preferences.
35
- </p>
33
+ <p style={{ marginTop: "8px" }}>Manage your account settings and preferences.</p>
36
34
  </Card>
37
35
  ),
38
36
  },
@@ -42,9 +40,7 @@ export const Default: Story = {
42
40
  content: (
43
41
  <Card>
44
42
  <h3>Password Settings</h3>
45
- <p style={{ marginTop: "8px" }}>
46
- Update your password and security options.
47
- </p>
43
+ <p style={{ marginTop: "8px" }}>Update your password and security options.</p>
48
44
  </Card>
49
45
  ),
50
46
  },
@@ -54,9 +50,7 @@ export const Default: Story = {
54
50
  content: (
55
51
  <Card>
56
52
  <h3>Notification Preferences</h3>
57
- <p style={{ marginTop: "8px" }}>
58
- Configure how you receive notifications.
59
- </p>
53
+ <p style={{ marginTop: "8px" }}>Configure how you receive notifications.</p>
60
54
  </Card>
61
55
  ),
62
56
  },
@@ -75,7 +69,7 @@ export const WithDisabledTab: Story = {
75
69
  {
76
70
  id: "disabled",
77
71
  label: "Disabled",
78
- content: <Card>You shouldn't see this.</Card>,
72
+ content: <Card>You shouldn&apos;t see this.</Card>,
79
73
  disabled: true,
80
74
  },
81
75
  {
@@ -98,4 +92,3 @@ export const ManyTabs: Story = {
98
92
  ],
99
93
  },
100
94
  };
101
-
@@ -45,11 +45,7 @@ export const Tabs = forwardRef<HTMLDivElement, TabsProps>(
45
45
  ))}
46
46
  </TabsPrimitive.List>
47
47
  {tabs.map((tab) => (
48
- <TabsPrimitive.Content
49
- key={tab.id}
50
- value={tab.id}
51
- className={styles.content}
52
- >
48
+ <TabsPrimitive.Content key={tab.id} value={tab.id} className={styles.content}>
53
49
  {tab.content}
54
50
  </TabsPrimitive.Content>
55
51
  ))}
@@ -59,4 +55,3 @@ export const Tabs = forwardRef<HTMLDivElement, TabsProps>(
59
55
  );
60
56
 
61
57
  Tabs.displayName = "Tabs";
62
-
@@ -1,2 +1 @@
1
1
  export { Tabs, type TabsProps, type TabItem } from "./Tabs";
2
-
@@ -97,7 +97,9 @@
97
97
  background: transparent;
98
98
  border: none;
99
99
  cursor: pointer;
100
- transition: background-color 150ms ease, color 150ms ease;
100
+ transition:
101
+ background-color 150ms ease,
102
+ color 150ms ease;
101
103
  }
102
104
 
103
105
  .close:hover {
@@ -142,4 +144,3 @@
142
144
  transform: translateX(100%);
143
145
  }
144
146
  }
145
-
@@ -98,9 +98,7 @@ const AllVariantsDemo = () => {
98
98
  };
99
99
 
100
100
  const closeToast = (id: number) => {
101
- setToasts((prev) =>
102
- prev.map((t) => (t.id === id ? { ...t, open: false } : t))
103
- );
101
+ setToasts((prev) => prev.map((t) => (t.id === id ? { ...t, open: false } : t)));
104
102
  };
105
103
 
106
104
  const titles = {
@@ -140,4 +138,3 @@ const AllVariantsDemo = () => {
140
138
  export const AllVariants: Story = {
141
139
  render: () => <AllVariantsDemo />,
142
140
  };
143
-
@@ -1,13 +1,6 @@
1
1
  "use client";
2
2
 
3
- import {
4
- forwardRef,
5
- type ReactNode,
6
- createContext,
7
- useContext,
8
- useState,
9
- useCallback,
10
- } from "react";
3
+ import { forwardRef, type ReactNode, createContext, useContext } from "react";
11
4
  import * as ToastPrimitive from "@radix-ui/react-toast";
12
5
  import { clsx } from "clsx";
13
6
  import styles from "./Toast.module.css";
@@ -39,15 +32,7 @@ export interface ToastProps {
39
32
 
40
33
  export const Toast = forwardRef<HTMLLIElement, ToastProps>(
41
34
  (
42
- {
43
- open,
44
- onOpenChange,
45
- title,
46
- description,
47
- action,
48
- variant = "default",
49
- duration = 5000,
50
- },
35
+ { open, onOpenChange, title, description, action, variant = "default", duration = 5000 },
51
36
  ref
52
37
  ) => {
53
38
  return (
@@ -59,11 +44,7 @@ export const Toast = forwardRef<HTMLLIElement, ToastProps>(
59
44
  className={clsx(styles.root, styles[variant])}
60
45
  >
61
46
  <div className={styles.content}>
62
- {title && (
63
- <ToastPrimitive.Title className={styles.title}>
64
- {title}
65
- </ToastPrimitive.Title>
66
- )}
47
+ {title && <ToastPrimitive.Title className={styles.title}>{title}</ToastPrimitive.Title>}
67
48
  {description && (
68
49
  <ToastPrimitive.Description className={styles.description}>
69
50
  {description}
@@ -120,4 +101,3 @@ export function useToast() {
120
101
  }
121
102
  return context;
122
103
  }
123
-
@@ -1,2 +1 @@
1
1
  export { Toast, ToastProvider, useToast, type ToastProps, type ToastProviderProps } from "./Toast";
2
-
@@ -15,17 +15,10 @@ export {
15
15
  // Feedback Components
16
16
  export { Badge, type BadgeProps } from "./Badge";
17
17
  export { Modal, type ModalProps } from "./Modal";
18
- export {
19
- Toast,
20
- ToastProvider,
21
- useToast,
22
- type ToastProps,
23
- type ToastProviderProps,
24
- } from "./Toast";
18
+ export { Toast, ToastProvider, useToast, type ToastProps, type ToastProviderProps } from "./Toast";
25
19
 
26
20
  // Navigation Components
27
21
  export { Tabs, type TabsProps, type TabItem } from "./Tabs";
28
22
 
29
23
  // Action Components
30
24
  export { RefreshButton } from "./RefreshButton";
31
-
package/lib/index.ts CHANGED
@@ -4,4 +4,3 @@
4
4
  */
5
5
 
6
6
  export { formatRelativeTime, clsx } from "./utils";
7
-
package/lib/utils.ts CHANGED
@@ -8,25 +8,24 @@
8
8
  */
9
9
  export function formatRelativeTime(date: Date | string | null): string {
10
10
  if (!date) return "Never";
11
-
11
+
12
12
  const now = new Date();
13
13
  const then = typeof date === "string" ? new Date(date) : date;
14
14
  const diffMs = now.getTime() - then.getTime();
15
-
15
+
16
16
  const seconds = Math.floor(diffMs / 1000);
17
17
  const minutes = Math.floor(seconds / 60);
18
18
  const hours = Math.floor(minutes / 60);
19
19
  const days = Math.floor(hours / 24);
20
-
20
+
21
21
  if (seconds < 10) return "Just now";
22
22
  if (seconds < 60) return `${seconds}s ago`;
23
23
  if (minutes < 60) return `${minutes}m ago`;
24
24
  if (hours < 24) return `${hours}h ago`;
25
25
  if (days < 7) return `${days}d ago`;
26
-
26
+
27
27
  return then.toLocaleDateString();
28
28
  }
29
29
 
30
30
  // Re-export clsx for convenience
31
31
  export { clsx } from "clsx";
32
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danielthurau/atlas-labs-codex",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Personal design system with React components, CSS tokens, and utilities",
5
5
  "author": "thurau",
6
6
  "license": "MIT",
@@ -31,6 +31,7 @@
31
31
  "import": "./lib/index.ts",
32
32
  "types": "./lib/index.ts"
33
33
  },
34
+ "./themes/css/reset.css": "./themes/css/reset.css",
34
35
  "./themes/css/base.css": "./themes/css/base.css",
35
36
  "./themes/css/theme-light.css": "./themes/css/theme-light.css",
36
37
  "./themes/css/theme-dark.css": "./themes/css/theme-dark.css"
@@ -52,9 +53,13 @@
52
53
  "build": "next build",
53
54
  "start": "next start",
54
55
  "lint": "next lint",
56
+ "lint:fix": "next lint --fix",
57
+ "format": "prettier --write .",
58
+ "format:check": "prettier --check .",
59
+ "check": "npm run lint && npm run format:check",
55
60
  "storybook": "storybook dev -p 6006",
56
61
  "build-storybook": "storybook build",
57
- "prepublishOnly": "echo 'Ready to publish!'"
62
+ "prepublishOnly": "npm run check && echo 'Ready to publish!'"
58
63
  },
59
64
  "peerDependencies": {
60
65
  "react": "^18.0.0",
@@ -89,6 +94,7 @@
89
94
  "react": "^18.3.1",
90
95
  "react-dom": "^18.3.1",
91
96
  "storybook": "^8.4.7",
97
+ "prettier": "^3.4.2",
92
98
  "typescript": "^5.7.2",
93
99
  "vite": "^5.4.0"
94
100
  }
@@ -2,8 +2,8 @@
2
2
 
3
3
  /* Font Faces */
4
4
  @font-face {
5
- font-family: 'Martian Mono';
6
- src: url('/fonts/MartianMono-VariableFont_wdth,wght.ttf') format('truetype');
5
+ font-family: "Martian Mono";
6
+ src: url("/fonts/MartianMono-VariableFont_wdth,wght.ttf") format("truetype");
7
7
  font-weight: 100 800;
8
8
  font-stretch: 75% 112.5%;
9
9
  font-display: swap;
@@ -55,10 +55,14 @@
55
55
  --space-2: 0.5rem;
56
56
  --space-3: 0.75rem;
57
57
  --space-4: 1rem;
58
+ --space-5: 1.25rem;
58
59
  --space-6: 1.5rem;
59
60
  --space-8: 2rem;
61
+ --space-10: 2.5rem;
60
62
  --space-12: 3rem;
61
63
  --space-16: 4rem;
64
+ --space-20: 5rem;
65
+ --space-24: 6rem;
62
66
 
63
67
  /* Semantic Spacing */
64
68
  --spacing-inline: var(--space-2);
@@ -82,6 +86,8 @@
82
86
  --text-lg: 1.125rem;
83
87
  --text-xl: 1.5rem;
84
88
  --text-2xl: 2rem;
89
+ --text-3xl: 2.5rem;
90
+ --text-4xl: 3rem;
85
91
 
86
92
  /* Typography - Line Height */
87
93
  --leading-xs: 1rem;
@@ -103,8 +109,8 @@
103
109
  --tracking-wide: 0.05em;
104
110
 
105
111
  /* Typography - Font Family */
106
- --font-primary: 'Martian Mono', 'JetBrains Mono', 'Fira Code', Consolas, monospace;
107
- --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
112
+ --font-primary: "Martian Mono", "JetBrains Mono", "Fira Code", Consolas, monospace;
113
+ --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
108
114
  --font-mono: var(--font-primary);
109
115
 
110
116
  /* Shadows */
@@ -139,4 +145,3 @@
139
145
  --badge-radius: var(--radius-full);
140
146
  --badge-font-size: var(--text-xs);
141
147
  }
142
-
@@ -0,0 +1,140 @@
1
+ /* Design Codex - CSS Reset & Base Styles */
2
+
3
+ /* Box Sizing Reset */
4
+ *,
5
+ *::before,
6
+ *::after {
7
+ box-sizing: border-box;
8
+ }
9
+
10
+ /* Margin/Padding Reset */
11
+ * {
12
+ margin: 0;
13
+ padding: 0;
14
+ }
15
+
16
+ /* Base HTML */
17
+ html {
18
+ -webkit-font-smoothing: antialiased;
19
+ -moz-osx-font-smoothing: grayscale;
20
+ text-size-adjust: 100%;
21
+ }
22
+
23
+ /* Body Defaults */
24
+ body {
25
+ font-family: var(--font-primary);
26
+ font-size: var(--text-base);
27
+ line-height: 1.5;
28
+ color: var(--color-text-primary);
29
+ background-color: var(--color-bg-default);
30
+ min-height: 100vh;
31
+ }
32
+
33
+ /* Typography - Headings */
34
+ h1,
35
+ h2,
36
+ h3,
37
+ h4,
38
+ h5,
39
+ h6 {
40
+ font-weight: var(--font-semibold);
41
+ color: var(--color-text-primary);
42
+ line-height: 1.25;
43
+ }
44
+
45
+ h1 {
46
+ font-size: var(--text-2xl);
47
+ }
48
+ h2 {
49
+ font-size: var(--text-xl);
50
+ }
51
+ h3 {
52
+ font-size: var(--text-lg);
53
+ }
54
+ h4 {
55
+ font-size: var(--text-base);
56
+ }
57
+ h5 {
58
+ font-size: var(--text-sm);
59
+ }
60
+ h6 {
61
+ font-size: var(--text-xs);
62
+ }
63
+
64
+ /* Typography - Paragraphs */
65
+ p {
66
+ color: var(--color-text-secondary);
67
+ }
68
+
69
+ /* Links */
70
+ a {
71
+ color: inherit;
72
+ text-decoration: none;
73
+ }
74
+
75
+ a:hover {
76
+ text-decoration: underline;
77
+ }
78
+
79
+ /* Buttons */
80
+ button {
81
+ font: inherit;
82
+ cursor: pointer;
83
+ border: none;
84
+ background: none;
85
+ color: inherit;
86
+ }
87
+
88
+ /* Form Elements */
89
+ input,
90
+ textarea,
91
+ select {
92
+ font: inherit;
93
+ color: inherit;
94
+ }
95
+
96
+ /* Images */
97
+ img,
98
+ picture,
99
+ video,
100
+ canvas,
101
+ svg {
102
+ display: block;
103
+ max-width: 100%;
104
+ }
105
+
106
+ /* Lists */
107
+ ul,
108
+ ol {
109
+ list-style: none;
110
+ }
111
+
112
+ /* Tables */
113
+ table {
114
+ border-collapse: collapse;
115
+ border-spacing: 0;
116
+ }
117
+
118
+ /* Focus States */
119
+ :focus-visible {
120
+ outline: none;
121
+ box-shadow: var(--focus-ring);
122
+ }
123
+
124
+ /* Selection */
125
+ ::selection {
126
+ background-color: var(--color-intent-primary);
127
+ color: white;
128
+ }
129
+
130
+ /* Reduced Motion */
131
+ @media (prefers-reduced-motion: reduce) {
132
+ *,
133
+ *::before,
134
+ *::after {
135
+ animation-duration: 0.01ms !important;
136
+ animation-iteration-count: 1 !important;
137
+ transition-duration: 0.01ms !important;
138
+ scroll-behavior: auto !important;
139
+ }
140
+ }
@@ -45,4 +45,3 @@
45
45
 
46
46
  color-scheme: dark;
47
47
  }
48
-
@@ -46,4 +46,3 @@
46
46
 
47
47
  color-scheme: light;
48
48
  }
49
-