pishposh
Version:
Visual Programming Language
465 lines (435 loc) • 15.5 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bootstrap Utility API Generator</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f8f9fa;
}
.container {
background: white;
border-radius: 8px;
padding: 30px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #212529;
margin-bottom: 30px;
text-align: center;
}
.config-section {
margin-bottom: 30px;
padding: 20px;
background: #f8f9fa;
border-radius: 6px;
border-left: 4px solid #007bff;
}
.config-section h3 {
margin-top: 0;
color: #495057;
}
textarea {
width: 100%;
min-height: 200px;
padding: 15px;
border: 1px solid #ced4da;
border-radius: 4px;
font-family: 'Monaco', 'Consolas', monospace;
font-size: 14px;
resize: vertical;
}
button {
background: #007bff;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin: 10px 5px;
}
button:hover {
background: #0056b3;
}
.output {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 4px;
padding: 20px;
margin-top: 20px;
max-height: 400px;
overflow-y: auto;
}
.demo-area {
margin-top: 30px;
padding: 20px;
border: 2px dashed #dee2e6;
border-radius: 6px;
}
.demo-box {
background: linear-gradient(45deg, #007bff, #6610f2);
color: white;
padding: 20px;
border-radius: 4px;
margin: 10px 0;
text-align: center;
}
.controls {
display: flex;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.status {
padding: 10px;
border-radius: 4px;
margin: 10px 0;
font-weight: 500;
}
.status.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.status.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
</style>
</head>
<body>
<div class="container">
<h1>Bootstrap Utility API Generator</h1>
<div class="config-section">
<h3>Utility Configuration</h3>
<p>Define your utility classes using Bootstrap's Utility API format:</p>
<textarea id="configInput" placeholder="Enter your utility configuration...">
{
"margin": {
"property": "margin",
"class": "m",
"values": {
"0": "0",
"1": "0.25rem",
"2": "0.5rem",
"3": "1rem",
"4": "1.5rem",
"5": "3rem",
"auto": "auto"
}
},
"padding": {
"property": "padding",
"class": "p",
"values": {
"0": "0",
"1": "0.25rem",
"2": "0.5rem",
"3": "1rem",
"4": "1.5rem",
"5": "3rem"
}
},
"width": {
"property": "width",
"class": "w",
"values": {
"25": "25%",
"50": "50%",
"75": "75%",
"100": "100%",
"auto": "auto"
}
},
"text-color": {
"property": "color",
"class": "text",
"values": {
"primary": "#007bff",
"secondary": "#6c757d",
"success": "#28a745",
"danger": "#dc3545",
"warning": "#ffc107",
"info": "#17a2b8",
"light": "#f8f9fa",
"dark": "#343a40",
"white": "#fff"
}
},
"background-color": {
"property": "background-color",
"class": "bg",
"values": {
"primary": "#007bff",
"secondary": "#6c757d",
"success": "#28a745",
"danger": "#dc3545",
"warning": "#ffc107",
"info": "#17a2b8",
"light": "#f8f9fa",
"dark": "#343a40",
"white": "#fff"
}
}
}
</textarea>
</div>
<div class="controls">
<button onclick="generateUtilities()">Generate CSS</button>
<button onclick="loadPreset('spacing')">Load Spacing Preset</button>
<button onclick="loadPreset('colors')">Load Colors Preset</button>
<button onclick="loadPreset('layout')">Load Layout Preset</button>
<button onclick="clearConfig()">Clear</button>
</div>
<div id="status"></div>
<div class="config-section">
<h3>Generated CSS</h3>
<textarea id="cssOutput" readonly placeholder="Generated CSS will appear here..."></textarea>
</div>
<div class="demo-area">
<h3>Live Demo</h3>
<p>The generated CSS is automatically applied. Test your utilities:</p>
<div class="demo-box m-3 p-4 bg-primary text-white w-50">
Demo Element - Try adding classes like: m-2, p-3, bg-success, text-white, w-75
</div>
<input type="text" id="demoClasses" placeholder="Enter classes to apply (e.g., m-4 p-2 bg-danger text-white w-100)"
style="width: 100%; padding: 10px; margin: 10px 0;">
<button onclick="applyDemoClasses()">Apply Classes</button>
</div>
</div>
<script>
class BootstrapUtilityGenerator {
constructor() {
this.generatedCSS = '';
this.styleElement = null;
this.init();
}
init() {
// Create a style element to inject generated CSS
this.styleElement = document.createElement('style');
this.styleElement.id = 'generated-utilities';
document.head.appendChild(this.styleElement);
}
generateUtilities(config) {
let css = '';
for (const [utilityName, utilityConfig] of Object.entries(config)) {
const { property, class: className, values, responsive = false, directional = false } = utilityConfig;
// Generate base utility classes
for (const [key, value] of Object.entries(values)) {
const selector = `.${className}-${key}`;
css += `${selector} { ${property}: ${value} !important; }\n`;
}
// Generate responsive variants if enabled
if (responsive) {
const breakpoints = {
'sm': '576px',
'md': '768px',
'lg': '992px',
'xl': '1200px',
'xxl': '1400px'
};
for (const [breakpoint, minWidth] of Object.entries(breakpoints)) {
css += `@media (min-width: ${minWidth}) {\n`;
for (const [key, value] of Object.entries(values)) {
const selector = `.${className}-${breakpoint}-${key}`;
css += ` ${selector} { ${property}: ${value} !important; }\n`;
}
css += '}\n';
}
}
// Generate directional utilities for spacing
if (directional || property === 'margin' || property === 'padding') {
const directions = {
't': `${property}-top`,
'b': `${property}-bottom`,
's': `${property}-start`,
'e': `${property}-end`,
'x': [`${property}-start`, `${property}-end`],
'y': [`${property}-top`, `${property}-bottom`]
};
for (const [direction, props] of Object.entries(directions)) {
for (const [key, value] of Object.entries(values)) {
const selector = `.${className}${direction}-${key}`;
if (Array.isArray(props)) {
css += `${selector} { `;
props.forEach(prop => {
css += `${prop}: ${value} !important; `;
});
css += '}\n';
} else {
css += `${selector} { ${props}: ${value} !important; }\n`;
}
}
}
}
}
return css;
}
applyCSS(css) {
this.generatedCSS = css;
this.styleElement.textContent = css;
}
showStatus(message, type = 'success') {
const statusDiv = document.getElementById('status');
statusDiv.innerHTML = `<div class="status ${type}">${message}</div>`;
setTimeout(() => {
statusDiv.innerHTML = '';
}, 3000);
}
}
// Initialize the generator
const generator = new BootstrapUtilityGenerator();
// Preset configurations
const presets = {
spacing: {
"margin": {
"property": "margin",
"class": "m",
"values": {
"0": "0",
"1": "0.25rem",
"2": "0.5rem",
"3": "1rem",
"4": "1.5rem",
"5": "3rem",
"auto": "auto"
},
"responsive": true
},
"padding": {
"property": "padding",
"class": "p",
"values": {
"0": "0",
"1": "0.25rem",
"2": "0.5rem",
"3": "1rem",
"4": "1.5rem",
"5": "3rem"
},
"responsive": true
}
},
colors: {
"text-color": {
"property": "color",
"class": "text",
"values": {
"primary": "#007bff",
"secondary": "#6c757d",
"success": "#28a745",
"danger": "#dc3545",
"warning": "#ffc107",
"info": "#17a2b8",
"light": "#f8f9fa",
"dark": "#343a40",
"white": "#fff",
"muted": "#6c757d"
}
},
"background-color": {
"property": "background-color",
"class": "bg",
"values": {
"primary": "#007bff",
"secondary": "#6c757d",
"success": "#28a745",
"danger": "#dc3545",
"warning": "#ffc107",
"info": "#17a2b8",
"light": "#f8f9fa",
"dark": "#343a40",
"white": "#fff",
"transparent": "transparent"
}
}
},
layout: {
"display": {
"property": "display",
"class": "d",
"values": {
"none": "none",
"inline": "inline",
"inline-block": "inline-block",
"block": "block",
"flex": "flex",
"inline-flex": "inline-flex",
"grid": "grid",
"table": "table"
},
"responsive": true
},
"width": {
"property": "width",
"class": "w",
"values": {
"25": "25%",
"50": "50%",
"75": "75%",
"100": "100%",
"auto": "auto"
}
},
"height": {
"property": "height",
"class": "h",
"values": {
"25": "25%",
"50": "50%",
"75": "75%",
"100": "100%",
"auto": "auto"
}
}
}
};
function generateUtilities() {
try {
const configText = document.getElementById('configInput').value;
const config = JSON.parse(configText);
const css = generator.generateUtilities(config);
document.getElementById('cssOutput').value = css;
generator.applyCSS(css);
generator.showStatus('✅ Utilities generated successfully!');
} catch (error) {
generator.showStatus(`❌ Error: ${error.message}`, 'error');
}
}
function loadPreset(presetName) {
if (presets[presetName]) {
document.getElementById('configInput').value = JSON.stringify(presets[presetName], null, 2);
generator.showStatus(`📋 ${presetName.charAt(0).toUpperCase() + presetName.slice(1)} preset loaded!`);
}
}
function clearConfig() {
document.getElementById('configInput').value = '';
document.getElementById('cssOutput').value = '';
generator.applyCSS('');
generator.showStatus('🗑️ Configuration cleared!');
}
function applyDemoClasses() {
const classes = document.getElementById('demoClasses').value;
const demoBox = document.querySelector('.demo-box');
// Reset classes
demoBox.className = 'demo-box';
// Apply new classes
if (classes.trim()) {
demoBox.className += ' ' + classes.trim();
}
generator.showStatus(`🎨 Applied classes: ${classes}`);
}
// Generate initial utilities on page load
window.addEventListener('load', () => {
generateUtilities();
});
</script>
</body>
</html>