Skip to content

Commit a2bbed2

Browse files
committed
feat(ui-new): add ButtonPaletteSwitcher component and update button styles
1 parent b4d042f commit a2bbed2

File tree

20 files changed

+255
-274
lines changed

20 files changed

+255
-274
lines changed

apps/portal/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,4 @@
5959
"prebuild": "bun run db:generate",
6060
"start": "next start"
6161
}
62-
}
62+
}

apps/portal/src/app/(app)/(home)/[orgId]/page.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ export default async function OrganizationPage({ params }: { params: Promise<{ o
1313
const { orgId } = await params;
1414

1515
// Auth check with error handling
16-
const session = await auth.api.getSession({
17-
headers: await headers(),
18-
}).catch((error) => {
19-
console.error('Error getting session:', error);
20-
redirect('/');
21-
});
16+
const session = await auth.api
17+
.getSession({
18+
headers: await headers(),
19+
})
20+
.catch((error) => {
21+
console.error('Error getting session:', error);
22+
redirect('/');
23+
});
2224

2325
if (!session?.user) {
2426
redirect('/auth');

apps/portal/src/app/(app)/(home)/[orgId]/types/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,4 @@ export type MDM = {
8888
enrollment_status: string;
8989
name?: string;
9090
server_url?: string;
91-
};
91+
};
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
'use client';
2+
3+
import {
4+
Button,
5+
HStack,
6+
SUPPORTED_COLOR_PALETTES,
7+
type SupportedColorPalette,
8+
Text,
9+
} from '@trycompai/ui-new';
10+
11+
export type ButtonColorPalette = SupportedColorPalette;
12+
13+
const isButtonColorPalette = (value: string): value is ButtonColorPalette => {
14+
return (SUPPORTED_COLOR_PALETTES as readonly string[]).includes(value);
15+
};
16+
17+
export function ButtonPaletteSwitcher({
18+
value,
19+
onChange,
20+
}: {
21+
value: ButtonColorPalette;
22+
onChange: (value: ButtonColorPalette) => void;
23+
}) {
24+
return (
25+
<HStack gap={3} align="center" flexWrap="wrap">
26+
<Text color="fg" fontSize="sm" fontWeight="medium">
27+
Palette
28+
</Text>
29+
<HStack
30+
gap="2"
31+
flexWrap="wrap"
32+
bg="bg"
33+
borderWidth="1px"
34+
borderColor="border"
35+
borderRadius="lg"
36+
p="1"
37+
boxShadow="xs"
38+
role="group"
39+
aria-label="Button palette"
40+
>
41+
{SUPPORTED_COLOR_PALETTES.map((palette) => {
42+
const isSelected = palette === value;
43+
44+
return (
45+
<Button
46+
key={palette}
47+
size="sm"
48+
variant={isSelected ? 'solid' : 'outline'}
49+
colorPalette={palette}
50+
onClick={() => onChange(palette)}
51+
aria-pressed={isSelected}
52+
>
53+
<HStack gap="2">
54+
<Text as="span" textTransform="capitalize">
55+
{palette}
56+
</Text>
57+
</HStack>
58+
</Button>
59+
);
60+
})}
61+
</HStack>
62+
</HStack>
63+
);
64+
}

apps/portal/src/app/(public)/test-ui/components/TestUiPage.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@ export function TestUiPage() {
88
return (
99
<Box pb="20">
1010
<Container maxW="1400px" py={8}>
11-
<Heading size="2xl" mb={2}>
11+
<Heading size="2xl" mb={8}>
1212
Design System Preview
1313
</Heading>
14-
<Text color="secondary.700" mb={8}>
15-
Theme palettes + components
16-
</Text>
1714

1815
<TestUiSectionsTop />
1916
<TestUiSectionsBottom />

apps/portal/src/app/(public)/test-ui/components/TestUiPrimitives.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,24 @@ export function ColorRow({
4343
name,
4444
description,
4545
shades = DEFAULT_SHADES,
46+
highlightShade = '700',
4647
}: {
4748
name: string;
48-
description: string;
49+
description?: string;
4950
shades?: readonly string[];
51+
highlightShade?: string;
5052
}) {
5153
return (
5254
<Box w="full">
5355
<HStack>
5456
<Text fontWeight="semibold" fontSize="sm">
5557
{name}
5658
</Text>
57-
<Text fontSize="xs" color="gray.600">
58-
{description}
59-
</Text>
59+
{description && (
60+
<Text fontSize="xs" color="gray.600">
61+
{description}
62+
</Text>
63+
)}
6064
</HStack>
6165
{/* Add top padding (lg+) so shade labels above swatches don't overlap the header */}
6266
<Flex gap={1} mt={2} pt={{ base: 0, lg: 6 }}>
@@ -69,6 +73,9 @@ export function ColorRow({
6973
borderRadius="sm"
7074
title={`${name}.${shade}`}
7175
position="relative"
76+
outline={shade === highlightShade ? '2px solid' : undefined}
77+
outlineColor={shade === highlightShade ? 'fg' : undefined}
78+
outlineOffset={shade === highlightShade ? '2px' : undefined}
7279
>
7380
<Text
7481
position="absolute"

apps/portal/src/app/(public)/test-ui/components/TestUiSectionsTop.tsx

Lines changed: 48 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import {
44
Badge,
5-
Box,
65
Button,
76
Card,
87
Checkbox,
@@ -17,142 +16,75 @@ import {
1716
Textarea,
1817
VStack,
1918
} from '@trycompai/ui-new';
19+
import { useState } from 'react';
20+
import { ButtonPaletteSwitcher, type ButtonColorPalette } from './ButtonPaletteSwitcher';
2021
import { ColorRow, Section, SubSection } from './TestUiPrimitives';
2122

2223
export function TestUiSectionsTop() {
24+
const [buttonPalette, setButtonPalette] = useState<ButtonColorPalette>('primary');
25+
2326
return (
2427
<>
25-
<Section title="Color Tokens (Comp)">
26-
<Text color="gray.600" mb={4}>
27-
Theme palettes (primary, secondary, and accent palettes)
28-
</Text>
28+
<Section title="Color Tokens">
2929
<VStack align="start" gap={8}>
30-
<ColorRow name="primary" description="comp green" />
31-
<ColorRow name="secondary" description="neutral / gray scale" />
32-
<ColorRow name="blue" description="accent blue" />
33-
<ColorRow name="orange" description="accent orange" />
34-
<ColorRow name="rose" description="accent rose" />
35-
<ColorRow name="yellow" description="accent yellow" />
36-
<ColorRow name="sand" description="accent sand" />
30+
<ColorRow name="primary" />
31+
<ColorRow name="secondary" />
32+
<ColorRow name="blue" />
33+
<ColorRow name="orange" />
34+
<ColorRow name="rose" />
35+
<ColorRow name="yellow" />
36+
<ColorRow name="sand" />
3737
</VStack>
3838
</Section>
3939

40-
<Section title="Surface Tokens">
41-
<Text color="gray.600" mb={4}>
42-
Simple surfaces using our theme palettes
43-
</Text>
44-
<Grid templateColumns={{ base: '1fr', md: 'repeat(3, 1fr)' }} gap={4}>
45-
<Box
46-
bg="white"
47-
color="gray.900"
48-
p={4}
49-
borderWidth="1px"
50-
borderColor="secondary.200"
51-
borderRadius="md"
52-
>
53-
white / gray.900
54-
</Box>
55-
<Box
56-
bg="secondary.50"
57-
color="secondary.900"
58-
p={4}
59-
borderWidth="1px"
60-
borderColor="secondary.200"
61-
borderRadius="md"
62-
>
63-
secondary.50 / secondary.900
64-
</Box>
65-
<Box
66-
bg="secondary.100"
67-
color="secondary.900"
68-
p={4}
69-
borderWidth="1px"
70-
borderColor="secondary.200"
71-
borderRadius="md"
72-
>
73-
secondary.100 / secondary.900
74-
</Box>
75-
<Box
76-
bg="secondary.900"
77-
color="white"
78-
p={4}
79-
borderWidth="1px"
80-
borderColor="secondary.700"
81-
borderRadius="md"
82-
>
83-
secondary.900 / white
84-
</Box>
85-
<Box
86-
bg="primary.50"
87-
color="primary.900"
88-
p={4}
89-
borderWidth="1px"
90-
borderColor="primary.200"
91-
borderRadius="md"
92-
>
93-
primary.50 / primary.900
94-
</Box>
95-
<Box
96-
bg="blue.50"
97-
color="blue.900"
98-
p={4}
99-
borderWidth="1px"
100-
borderColor="blue.200"
101-
borderRadius="md"
102-
>
103-
blue.50 / blue.900
104-
</Box>
105-
</Grid>
106-
<HStack gap={4} mt={4} flexWrap="wrap">
107-
<Box p={4} borderWidth="1px" borderColor="secondary.200" borderRadius="md">
108-
border: secondary.200
109-
</Box>
110-
<Box p={4} borderWidth="2px" borderColor="primary.700" borderRadius="md">
111-
focus: primary.700
112-
</Box>
113-
</HStack>
114-
</Section>
115-
11640
<Section title="Buttons">
117-
<SubSection title="Default (Primary)">
118-
<Text color="gray.600" fontSize="sm" mb={2}>
119-
Button variants
120-
</Text>
121-
<HStack gap={4} flexWrap="wrap">
122-
<Button>Default Button</Button>
123-
<Button variant="outline">Outline</Button>
124-
<Button variant="ghost">Ghost</Button>
125-
<Button variant="plain">Plain</Button>
126-
</HStack>
127-
</SubSection>
128-
129-
<SubSection title="Color Palettes">
41+
<HStack mb={3}>
42+
<ButtonPaletteSwitcher value={buttonPalette} onChange={setButtonPalette} />
43+
</HStack>
44+
<SubSection title="Variants">
13045
<HStack gap={4} flexWrap="wrap">
131-
<Button colorPalette="primary">Primary</Button>
132-
<Button colorPalette="secondary">Secondary</Button>
133-
<Button colorPalette="blue">Blue</Button>
134-
<Button colorPalette="orange">Orange</Button>
135-
<Button colorPalette="rose">Rose</Button>
136-
<Button colorPalette="yellow">Yellow</Button>
137-
<Button colorPalette="sand">Sand</Button>
46+
<Button colorPalette={buttonPalette}>Default Button</Button>
47+
<Button colorPalette={buttonPalette} variant="outline">
48+
Outline
49+
</Button>
50+
<Button colorPalette={buttonPalette} variant="ghost">
51+
Ghost
52+
</Button>
53+
<Button colorPalette={buttonPalette} variant="link">
54+
Link
55+
</Button>
13856
</HStack>
13957
</SubSection>
14058

14159
<SubSection title="Sizes">
14260
<HStack gap={4} alignItems="center" flexWrap="wrap">
143-
<Button size="xs">XS</Button>
144-
<Button size="sm">SM</Button>
145-
<Button size="md">MD</Button>
146-
<Button size="lg">LG</Button>
147-
<Button size="xl">XL</Button>
61+
<Button colorPalette={buttonPalette} size="xs">
62+
XS
63+
</Button>
64+
<Button colorPalette={buttonPalette} size="sm">
65+
SM
66+
</Button>
67+
<Button colorPalette={buttonPalette} size="md">
68+
MD
69+
</Button>
70+
<Button colorPalette={buttonPalette} size="lg">
71+
LG
72+
</Button>
73+
<Button colorPalette={buttonPalette} size="xl">
74+
XL
75+
</Button>
14876
</HStack>
14977
</SubSection>
15078

15179
<SubSection title="States">
15280
<HStack gap={4} flexWrap="wrap">
153-
<Button>Normal</Button>
154-
<Button disabled>Disabled</Button>
155-
<Button loading>Loading</Button>
81+
<Button colorPalette={buttonPalette}>Normal</Button>
82+
<Button colorPalette={buttonPalette} disabled>
83+
Disabled
84+
</Button>
85+
<Button colorPalette={buttonPalette} loading>
86+
Loading
87+
</Button>
15688
</HStack>
15789
</SubSection>
15890
</Section>

apps/portal/src/app/actions/login.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ const handleServerError = (e: Error) => {
1818
if (errorMessage.includes('expired') && errorMessage.includes('otp')) {
1919
return 'OTP code has expired. Please request a new code.';
2020
}
21-
21+
2222
if (errorMessage.includes('not found') || errorMessage.includes('user not found')) {
2323
return 'No account found with this email address.';
2424
}
25-
25+
2626
// For other authentication errors, provide a more specific message
2727
if (errorMessage.includes('unauthorized') || errorMessage.includes('authentication')) {
2828
return 'Authentication failed. Please try again.';
@@ -48,7 +48,7 @@ export const login = createSafeActionClient({ handleServerError })
4848
)
4949
.action(async ({ parsedInput }) => {
5050
const headersList = await headers();
51-
51+
5252
await auth.api.signInEmailOTP({
5353
headers: headersList,
5454
body: {
Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
import { getPackageFilename, getReadmeContent, getScriptFilename } from './scripts/common';
22
import { generateMacScript } from './scripts/mac';
33

4-
export {
5-
generateMacScript,
6-
getPackageFilename,
7-
getReadmeContent,
8-
getScriptFilename,
9-
};
4+
export { generateMacScript, getPackageFilename, getReadmeContent, getScriptFilename };

0 commit comments

Comments
 (0)