@hakxel/mantine-ui-server
Version:
MCP server for working with Mantine UI components - provides documentation, generation, and theme utilities
290 lines (289 loc) • 9.1 kB
JavaScript
/**
* Theme utilities for the Mantine UI MCP server
*/
/**
* Generate a theme configuration based on provided settings
* @param config Theme configuration
* @returns Generated theme configuration
*/
export function generateTheme(config) {
const { extension, definitions, darkMode = false } = config;
switch (extension) {
case 'colors':
return generateColorPalettes(definitions);
case 'components':
return generateComponentThemes(definitions);
case 'typography':
return generateTypographyTheme(definitions);
case 'spacing':
return generateSpacingTheme(definitions);
case 'radius':
return generateRadiusTheme(definitions);
case 'shadows':
return generateShadowsTheme(definitions);
case 'other':
default:
return definitions;
}
}
/**
* Generate color palettes based on provided definitions
* @param definitions Color definitions
* @returns Generated color palettes
*/
export function generateColorPalettes(definitions) {
const palettes = {};
for (const [name, value] of Object.entries(definitions)) {
if (typeof value === 'string') {
// If a single color is provided, generate a palette
palettes[name] = generateColorShades(value);
}
else if (Array.isArray(value) && value.length === 10) {
// If a complete palette is provided, use it directly
palettes[name] = value;
}
}
return palettes;
}
/**
* Generate color shades from a base color
* @param baseColor Base color in hex format
* @returns Array of 10 color shades
*/
export function generateColorShades(baseColor) {
// This is a simplified algorithm; in a real implementation, this would use
// color manipulation libraries to generate proper shades
const hexToRgb = (hex) => {
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return [r, g, b];
};
const rgbToHex = (r, g, b) => {
return `#${Math.round(r).toString(16).padStart(2, '0')}${Math.round(g).toString(16).padStart(2, '0')}${Math.round(b).toString(16).padStart(2, '0')}`;
};
const lighten = (rgb, amount) => {
return [
rgb[0] + (255 - rgb[0]) * amount,
rgb[1] + (255 - rgb[1]) * amount,
rgb[2] + (255 - rgb[2]) * amount
];
};
const darken = (rgb, amount) => {
return [
rgb[0] * (1 - amount),
rgb[1] * (1 - amount),
rgb[2] * (1 - amount)
];
};
const rgb = hexToRgb(baseColor);
// Generate 10 shades, with the base color at index 5
return [
rgbToHex(...lighten(rgb, 0.9)),
rgbToHex(...lighten(rgb, 0.7)),
rgbToHex(...lighten(rgb, 0.5)),
rgbToHex(...lighten(rgb, 0.3)),
rgbToHex(...lighten(rgb, 0.1)),
baseColor,
rgbToHex(...darken(rgb, 0.1)),
rgbToHex(...darken(rgb, 0.2)),
rgbToHex(...darken(rgb, 0.3)),
rgbToHex(...darken(rgb, 0.4))
];
}
/**
* Generate component theme configurations
* @param definitions Component theme definitions
* @returns Generated component theme configurations
*/
export function generateComponentThemes(definitions) {
const componentThemes = {};
for (const [component, config] of Object.entries(definitions)) {
componentThemes[component] = {
defaultProps: config.defaultProps || {},
styles: (theme) => ({
root: {
...(config.styles?.root || {})
},
...(config.styles || {})
}),
variants: config.variants || {}
};
}
return { components: componentThemes };
}
/**
* Generate typography theme configuration
* @param definitions Typography definitions
* @returns Generated typography theme
*/
export function generateTypographyTheme(definitions) {
return {
fontFamily: definitions.fontFamily || undefined,
fontFamilyMonospace: definitions.fontFamilyMonospace || undefined,
headings: definitions.headings || undefined,
fontSizes: definitions.fontSizes || undefined,
lineHeights: definitions.lineHeights || undefined,
};
}
/**
* Generate spacing theme configuration
* @param definitions Spacing definitions
* @returns Generated spacing theme
*/
export function generateSpacingTheme(definitions) {
return {
spacing: definitions.values || definitions
};
}
/**
* Generate radius theme configuration
* @param definitions Radius definitions
* @returns Generated radius theme
*/
export function generateRadiusTheme(definitions) {
return {
radius: definitions.values || definitions
};
}
/**
* Generate shadows theme configuration
* @param definitions Shadow definitions
* @returns Generated shadows theme
*/
export function generateShadowsTheme(definitions) {
return {
shadows: definitions.values || definitions
};
}
/**
* Generate theme for a specific component
* @param config Component theme configuration
* @returns Generated component theme
*/
export function generateComponentTheme(config) {
const { component, colorScheme = 'both', baseColor, variants, customSelectors } = config;
// Base theme structure
const componentTheme = {
defaultProps: {},
styles: (theme) => ({
root: {
// Base styles for the component
},
// Add custom selectors if provided
...(customSelectors || {})
})
};
// Add variants if provided
if (variants && variants.length > 0) {
componentTheme.variants = {};
variants.forEach(variant => {
componentTheme.variants[variant.name] = (theme) => ({
root: {
...variant.styles
}
});
});
}
// Create final theme object
const themeObject = {
components: {
[component]: componentTheme
}
};
return themeObject;
}
/**
* Generate a Mantine theme configuration
* @param configs Array of theme configurations
* @returns Complete Mantine theme configuration
*/
export function generateCompleteTheme(configs) {
// Start with empty theme
const theme = {};
// Apply each configuration
configs.forEach(config => {
const generatedConfig = generateTheme(config);
// Merge the generated config into the theme
if (config.extension === 'components') {
theme.components = {
...theme.components,
...generatedConfig.components
};
}
else if (config.extension === 'colors') {
theme.colors = {
...theme.colors,
...generatedConfig
};
}
else {
// For other extensions, merge at the top level
Object.assign(theme, generatedConfig);
}
});
return theme;
}
/**
* Generate academic-specific theme
* @returns Academic theme configuration
*/
export function generateAcademicTheme() {
return {
// Academic-focused typography
fontFamily: '"Merriweather", serif',
fontFamilyMonospace: '"Roboto Mono", monospace',
headings: {
fontFamily: '"Roboto", sans-serif',
fontWeight: '500',
},
// Academic color palette
colors: {
// Example academic-focused colors
academicBlue: generateColorShades('#2C3E50'),
academicGreen: generateColorShades('#27AE60'),
academicRed: generateColorShades('#C0392B'),
academicGold: generateColorShades('#F39C12'),
paperWhite: generateColorShades('#FAFAFA'),
},
// Component-specific overrides
components: {
Paper: {
defaultProps: {
p: 'md',
shadow: 'xs',
withBorder: true,
},
styles: () => ({
root: {
backgroundColor: 'var(--mantine-color-paperWhite-0)',
transition: 'all 200ms ease',
}
})
},
Text: {
defaultProps: {
size: 'md',
},
styles: () => ({
root: {
lineHeight: 1.6,
}
})
},
// Publication-specific components
Card: {
defaultProps: {
shadow: 'sm',
p: 'lg',
radius: 'md',
},
styles: () => ({
root: {
backgroundColor: 'var(--mantine-color-paperWhite-0)',
}
})
},
},
};
}