Implement standardized color system: update theme with new color tokens, add color inventory and migration guide documentation, and create ColorPalette component for showcasing colors.

This commit is contained in:
Craig
2025-04-15 15:52:13 +01:00
parent 1450d36a63
commit 884ca29046
7 changed files with 765 additions and 3 deletions

View File

@@ -0,0 +1,16 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ColorPalette } from './ColorPalette';
const meta = {
title: 'Design System/ColorPalette',
component: ColorPalette,
tags: ['autodocs'],
parameters: {
layout: 'padded',
},
} satisfies Meta<typeof ColorPalette>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {};

View File

@@ -0,0 +1,154 @@
import { Box, Group, Stack, Text, Title, useMantineTheme } from '@mantine/core';
interface ColorSwatchProps {
colorName: string;
shade: number;
hex: string;
}
function ColorSwatch({ colorName, shade, hex }: ColorSwatchProps) {
return (
<Box>
<Box
style={{
backgroundColor: hex,
width: '100%',
height: 50,
borderRadius: 5,
marginBottom: 5,
border: '1px solid var(--mantine-color-brand-gray-3)',
}}
/>
<Text size="xs" fw={700}>
{colorName}-{shade}
</Text>
<Text size="xs" c="dimmed">
{hex}
</Text>
</Box>
);
}
interface ColorGroupProps {
title: string;
colorName: string;
description: string;
colors: readonly string[];
}
function ColorGroup({ title, colorName, description, colors }: ColorGroupProps) {
return (
<Stack gap="md">
<Box mb={10}>
<Title order={3}>{title}</Title>
<Text size="sm">{description}</Text>
</Box>
<Group grow>
{colors.map((color, index) => (
<ColorSwatch key={index} colorName={colorName} shade={index} hex={color} />
))}
</Group>
</Stack>
);
}
export function ColorPalette() {
const theme = useMantineTheme();
return (
<Stack gap="xl">
<Title order={1}>Color Palette Documentation</Title>
<Text>
This component showcases all colors defined in our theme system. Use these colors
consistently throughout the application for a cohesive design.
</Text>
<ColorGroup
title="Brand Primary"
colorName="brand-primary"
description="Main brand color for primary actions, links, and brand identity elements."
colors={theme.colors['brand-primary']}
/>
<ColorGroup
title="Brand Secondary"
colorName="brand-secondary"
description="Complementary color for secondary UI elements and visual hierarchy."
colors={theme.colors['brand-secondary']}
/>
<ColorGroup
title="Brand Accent"
colorName="brand-accent"
description="Accent color for call-to-actions and highlighting important elements."
colors={theme.colors['brand-accent']}
/>
<ColorGroup
title="Brand Gray"
colorName="brand-gray"
description="Neutral colors for text, backgrounds, borders, and non-emphasized UI elements."
colors={theme.colors['brand-gray']}
/>
<ColorGroup
title="Success"
colorName="success"
description="Used for positive actions, success messages, and confirmations."
colors={theme.colors.success}
/>
<ColorGroup
title="Warning"
colorName="warning"
description="Used for warnings and alerts that need attention but aren't critical."
colors={theme.colors.warning}
/>
<ColorGroup
title="Error"
colorName="error"
description="Used for errors, destructive actions, and critical alerts."
colors={theme.colors.error}
/>
<Box my={20}>
<Title order={2}>Semantic Color Usage</Title>
<Text mb={10}>These are recommended usages for our color system:</Text>
<Stack gap="xs">
<Text>
<b>Primary Buttons:</b> brand-primary-6
</Text>
<Text>
<b>Secondary Buttons:</b> brand-secondary-6
</Text>
<Text>
<b>Accent Buttons:</b> brand-accent-6
</Text>
<Text>
<b>Text on Light Backgrounds:</b> brand-gray-7
</Text>
<Text>
<b>Text on Dark Backgrounds:</b> brand-gray-0
</Text>
<Text>
<b>Borders & Dividers:</b> brand-gray-3
</Text>
<Text>
<b>Page Backgrounds:</b> brand-gray-0
</Text>
<Text>
<b>Success States:</b> success-6
</Text>
<Text>
<b>Warning States:</b> warning-6
</Text>
<Text>
<b>Error States:</b> error-6
</Text>
</Stack>
</Box>
</Stack>
);
}

