571 lines
17 KiB
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;">×</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"><box></span></td><td><code><div></code></td><td>Container box ("If it fits, I sits")</td></tr>
|
|
<tr><td><span class="badge"><purr></span></td><td><code><p></code></td><td>Paragraph text / steady purr</td></tr>
|
|
<tr><td><span class="badge"><meow1>..<meow6></span></td><td><code><h1>..<h6></code></td><td>Headings (roaring to tiny squeak)</td></tr>
|
|
<tr><td><span class="badge"><scratch></span></td><td><code><a></code></td><td>Hyperlink to scratch and chase</td></tr>
|
|
<tr><td><span class="badge"><stare></span></td><td><code><img></code></td><td>Visual image</td></tr>
|
|
<tr><td><span class="badge"><bap></span></td><td><code><button></code></td><td>Action button</td></tr>
|
|
<tr><td><span class="badge"><sniff></span></td><td><code><input></code></td><td>Input field</td></tr>
|
|
<tr><td><span class="badge"><bowl></span></td><td><code><ul></code></td><td>List of food</td></tr>
|
|
<tr><td><span class="badge"><treat></span></td><td><code><li></code></td><td>Individual treat / item</td></tr>
|
|
<tr><td><span class="badge"><claw></span> / <span class="badge"><hiss></span></td><td><code><strong></code> / <code><em></code></td><td>Bold and italic styling</td></tr>
|
|
<tr><td><span class="badge"><groom></span></td><td><code><style></code></td><td>CSS Stylesheet</td></tr>
|
|
<tr><td><span class="badge"><catnip></span></td><td><code><script></code></td><td>JavaScript code (zoomies!)</td></tr>
|
|
<tr><td><span class="badge"><litterbox></span></td><td><code><footer></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><box></claw> instead of divs (if I fits, I sits)</treat>
|
|
<treat>🐟 <claw><bowl></claw> and <claw><treat></claw> for lists</treat>
|
|
<treat>🐾 <claw><bap></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>
|