mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
feat: refactor theme structure by adding design tokens, component overrides, and updating mui-theme for better customization
chore: remove unused dependency 'cmdk' from package.json
This commit is contained in:
@@ -70,7 +70,6 @@
|
||||
"@prisma/client": "^6.19.1",
|
||||
"@tanstack/react-query": "^5.83.1",
|
||||
"@types/jszip": "^3.4.0",
|
||||
"cmdk": "^1.1.1",
|
||||
"d3": "^7.9.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"fengari-interop": "^0.1.4",
|
||||
|
||||
103
frontends/nextjs/src/theme/components.ts
Normal file
103
frontends/nextjs/src/theme/components.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
/** Component style overrides for MUI */
|
||||
|
||||
import { ThemeOptions, alpha } from '@mui/material/styles'
|
||||
import { colors, fonts } from './tokens'
|
||||
|
||||
export const getComponentOverrides = (mode: 'light' | 'dark'): ThemeOptions['components'] => {
|
||||
const isDark = mode === 'dark'
|
||||
const n = colors.neutral
|
||||
|
||||
return {
|
||||
MuiCssBaseline: {
|
||||
styleOverrides: {
|
||||
':root': { '--font-body': fonts.body, '--font-heading': fonts.heading, '--font-mono': fonts.mono },
|
||||
html: { scrollBehavior: 'smooth' },
|
||||
body: { WebkitFontSmoothing: 'antialiased', MozOsxFontSmoothing: 'grayscale' },
|
||||
'code, pre, kbd': { fontFamily: fonts.mono },
|
||||
'::selection': { backgroundColor: isDark ? colors.primary.dark.main : colors.primary.light.main, color: '#fff' },
|
||||
'::-webkit-scrollbar': { width: 8, height: 8 },
|
||||
'::-webkit-scrollbar-track': { backgroundColor: isDark ? n[800] : n[100] },
|
||||
'::-webkit-scrollbar-thumb': { backgroundColor: isDark ? n[600] : n[400], borderRadius: 4 },
|
||||
},
|
||||
},
|
||||
MuiButton: {
|
||||
defaultProps: { disableElevation: true },
|
||||
styleOverrides: {
|
||||
root: { borderRadius: 8, textTransform: 'none', fontWeight: 500, padding: '8px 16px' },
|
||||
sizeSmall: { padding: '4px 12px', fontSize: '0.8125rem' },
|
||||
sizeLarge: { padding: '12px 24px', fontSize: '0.9375rem' },
|
||||
containedPrimary: {
|
||||
'&:hover': { boxShadow: `0 4px 12px ${alpha(isDark ? colors.primary.dark.main : colors.primary.light.main, 0.4)}` },
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCard: {
|
||||
defaultProps: { elevation: 0 },
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 12,
|
||||
border: `1px solid ${isDark ? n[800] : n[200]}`,
|
||||
backgroundImage: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardHeader: {
|
||||
styleOverrides: {
|
||||
root: { padding: '20px 24px 16px' },
|
||||
title: { fontFamily: fonts.heading, fontWeight: 600, fontSize: '1.125rem' },
|
||||
subheader: { fontSize: '0.875rem', color: isDark ? n[400] : n[600] },
|
||||
},
|
||||
},
|
||||
MuiCardContent: { styleOverrides: { root: { padding: '16px 24px', '&:last-child': { paddingBottom: 24 } } } },
|
||||
MuiCardActions: { styleOverrides: { root: { padding: '16px 24px', borderTop: `1px solid ${isDark ? n[800] : n[200]}` } } },
|
||||
MuiPaper: { defaultProps: { elevation: 0 }, styleOverrides: { root: { backgroundImage: 'none' }, outlined: { borderColor: isDark ? n[800] : n[200] } } },
|
||||
MuiTextField: {
|
||||
defaultProps: { variant: 'outlined', size: 'small' },
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiOutlinedInput-root': { borderRadius: 8, backgroundColor: isDark ? n[900] : '#fff' },
|
||||
'& .MuiOutlinedInput-notchedOutline': { borderColor: isDark ? n[700] : n[300] },
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiOutlinedInput: { styleOverrides: { root: { borderRadius: 8 } } },
|
||||
MuiSelect: { styleOverrides: { root: { borderRadius: 8 } } },
|
||||
MuiChip: { styleOverrides: { root: { borderRadius: 6, fontWeight: 500 }, sizeSmall: { height: 24 } } },
|
||||
MuiAlert: {
|
||||
styleOverrides: {
|
||||
root: { borderRadius: 8, alignItems: 'center' },
|
||||
standardSuccess: { backgroundColor: alpha(isDark ? colors.success.dark.main : colors.success.light.main, isDark ? 0.15 : 0.1) },
|
||||
standardError: { backgroundColor: alpha(isDark ? colors.error.dark.main : colors.error.light.main, isDark ? 0.15 : 0.1) },
|
||||
standardWarning: { backgroundColor: alpha(isDark ? colors.warning.dark.main : colors.warning.light.main, isDark ? 0.15 : 0.1) },
|
||||
standardInfo: { backgroundColor: alpha(isDark ? colors.info.dark.main : colors.info.light.main, isDark ? 0.15 : 0.1) },
|
||||
},
|
||||
},
|
||||
MuiDialog: { styleOverrides: { paper: { borderRadius: 16 } } },
|
||||
MuiDialogTitle: { styleOverrides: { root: { fontFamily: fonts.heading, fontWeight: 600, fontSize: '1.25rem', padding: '24px 24px 16px' } } },
|
||||
MuiDialogContent: { styleOverrides: { root: { padding: '16px 24px' } } },
|
||||
MuiDialogActions: { styleOverrides: { root: { padding: '16px 24px 24px', gap: 8 } } },
|
||||
MuiTable: { styleOverrides: { root: { borderCollapse: 'separate', borderSpacing: 0 } } },
|
||||
MuiTableHead: { styleOverrides: { root: { '& .MuiTableCell-root': { fontWeight: 600, backgroundColor: isDark ? n[900] : n[50], borderBottom: `2px solid ${isDark ? n[700] : n[300]}` } } } },
|
||||
MuiTableCell: { styleOverrides: { root: { borderBottom: `1px solid ${isDark ? n[800] : n[200]}`, padding: '12px 16px' } } },
|
||||
MuiTableRow: { styleOverrides: { root: { '&:hover': { backgroundColor: isDark ? alpha(n[700], 0.3) : alpha(n[100], 0.5) } } } },
|
||||
MuiTabs: { styleOverrides: { root: { minHeight: 48 }, indicator: { height: 3, borderRadius: '3px 3px 0 0' } } },
|
||||
MuiTab: { styleOverrides: { root: { textTransform: 'none', fontWeight: 500, minHeight: 48, padding: '12px 16px' } } },
|
||||
MuiTooltip: { styleOverrides: { tooltip: { backgroundColor: isDark ? n[700] : n[900], fontSize: '0.75rem', padding: '6px 12px', borderRadius: 6 }, arrow: { color: isDark ? n[700] : n[900] } } },
|
||||
MuiMenu: { styleOverrides: { paper: { borderRadius: 8, border: `1px solid ${isDark ? n[800] : n[200]}` } } },
|
||||
MuiMenuItem: { styleOverrides: { root: { padding: '8px 16px', borderRadius: 4, margin: '2px 8px' } } },
|
||||
MuiDrawer: { styleOverrides: { paper: { borderRight: `1px solid ${isDark ? n[800] : n[200]}` } } },
|
||||
MuiAppBar: { defaultProps: { elevation: 0 }, styleOverrides: { root: { backgroundColor: isDark ? n[900] : '#fff', borderBottom: `1px solid ${isDark ? n[800] : n[200]}` } } },
|
||||
MuiDivider: { styleOverrides: { root: { borderColor: isDark ? n[800] : n[200] } } },
|
||||
MuiAvatar: { styleOverrides: { root: { fontFamily: fonts.heading, fontWeight: 600 } } },
|
||||
MuiBadge: { styleOverrides: { badge: { fontWeight: 600, fontSize: '0.6875rem' } } },
|
||||
MuiLinearProgress: { styleOverrides: { root: { borderRadius: 4, height: 6 } } },
|
||||
MuiSkeleton: { styleOverrides: { root: { borderRadius: 4, backgroundColor: isDark ? n[800] : n[200] } } },
|
||||
MuiAccordion: { defaultProps: { elevation: 0 }, styleOverrides: { root: { border: `1px solid ${isDark ? n[800] : n[200]}`, borderRadius: 8, '&:before': { display: 'none' } } } },
|
||||
MuiAccordionSummary: { styleOverrides: { root: { padding: '0 16px', minHeight: 56 }, content: { fontWeight: 500 } } },
|
||||
MuiAccordionDetails: { styleOverrides: { root: { padding: '0 16px 16px' } } },
|
||||
MuiSwitch: { styleOverrides: { root: { width: 46, height: 26, padding: 0 }, switchBase: { padding: 2, '&.Mui-checked': { transform: 'translateX(20px)' } }, thumb: { width: 22, height: 22 }, track: { borderRadius: 13, opacity: 1, backgroundColor: isDark ? n[700] : n[300] } } },
|
||||
MuiIconButton: { styleOverrides: { root: { borderRadius: 8 } } },
|
||||
MuiListItemButton: { styleOverrides: { root: { borderRadius: 8, margin: '2px 8px', padding: '8px 12px' } } },
|
||||
MuiSnackbar: { styleOverrides: { root: { '& .MuiPaper-root': { borderRadius: 8 } } } },
|
||||
}
|
||||
}
|
||||
8
frontends/nextjs/src/theme/index.ts
Normal file
8
frontends/nextjs/src/theme/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Theme Module - Central export for all theme functionality
|
||||
*/
|
||||
|
||||
export { lightTheme, darkTheme, colors, fonts, layout } from './mui-theme'
|
||||
export { useTheme, styled, alpha } from '@mui/material/styles'
|
||||
export type { Theme, SxProps } from '@mui/material/styles'
|
||||
|
||||
@@ -1,753 +1,41 @@
|
||||
'use client'
|
||||
|
||||
import { createTheme, ThemeOptions, alpha, Theme } from '@mui/material/styles'
|
||||
import './theme.d.ts' // Import type extensions
|
||||
|
||||
// ========================================
|
||||
// Design Tokens - Unified color system
|
||||
// ========================================
|
||||
|
||||
// Primary colors - Purple/Magenta accent
|
||||
const colors = {
|
||||
primary: {
|
||||
light: {
|
||||
main: '#8b5cf6',
|
||||
light: '#a78bfa',
|
||||
dark: '#7c3aed',
|
||||
contrastText: '#ffffff',
|
||||
},
|
||||
dark: {
|
||||
main: '#a78bfa',
|
||||
light: '#c4b5fd',
|
||||
dark: '#8b5cf6',
|
||||
contrastText: '#ffffff',
|
||||
},
|
||||
},
|
||||
secondary: {
|
||||
light: {
|
||||
main: '#f59e0b',
|
||||
light: '#fbbf24',
|
||||
dark: '#d97706',
|
||||
contrastText: '#ffffff',
|
||||
},
|
||||
dark: {
|
||||
main: '#fbbf24',
|
||||
light: '#fcd34d',
|
||||
dark: '#f59e0b',
|
||||
contrastText: '#000000',
|
||||
},
|
||||
},
|
||||
error: {
|
||||
light: { main: '#ef4444', light: '#f87171', dark: '#dc2626' },
|
||||
dark: { main: '#f87171', light: '#fca5a5', dark: '#ef4444' },
|
||||
},
|
||||
warning: {
|
||||
light: { main: '#f59e0b', light: '#fbbf24', dark: '#d97706' },
|
||||
dark: { main: '#fbbf24', light: '#fcd34d', dark: '#f59e0b' },
|
||||
},
|
||||
info: {
|
||||
light: { main: '#06b6d4', light: '#22d3ee', dark: '#0891b2' },
|
||||
dark: { main: '#22d3ee', light: '#67e8f9', dark: '#06b6d4' },
|
||||
},
|
||||
success: {
|
||||
light: { main: '#10b981', light: '#34d399', dark: '#059669' },
|
||||
dark: { main: '#34d399', light: '#6ee7b7', dark: '#10b981' },
|
||||
},
|
||||
// Neutral grays
|
||||
neutral: {
|
||||
50: '#fafafa',
|
||||
100: '#f4f4f5',
|
||||
200: '#e4e4e7',
|
||||
300: '#d4d4d8',
|
||||
400: '#a1a1aa',
|
||||
500: '#71717a',
|
||||
600: '#52525b',
|
||||
700: '#3f3f46',
|
||||
800: '#27272a',
|
||||
900: '#18181b',
|
||||
950: '#09090b',
|
||||
},
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Typography System
|
||||
// ========================================
|
||||
|
||||
const fontFamilyBody = [
|
||||
'IBM Plex Sans',
|
||||
'-apple-system',
|
||||
'BlinkMacSystemFont',
|
||||
'Segoe UI',
|
||||
'Roboto',
|
||||
'Helvetica Neue',
|
||||
'Arial',
|
||||
'sans-serif',
|
||||
].join(',')
|
||||
|
||||
const fontFamilyHeading = ['Space Grotesk', 'IBM Plex Sans', 'sans-serif'].join(',')
|
||||
const fontFamilyMono = ['JetBrains Mono', 'Consolas', 'Monaco', 'monospace'].join(',')
|
||||
import { createTheme, alpha, ThemeOptions } from '@mui/material/styles'
|
||||
import { colors, fonts, layout } from './tokens'
|
||||
import { getComponentOverrides } from './components'
|
||||
|
||||
const typography = {
|
||||
fontFamily: fontFamilyBody,
|
||||
h1: {
|
||||
fontFamily: fontFamilyHeading,
|
||||
fontWeight: 700,
|
||||
fontSize: '3rem', // 48px
|
||||
lineHeight: 1.2,
|
||||
letterSpacing: '-0.02em',
|
||||
},
|
||||
h2: {
|
||||
fontFamily: fontFamilyHeading,
|
||||
fontWeight: 700,
|
||||
fontSize: '2.25rem', // 36px
|
||||
lineHeight: 1.25,
|
||||
letterSpacing: '-0.01em',
|
||||
},
|
||||
h3: {
|
||||
fontFamily: fontFamilyHeading,
|
||||
fontWeight: 600,
|
||||
fontSize: '1.875rem', // 30px
|
||||
lineHeight: 1.3,
|
||||
},
|
||||
h4: {
|
||||
fontFamily: fontFamilyHeading,
|
||||
fontWeight: 600,
|
||||
fontSize: '1.5rem', // 24px
|
||||
lineHeight: 1.35,
|
||||
},
|
||||
h5: {
|
||||
fontFamily: fontFamilyHeading,
|
||||
fontWeight: 600,
|
||||
fontSize: '1.25rem', // 20px
|
||||
lineHeight: 1.4,
|
||||
},
|
||||
h6: {
|
||||
fontFamily: fontFamilyHeading,
|
||||
fontWeight: 600,
|
||||
fontSize: '1rem', // 16px
|
||||
lineHeight: 1.5,
|
||||
},
|
||||
subtitle1: {
|
||||
fontFamily: fontFamilyBody,
|
||||
fontWeight: 500,
|
||||
fontSize: '1rem',
|
||||
lineHeight: 1.5,
|
||||
},
|
||||
subtitle2: {
|
||||
fontFamily: fontFamilyBody,
|
||||
fontWeight: 500,
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: 1.5,
|
||||
},
|
||||
body1: {
|
||||
fontFamily: fontFamilyBody,
|
||||
fontWeight: 400,
|
||||
fontSize: '1rem',
|
||||
lineHeight: 1.6,
|
||||
},
|
||||
body2: {
|
||||
fontFamily: fontFamilyBody,
|
||||
fontWeight: 400,
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: 1.5,
|
||||
},
|
||||
caption: {
|
||||
fontFamily: fontFamilyBody,
|
||||
fontWeight: 400,
|
||||
fontSize: '0.75rem',
|
||||
lineHeight: 1.4,
|
||||
},
|
||||
overline: {
|
||||
fontFamily: fontFamilyBody,
|
||||
fontWeight: 600,
|
||||
fontSize: '0.75rem',
|
||||
lineHeight: 1.5,
|
||||
letterSpacing: '0.08em',
|
||||
textTransform: 'uppercase' as const,
|
||||
},
|
||||
button: {
|
||||
fontFamily: fontFamilyBody,
|
||||
fontWeight: 500,
|
||||
fontSize: '0.875rem',
|
||||
textTransform: 'none' as const,
|
||||
letterSpacing: '0.01em',
|
||||
},
|
||||
fontFamily: fonts.body,
|
||||
h1: { fontFamily: fonts.heading, fontWeight: 700, fontSize: '3rem', lineHeight: 1.2, letterSpacing: '-0.02em' },
|
||||
h2: { fontFamily: fonts.heading, fontWeight: 700, fontSize: '2.25rem', lineHeight: 1.25, letterSpacing: '-0.01em' },
|
||||
h3: { fontFamily: fonts.heading, fontWeight: 600, fontSize: '1.875rem', lineHeight: 1.3 },
|
||||
h4: { fontFamily: fonts.heading, fontWeight: 600, fontSize: '1.5rem', lineHeight: 1.35 },
|
||||
h5: { fontFamily: fonts.heading, fontWeight: 600, fontSize: '1.25rem', lineHeight: 1.4 },
|
||||
h6: { fontFamily: fonts.heading, fontWeight: 600, fontSize: '1rem', lineHeight: 1.5 },
|
||||
subtitle1: { fontWeight: 500, fontSize: '1rem', lineHeight: 1.5 },
|
||||
subtitle2: { fontWeight: 500, fontSize: '0.875rem', lineHeight: 1.5 },
|
||||
body1: { fontSize: '1rem', lineHeight: 1.6 },
|
||||
body2: { fontSize: '0.875rem', lineHeight: 1.5 },
|
||||
caption: { fontSize: '0.75rem', lineHeight: 1.4 },
|
||||
overline: { fontWeight: 600, fontSize: '0.75rem', letterSpacing: '0.08em', textTransform: 'uppercase' as const },
|
||||
button: { fontWeight: 500, fontSize: '0.875rem', textTransform: 'none' as const },
|
||||
code: { fontFamily: fonts.mono, fontSize: '0.875rem', backgroundColor: 'rgba(0,0,0,0.06)', padding: '2px 6px', borderRadius: 4 },
|
||||
kbd: { fontFamily: fonts.mono, fontSize: '0.75rem', fontWeight: 500, padding: '2px 8px', borderRadius: 4, border: '1px solid' },
|
||||
label: { fontSize: '0.875rem', fontWeight: 500, lineHeight: 1.5 },
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Spacing & Shape
|
||||
// ========================================
|
||||
|
||||
const spacing = 8 // Base 8px grid
|
||||
|
||||
const shape = {
|
||||
borderRadius: 8,
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Shadows System
|
||||
// ========================================
|
||||
|
||||
const lightShadows = [
|
||||
const shadows = (opacity: number) => [
|
||||
'none',
|
||||
'0 1px 2px 0 rgba(0, 0, 0, 0.05)',
|
||||
'0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1)',
|
||||
'0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)',
|
||||
'0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)',
|
||||
'0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)',
|
||||
'0 25px 50px -12px rgba(0, 0, 0, 0.25)',
|
||||
// Remaining slots (7-24) - using progressive shadows
|
||||
...Array(18).fill('0 25px 50px -12px rgba(0, 0, 0, 0.25)'),
|
||||
`0 1px 2px rgba(0,0,0,${opacity * 0.5})`,
|
||||
`0 1px 3px rgba(0,0,0,${opacity}), 0 1px 2px rgba(0,0,0,${opacity})`,
|
||||
`0 4px 6px rgba(0,0,0,${opacity}), 0 2px 4px rgba(0,0,0,${opacity})`,
|
||||
`0 10px 15px rgba(0,0,0,${opacity}), 0 4px 6px rgba(0,0,0,${opacity})`,
|
||||
`0 20px 25px rgba(0,0,0,${opacity}), 0 8px 10px rgba(0,0,0,${opacity})`,
|
||||
`0 25px 50px rgba(0,0,0,${opacity * 2.5})`,
|
||||
...Array(18).fill(`0 25px 50px rgba(0,0,0,${opacity * 2.5})`),
|
||||
] as ThemeOptions['shadows']
|
||||
|
||||
const darkShadows = [
|
||||
'none',
|
||||
'0 1px 2px 0 rgba(0, 0, 0, 0.3)',
|
||||
'0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px -1px rgba(0, 0, 0, 0.3)',
|
||||
'0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -2px rgba(0, 0, 0, 0.3)',
|
||||
'0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.3)',
|
||||
'0 20px 25px -5px rgba(0, 0, 0, 0.4), 0 8px 10px -6px rgba(0, 0, 0, 0.3)',
|
||||
'0 25px 50px -12px rgba(0, 0, 0, 0.5)',
|
||||
...Array(18).fill('0 25px 50px -12px rgba(0, 0, 0, 0.5)'),
|
||||
] as ThemeOptions['shadows']
|
||||
|
||||
// ========================================
|
||||
// Z-Index Scale
|
||||
// ========================================
|
||||
|
||||
const zIndex = {
|
||||
mobileStepper: 1000,
|
||||
fab: 1050,
|
||||
speedDial: 1050,
|
||||
appBar: 1100,
|
||||
drawer: 1200,
|
||||
modal: 1300,
|
||||
snackbar: 1400,
|
||||
tooltip: 1500,
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Transitions
|
||||
// ========================================
|
||||
|
||||
const transitions = {
|
||||
duration: {
|
||||
shortest: 150,
|
||||
shorter: 200,
|
||||
short: 250,
|
||||
standard: 300,
|
||||
complex: 375,
|
||||
enteringScreen: 225,
|
||||
leavingScreen: 195,
|
||||
},
|
||||
easing: {
|
||||
easeInOut: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
easeOut: 'cubic-bezier(0.0, 0, 0.2, 1)',
|
||||
easeIn: 'cubic-bezier(0.4, 0, 1, 1)',
|
||||
sharp: 'cubic-bezier(0.4, 0, 0.6, 1)',
|
||||
},
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Component Overrides
|
||||
// ========================================
|
||||
|
||||
const getComponentOverrides = (mode: 'light' | 'dark'): ThemeOptions['components'] => {
|
||||
const isDark = mode === 'dark'
|
||||
const neutral = colors.neutral
|
||||
|
||||
return {
|
||||
MuiCssBaseline: {
|
||||
styleOverrides: {
|
||||
':root': {
|
||||
'--font-family-body': fontFamilyBody,
|
||||
'--font-family-heading': fontFamilyHeading,
|
||||
'--font-family-mono': fontFamilyMono,
|
||||
},
|
||||
html: {
|
||||
scrollBehavior: 'smooth',
|
||||
},
|
||||
body: {
|
||||
WebkitFontSmoothing: 'antialiased',
|
||||
MozOsxFontSmoothing: 'grayscale',
|
||||
},
|
||||
'code, pre, kbd': {
|
||||
fontFamily: fontFamilyMono,
|
||||
},
|
||||
'::selection': {
|
||||
backgroundColor: isDark ? colors.primary.dark.main : colors.primary.light.main,
|
||||
color: '#ffffff',
|
||||
},
|
||||
// Custom scrollbar
|
||||
'::-webkit-scrollbar': {
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
},
|
||||
'::-webkit-scrollbar-track': {
|
||||
backgroundColor: isDark ? neutral[800] : neutral[100],
|
||||
},
|
||||
'::-webkit-scrollbar-thumb': {
|
||||
backgroundColor: isDark ? neutral[600] : neutral[400],
|
||||
borderRadius: '4px',
|
||||
'&:hover': {
|
||||
backgroundColor: isDark ? neutral[500] : neutral[500],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiButton: {
|
||||
defaultProps: {
|
||||
disableElevation: true,
|
||||
},
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 8,
|
||||
textTransform: 'none',
|
||||
fontWeight: 500,
|
||||
padding: '8px 16px',
|
||||
transition: 'all 200ms ease-in-out',
|
||||
},
|
||||
sizeSmall: {
|
||||
padding: '4px 12px',
|
||||
fontSize: '0.8125rem',
|
||||
},
|
||||
sizeLarge: {
|
||||
padding: '12px 24px',
|
||||
fontSize: '0.9375rem',
|
||||
},
|
||||
containedPrimary: {
|
||||
'&:hover': {
|
||||
boxShadow: `0 4px 12px ${alpha(isDark ? colors.primary.dark.main : colors.primary.light.main, 0.4)}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCard: {
|
||||
defaultProps: {
|
||||
elevation: 0,
|
||||
},
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 12,
|
||||
border: `1px solid ${isDark ? neutral[800] : neutral[200]}`,
|
||||
backgroundImage: 'none',
|
||||
transition: 'box-shadow 200ms ease-in-out, border-color 200ms ease-in-out',
|
||||
'&:hover': {
|
||||
boxShadow: isDark
|
||||
? '0 4px 12px rgba(0, 0, 0, 0.4)'
|
||||
: '0 4px 12px rgba(0, 0, 0, 0.1)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardHeader: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: '20px 24px 16px',
|
||||
},
|
||||
title: {
|
||||
fontFamily: fontFamilyHeading,
|
||||
fontWeight: 600,
|
||||
fontSize: '1.125rem',
|
||||
},
|
||||
subheader: {
|
||||
fontSize: '0.875rem',
|
||||
color: isDark ? neutral[400] : neutral[600],
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: '16px 24px',
|
||||
'&:last-child': {
|
||||
paddingBottom: '24px',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardActions: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: '16px 24px',
|
||||
borderTop: `1px solid ${isDark ? neutral[800] : neutral[200]}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPaper: {
|
||||
defaultProps: {
|
||||
elevation: 0,
|
||||
},
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundImage: 'none',
|
||||
},
|
||||
outlined: {
|
||||
borderColor: isDark ? neutral[800] : neutral[200],
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTextField: {
|
||||
defaultProps: {
|
||||
variant: 'outlined',
|
||||
size: 'small',
|
||||
},
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiOutlinedInput-root': {
|
||||
borderRadius: 8,
|
||||
backgroundColor: isDark ? neutral[900] : '#ffffff',
|
||||
transition: 'border-color 200ms ease-in-out, box-shadow 200ms ease-in-out',
|
||||
'&:hover .MuiOutlinedInput-notchedOutline': {
|
||||
borderColor: isDark ? neutral[600] : neutral[400],
|
||||
},
|
||||
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
|
||||
borderWidth: 2,
|
||||
},
|
||||
},
|
||||
'& .MuiOutlinedInput-notchedOutline': {
|
||||
borderColor: isDark ? neutral[700] : neutral[300],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiOutlinedInput: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiSelect: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiChip: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 6,
|
||||
fontWeight: 500,
|
||||
},
|
||||
sizeSmall: {
|
||||
height: 24,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAlert: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 8,
|
||||
alignItems: 'center',
|
||||
},
|
||||
standardSuccess: {
|
||||
backgroundColor: isDark ? alpha(colors.success.dark.main, 0.15) : alpha(colors.success.light.main, 0.1),
|
||||
color: isDark ? colors.success.dark.light : colors.success.light.dark,
|
||||
},
|
||||
standardError: {
|
||||
backgroundColor: isDark ? alpha(colors.error.dark.main, 0.15) : alpha(colors.error.light.main, 0.1),
|
||||
color: isDark ? colors.error.dark.light : colors.error.light.dark,
|
||||
},
|
||||
standardWarning: {
|
||||
backgroundColor: isDark ? alpha(colors.warning.dark.main, 0.15) : alpha(colors.warning.light.main, 0.1),
|
||||
color: isDark ? colors.warning.dark.dark : colors.warning.light.dark,
|
||||
},
|
||||
standardInfo: {
|
||||
backgroundColor: isDark ? alpha(colors.info.dark.main, 0.15) : alpha(colors.info.light.main, 0.1),
|
||||
color: isDark ? colors.info.dark.light : colors.info.light.dark,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDialog: {
|
||||
styleOverrides: {
|
||||
paper: {
|
||||
borderRadius: 16,
|
||||
boxShadow: isDark ? '0 25px 50px -12px rgba(0, 0, 0, 0.5)' : '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDialogTitle: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
fontFamily: fontFamilyHeading,
|
||||
fontWeight: 600,
|
||||
fontSize: '1.25rem',
|
||||
padding: '24px 24px 16px',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDialogContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: '16px 24px',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDialogActions: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: '16px 24px 24px',
|
||||
gap: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTable: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderCollapse: 'separate',
|
||||
borderSpacing: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableHead: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiTableCell-root': {
|
||||
fontWeight: 600,
|
||||
backgroundColor: isDark ? neutral[900] : neutral[50],
|
||||
borderBottom: `2px solid ${isDark ? neutral[700] : neutral[300]}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableCell: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderBottom: `1px solid ${isDark ? neutral[800] : neutral[200]}`,
|
||||
padding: '12px 16px',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableRow: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&:hover': {
|
||||
backgroundColor: isDark ? alpha(neutral[700], 0.3) : alpha(neutral[100], 0.5),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTabs: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
minHeight: 48,
|
||||
},
|
||||
indicator: {
|
||||
height: 3,
|
||||
borderRadius: '3px 3px 0 0',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTab: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
textTransform: 'none',
|
||||
fontWeight: 500,
|
||||
minHeight: 48,
|
||||
padding: '12px 16px',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTooltip: {
|
||||
styleOverrides: {
|
||||
tooltip: {
|
||||
backgroundColor: isDark ? neutral[700] : neutral[900],
|
||||
color: isDark ? neutral[100] : '#ffffff',
|
||||
fontSize: '0.75rem',
|
||||
padding: '6px 12px',
|
||||
borderRadius: 6,
|
||||
},
|
||||
arrow: {
|
||||
color: isDark ? neutral[700] : neutral[900],
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiMenu: {
|
||||
styleOverrides: {
|
||||
paper: {
|
||||
borderRadius: 8,
|
||||
boxShadow: isDark
|
||||
? '0 10px 40px rgba(0, 0, 0, 0.5)'
|
||||
: '0 10px 40px rgba(0, 0, 0, 0.15)',
|
||||
border: `1px solid ${isDark ? neutral[800] : neutral[200]}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiMenuItem: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: '8px 16px',
|
||||
borderRadius: 4,
|
||||
margin: '2px 8px',
|
||||
'&:hover': {
|
||||
backgroundColor: isDark ? neutral[800] : neutral[100],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDrawer: {
|
||||
styleOverrides: {
|
||||
paper: {
|
||||
borderRight: `1px solid ${isDark ? neutral[800] : neutral[200]}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAppBar: {
|
||||
defaultProps: {
|
||||
elevation: 0,
|
||||
},
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: isDark ? neutral[900] : '#ffffff',
|
||||
borderBottom: `1px solid ${isDark ? neutral[800] : neutral[200]}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDivider: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderColor: isDark ? neutral[800] : neutral[200],
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAvatar: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
fontFamily: fontFamilyHeading,
|
||||
fontWeight: 600,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiBadge: {
|
||||
styleOverrides: {
|
||||
badge: {
|
||||
fontWeight: 600,
|
||||
fontSize: '0.6875rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiLinearProgress: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 4,
|
||||
height: 6,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCircularProgress: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
strokeLinecap: 'round',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiSkeleton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 4,
|
||||
backgroundColor: isDark ? neutral[800] : neutral[200],
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAccordion: {
|
||||
defaultProps: {
|
||||
elevation: 0,
|
||||
},
|
||||
styleOverrides: {
|
||||
root: {
|
||||
border: `1px solid ${isDark ? neutral[800] : neutral[200]}`,
|
||||
borderRadius: 8,
|
||||
'&:before': {
|
||||
display: 'none',
|
||||
},
|
||||
'&.Mui-expanded': {
|
||||
margin: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAccordionSummary: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: '0 16px',
|
||||
minHeight: 56,
|
||||
'&.Mui-expanded': {
|
||||
minHeight: 56,
|
||||
},
|
||||
},
|
||||
content: {
|
||||
fontWeight: 500,
|
||||
'&.Mui-expanded': {
|
||||
margin: '12px 0',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiAccordionDetails: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: '0 16px 16px',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiSwitch: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
width: 46,
|
||||
height: 26,
|
||||
padding: 0,
|
||||
},
|
||||
switchBase: {
|
||||
padding: 2,
|
||||
'&.Mui-checked': {
|
||||
transform: 'translateX(20px)',
|
||||
},
|
||||
},
|
||||
thumb: {
|
||||
width: 22,
|
||||
height: 22,
|
||||
},
|
||||
track: {
|
||||
borderRadius: 13,
|
||||
opacity: 1,
|
||||
backgroundColor: isDark ? neutral[700] : neutral[300],
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiIconButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 8,
|
||||
transition: 'background-color 200ms ease-in-out',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiListItemButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 8,
|
||||
margin: '2px 8px',
|
||||
padding: '8px 12px',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiSnackbar: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& .MuiPaper-root': {
|
||||
borderRadius: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Create Themes
|
||||
// ========================================
|
||||
const custom = { fonts, borderRadius: layout.borderRadius, contentWidth: layout.contentWidth, sidebar: layout.sidebar, header: layout.header }
|
||||
|
||||
export const lightTheme = createTheme({
|
||||
palette: {
|
||||
@@ -758,31 +46,18 @@ export const lightTheme = createTheme({
|
||||
warning: colors.warning.light,
|
||||
info: colors.info.light,
|
||||
success: colors.success.light,
|
||||
background: {
|
||||
default: '#ffffff',
|
||||
paper: colors.neutral[50],
|
||||
},
|
||||
text: {
|
||||
primary: colors.neutral[900],
|
||||
secondary: colors.neutral[600],
|
||||
disabled: colors.neutral[400],
|
||||
},
|
||||
neutral: colors.neutral,
|
||||
background: { default: '#ffffff', paper: colors.neutral[50] },
|
||||
text: { primary: colors.neutral[900], secondary: colors.neutral[600], disabled: colors.neutral[400] },
|
||||
divider: colors.neutral[200],
|
||||
action: {
|
||||
active: colors.neutral[700],
|
||||
hover: alpha(colors.neutral[500], 0.08),
|
||||
selected: alpha(colors.primary.light.main, 0.12),
|
||||
disabled: colors.neutral[400],
|
||||
disabledBackground: colors.neutral[200],
|
||||
},
|
||||
action: { active: colors.neutral[700], hover: alpha(colors.neutral[500], 0.08), selected: alpha(colors.primary.light.main, 0.12), disabled: colors.neutral[400], disabledBackground: colors.neutral[200] },
|
||||
},
|
||||
typography,
|
||||
spacing,
|
||||
shape,
|
||||
shadows: lightShadows,
|
||||
zIndex,
|
||||
transitions,
|
||||
spacing: layout.spacing,
|
||||
shape: { borderRadius: 8 },
|
||||
shadows: shadows(0.1),
|
||||
components: getComponentOverrides('light'),
|
||||
custom,
|
||||
})
|
||||
|
||||
export const darkTheme = createTheme({
|
||||
@@ -794,38 +69,18 @@ export const darkTheme = createTheme({
|
||||
warning: colors.warning.dark,
|
||||
info: colors.info.dark,
|
||||
success: colors.success.dark,
|
||||
background: {
|
||||
default: colors.neutral[950],
|
||||
paper: colors.neutral[900],
|
||||
},
|
||||
text: {
|
||||
primary: colors.neutral[100],
|
||||
secondary: colors.neutral[400],
|
||||
disabled: colors.neutral[600],
|
||||
},
|
||||
neutral: colors.neutral,
|
||||
background: { default: colors.neutral[950], paper: colors.neutral[900] },
|
||||
text: { primary: colors.neutral[100], secondary: colors.neutral[400], disabled: colors.neutral[600] },
|
||||
divider: colors.neutral[800],
|
||||
action: {
|
||||
active: colors.neutral[300],
|
||||
hover: alpha(colors.neutral[400], 0.12),
|
||||
selected: alpha(colors.primary.dark.main, 0.2),
|
||||
disabled: colors.neutral[600],
|
||||
disabledBackground: colors.neutral[800],
|
||||
},
|
||||
action: { active: colors.neutral[300], hover: alpha(colors.neutral[400], 0.12), selected: alpha(colors.primary.dark.main, 0.2), disabled: colors.neutral[600], disabledBackground: colors.neutral[800] },
|
||||
},
|
||||
typography,
|
||||
spacing,
|
||||
shape,
|
||||
shadows: darkShadows,
|
||||
zIndex,
|
||||
transitions,
|
||||
spacing: layout.spacing,
|
||||
shape: { borderRadius: 8 },
|
||||
shadows: shadows(0.4),
|
||||
components: getComponentOverrides('dark'),
|
||||
custom,
|
||||
})
|
||||
|
||||
// Export design tokens for SCSS interop
|
||||
export const designTokens = {
|
||||
colors,
|
||||
fontFamilyBody,
|
||||
fontFamilyHeading,
|
||||
fontFamilyMono,
|
||||
spacing,
|
||||
}
|
||||
export { colors, fonts, layout } from './tokens'
|
||||
|
||||
47
frontends/nextjs/src/theme/tokens.ts
Normal file
47
frontends/nextjs/src/theme/tokens.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/** Design tokens - colors, spacing, typography */
|
||||
|
||||
export const colors = {
|
||||
primary: {
|
||||
light: { main: '#8b5cf6', light: '#a78bfa', dark: '#7c3aed', contrastText: '#ffffff' },
|
||||
dark: { main: '#a78bfa', light: '#c4b5fd', dark: '#8b5cf6', contrastText: '#ffffff' },
|
||||
},
|
||||
secondary: {
|
||||
light: { main: '#f59e0b', light: '#fbbf24', dark: '#d97706', contrastText: '#ffffff' },
|
||||
dark: { main: '#fbbf24', light: '#fcd34d', dark: '#f59e0b', contrastText: '#000000' },
|
||||
},
|
||||
error: {
|
||||
light: { main: '#ef4444', light: '#f87171', dark: '#dc2626' },
|
||||
dark: { main: '#f87171', light: '#fca5a5', dark: '#ef4444' },
|
||||
},
|
||||
warning: {
|
||||
light: { main: '#f59e0b', light: '#fbbf24', dark: '#d97706' },
|
||||
dark: { main: '#fbbf24', light: '#fcd34d', dark: '#f59e0b' },
|
||||
},
|
||||
info: {
|
||||
light: { main: '#06b6d4', light: '#22d3ee', dark: '#0891b2' },
|
||||
dark: { main: '#22d3ee', light: '#67e8f9', dark: '#06b6d4' },
|
||||
},
|
||||
success: {
|
||||
light: { main: '#10b981', light: '#34d399', dark: '#059669' },
|
||||
dark: { main: '#34d399', light: '#6ee7b7', dark: '#10b981' },
|
||||
},
|
||||
neutral: {
|
||||
50: '#fafafa', 100: '#f4f4f5', 200: '#e4e4e7', 300: '#d4d4d8',
|
||||
400: '#a1a1aa', 500: '#71717a', 600: '#52525b', 700: '#3f3f46',
|
||||
800: '#27272a', 900: '#18181b', 950: '#09090b',
|
||||
},
|
||||
}
|
||||
|
||||
export const fonts = {
|
||||
body: ['IBM Plex Sans', '-apple-system', 'BlinkMacSystemFont', 'sans-serif'].join(','),
|
||||
heading: ['Space Grotesk', 'IBM Plex Sans', 'sans-serif'].join(','),
|
||||
mono: ['JetBrains Mono', 'Consolas', 'Monaco', 'monospace'].join(','),
|
||||
}
|
||||
|
||||
export const layout = {
|
||||
spacing: 8,
|
||||
borderRadius: { none: 0, sm: 4, md: 8, lg: 12, xl: 16, full: 9999 },
|
||||
contentWidth: { sm: '640px', md: '768px', lg: '1024px', xl: '1280px', full: '100%' },
|
||||
sidebar: { width: 280, collapsedWidth: 72 },
|
||||
header: { height: 64 },
|
||||
}
|
||||
Reference in New Issue
Block a user