const { hairlineWidth, platformSelect } = require('nativewind/theme'); const tokens = require('./design-tokens.json'); const toKebabCase = (value) => value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`); const px = (value) => `${value}px`; const fontConfig = (fontKey) => { const font = tokens.fonts[fontKey]; return platformSelect(font); }; const typographyVarName = (key) => { const kebab = toKebabCase(key); return key.startsWith('lineHeight') ? `--line-height-${kebab.replace('line-height-', '')}` : `--font-size-${kebab}`; }; const typographyVars = (mode) => Object.fromEntries( Object.entries(tokens.typography[mode]).map(([key, value]) => [ typographyVarName(key), px(value), ]), ); // Use default theme for Tailwind base (runtime theme switch via ThemeProvider) const defaultLight = tokens.colors.default.light; const defaultDark = tokens.colors.default.dark; const rootVariables = Object.fromEntries([ ...Object.entries(defaultLight).map(([key, value]) => [ `--${toKebabCase(key)}`, value, ]), ['--radius', px(tokens.radius.default)], ...Object.entries(typographyVars('normal')), ]); const darkVariables = Object.fromEntries( Object.entries(defaultDark).map(([key, value]) => [ `--${toKebabCase(key)}`, value, ]), ); // Mobile-first breakpoints for native (phone/tablet) and web const breakpoints = Object.fromEntries( Object.entries(tokens.layout.breakpoints).map(([key, value]) => [ key, `${value}px`, ]), ); /** @type {import('tailwindcss').Config} */ module.exports = { darkMode: 'class', content: [ './src/app/**/*.{ts,tsx}', './src/components/**/*.{ts,tsx}', './src/core/**/*.{ts,tsx}', './src/hooks/**/*.{ts,tsx}', './src/lib/**/*.{ts,tsx}', ], presets: [require('nativewind/preset')], theme: { screens: breakpoints, extend: { colors: { border: 'hsl(var(--border))', input: 'hsl(var(--input))', ring: 'hsl(var(--ring))', background: 'hsl(var(--background))', foreground: 'hsl(var(--foreground))', primary: { DEFAULT: 'hsl(var(--primary))', foreground: 'hsl(var(--primary-foreground))', }, secondary: { DEFAULT: 'hsl(var(--secondary))', foreground: 'hsl(var(--secondary-foreground))', }, destructive: { DEFAULT: 'hsl(var(--destructive))', foreground: 'hsl(var(--destructive-foreground))', }, muted: { DEFAULT: 'hsl(var(--muted))', foreground: 'hsl(var(--muted-foreground))', }, accent: { DEFAULT: 'hsl(var(--accent))', foreground: 'hsl(var(--accent-foreground))', }, popover: { DEFAULT: 'hsl(var(--popover))', foreground: 'hsl(var(--popover-foreground))', }, card: { DEFAULT: 'hsl(var(--card))', foreground: 'hsl(var(--card-foreground))', }, success: { DEFAULT: 'hsl(var(--success))', foreground: 'hsl(var(--success-foreground))', }, warning: { DEFAULT: 'hsl(var(--warning))', foreground: 'hsl(var(--warning-foreground))', }, info: { DEFAULT: 'hsl(var(--info))', foreground: 'hsl(var(--info-foreground))', }, }, fontFamily: { sans: fontConfig('sans'), display: fontConfig('display'), rounded: fontConfig('rounded'), serif: fontConfig('serif'), mono: fontConfig('mono'), }, fontSize: { headingLarge: 'var(--font-size-heading-large)', headingMedium: 'var(--font-size-heading-medium)', headingSmall: 'var(--font-size-heading-small)', titleLarge: 'var(--font-size-title-large)', titleMedium: 'var(--font-size-title-medium)', titleSmall: 'var(--font-size-title-small)', bodyLarge: 'var(--font-size-body-large)', bodyMedium: 'var(--font-size-body-medium)', bodySmall: 'var(--font-size-body-small)', captionLarge: 'var(--font-size-caption-large)', captionMedium: 'var(--font-size-caption-medium)', captionSmall: 'var(--font-size-caption-small)', sectionTitle: 'var(--font-size-section-title)', badge: 'var(--font-size-badge)', }, lineHeight: { normal: 'var(--line-height-normal)', tight: 'var(--line-height-tight)', loose: 'var(--line-height-loose)', xLoose: 'var(--line-height-x-loose)', }, borderRadius: { lg: 'var(--radius)', md: 'calc(var(--radius) - 2px)', sm: 'calc(var(--radius) - 4px)', xl: px(tokens.radius.xl), }, spacing: { 'screen-gutter': px(tokens.layout.screenGutter), }, borderWidth: { hairline: hairlineWidth(), }, maxWidth: { content: px(tokens.layout.contentMaxWidth), }, keyframes: { 'accordion-down': { from: { height: '0' }, to: { height: 'var(--radix-accordion-content-height)' }, }, 'accordion-up': { from: { height: 'var(--radix-accordion-content-height)' }, to: { height: '0' }, }, }, animation: { 'accordion-down': 'accordion-down 0.2s ease-out', 'accordion-up': 'accordion-up 0.2s ease-out', }, }, }, future: { hoverOnlyWhenSupported: true, }, plugins: [ require('tailwindcss-animate'), ({ addBase }) => { addBase({ ':root': rootVariables, '.dark:root': darkVariables, }); }, ], };