sunpeak 0.1.25 → 0.2.2

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 (44) hide show
  1. package/README.md +9 -76
  2. package/bin/sunpeak.js +87 -0
  3. package/dist/index.cjs +827 -1361
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +98 -589
  6. package/dist/index.d.ts +98 -589
  7. package/dist/index.js +795 -1337
  8. package/dist/index.js.map +1 -1
  9. package/dist/styles/chatgpt/index.css +146 -0
  10. package/dist/styles/globals.css +220 -0
  11. package/package.json +34 -36
  12. package/template/.prettierignore +4 -0
  13. package/template/.prettierrc +9 -0
  14. package/template/README.md +47 -0
  15. package/template/assets/favicon.ico +0 -0
  16. package/template/components.json +21 -0
  17. package/template/dev/main.tsx +65 -0
  18. package/template/dev/styles.css +5 -0
  19. package/template/eslint.config.cjs +49 -0
  20. package/template/index.html +13 -0
  21. package/template/package.json +56 -0
  22. package/template/src/App.tsx +45 -0
  23. package/template/src/components/index.ts +2 -0
  24. package/template/src/components/shadcn/button.tsx +60 -0
  25. package/template/src/components/shadcn/card.tsx +76 -0
  26. package/template/src/components/shadcn/carousel.tsx +260 -0
  27. package/template/src/components/shadcn/index.ts +5 -0
  28. package/template/src/components/shadcn/label.tsx +24 -0
  29. package/template/src/components/shadcn/select.tsx +157 -0
  30. package/template/src/components/sunpeak-card.test.tsx +76 -0
  31. package/template/src/components/sunpeak-card.tsx +140 -0
  32. package/template/src/components/sunpeak-carousel.test.tsx +42 -0
  33. package/template/src/components/sunpeak-carousel.tsx +126 -0
  34. package/template/src/index.ts +3 -0
  35. package/template/src/lib/index.ts +1 -0
  36. package/template/src/lib/utils.ts +6 -0
  37. package/template/src/styles/chatgpt.css +146 -0
  38. package/template/src/styles/globals.css +220 -0
  39. package/template/src/test/setup.ts +37 -0
  40. package/template/tsconfig.json +32 -0
  41. package/template/tsconfig.node.json +11 -0
  42. package/template/tsup.config.ts +23 -0
  43. package/template/vite.config.ts +35 -0
  44. package/template/vitest.config.ts +15 -0
