CaTML/index.html

571 lines
17 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CaTML - Cat Altered Text Markup Language Playground</title>
<script src="catml.js"></script>
<style>
:root {
--bg-warm: #fcf9f5;
--cat-orange: #f76707;
--cat-amber: #ff922b;
--cat-cream: #ffe8cc;
--cat-dark: #2b2622;
--card-bg: #ffffff;
--border-color: #e9ecef;
--code-bg: #1e1e24;
--code-text: #f8f9fa;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: var(--bg-warm);
color: var(--cat-dark);
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
}
header {
background: white;
border-bottom: 2px solid var(--cat-cream);
padding: 12px 24px;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
}
.brand {
display: flex;
align-items: center;
gap: 12px;
}
.brand h1 {
font-size: 20px;
font-weight: 800;
color: var(--cat-orange);
display: flex;
align-items: center;
gap: 8px;
}
.brand .subtitle {
font-size: 13px;
color: #868e96;
font-weight: 500;
}
.controls {
display: flex;
align-items: center;
gap: 10px;
}
select, button {
font-family: inherit;
font-size: 13px;
padding: 8px 14px;
border-radius: 8px;
border: 1px solid #ced4da;
background: white;
cursor: pointer;
transition: all 0.15s ease;
}
select:hover, button:hover {
border-color: var(--cat-amber);
}
.btn-action {
background: var(--cat-orange);
color: white;
font-weight: 600;
border: none;
}
.btn-action:hover {
background: #d9480f;
}
.btn-docs {
background: #f1f3f5;
color: #495057;
border: none;
font-weight: 600;
}
.main-container {
display: flex;
flex: 1;
height: calc(100vh - 65px);
overflow: hidden;
}
.panel {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
border-right: 1px solid var(--border-color);
background: white;
}
.panel:last-child {
border-right: none;
}
.panel-header {
padding: 10px 16px;
background: #f8f9fa;
border-bottom: 1px solid var(--border-color);
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #6c757d;
display: flex;
justify-content: space-between;
align-items: center;
}
.editor-wrapper {
flex: 1;
position: relative;
}
#catml-input {
width: 100%;
height: 100%;
border: none;
padding: 16px;
font-family: "Fira Code", Consolas, "Courier New", monospace;
font-size: 14px;
line-height: 1.5;
background: var(--code-bg);
color: var(--code-text);
resize: none;
outline: none;
tab-size: 2;
}
.tabs {
display: flex;
gap: 4px;
}
.tab-btn {
padding: 4px 10px;
font-size: 11px;
border-radius: 4px;
background: transparent;
border: none;
color: #868e96;
}
.tab-btn.active {
background: white;
color: var(--cat-orange);
font-weight: bold;
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
}
.preview-frame-container {
flex: 1;
position: relative;
background: white;
overflow: auto;
}
#preview-target {
padding: 24px;
min-height: 100%;
}
#html-output-raw {
display: none;
padding: 16px;
font-family: Consolas, monospace;
font-size: 13px;
white-space: pre-wrap;
word-break: break-all;
background: #f8f9fa;
height: 100%;
overflow: auto;
color: #212529;
}
/* Modal for Dictionary */
.modal-overlay {
display: none;
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.5);
z-index: 100;
align-items: center;
justify-content: center;
}
.modal-overlay.open { display: flex; }
.modal-card {
background: white;
width: 700px;
max-width: 90vw;
max-height: 85vh;
border-radius: 12px;
display: flex;
flex-direction: column;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
.modal-header {
padding: 16px 20px;
background: var(--cat-cream);
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-header h2 { font-size: 18px; color: var(--cat-orange); }
.modal-body {
padding: 20px;
overflow-y: auto;
font-size: 14px;
line-height: 1.6;
}
.dict-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
margin-bottom: 20px;
}
.dict-table th, .dict-table td {
border: 1px solid #dee2e6;
padding: 8px 12px;
text-align: left;
}
.dict-table th { background: #f8f9fa; }
.badge {
display: inline-block;
padding: 2px 6px;
background: #e9ecef;
border-radius: 4px;
font-family: monospace;
font-size: 12px;
}
</style>
</head>
<body>
<header>
<div class="brand">
<h1>🐾 CaTML Playground</h1>
<span class="subtitle">Cat Altered Text Markup Language</span>
</div>
<div class="controls">
<select id="template-select">
<option value="welcome">Template: Welcome to CaTML</option>
<option value="bapGame">Template: Interactive Bap Game</option>
<option value="adoptionForm">Template: Feline Adoption Form</option>
<option value="portfolio">Template: Whiskers Portfolio</option>
</select>
<button class="btn-docs" onclick="toggleDictionary()">📖 Dictionary</button>
<button class="btn-action" onclick="runCatML()">▶ Run / Compile</button>
</div>
</header>
<div class="main-container">
<!-- Left Panel: Editor -->
<div class="panel">
<div class="panel-header">
<span>CaTML Code Input</span>
<span style="font-size: 10px; text-transform: none; color: #adb5bd;">Type in CaTML - updates automatically</span>
</div>
<div class="editor-wrapper">
<textarea id="catml-input" spellcheck="false" placeholder="Write your CaTML code here..."></textarea>
</div>
</div>
<!-- Right Panel: Output & Live Preview -->
<div class="panel">
<div class="panel-header">
<span>Output</span>
<div class="tabs">
<button class="tab-btn active" id="tab-btn-preview" onclick="showTab('preview')">Live Browser Preview</button>
<button class="tab-btn" id="tab-btn-html" onclick="showTab('html')">Generated HTML</button>
</div>
</div>
<div class="preview-frame-container">
<div id="preview-target"></div>
<pre id="html-output-raw"></pre>
</div>
</div>
</div>
<!-- Dictionary Modal -->
<div class="modal-overlay" id="dict-modal" onclick="if(event.target===this) toggleDictionary()">
<div class="modal-card">
<div class="modal-header">
<h2>🐾 CaTML Feline Vocabulary Guide</h2>
<button onclick="toggleDictionary()" style="border:none;background:none;font-size:20px;cursor:pointer;">&times;</button>
</div>
<div class="modal-body">
<h3>Core Tags</h3>
<table class="dict-table">
<tr><th>CaTML Tag</th><th>HTML Equivalent</th><th>Meaning</th></tr>
<tr><td><span class="badge">&lt;box&gt;</span></td><td><code>&lt;div&gt;</code></td><td>Container box ("If it fits, I sits")</td></tr>
<tr><td><span class="badge">&lt;purr&gt;</span></td><td><code>&lt;p&gt;</code></td><td>Paragraph text / steady purr</td></tr>
<tr><td><span class="badge">&lt;meow1&gt;..&lt;meow6&gt;</span></td><td><code>&lt;h1&gt;..&lt;h6&gt;</code></td><td>Headings (roaring to tiny squeak)</td></tr>
<tr><td><span class="badge">&lt;scratch&gt;</span></td><td><code>&lt;a&gt;</code></td><td>Hyperlink to scratch and chase</td></tr>
<tr><td><span class="badge">&lt;stare&gt;</span></td><td><code>&lt;img&gt;</code></td><td>Visual image</td></tr>
<tr><td><span class="badge">&lt;bap&gt;</span></td><td><code>&lt;button&gt;</code></td><td>Action button</td></tr>
<tr><td><span class="badge">&lt;sniff&gt;</span></td><td><code>&lt;input&gt;</code></td><td>Input field</td></tr>
<tr><td><span class="badge">&lt;bowl&gt;</span></td><td><code>&lt;ul&gt;</code></td><td>List of food</td></tr>
<tr><td><span class="badge">&lt;treat&gt;</span></td><td><code>&lt;li&gt;</code></td><td>Individual treat / item</td></tr>
<tr><td><span class="badge">&lt;claw&gt;</span> / <span class="badge">&lt;hiss&gt;</span></td><td><code>&lt;strong&gt;</code> / <code>&lt;em&gt;</code></td><td>Bold and italic styling</td></tr>
<tr><td><span class="badge">&lt;groom&gt;</span></td><td><code>&lt;style&gt;</code></td><td>CSS Stylesheet</td></tr>
<tr><td><span class="badge">&lt;catnip&gt;</span></td><td><code>&lt;script&gt;</code></td><td>JavaScript code (zoomies!)</td></tr>
<tr><td><span class="badge">&lt;litterbox&gt;</span></td><td><code>&lt;footer&gt;</code></td><td>Footer container</td></tr>
</table>
<h3>Attributes</h3>
<table class="dict-table">
<tr><th>CaTML Attribute</th><th>HTML Equivalent</th><th>Purpose</th></tr>
<tr><td><span class="badge">catch="..."</span></td><td><code>href="..."</code></td><td>Link URL</td></tr>
<tr><td><span class="badge">prey="..."</span></td><td><code>src="..."</code></td><td>Image Source</td></tr>
<tr><td><span class="badge">scent="..."</span></td><td><code>alt="..."</code></td><td>Alternative text</td></tr>
<tr><td><span class="badge">tag="..."</span></td><td><code>id="..."</code></td><td>Element ID</td></tr>
<tr><td><span class="badge">breed="..."</span></td><td><code>class="..."</code></td><td>CSS Class</td></tr>
<tr><td><span class="badge">fluff="..."</span></td><td><code>style="..."</code></td><td>Inline Styles</td></tr>
<tr><td><span class="badge">on-bap="..."</span></td><td><code>onclick="..."</code></td><td>Click handler</td></tr>
<tr><td><span class="badge">on-sniff="..."</span></td><td><code>oninput="..."</code></td><td>Input listener</td></tr>
<tr><td><span class="badge">treat-type="..."</span></td><td><code>type="..."</code></td><td>Input type</td></tr>
<tr><td><span class="badge">curiosity="..."</span></td><td><code>placeholder="..."</code></td><td>Placeholder prompt</td></tr>
</table>
</div>
</div>
</div>
<script>
const TEMPLATES = {
welcome: `<groom>
.cat-hero {
background: linear-gradient(135deg, #ffe8cc, #ffd8a8);
border-radius: 12px;
padding: 24px;
border: 2px dashed #f76707;
}
.highlight { color: #d9480f; font-weight: bold; }
.bap-btn {
background: #f76707;
color: white;
border: none;
padding: 10px 18px;
border-radius: 20px;
cursor: pointer;
font-weight: bold;
}
</groom>
<box breed="cat-hero">
<meow1>🐾 Welcome to CaTML!</meow1>
<purr>
You are writing <claw>Cat Altered Text Markup Language</claw>.
Standard web markup translated for fine felines.
</purr>
<meow2>Why CaTML?</meow2>
<bowl>
<treat>🐱 <claw>&lt;box&gt;</claw> instead of divs (if I fits, I sits)</treat>
<treat>🐟 <claw>&lt;bowl&gt;</claw> and <claw>&lt;treat&gt;</claw> for lists</treat>
<treat>🐾 <claw>&lt;bap&gt;</claw> buttons with <hiss>on-bap</hiss> events</treat>
</bowl>
<bap breed="bap-btn" on-bap="alert('🐾 MEOW! You clicked with your furry paw!')">
Bap Me Now!
</bap>
</box>`,
bapGame: `<groom>
.counter-box {
text-align: center;
padding: 30px;
background: #f8f9fa;
border-radius: 16px;
border: 3px solid #ffa94d;
}
.score-display {
font-size: 48px;
color: #e8590c;
font-weight: 900;
margin: 15px 0;
}
.btn-counter {
background: #e8590c;
color: white;
font-size: 18px;
padding: 12px 28px;
border: none;
border-radius: 24px;
cursor: pointer;
box-shadow: 0 4px 12px rgba(232, 89, 12, 0.3);
}
.btn-counter:active {
transform: scale(0.95);
}
</groom>
<box breed="counter-box">
<meow1>🐾 The Infinite Counter-Bapper</meow1>
<purr>How many cups can your paws knock off the edge?</purr>
<box tag="score" breed="score-display">0</box>
<bap breed="btn-counter" on-bap="let el=document.getElementById('score'); el.innerText=parseInt(el.innerText)+1;">
🥛 Bap The Cup!
</bap>
<purr fluff="margin-top: 15px; color: #868e96; font-size: 13px;">
Each bap increases your feline chaos level.
</purr>
</box>`,
adoptionForm: `<groom>
.form-card {
background: #fff;
border: 1px solid #dee2e6;
border-radius: 12px;
padding: 24px;
max-width: 500px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
}
.input-group { margin-bottom: 16px; }
.input-group label { display: block; font-weight: bold; margin-bottom: 6px; font-size: 14px; }
.field {
width: 100%;
padding: 10px;
border: 2px solid #e9ecef;
border-radius: 8px;
font-size: 14px;
}
.field:focus { border-color: #f76707; outline: none; }
.submit-paw {
width: 100%;
background: #2b8a3e;
color: white;
padding: 12px;
border-radius: 8px;
border: none;
font-size: 16px;
font-weight: bold;
cursor: pointer;
}
</groom>
<box breed="form-card">
<meow2>🐾 Royal Kitten Adoption Application</meow2>
<purr>Tell us about your home and treat budget.</purr>
<door>
<box breed="input-group">
<purr><claw>Human Name:</claw></purr>
<sniff breed="field" treat-type="text" curiosity="e.g. Servant John" />
</box>
<box breed="input-group">
<purr><claw>Daily Salmon Guarantee:</claw></purr>
<sniff breed="field" treat-type="number" kibble="3" curiosity="Cans per day" />
</box>
<box breed="input-group">
<purr><claw>Special Sleeping Spots:</claw></purr>
<yowl breed="field" curiosity="Describe all pillows, laps, and warm laptops available..."></yowl>
</box>
<bap breed="submit-paw" on-bap="alert('Application received! A council of cats will inspect your lap.')">
Pledge Loyalty (Submit)
</bap>
</door>
</box>`,
portfolio: `<groom>
.profile-wrap { display: flex; gap: 20px; align-items: center; margin-bottom: 20px; }
.avatar { font-size: 60px; background: #ffe8cc; border-radius: 50%; padding: 15px; }
.badge { background: #ffe3e3; color: #e03131; padding: 4px 8px; border-radius: 4px; font-size: 12px; }
</groom>
<box>
<curtain>
<box breed="profile-wrap">
<feather breed="avatar">🐱</feather>
<box>
<meow1>Sir Pounce-a-Lot</meow1>
<purr><hiss>Senior Software Mouse Catcher & Nap Architect</hiss></purr>
<feather breed="badge">Open to Treats</feather>
</box>
</box>
</curtain>
<perch>
<meow3>Core Proficiencies</meow3>
<bowl>
<treat><claw>Zoomies at 3 AM</claw> - 99.8% Efficiency</treat>
<treat><claw>Keyboard Warming</claw> - Full-stack coverage</treat>
<treat><claw>Laser Chasing</claw> - High-frequency agile response</treat>
</bowl>
</perch>
<litterbox fluff="margin-top: 30px; border-top: 1px solid #eee; padding-top: 10px;">
<purr>Contact: <scratch catch="mailto:pounce@catml.org">pounce@catml.org</scratch></purr>
</litterbox>
</box>`
};
const editor = document.getElementById('catml-input');
const previewTarget = document.getElementById('preview-target');
const htmlOutputRaw = document.getElementById('html-output-raw');
const templateSelect = document.getElementById('template-select');
const modal = document.getElementById('dict-modal');
function runCatML() {
const source = editor.value;
const compiledHTML = CatML.compile(source);
// Update Preview
CatML.render(source, previewTarget);
// Update Raw HTML
htmlOutputRaw.textContent = compiledHTML;
}
let debounceTimer;
editor.addEventListener('input', () => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(runCatML, 250);
});
templateSelect.addEventListener('change', (e) => {
const selected = e.target.value;
if (TEMPLATES[selected]) {
editor.value = TEMPLATES[selected];
runCatML();
}
});
function showTab(tab) {
if (tab === 'preview') {
previewTarget.style.display = 'block';
htmlOutputRaw.style.display = 'none';
document.getElementById('tab-btn-preview').classList.add('active');
document.getElementById('tab-btn-html').classList.remove('active');
} else {
previewTarget.style.display = 'none';
htmlOutputRaw.style.display = 'block';
document.getElementById('tab-btn-preview').classList.remove('active');
document.getElementById('tab-btn-html').classList.add('active');
}
}
function toggleDictionary() {
modal.classList.toggle('open');
}
// Initialize with default template
editor.value = TEMPLATES.welcome;
runCatML();
</script>
</body>
</html>