View File

@@ -1,5 +1,140 @@
import { createTheme } from '@mantine/core';
import { createTheme, rem } from '@mantine/core';
export const theme = createTheme({
/** Put your mantine theme override here */
/** Color system for the application */
colors: {
// Primary brand color (blue shades from inventory with consistent gradation)
'brand-primary': [
'#EAF4FF', // 0: Lightest shade
'#D5E9FF', // 1
'#B0D3FF', // 2
'#8BBDFF', // 3
'#66A7FF', // 4: Base blue shade
'#4191FF', // 5
'#1C7BFF', // 6
'#0065F2', // 7: Original blue-7 shade
'#0055CC', // 8
'#004099', // 9: Darkest shade
],
// Secondary brand color - a complementary shade to the primary
'brand-secondary': [
'#F0F4F9', // 0
'#E1E9F4', // 1
'#C3D4E9', // 2
'#A5BFDE', // 3
'#87AAD3', // 4
'#6995C8', // 5
'#4B80BD', // 6
'#2D6BB2', // 7
'#1F5A99', // 8
'#114480', // 9
],
// Accent color for highlights, call to actions, important elements
'brand-accent': [
'#FFF0EA', // 0
'#FFE1D5', // 1
'#FFC3AD', // 2
'#FFA584', // 3
'#FF875B', // 4
'#FF6932', // 5
'#FF4A09', // 6
'#D93A00', // 7
'#B02F00', // 8
'#882400', // 9
],
// Standardized gray shades for consistency
'brand-gray': [
'#F8F9FA', // 0
'#F1F3F5', // 1
'#E9ECEF', // 2
'#DEE2E6', // 3
'#CED4DA', // 4
'#ADB5BD', // 5
'#868E96', // 6
'#495057', // 7
'#343A40', // 8
'#212529', // 9
],
// Semantic colors for state indications
success: [
'#EAFAF1', // 0
'#D5F5E3', // 1
'#ABEBC6', // 2
'#82E0AA', // 3
'#58D68D', // 4
'#2ECC71', // 5
'#27AE60', // 6
'#229954', // 7
'#1E8449', // 8
'#196F3D', // 9
],
warning: [
'#FEF9E7', // 0
'#FCF3CF', // 1
'#F9E79F', // 2
'#F7DC6F', // 3
'#F4D03F', // 4
'#F1C40F', // 5
'#D4AC0D', // 6
'#B7950B', // 7
'#9A7D0A', // 8
'#7D6608', // 9
],
error: [
'#FDEDEC', // 0
'#FADBD8', // 1
'#F5B7B1', // 2
'#F1948A', // 3
'#EC7063', // 4
'#E74C3C', // 5
'#CB4335', // 6
'#B03A2E', // 7
'#943126', // 8
'#78281F', // 9
],
},
// Set the primary color to our brand-primary
primaryColor: 'brand-primary',
// Add consistent spacing values
spacing: {
xs: rem(4),
sm: rem(8),
md: rem(16),
lg: rem(24),
xl: rem(32),
'2xl': rem(40),
'3xl': rem(64),
},
// Add consistent border radius values
radius: {
xs: rem(2),
sm: rem(4),
md: rem(8),
lg: rem(16),
xl: rem(24),
},
// Other theme customizations
fontFamily:
'"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
// Add semantic tokens for common elements
other: {
headerBgColor: 'var(--mantine-color-body)',
headerBorderColor: 'var(--mantine-color-brand-gray-3)',
navigationActiveColor: 'var(--mantine-color-brand-primary-6)',
navigationHoverColor: 'var(--mantine-color-brand-primary-0)',
buttonPrimaryBg: 'var(--mantine-color-brand-primary-6)',
buttonSecondaryBg: 'var(--mantine-color-brand-secondary-6)',
buttonAccentBg: 'var(--mantine-color-brand-accent-6)',
},
});