Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>HTML/CSS to MAUI XAML Converter</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/xml.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/css.min.js"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
.editor-container { | |
height: calc(100vh - 180px); | |
} | |
.editor-panel { | |
height: 100%; | |
overflow: auto; | |
} | |
.hljs { | |
background: transparent ; | |
} | |
.tab-button { | |
transition: all 0.2s ease; | |
} | |
.tab-button.active { | |
border-bottom: 3px solid #3b82f6; | |
color: #3b82f6; | |
} | |
.copy-btn { | |
opacity: 0; | |
transition: opacity 0.2s ease; | |
} | |
.code-block:hover .copy-btn { | |
opacity: 1; | |
} | |
.gradient-bg { | |
background: linear-gradient(135deg, #6b46c1 0%, #3b82f6 100%); | |
} | |
</style> | |
</head> | |
<body class="bg-gray-100"> | |
<div class="gradient-bg text-white py-6 px-4 shadow-lg"> | |
<div class="container mx-auto"> | |
<div class="flex items-center justify-between"> | |
<div> | |
<h1 class="text-3xl font-bold"><i class="fas fa-code mr-2"></i>HTML/CSS to MAUI XAML</h1> | |
<p class="text-blue-100 mt-1">Convert your web UI to .NET MAUI XAML instantly</p> | |
</div> | |
<div class="flex space-x-2"> | |
<button id="convertBtn" class="bg-white text-blue-600 px-6 py-2 rounded-lg font-semibold hover:bg-blue-50 transition flex items-center"> | |
<i class="fas fa-sync-alt mr-2"></i> Convert | |
</button> | |
<button id="clearBtn" class="bg-blue-800 text-white px-4 py-2 rounded-lg font-semibold hover:bg-blue-700 transition flex items-center"> | |
<i class="fas fa-trash-alt mr-2"></i> Clear | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="container mx-auto px-4 mt-6"> | |
<div class="bg-white rounded-xl shadow-lg overflow-hidden"> | |
<div class="flex border-b"> | |
<button class="tab-button active px-6 py-3 font-medium text-gray-700" data-tab="input"> | |
<i class="fas fa-code mr-2"></i>Input | |
</button> | |
<button class="tab-button px-6 py-3 font-medium text-gray-500" data-tab="output"> | |
<i class="fas fa-file-code mr-2"></i>Output | |
</button> | |
<button class="tab-button px-6 py-3 font-medium text-gray-500" data-tab="preview"> | |
<i class="fas fa-eye mr-2"></i>Preview | |
</button> | |
</div> | |
<div class="editor-container flex"> | |
<!-- Input Panel --> | |
<div id="input-panel" class="editor-panel w-1/2 border-r p-4"> | |
<div class="mb-4"> | |
<div class="flex justify-between items-center mb-2"> | |
<h3 class="font-semibold text-gray-700"><i class="fas fa-html5 mr-2 text-orange-500"></i>HTML</h3> | |
<button class="copy-btn text-sm bg-gray-100 px-2 py-1 rounded" onclick="copyCode('html-editor')"> | |
<i class="fas fa-copy mr-1"></i>Copy | |
</button> | |
</div> | |
<div class="relative"> | |
<textarea id="html-editor" class="w-full h-64 p-3 font-mono text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="Paste your HTML here..."><div class="p-4 bg-blue-100 rounded-lg"> | |
<h1 class="text-2xl font-bold text-blue-800">Hello MAUI!</h1> | |
<p class="text-blue-600 mt-2">This will be converted to XAML</p> | |
<button class="mt-4 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">Click Me</button> | |
</div></textarea> | |
</div> | |
</div> | |
<div> | |
<div class="flex justify-between items-center mb-2"> | |
<h3 class="font-semibold text-gray-700"><i class="fas fa-css3-alt mr-2 text-blue-500"></i>CSS</h3> | |
<button class="copy-btn text-sm bg-gray-100 px-2 py-1 rounded" onclick="copyCode('css-editor')"> | |
<i class="fas fa-copy mr-1"></i>Copy | |
</button> | |
</div> | |
<div class="relative"> | |
<textarea id="css-editor" class="w-full h-32 p-3 font-mono text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="Paste your CSS here (optional)..."></textarea> | |
</div> | |
</div> | |
</div> | |
<!-- Output Panel --> | |
<div id="output-panel" class="editor-panel w-1/2 p-4 hidden"> | |
<div class="flex justify-between items-center mb-2"> | |
<h3 class="font-semibold text-gray-700"><i class="fab fa-microsoft mr-2 text-purple-500"></i>MAUI XAML Output</h3> | |
<button class="copy-btn text-sm bg-gray-100 px-2 py-1 rounded" onclick="copyCode('xaml-output')"> | |
<i class="fas fa-copy mr-1"></i>Copy | |
</button> | |
</div> | |
<div class="relative"> | |
<pre id="xaml-output" class="p-3 bg-gray-50 rounded-lg h-full overflow-auto"><code class="language-xml">Your XAML output will appear here...</code></pre> | |
</div> | |
</div> | |
<!-- Preview Panel --> | |
<div id="preview-panel" class="editor-panel w-1/2 p-4 hidden"> | |
<div class="flex justify-between items-center mb-2"> | |
<h3 class="font-semibold text-gray-700"><i class="fas fa-mobile-alt mr-2 text-green-500"></i>MAUI Preview</h3> | |
<div class="flex space-x-2"> | |
<button id="ios-btn" class="text-sm bg-gray-100 px-2 py-1 rounded"> | |
<i class="fab fa-apple mr-1"></i>iOS | |
</button> | |
<button id="android-btn" class="text-sm bg-gray-100 px-2 py-1 rounded"> | |
<i class="fab fa-android mr-1"></i>Android | |
</button> | |
</div> | |
</div> | |
<div class="bg-gray-50 rounded-lg h-full overflow-auto flex items-center justify-center p-6"> | |
<div id="preview-content" class="w-full max-w-md"> | |
<div class="text-center text-gray-500"> | |
<i class="fas fa-mobile-alt text-4xl mb-2"></i> | |
<p>Preview will appear here after conversion</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="mt-6 bg-white rounded-xl shadow-lg p-6"> | |
<h2 class="text-xl font-semibold text-gray-800 mb-4"><i class="fas fa-lightbulb mr-2 text-yellow-500"></i>Conversion Tips</h2> | |
<div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
<div class="bg-blue-50 p-4 rounded-lg"> | |
<h3 class="font-medium text-blue-800 mb-2"><i class="fas fa-check-circle mr-2"></i>Supported</h3> | |
<ul class="text-sm text-blue-700 space-y-1"> | |
<li>Basic HTML elements (div, span, etc.)</li> | |
<li>Tailwind-like classes (p-4, bg-blue-500)</li> | |
<li>Common CSS properties</li> | |
<li>Flexbox layouts</li> | |
</ul> | |
</div> | |
<div class="bg-yellow-50 p-4 rounded-lg"> | |
<h3 class="font-medium text-yellow-800 mb-2"><i class="fas fa-exclamation-triangle mr-2"></i>Limited</h3> | |
<ul class="text-sm text-yellow-700 space-y-1"> | |
<li>Complex CSS selectors</li> | |
<li>CSS Grid (use StackLayout instead)</li> | |
<li>CSS animations</li> | |
<li>Pseudo-classes (:hover, etc.)</li> | |
</ul> | |
</div> | |
<div class="bg-purple-50 p-4 rounded-lg"> | |
<h3 class="font-medium text-purple-800 mb-2"><i class="fas fa-info-circle mr-2"></i>Best Practices</h3> | |
<ul class="text-sm text-purple-700 space-y-1"> | |
<li>Use simple, flat HTML structures</li> | |
<li>Prefer Tailwind-like utility classes</li> | |
<li>Test in MAUI after conversion</li> | |
<li>Adjust margins/padding as needed</li> | |
</ul> | |
</div> | |
</div> | |
</div> | |
</div> | |
<footer class="bg-gray-800 text-white py-6 mt-8"> | |
<div class="container mx-auto px-4 text-center"> | |
<p>HTML/CSS to MAUI XAML Converter Tool</p> | |
<p class="text-gray-400 text-sm mt-2">Convert web UI components to native MAUI XAML with ease</p> | |
</div> | |
</footer> | |
<script> | |
// Initialize syntax highlighting | |
hljs.highlightAll(); | |
// Tab switching | |
const tabs = document.querySelectorAll('.tab-button'); | |
const panels = { | |
'input': document.getElementById('input-panel'), | |
'output': document.getElementById('output-panel'), | |
'preview': document.getElementById('preview-panel') | |
}; | |
tabs.forEach(tab => { | |
tab.addEventListener('click', () => { | |
// Update tab styles | |
tabs.forEach(t => t.classList.remove('active', 'text-blue-600')); | |
tab.classList.add('active', 'text-blue-600'); | |
// Show the selected panel | |
const tabName = tab.getAttribute('data-tab'); | |
Object.values(panels).forEach(panel => panel.classList.add('hidden')); | |
panels[tabName].classList.remove('hidden'); | |
}); | |
}); | |
// Copy code function | |
function copyCode(elementId) { | |
const element = document.getElementById(elementId); | |
element.select(); | |
document.execCommand('copy'); | |
// Show feedback | |
const originalText = element.nextElementSibling?.innerText; | |
if (element.nextElementSibling) { | |
element.nextElementSibling.innerHTML = '<i class="fas fa-check mr-1"></i>Copied!'; | |
setTimeout(() => { | |
element.nextElementSibling.innerHTML = originalText; | |
}, 2000); | |
} | |
} | |
// Convert HTML/CSS to MAUI XAML | |
document.getElementById('convertBtn').addEventListener('click', () => { | |
const html = document.getElementById('html-editor').value; | |
const css = document.getElementById('css-editor').value; | |
// Simple conversion logic (this would be more complex in a real app) | |
let xaml = convertToXaml(html, css); | |
// Display the XAML output | |
const outputElement = document.getElementById('xaml-output'); | |
outputElement.innerHTML = hljs.highlight(xaml, {language: 'xml'}).value; | |
// Update preview | |
updatePreview(html, css); | |
// Switch to output tab | |
tabs[1].click(); | |
}); | |
// Clear all inputs | |
document.getElementById('clearBtn').addEventListener('click', () => { | |
document.getElementById('html-editor').value = ''; | |
document.getElementById('css-editor').value = ''; | |
document.getElementById('xaml-output').innerHTML = '<code class="language-xml">Your XAML output will appear here...</code>'; | |
document.getElementById('preview-content').innerHTML = ` | |
<div class="text-center text-gray-500"> | |
<i class="fas fa-mobile-alt text-4xl mb-2"></i> | |
<p>Preview will appear here after conversion</p> | |
</div> | |
`; | |
}); | |
// Simple conversion function (simplified for demo) | |
function convertToXaml(html, css) { | |
// This is a simplified conversion - a real converter would be much more sophisticated | |
let xaml = `<?xml version="1.0" encoding="utf-8" ?>\n<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"\n xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"\n x:Class="YourNamespace.YourPage">\n\n`; | |
// Convert HTML to XAML | |
let convertedHtml = html | |
.replace(/class="/g, 'StyleClass="') | |
.replace(/<div/g, '<VerticalStackLayout') | |
.replace(/<\/div>/g, '</VerticalStackLayout>') | |
.replace(/<span/g, '<Label') | |
.replace(/<\/span>/g, '</Label>') | |
.replace(/<button/g, '<Button') | |
.replace(/<\/button>/g, '</Button>') | |
.replace(/<h1/g, '<Label FontSize="24" FontAttributes="Bold"') | |
.replace(/<h2/g, '<Label FontSize="20" FontAttributes="Bold"') | |
.replace(/<h3/g, '<Label FontSize="18" FontAttributes="Bold"') | |
.replace(/<p/g, '<Label') | |
.replace(/<\/p>/g, '</Label>'); | |
// Add converted HTML to XAML | |
xaml += ` ${convertedHtml}\n\n`; | |
// Add resources for styles if CSS is provided | |
if (css.trim()) { | |
xaml += ` <ContentPage.Resources>\n <ResourceDictionary>\n`; | |
// Simple CSS to XAML style conversion (very basic) | |
const styles = css.split('}').filter(rule => rule.trim()); | |
styles.forEach(rule => { | |
const [selector, properties] = rule.split('{'); | |
if (selector && properties) { | |
const styleName = selector.trim().replace('.', '').replace(/\s+/g, ''); | |
xaml += ` <Style x:Key="${styleName}" TargetType="View">\n`; | |
const props = properties.split(';').filter(p => p.trim()); | |
props.forEach(prop => { | |
const [key, value] = prop.split(':').map(p => p.trim()); | |
if (key && value) { | |
// Convert CSS properties to XAML | |
if (key === 'background-color' || key === 'background') { | |
xaml += ` <Setter Property="BackgroundColor" Value="${convertColor(value)}" />\n`; | |
} else if (key === 'color') { | |
xaml += ` <Setter Property="TextColor" Value="${convertColor(value)}" />\n`; | |
} else if (key === 'font-size') { | |
xaml += ` <Setter Property="FontSize" Value="${value.replace('px', '')}" />\n`; | |
} else if (key === 'font-weight') { | |
xaml += ` <Setter Property="FontAttributes" Value="${value === 'bold' ? 'Bold' : 'None'}" />\n`; | |
} else if (key === 'margin') { | |
xaml += ` <Setter Property="Margin" Value="${value.replace(' ', ',')}" />\n`; | |
} else if (key === 'padding') { | |
xaml += ` <Setter Property="Padding" Value="${value.replace(' ', ',')}" />\n`; | |
} | |
} | |
}); | |
xaml += ` </Style>\n`; | |
} | |
}); | |
xaml += ` </ResourceDictionary>\n </ContentPage.Resources>\n`; | |
} | |
xaml += `</ContentPage>`; | |
return xaml; | |
} | |
// Helper function to convert CSS colors to XAML colors | |
function convertColor(cssColor) { | |
if (cssColor.startsWith('#')) { | |
return cssColor; | |
} else if (cssColor.startsWith('rgb(')) { | |
return `#${cssColor.match(/\d+/g).map(v => parseInt(v).toString(16).padStart(2, '0')).join('')}`; | |
} else { | |
// Map common color names | |
const colorMap = { | |
'red': '#FF0000', | |
'blue': '#0000FF', | |
'green': '#008000', | |
'black': '#000000', | |
'white': '#FFFFFF', | |
'gray': '#808080', | |
'yellow': '#FFFF00', | |
'orange': '#FFA500', | |
'purple': '#800080' | |
}; | |
return colorMap[cssColor] || '#000000'; | |
} | |
} | |
// Update preview panel | |
function updatePreview(html, css) { | |
const previewContent = document.getElementById('preview-content'); | |
// Create a style element for the CSS | |
const style = document.createElement('style'); | |
style.textContent = css; | |
// Create a container for the preview | |
previewContent.innerHTML = ` | |
<div class="p-4"> | |
${html} | |
</div> | |
`; | |
// Add the style to the preview | |
previewContent.appendChild(style); | |
} | |
// Platform toggle buttons | |
document.getElementById('ios-btn').addEventListener('click', () => { | |
const preview = document.getElementById('preview-content'); | |
preview.className = 'ios-preview bg-white rounded-3xl p-6 shadow-lg w-full max-w-xs mx-auto border-8 border-gray-800'; | |
}); | |
document.getElementById('android-btn').addEventListener('click', () => { | |
const preview = document.getElementById('preview-content'); | |
preview.className = 'android-preview bg-white rounded-xl p-6 shadow-lg w-full max-w-xs mx-auto border-4 border-green-500'; | |
}); | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> | |
</html> |