@@ -0,0 +1,140 @@
1
+ import * as React from "react"
2
+ import { cn } from "@/lib/index"
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ CardDescription,
7
+ CardFooter,
8
+ CardHeader,
9
+ CardTitle,
10
+ } from "@/components/shadcn/card"
11
+ import { Button } from "@/components/shadcn/button"
12
+
13
+ export interface SunpeakButtonProps extends Omit<React.ComponentProps<typeof Button>, 'onClick'> {
14
+ isPrimary?: boolean
15
+ onClick: () => void
16
+ }
17
+
18
+ export interface SunpeakCardProps extends React.HTMLAttributes<HTMLDivElement> {
19
+ children?: React.ReactNode
20
+ image: string
21
+ imageAlt: string
22
+ imageMaxWidth?: number
23
+ imageMaxHeight?: number
24
+ header?: React.ReactNode
25
+ metadata?: React.ReactNode
26
+ button1?: SunpeakButtonProps
27
+ button2?: SunpeakButtonProps
28
+ variant?: "default" | "bordered" | "elevated"
29
+ }
30
+
31
+ export const SunpeakCard = React.forwardRef<HTMLDivElement, SunpeakCardProps>(
32
+ (
33
+ {
34
+ children,
35
+ image,
36
+ imageAlt,
37
+ imageMaxWidth = 400,
38
+ imageMaxHeight = 400,
39
+ header,
40
+ metadata,
41
+ button1,
42
+ button2,
43
+ variant = "default",
44
+ className,
45
+ onClick,
46
+ ...props
47
+ },
48
+ ref
49
+ ) => {
50
+ const hasButtons = button1 || button2
51
+
52
+ const handleCardClick = (e: React.MouseEvent<HTMLDivElement>) => {
53
+ onClick?.(e)
54
+ }
55
+
56
+ const renderButton = (buttonProps: SunpeakButtonProps) => {
57
+ const { isPrimary = false, onClick: buttonOnClick, children, ...restProps } = buttonProps
58
+
59
+ const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
60
+ e.stopPropagation()
61
+ buttonOnClick()
62
+ }
63
+
64
+ return (
65
+ <Button
66
+ {...restProps}
67
+ variant={isPrimary ? "default" : "outline"}
68
+ onClick={handleClick}
69
+ >
70
+ {children}
71
+ </Button>
72
+ )
73
+ }
74
+
75
+ const variantClasses = {
76
+ default: "",
77
+ bordered: "border-2",
78
+ elevated: "shadow-lg",
79
+ }
80
+
81
+ return (
82
+ <Card
83
+ ref={ref}
84
+ className={cn(
85
+ "overflow-hidden cursor-pointer select-none",
86
+ variantClasses[variant],
87
+ className
88
+ )}
89
+ onClick={handleCardClick}
90
+ {...props}
91
+ >
92
+ {image && (
93
+ <div className="w-full overflow-hidden">
94
+ <img
95
+ src={image}
96
+ alt={imageAlt}
97
+ loading="lazy"
98
+ className="w-full h-auto aspect-square object-cover"
99
+ style={{
100
+ maxWidth: `${imageMaxWidth}px`,
101
+ maxHeight: `${imageMaxHeight}px`,
102
+ }}
103
+ />
104
+ </div>
105
+ )}
106
+ <div className="flex flex-col flex-1">
107
+ {(header || metadata) && (
108
+ <CardHeader className={cn(image && "pt-3")}>
109
+ {header && (
110
+ <CardTitle className="text-base font-medium leading-tight overflow-hidden text-ellipsis whitespace-nowrap">
111
+ {header}
112
+ </CardTitle>
113
+ )}
114
+ {metadata && (
115
+ <CardDescription className="text-xs leading-normal">
116
+ {metadata}
117
+ </CardDescription>
118
+ )}
119
+ </CardHeader>
120
+ )}
121
+ {children && (
122
+ <CardContent className={cn(
123
+ "text-sm leading-normal",
124
+ (header || metadata) && "pt-1"
125
+ )}>
126
+ <div className="line-clamp-2">{children}</div>
127
+ </CardContent>
128
+ )}
129
+ {hasButtons && (
130
+ <CardFooter className="flex gap-2 flex-wrap">
131
+ {button1 && renderButton(button1)}
132
+ {button2 && renderButton(button2)}
133
+ </CardFooter>
134
+ )}
135
+ </div>
136
+ </Card>
137
+ )
138
+ }
139
+ )
140
+ SunpeakCard.displayName = "SunpeakCard"
@@ -0,0 +1,42 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, it, expect } from 'vitest';
3
+ import { SunpeakCarousel } from './sunpeak-carousel';
4
+
5
+ describe('SunpeakCarousel', () => {
6
+ it('renders all children as carousel items', () => {
7
+ render(
8
+ <SunpeakCarousel>
9
+ <div>Item 1</div>
10
+ <div>Item 2</div>
11
+ <div>Item 3</div>
12
+ </SunpeakCarousel>
13
+ );
14
+
15
+ expect(screen.getByText('Item 1')).toBeInTheDocument();
16
+ expect(screen.getByText('Item 2')).toBeInTheDocument();
17
+ expect(screen.getByText('Item 3')).toBeInTheDocument();
18
+ });
19
+
20
+ it('applies custom gap spacing to carousel content', () => {
21
+ render(
22
+ <SunpeakCarousel gap={24} data-testid="carousel">
23
+ <div>Item 1</div>
24
+ <div>Item 2</div>
25
+ </SunpeakCarousel>
26
+ );
27
+
28
+ const carouselContent = document.querySelector('[class*="ml-0"]');
29
+ expect(carouselContent).toHaveStyle({ gap: '24px' });
30
+ });
31
+
32
+ it('applies custom card width to carousel items', () => {
33
+ render(
34
+ <SunpeakCarousel cardWidth={300}>
35
+ <div>Item 1</div>
36
+ </SunpeakCarousel>
37
+ );
38
+
39
+ const carouselItem = document.querySelector('[class*="pl-0"]');
40
+ expect(carouselItem).toHaveStyle({ flexBasis: '300px', minWidth: '300px' });
41
+ });
42
+ });
@@ -0,0 +1,126 @@
1
+ import * as React from "react"
2
+ import { WheelGesturesPlugin } from "embla-carousel-wheel-gestures"
3
+ import { cn } from "@/lib/index"
4
+ import {
5
+ Carousel,
6
+ CarouselContent,
7
+ CarouselItem,
8
+ CarouselNext,
9
+ CarouselPrevious,
10
+ type CarouselApi,
11
+ } from "@/components/shadcn/carousel"
12
+
13
+ export type SunpeakCarouselProps = {
14
+ children?: React.ReactNode
15
+ gap?: number
16
+ showArrows?: boolean
17
+ showEdgeGradients?: boolean
18
+ cardWidth?: number | { inline?: number; fullscreen?: number }
19
+ className?: string
20
+ }
21
+
22
+ export const SunpeakCarousel = React.forwardRef<
23
+ HTMLDivElement,
24
+ SunpeakCarouselProps
25
+ >(
26
+ (
27
+ {
28
+ children,
29
+ gap = 16,
30
+ showArrows = true,
31
+ showEdgeGradients = true,
32
+ cardWidth,
33
+ className,
34
+ },
35
+ ref
36
+ ) => {
37
+ const [api, setApi] = React.useState<CarouselApi>()
38
+ const [canScrollPrev, setCanScrollPrev] = React.useState(false)
39
+ const [canScrollNext, setCanScrollNext] = React.useState(false)
40
+
41
+ React.useEffect(() => {
42
+ if (!api) return
43
+
44
+ const onSelect = () => {
45
+ setCanScrollPrev(api.canScrollPrev())
46
+ setCanScrollNext(api.canScrollNext())
47
+ }
48
+
49
+ onSelect()
50
+ api.on("select", onSelect)
51
+ api.on("reInit", onSelect)
52
+
53
+ return () => {
54
+ api.off("select", onSelect)
55
+ api.off("reInit", onSelect)
56
+ }
57
+ }, [api])
58
+
59
+ const childArray = React.Children.toArray(children)
60
+
61
+ const getCardWidth = () => {
62
+ if (typeof cardWidth === "number") {
63
+ return `${cardWidth}px`
64
+ }
65
+ if (cardWidth?.inline) {
66
+ return `${cardWidth.inline}px`
67
+ }
68
+ return "220px"
69
+ }
70
+
71
+ return (
72
+ <div ref={ref} className={cn("relative w-full", className)}>
73
+ {showEdgeGradients && canScrollPrev && (
74
+ <div
75
+ className="pointer-events-none absolute left-0 top-0 z-10 h-full w-12 bg-gradient-to-r from-background to-transparent transition-opacity"
76
+ aria-hidden="true"
77
+ />
78
+ )}
79
+ {showEdgeGradients && canScrollNext && (
80
+ <div
81
+ className="pointer-events-none absolute right-0 top-0 z-10 h-full w-12 bg-gradient-to-l from-background to-transparent transition-opacity"
82
+ aria-hidden="true"
83
+ />
84
+ )}
85
+
86
+ <Carousel
87
+ opts={{
88
+ align: "start",
89
+ dragFree: true,
90
+ }}
91
+ plugins={[WheelGesturesPlugin()]}
92
+ setApi={setApi}
93
+ className="w-full"
94
+ >
95
+ <CarouselContent
96
+ className="ml-0"
97
+ style={{
98
+ gap: `${gap}px`,
99
+ }}
100
+ >
101
+ {childArray.map((child, index) => (
102
+ <CarouselItem
103
+ key={index}
104
+ className="pl-0"
105
+ style={{
106
+ flexBasis: getCardWidth(),
107
+ minWidth: getCardWidth(),
108
+ }}
109
+ >
110
+ {child}
111
+ </CarouselItem>
112
+ ))}
113
+ </CarouselContent>
114
+
115
+ {showArrows && canScrollPrev && (
116
+ <CarouselPrevious className="left-2" />
117
+ )}
118
+ {showArrows && canScrollNext && (
119
+ <CarouselNext className="right-2" />
120
+ )}
121
+ </Carousel>
122
+ </div>
123
+ )
124
+ }
125
+ )
126
+ SunpeakCarousel.displayName = "SunpeakCarousel"
@@ -0,0 +1,3 @@
1
+ export * from './components';
2
+ export * from './lib';
3
+ export * from './App'
@@ -0,0 +1 @@
1
+ export { cn } from './utils';
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -0,0 +1,146 @@
1
+ /**
2
+ * OpenAI ChatGPT Apps SDK Design System
3
+ *
4
+ * Implements Sunpeak base variables according to OpenAI ChatGPT Apps SDK design guidelines.
5
+ * https://developers.openai.com/apps-sdk/concepts/design-guidelines
6
+ *
7
+ * Design Principles:
8
+ * - "Always inherit the system font stack"
9
+ * - "Use system colors for text, icons, and spatial elements"
10
+ * - "Use system grid spacing"
11
+ * - "Respect system specified corner rounds"
12
+ *
13
+ * ⚠️ These values should NOT be overridden unless you want to break
14
+ * compliance with OpenAI ChatGPT Apps SDK design guidelines.
15
+ */
16
+
17
+ :root {
18
+ /* ===================================
19
+ * TYPOGRAPHY - System Fonts
20
+ * ===================================
21
+ * "Always inherit the system font stack"
22
+ * Platform-native: SF Pro (iOS/macOS), Roboto (Android), Segoe UI (Windows)
23
+ */
24
+
25
+ --sp-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
26
+
27
+ /* Font sizes - System-defined scale */
28
+ --sp-font-size-xs: 0.75rem; /* 12px - metadata */
29
+ --sp-font-size-sm: 0.875rem; /* 14px - descriptions */
30
+ --sp-font-size-base: 1rem; /* 16px - headers */
31
+ --sp-font-size-lg: 1.125rem; /* 18px */
32
+ --sp-font-size-xl: 1.25rem; /* 20px */
33
+
34
+ /* Font weights - System-defined */
35
+ --sp-font-weight-normal: 400;
36
+ --sp-font-weight-medium: 500;
37
+ --sp-font-weight-semibold: 600;
38
+ --sp-font-weight-bold: 700;
39
+
40
+ /* Line heights - System-defined */
41
+ --sp-line-height-tight: 1.25;
42
+ --sp-line-height-normal: 1.5;
43
+ --sp-line-height-relaxed: 1.75;
44
+
45
+ /* ===================================
46
+ * SYSTEM COLORS
47
+ * ===================================
48
+ * "Use system colors for text, icons, and spatial elements"
49
+ */
50
+
51
+ /* Light Mode - OpenAI ChatGPT System Colors */
52
+ --sp-light-color-bg-primary: #ffffff;
53
+ --sp-light-color-bg-secondary: #e8e8e8;
54
+ --sp-light-color-bg-tertiary: #f3f3f3;
55
+ --sp-light-color-text-primary: #0d0d0d;
56
+ --sp-light-color-text-secondary: #5d5d5d;
57
+ --sp-light-color-text-tertiary: #8f8f8f;
58
+ --sp-light-color-text-inverted: #8f8f8f;
59
+ --sp-light-color-border: rgba(0, 0, 0, 0.05);
60
+ --sp-light-success: #008635;
61
+ --sp-light-warning: #e25507;
62
+ --sp-light-error: #e02e2a;
63
+ --sp-light-info: #0285ff;
64
+ --sp-light-sidebar: #f9f9f9;
65
+ /* Customizable light styles */
66
+ --sp-light-accent: #f46c21;
67
+ --sp-light-accent-hover: rgba(244, 108, 33, 0.9);
68
+ --sp-light-accent-active: #d45e1c;
69
+ --sp-light-accent-foreground: #ffffff;
70
+
71
+ /* Dark Mode - OpenAI ChatGPT System Colors */
72
+ --sp-dark-color-bg-primary: #212121;
73
+ --sp-dark-color-bg-secondary: #303030;
74
+ --sp-dark-color-bg-tertiary: #414141;
75
+ --sp-dark-color-text-primary: #ffffff;
76
+ --sp-dark-color-text-secondary: #cdcdcd;
77
+ --sp-dark-color-text-tertiary: #afafaf;
78
+ --sp-dark-color-text-inverted: #afafaf;
79
+ --sp-dark-color-border: #ffffff0d;
80
+ --sp-dark-success: #40c977;
81
+ --sp-dark-warning: #ff9e6c;
82
+ --sp-dark-error: #ff8583;
83
+ --sp-dark-info: #0285ff;
84
+ --sp-dark-sidebar: #181818;
85
+ /* Customizable dark styles */
86
+ --sp-dark-accent: #f46c21;
87
+ --sp-dark-accent-hover: rgba(244, 108, 33, 0.9);
88
+ --sp-dark-accent-active: #d45e1c;
89
+ --sp-dark-accent-foreground: #ffffff;
90
+
91
+ /* ===================================
92
+ * SPACING - System Grid
93
+ * ===================================
94
+ * "Use system grid spacing"
95
+ * 4px base grid system
96
+ */
97
+
98
+ --sp-spacing-1: 0.25rem; /* 4px */
99
+ --sp-spacing-2: 0.5rem; /* 8px */
100
+ --sp-spacing-3: 0.75rem; /* 12px */
101
+ --sp-spacing-4: 1rem; /* 16px */
102
+ --sp-spacing-5: 1.25rem; /* 20px */
103
+ --sp-spacing-6: 1.5rem; /* 24px */
104
+ --sp-spacing-8: 2rem; /* 32px */
105
+
106
+ /* ===================================
107
+ * BORDER RADIUS
108
+ * ===================================
109
+ * "Respect system specified corner rounds"
110
+ */
111
+
112
+ --sp-radius-sm: 0.375rem; /* 6px */
113
+ --sp-radius-md: 0.5rem; /* 8px */
114
+ --sp-radius-lg: 0.75rem; /* 12px */
115
+ --sp-radius-xl: 1rem; /* 16px */
116
+ --sp-radius-2xl: 1.5rem; /* 24px */
117
+ --sp-radius-full: 9999px;
118
+
119
+ /* ===================================
120
+ * SHADOWS - System Elevation
121
+ * ===================================
122
+ */
123
+
124
+ --sp-shadow-sm: 0px 1px 2px rgba(0, 0, 0, 0.05);
125
+ --sp-shadow-md: 0px 2px 6px rgba(0, 0, 0, 0.06);
126
+ --sp-shadow-lg: 0px 4px 12px rgba(0, 0, 0, 0.1);
127
+ --sp-shadow-xl: 0px 8px 24px rgba(0, 0, 0, 0.12);
128
+
129
+ /* ===================================
130
+ * COMPONENT DIMENSIONS
131
+ * ===================================
132
+ * Standard component sizing from OpenAI ChatGPT examples
133
+ */
134
+
135
+ /* Card width - 220px (OpenAI ChatGPT standard) */
136
+ --sp-card-width: 220px;
137
+
138
+ /* Card gap - 16px (OpenAI ChatGPT standard) */
139
+ --sp-card-gap: 1rem;
140
+
141
+ /* Button padding */
142
+ --sp-button-padding-x: 1rem; /* 16px */
143
+ --sp-button-padding-y: 0.375rem; /* 6px */
144
+ --sp-button-padding-x-sm: 0.75rem; /* 12px */
145
+ --sp-button-padding-y-sm: 0.25rem; /* 4px */
146
+ }
@@ -0,0 +1,220 @@
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+
4
+ @custom-variant dark (&:is(.dark *));
5
+
6
+ /* Tailwind v4 theme configuration */
7
+ @theme {
8
+ /* ===================================
9
+ * COLORS - Mapped to shadcn and --sp- variables
10
+ * ===================================
11
+ */
12
+ --color-*: initial;
13
+
14
+ /* Shadcn colors */
15
+ --color-background: var(--background);
16
+ --color-foreground: var(--foreground);
17
+ --color-border: var(--border);
18
+ --color-card: var(--card);
19
+ --color-card-foreground: var(--card-foreground);
20
+ --color-popover: var(--popover);
21
+ --color-popover-foreground: var(--popover-foreground);
22
+ --color-primary: var(--primary);
23
+ --color-primary-foreground: var(--primary-foreground);
24
+ --color-secondary: var(--secondary);
25
+ --color-secondary-foreground: var(--secondary-foreground);
26
+ --color-muted: var(--muted);
27
+ --color-muted-foreground: var(--muted-foreground);
28
+ --color-accent: var(--accent);
29
+ --color-accent-foreground: var(--accent-foreground);
30
+ --color-destructive: var(--destructive);
31
+ --color-destructive-foreground: var(--destructive-foreground);
32
+ --color-input: var(--input);
33
+ --color-ring: var(--ring);
34
+
35
+ /* Sunpeak semantic colors */
36
+ --color-success: var(--sp-success);
37
+ --color-warning: var(--sp-warning);
38
+ --color-error: var(--sp-error);
39
+ --color-info: var(--sp-info);
40
+
41
+ /* ===================================
42
+ * TYPOGRAPHY - Mapped to --sp- variables
43
+ * ===================================
44
+ */
45
+
46
+ /* Font families */
47
+ --font-sans: var(--sp-font-family);
48
+
49
+ /* Font sizes */
50
+ --text-xs: var(--sp-font-size-xs);
51
+ --text-sm: var(--sp-font-size-sm);
52
+ --text-base: var(--sp-font-size-base);
53
+ --text-lg: var(--sp-font-size-lg);
54
+ --text-xl: var(--sp-font-size-xl);
55
+
56
+ /* Font weights */
57
+ --font-weight-normal: var(--sp-font-weight-normal);
58
+ --font-weight-medium: var(--sp-font-weight-medium);
59
+ --font-weight-semibold: var(--sp-font-weight-semibold);
60
+ --font-weight-bold: var(--sp-font-weight-bold);
61
+
62
+ /* Line heights */
63
+ --leading-tight: var(--sp-line-height-tight);
64
+ --leading-normal: var(--sp-line-height-normal);
65
+ --leading-relaxed: var(--sp-line-height-relaxed);
66
+
67
+ /* ===================================
68
+ * SPACING - Mapped to --sp- variables
69
+ * ===================================
70
+ */
71
+ --spacing-1: var(--sp-spacing-1);
72
+ --spacing-2: var(--sp-spacing-2);
73
+ --spacing-3: var(--sp-spacing-3);
74
+ --spacing-4: var(--sp-spacing-4);
75
+ --spacing-5: var(--sp-spacing-5);
76
+ --spacing-6: var(--sp-spacing-6);
77
+ --spacing-8: var(--sp-spacing-8);
78
+
79
+ /* ===================================
80
+ * BORDER RADIUS - Mapped to --sp- variables
81
+ * ===================================
82
+ */
83
+ --radius-sm: var(--sp-radius-sm);
84
+ --radius-md: var(--sp-radius-md);
85
+ --radius-lg: var(--sp-radius-lg);
86
+ --radius-xl: var(--sp-radius-xl);
87
+ --radius-2xl: var(--sp-radius-2xl);
88
+ --radius-full: var(--sp-radius-full);
89
+
90
+ /* ===================================
91
+ * SHADOWS - Mapped to --sp- variables
92
+ * ===================================
93
+ */
94
+ --shadow-sm: var(--sp-shadow-sm);
95
+ --shadow-md: var(--sp-shadow-md);
96
+ --shadow-lg: var(--sp-shadow-lg);
97
+ --shadow-xl: var(--sp-shadow-xl);
98
+ }
99
+
100
+ /* ===================================
101
+ * THEME MODE CLASSES
102
+ * ===================================
103
+ * Force light/dark mode on specific elements
104
+ */
105
+
106
+ .light {
107
+ --sp-color-bg-primary: var(--sp-light-color-bg-primary);
108
+ --sp-color-bg-secondary: var(--sp-light-color-bg-secondary);
109
+ --sp-color-bg-tertiary: var(--sp-light-color-bg-tertiary);
110
+ --sp-color-text-primary: var(--sp-light-color-text-primary);
111
+ --sp-color-text-secondary: var(--sp-light-color-text-secondary);
112
+ --sp-color-text-tertiary: var(--sp-light-color-text-tertiary);
113
+ --sp-color-text-inverted: var(--sp-light-color-text-inverted);
114
+ --sp-color-border: var(--sp-light-color-border);
115
+ --sp-success: var(--sp-light-success);
116
+ --sp-warning: var(--sp-light-warning);
117
+ --sp-error: var(--sp-light-error);
118
+ --sp-info: var(--sp-light-info);
119
+ --sp-accent: var(--sp-light-accent);
120
+ --sp-accent-hover: var(--sp-light-accent-hover);
121
+ --sp-accent-active: var(--sp-light-accent-active);
122
+ --sp-accent-foreground: var(--sp-light-accent-foreground);
123
+
124
+ /* shadcn/ui light mode variables */
125
+ --background: var(--sp-light-color-bg-primary);
126
+ --foreground: var(--sp-light-color-text-primary);
127
+ --card: var(--sp-light-color-bg-primary);
128
+ --card-foreground: var(--sp-light-color-text-primary);
129
+ --popover: var(--sp-light-color-bg-primary);
130
+ --popover-foreground: var(--sp-light-color-text-primary);
131
+ --primary: var(--sp-light-accent);
132
+ --primary-foreground: var(--sp-accent-foreground);
133
+ --secondary: var(--sp-light-color-bg-secondary);
134
+ --secondary-foreground: var(--sp-light-color-text-primary);
135
+ --muted: var(--sp-light-color-bg-tertiary);
136
+ --muted-foreground: var(--sp-light-color-text-tertiary);
137
+ --accent: var(--sp-light-accent);
138
+ --accent-foreground: var(--sp-accent-foreground);
139
+ --destructive: var(--sp-light-error);
140
+ --destructive-foreground: var(--sp-accent-foreground);
141
+ --border: var(--sp-light-color-border);
142
+ --input: var(--sp-light-color-bg-secondary);
143
+ --ring: var(--sp-light-accent);
144
+ --sidebar: var(--sp-light-sidebar);
145
+ --sidebar-foreground: var(--sp-light-color-text-primary);
146
+ --sidebar-primary: var(--sp-light-accent);
147
+ --sidebar-primary-foreground: var(--sp-light-color-text-primary);
148
+ --sidebar-accent: var(--sp-light-accent);
149
+ --sidebar-accent-foreground: var(--sp-light-color-text-primary);
150
+ --sidebar-border: var(--sp-light-color-border);
151
+ --sidebar-ring: var(--sp-light-accent);
152
+ }
153
+
154
+ .dark {
155
+ --sp-color-bg-primary: var(--sp-dark-color-bg-primary);
156
+ --sp-color-bg-secondary: var(--sp-dark-color-bg-secondary);
157
+ --sp-color-bg-tertiary: var(--sp-dark-color-bg-tertiary);
158
+ --sp-color-text-primary: var(--sp-dark-color-text-primary);
159
+ --sp-color-text-secondary: var(--sp-dark-color-text-secondary);
160
+ --sp-color-text-tertiary: var(--sp-dark-color-text-tertiary);
161
+ --sp-color-text-inverted: var(--sp-dark-color-text-inverted);
162
+ --sp-color-border: var(--sp-dark-color-border);
163
+ --sp-success: var(--sp-dark-success);
164
+ --sp-warning: var(--sp-dark-warning);
165
+ --sp-error: var(--sp-dark-error);
166
+ --sp-info: var(--sp-dark-info);
167
+ --sp-accent: var(--sp-dark-accent);
168
+ --sp-accent-hover: var(--sp-dark-accent-hover);
169
+ --sp-accent-active: var(--sp-dark-accent-active);
170
+ --sp-accent-foreground: var(--sp-dark-accent-foreground);
171
+
172
+ /* shadcn/ui dark mode variables */
173
+ --background: var(--sp-dark-color-bg-primary);
174
+ --foreground: var(--sp-dark-color-text-primary);
175
+ --card: var(--sp-dark-color-bg-primary);
176
+ --card-foreground: var(--sp-dark-color-text-primary);
177
+ --popover: var(--sp-dark-color-bg-primary);
178
+ --popover-foreground: var(--sp-dark-color-text-primary);
179
+ --primary: var(--sp-dark-accent);
180
+ --primary-foreground: var(--sp-accent-foreground);
181
+ --secondary: var(--sp-dark-color-bg-secondary);
182
+ --secondary-foreground: var(--sp-dark-color-text-primary);
183
+ --muted: var(--sp-dark-color-bg-tertiary);
184
+ --muted-foreground: var(--sp-dark-color-text-tertiary);
185
+ --accent: var(--sp-dark-accent);
186
+ --accent-foreground: var(--sp-accent-foreground);
187
+ --destructive: var(--sp-dark-error);
188
+ --destructive-foreground: var(--sp-accent-foreground);
189
+ --border: var(--sp-dark-color-border);
190
+ --input: var(--sp-dark-color-bg-secondary);
191
+ --ring: var(--sp-dark-accent);
192
+ --sidebar: var(--sp-dark-sidebar);
193
+ --sidebar-foreground: var(--sp-dark-color-text-primary);
194
+ --sidebar-primary: var(--sp-dark-accent);
195
+ --sidebar-primary-foreground: var(--sp-dark-color-text-primary);
196
+ --sidebar-accent: var(--sp-dark-accent);
197
+ --sidebar-accent-foreground: var(--sp-dark-color-text-primary);
198
+ --sidebar-border: var(--sp-dark-color-border);
199
+ --sidebar-ring: var(--sp-dark-accent);
200
+ }
201
+
202
+ @theme inline {
203
+ --color-sidebar: var(--sidebar);
204
+ --color-sidebar-foreground: var(--sidebar-foreground);
205
+ --color-sidebar-primary: var(--sidebar-primary);
206
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
207
+ --color-sidebar-accent: var(--sidebar-accent);
208
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
209
+ --color-sidebar-border: var(--sidebar-border);
210
+ --color-sidebar-ring: var(--sidebar-ring);
211
+ }
212
+
213
+ @layer base {
214
+ * {
215
+ @apply border-border outline-ring/50;
216
+ }
217
+ body {
218
+ @apply bg-background text-foreground;
219
+ }
220
+ }