@depthark/css-first
Version:
Advanced MCP server for intelligent, context-aware CSS suggestions with logical units, container queries, and automated feature discovery
307 lines (284 loc) • 9.04 kB
text/typescript
/**
* Implementation guidance and recommendations for CSS properties
*/
import { ImplementationGuidance } from './types.js';
/**
* Generates browser support recommendations based on support information
* @param supportInfo - Browser support information
* @returns Human-readable recommendation string
*/
export function generateBrowserSupportRecommendation(supportInfo: any): string {
const { overall_support } = supportInfo;
if (overall_support >= 95) {
return 'Excellent browser support. Safe to use in production without fallbacks.';
} else if (overall_support >= 85) {
return 'Good browser support. Consider fallbacks for legacy browsers if needed.';
} else if (overall_support >= 70) {
return 'Moderate browser support. Provide fallbacks for older browsers.';
} else {
return 'Limited browser support. Consider alternative approaches or polyfills.';
}
}
/**
* Gets alternative CSS properties when user declines a suggestion
* @param declinedProperty - The CSS property that was declined
* @returns Promise that resolves to alternative property suggestions
*/
export async function getAlternativeCSSProperties(declinedProperty: string): Promise<string[]> {
const alternatives: Record<string, string[]> = {
'scroll-snap-type': ['overflow-x with JavaScript', 'transform with JavaScript', 'intersection observer'],
'display: grid': ['display: flex', 'float-based layout', 'inline-block layout'],
'container-type': ['media queries', 'viewport units', 'JavaScript resize observer'],
'css-scroll-snap': ['JavaScript carousel library', 'touch event handling', 'transform animations']
};
return alternatives[declinedProperty] || ['JavaScript-based solution', 'Traditional CSS approach'];
}
/**
* Provides implementation guidance for approved CSS properties
* @param cssProperty - The approved CSS property
* @param needsFallback - Whether fallback solutions are needed
* @returns Promise that resolves to implementation guidance
*/
export async function getImplementationGuidance(
cssProperty: string,
needsFallback: boolean = false
): Promise<ImplementationGuidance> {
const guidance: Record<string, ImplementationGuidance> = {
'padding-inline': {
basic_usage: '.element { padding-inline: 1rem; }',
best_practices: [
'Use logical properties for international layouts',
'Combine with rem units for scalable spacing',
'Prefer over padding-left/right for better RTL support',
'Use padding-inline-start/end for fine control'
],
fallbacks: needsFallback ? [
'Use padding-left/right for older browsers',
'Provide CSS custom properties for direction-aware values',
'Use Autoprefixer for automatic fallbacks'
] : [],
example_code: `
.card {
padding-inline: 1.5rem;
padding-block: 1rem;
/* Fallback for older browsers */
padding: 1rem 1.5rem;
}
/* RTL support automatically handled */
[dir="rtl"] .card {
/* No additional styles needed */
}
/* Fine-grained control */
.asymmetric {
padding-inline-start: 2rem;
padding-inline-end: 1rem;
}`
},
'margin-inline': {
basic_usage: '.element { margin-inline: auto; }',
best_practices: [
'Use margin-inline: auto for centering',
'Combine with modern units like rem, ch, or vi',
'Prefer over margin-left/right for international layouts',
'Use negative values for overlapping effects'
],
fallbacks: needsFallback ? [
'Use margin-left/right for older browsers',
'Provide direction-specific fallbacks',
'Use CSS custom properties for dynamic values'
] : [],
example_code: `
.centered {
margin-inline: auto;
max-width: 60ch;
/* Fallback */
margin-left: auto;
margin-right: auto;
}
.offset {
margin-inline-start: 2rem;
margin-inline-end: 1rem;
}`
},
'border-inline': {
basic_usage: '.element { border-inline: 1px solid #ccc; }',
best_practices: [
'Use logical border properties for directional layouts',
'Combine with CSS custom properties for theming',
'Use border-inline-start/end for asymmetric borders',
'Consider border-inline-width for responsive borders'
],
fallbacks: needsFallback ? [
'Use border-left/right for older browsers',
'Provide direction-specific border styles',
'Use CSS feature queries for progressive enhancement'
] : [],
example_code: `
.sidebar {
border-inline-end: 1px solid var(--border-color);
/* Fallback */
border-right: 1px solid #ccc;
}
(border-inline-end: 1px solid black) {
.sidebar {
border-right: none;
}
}
/* Responsive borders */
(min-width: 768px) {
.content {
border-inline: 1px solid #e0e0e0;
}
}`
},
'overflow-inline': {
basic_usage: '.element { overflow-inline: scroll; }',
best_practices: [
'Use overflow-inline for horizontal scrolling',
'Combine with scroll-snap for better UX',
'Use overflow-block for vertical scrolling',
'Consider overflow-clip-margin for precise control'
],
fallbacks: needsFallback ? [
'Use overflow-x/y for older browsers',
'Provide JavaScript fallbacks for complex scrolling',
'Use CSS feature queries for progressive enhancement'
] : [],
example_code: `
.horizontal-scroll {
overflow-inline: scroll;
overflow-block: hidden;
scroll-snap-type: inline mandatory;
/* Fallback */
overflow-x: scroll;
overflow-y: hidden;
}
.item {
scroll-snap-align: start;
flex: 0 0 auto;
width: 80vi;
}`
},
'overflow-x': {
basic_usage: '.carousel { overflow-x: scroll; scroll-snap-type: x mandatory; }',
best_practices: [
'Hide scrollbars for better UX: scrollbar-width: none;',
'Use scroll-behavior: smooth for better UX',
'Ensure keyboard accessibility',
'Add touch-action: pan-x for mobile'
],
fallbacks: needsFallback ? [
'Use JavaScript for browsers without scroll-snap support',
'Provide navigation arrows for non-touch devices',
'Add swipe gesture support with touch events'
] : [],
example_code: `
<div class="carousel">
<div class="carousel-item">Item 1</div>
<div class="carousel-item">Item 2</div>
<div class="carousel-item">Item 3</div>
</div>
<style>
.carousel {
display: flex;
overflow-x: scroll;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
-ms-overflow-style: none;
}
.carousel::-webkit-scrollbar {
display: none;
}
.carousel-item {
flex: 0 0 100%;
scroll-snap-align: start;
scroll-snap-stop: always;
}
(max-width: 768px) {
.carousel {
scroll-snap-type: x proximity;
}
}
</style>`
},
'scroll-snap-type': {
basic_usage: '.container { scroll-snap-type: x mandatory; }',
best_practices: [
'Use "mandatory" for precise control, "proximity" for smoother scrolling',
'Combine with scroll-snap-align on child elements',
'Test on different devices and browsers',
'Consider scroll-snap-stop for better control'
],
fallbacks: needsFallback ? [
'Polyfill for older browsers',
'JavaScript-based snapping',
'Touch event handling for mobile'
] : [],
example_code: `
.carousel {
scroll-snap-type: x mandatory;
overflow-x: scroll;
display: flex;
}
.carousel-item {
scroll-snap-align: center;
scroll-snap-stop: always;
flex: 0 0 auto;
width: 100%;
}
/* Fallback for older browsers */
not (scroll-snap-type: x mandatory) {
.carousel {
/* JavaScript-based fallback */
}
}`
},
'display': {
basic_usage: '.container { display: flex; }',
best_practices: [
'Use flex for one-dimensional layouts',
'Use grid for two-dimensional layouts',
'Consider browser support for newer display values',
'Test with different content lengths'
],
fallbacks: needsFallback ? [
'Use float-based layouts for very old browsers',
'Provide inline-block fallbacks',
'Consider CSS Grid fallbacks'
] : [],
example_code: `
.carousel {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 1rem;
}
.carousel-item {
flex: 0 0 auto;
min-width: 200px;
}
/* Fallback for older browsers */
.no-flexbox .carousel {
display: block;
white-space: nowrap;
}
.no-flexbox .carousel-item {
display: inline-block;
vertical-align: top;
white-space: normal;
}`
}
};
return guidance[cssProperty] || {
basic_usage: `${cssProperty}: value;`,
best_practices: ['Test across browsers', 'Consider accessibility', 'Optimize for performance'],
fallbacks: needsFallback ? ['Provide JavaScript fallback', 'Use progressive enhancement'] : [],
example_code: `
.element {
${cssProperty}: value;
}
/* Add your specific implementation here */`
};
}