Add Tailwind v3 integration aligned with production config

- Create tailwind.config.js merging production tokens with design
  system palettes from Style Dictionary
- Extend Style Dictionary to output tailwind-tokens.js module
- Add PostCSS config and Tailwind directive CSS
- Import Tailwind CSS in Storybook preview
- Production breakpoints, colours, typography, spacing preserved
- Design system brand/sage/neutral/red/amber/green/blue palettes
  added alongside production's generic color-1..6 naming

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-22 13:27:33 +10:00
parent fcc69446f3
commit f18e2ed2e4
6 changed files with 470 additions and 6 deletions

198
tailwind.config.js Normal file
View File

@@ -0,0 +1,198 @@
/** @type {import('tailwindcss').Config} */
const defaultTheme = require('tailwindcss/defaultTheme');
const plugin = require('tailwindcss/plugin');
// Design system tokens generated from Style Dictionary
const dsTokens = require('./src/theme/generated/tailwind-tokens.js');
// ─── Split-background plugin (from production) ─────────────────────────────
function createSplitBgPlugin() {
const result = {};
result['.split-bg'] = {
background:
'linear-gradient(90deg, var(--left-color, #000) 50%, var(--right-color, #fff) 50%)',
'--left-color': '#000',
'--right-color': '#fff',
};
// Use design system palettes for split-bg utilities
const palettes = dsTokens.colors;
Object.entries(palettes).forEach(([colorName, shades]) => {
if (typeof shades !== 'object') return;
Object.entries(shades).forEach(([shade, value]) => {
result[`.split-left-${colorName}-${shade}`] = { '--left-color': value };
result[`.split-right-${colorName}-${shade}`] = { '--right-color': value };
});
});
return result;
}
// ─── Config ─────────────────────────────────────────────────────────────────
module.exports = {
content: [
'./src/**/*.{js,ts,jsx,tsx,mdx}',
'./.storybook/**/*.{js,ts,jsx,tsx}',
],
safelist: [{ pattern: /^line-clamp-.*/ }],
theme: {
// ── Breakpoints (match production + MUI v5/v7 defaults) ──
screens: {
xs: '0px',
sm: '600px',
md: '960px',
lg: '1280px',
xl: '1536px',
},
// ── List style types (from production) ──
listStyleType: {
none: 'none',
disc: 'disc',
circle: 'circle',
square: 'square',
decimal: 'decimal',
roman: 'lower-roman',
alpha: 'lower-alpha',
},
extend: {
// ── Colours ──
// Production's colour tokens (preserved for backward compatibility)
// plus design system semantic palettes
colors: {
// --- Production tokens (unchanged) ---
'grey-1': '#f4f3ef',
'grey-2': '#D7E1E2',
'grey-3': '#b9c7c9',
'grey-4': '#4c5459',
'grey-5': '#4c5b6b',
'grey-6': '#D9D9D9',
'grey-7': '#EEEEEE',
'warning-red': '#A41623',
'color-1': '#B0610F',
'color-1H': '#9e6f42',
'color-2': '#DCC1A6',
'color-2H': '#d1b79e',
'color-3': '#BA834E',
'color-4': '#D0A070',
'color-5': '#F4F3EF',
'color-6': '#51301B',
'action-orange': '#F89E53',
'success-green': '#76B041',
// --- Design system palettes (from tokens) ---
...dsTokens.colors,
},
// ── Font families ──
fontFamily: {
// Production names
sans: ['Montserrat', ...defaultTheme.fontFamily.sans],
arial: ['Arial', 'sans-serif'],
notoSerifSC: ['"Noto Serif SC"', 'serif'],
// Design system aliases
display: dsTokens.fontFamily.display?.split(',').map((f) => f.trim()) || ['"Noto Serif SC"', 'serif'],
mono: dsTokens.fontFamily.mono?.split(',').map((f) => f.trim()) || defaultTheme.fontFamily.mono,
},
// ── Spacing (production custom values + design system scale) ──
space: {
8.5: '30px',
},
padding: {
1.25: '5px',
3.1: '12px',
3.15: '12.5px',
3.5: '14px',
3.75: '15px',
7.5: '30px',
},
margin: {
1.25: '5px',
3.1: '12px',
3.15: '12.5px',
3.75: '15px',
7.5: '30px',
},
// ── Border width (from production) ──
borderWidth: {
3: '3px',
1.5: '1.5px',
10: '10px',
},
// ── Aspect ratio (from production) ──
aspectRatio: {
'16/9': '16 / 9',
'4/3': '3 / 2',
},
// ── Heights (from production) ──
height: {
18: '4.5rem',
22: '5.5rem',
},
minHeight: {
input: 'calc(30px + 1.5rem)',
},
// ── Box shadows (from production) ──
boxShadow: {
'br-md':
'8px 0 15px -4px rgba(0, 0, 0, 0.15), 0 8px 15px -4px rgba(0, 0, 0, 0.15)',
badge: '0 0 5px 4px #f4f3ef',
'br-sm': '0 4px 6px rgba(0,0,0,0.07)',
},
// ── Font sizes ──
// Production custom sizes
fontSize: {
xxs: '10px',
'1.5xl': '22px',
'2.15xl': '25px',
'2.3xl': '26px',
'3.3xl': '32px',
// Design system sizes (where they add values not in Tailwind defaults)
'2xs': dsTokens.fontSize['2xs'],
},
// ── Gap (from production) ──
gap: {
3.75: '15px',
7.5: '30px',
},
// ── Border radius ──
borderRadius: {
// Production
'1.5xl': '15px',
// Design system
...dsTokens.borderRadius,
},
// ── Animation (from production) ──
animation: {
logoScroll: 'logoScroll 25s linear infinite',
},
keyframes: {
logoScroll: {
'0%': { transform: 'translateX(0)' },
'100%': { transform: 'translateX(-50%)' },
},
},
// ── Line height (design system) ──
lineHeight: dsTokens.lineHeight,
// ── Letter spacing (design system) ──
letterSpacing: dsTokens.letterSpacing,
},
},
plugins: [
plugin(function ({ addUtilities }) {
addUtilities(createSplitBgPlugin(), ['responsive']);
}),
],
};