2663 lines
93 KiB
GDScript
2663 lines
93 KiB
GDScript
extends Node
|
||
|
||
const MAIN_COLOR = Color(27/255.0, 27/255.0, 27/255.0, 1)
|
||
const SECONDARY_COLOR = Color(43/255.0, 43/255.0, 43/255.0, 1)
|
||
|
||
const HOVER_COLOR = Color(0, 0, 0, 1)
|
||
|
||
const DEFAULT_CSS = """
|
||
body { text-base text-[#000000] text-left }
|
||
h1 { text-5xl font-bold }
|
||
h2 { text-4xl font-bold }
|
||
h3 { text-3xl font-bold }
|
||
h4 { text-2xl font-bold }
|
||
h5 { text-xl font-bold }
|
||
b { font-bold }
|
||
i { font-italic }
|
||
u { underline }
|
||
small { text-xl }
|
||
mark { bg-[#FFFF00] }
|
||
code { text-xl font-mono }
|
||
a { text-[#1a0dab] }
|
||
pre { text-xl font-mono }
|
||
|
||
button { text-[16px] bg-[#1b1b1b] rounded-md text-white hover:bg-[#2a2a2a] active:bg-[#101010] }
|
||
button[disabled] { bg-[#666666] text-[#999999] cursor-not-allowed }
|
||
"""
|
||
|
||
var HTML_CONTENT2 = """<head>
|
||
<title>My Custom Dashboard</title>
|
||
<icon src="https://cdn-icons-png.flaticon.com/512/1828/1828774.png">
|
||
<meta name="theme-color" content="#1a202c">
|
||
<meta name="description" content="A stylish no-script dashboard">
|
||
|
||
<font name="roboto" src="https://fonts.gstatic.com/s/roboto/v48/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3KUBGEe.woff2" />
|
||
|
||
<style>
|
||
h1 { text-[#ffffff] text-3xl font-bold }
|
||
h2 { text-[#cbd5e1] text-xl }
|
||
p { text-[#94a3b8] text-base }
|
||
button { bg-[#4ade80] text-[#ffffff] hover:bg-[#22c55e] active:bg-[#15803d] }
|
||
.card { bg-[#1e293b] text-[#f8fafc] rounded-xl p-4 shadow-lg }
|
||
</style>
|
||
</head>
|
||
|
||
<body style="bg-[#0f172a] p-8 text-white font-roboto">
|
||
<h1 style="text-center mb-4">📊 My Dashboard</h1>
|
||
|
||
<!-- Top Summary Cards -->
|
||
<div style="flex flex-row gap-4 justify-center flex-wrap">
|
||
<div style="card w-48 h-24 flex flex-col justify-center items-center">
|
||
<h2 style="text-red-500">Users</h2>
|
||
<p>1,240</p>
|
||
</div>
|
||
<div style="card w-48 h-24 flex flex-col justify-center items-center">
|
||
<h2>Sales</h2>
|
||
<p>$9,842</p>
|
||
</div>
|
||
<div style="card w-48 h-24 flex flex-col justify-center items-center">
|
||
<h2>Visitors</h2>
|
||
<p>3,590</p>
|
||
</div>
|
||
</div>
|
||
|
||
<separator direction="horizontal" />
|
||
|
||
<!-- User Info Panel -->
|
||
<h2 style="text-center mt-6">👤 User Panel</h2>
|
||
<div style="flex flex-row gap-4 justify-center mt-2">
|
||
<div style="card w-64">
|
||
<p>Name: Jane Doe</p>
|
||
<p>Email: jane@example.com</p>
|
||
<p>Status: <span style="text-[#22c55e]">Active</span></p>
|
||
</div>
|
||
<div style="card w-64">
|
||
<p>Plan: Pro</p>
|
||
<p>Projects: 8</p>
|
||
<p>Tasks: 42</p>
|
||
</div>
|
||
</div>
|
||
|
||
<separator direction="horizontal" />
|
||
|
||
<!-- Recent Activity Log -->
|
||
<h2 style="text-center mt-6">📝 Recent Activity</h2>
|
||
<ul style="w-[80%] mt-2 flex justify-center flex-column gap-2">
|
||
<li style="bg-[#334155] px-4 py-2 rounded-xl mb-1">✅ Task "Update UI" marked as complete</li>
|
||
<li style="bg-[#334155] px-4 py-2 rounded-xl mb-1">🔔 New comment on "Bug Fix #224"</li>
|
||
<li style="bg-[#334155] px-4 py-2 rounded-xl mb-1">📤 Exported report "Q2 Metrics"</li>
|
||
</ul>
|
||
|
||
<separator direction="horizontal" />
|
||
|
||
<!-- Action Buttons -->
|
||
<h2 style="text-center mt-6">🔧 Actions</h2>
|
||
<div style="flex flex-row gap-2 justify-center mt-2">
|
||
<button style="rounded-lg px-4 py-2">Create Report</button>
|
||
<button style="rounded-lg px-4 py-2 bg-[#3b82f6] hover:bg-[#2563eb] active:bg-[#1e40af]">Invite User</button>
|
||
<button style="rounded-lg px-4 py-2 bg-[#facc15] text-[#000] hover:bg-[#eab308] active:bg-[#ca8a04]">Upgrade Plan</button>
|
||
</div>
|
||
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
var HTML_CONTENTvv = """<head>
|
||
<title>My cool web</title>
|
||
<icon src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/768px-Google_%22G%22_logo.svg.png\">
|
||
|
||
<meta name=\"theme-color\" content=\"#000000\">
|
||
<meta name=\"description\" content=\"My cool web\">
|
||
|
||
<font name="roboto" src="https://fonts.gstatic.com/s/roboto/v48/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3KUBGEe.woff2" />
|
||
|
||
<style>
|
||
h1 { text-[#ff0000] font-italic hover:text-[#00ff00] }
|
||
button { hover:bg-[#FF6B35] hover:text-[#FFFFFF] active:bg-[#CC5429] active:text-[#F0F0F0] }
|
||
</style>
|
||
<style src=\"styles.css\">
|
||
<script src=\"script.lua\" />
|
||
</head>
|
||
|
||
<body>
|
||
<h1>Header 1</h1>
|
||
<h2>Header 2</h2>
|
||
<h3>Header 3</h3>
|
||
<h4>Header 4</h4>
|
||
<h5>Header 5</h5>
|
||
<h6>Header 6</h6>
|
||
|
||
<separator />
|
||
|
||
<p>Normal font</p>
|
||
<p style="font-mono">Mono font</p>
|
||
<p style="font-sans">Sans font</p>
|
||
<p style="font-roboto">Custom font - Roboto</p>
|
||
|
||
<p>Hey there! this is a test</p>
|
||
<b>This is bold</b>
|
||
<i>This is italic <mark>actually, and it's pretty <u>cool</u></mark></i>
|
||
<u>This is underline</u>
|
||
<small>this is small</small>
|
||
<mark>this is marked</mark>
|
||
<code>this is code<span> THIS IS A SPAN AND SHOULDNT BE ANY DIFFERENT</span></code>
|
||
|
||
<p>
|
||
<a href="https://youtube.com">Hello gang</a>
|
||
</p>
|
||
|
||
<pre>
|
||
Text in a pre element
|
||
is displayed in a fixed-width
|
||
font, and it preserves
|
||
both spaces and
|
||
line breaks
|
||
</pre>
|
||
|
||
<p style="text-center w-32 h-32">
|
||
So
|
||
</p>
|
||
|
||
<div>
|
||
<button style="rounded-lg px-4 py-2 cursor-pointer">Create Report</button>
|
||
<button style="rounded-lg px-4 py-2 bg-[#3b82f6] hover:bg-[#2563eb] active:bg-[#1e40af] cursor-pointer">Invite User</button>
|
||
<button style="rounded-lg px-4 py-2 bg-[#facc15] text-[#000] hover:bg-[#eab308] active:bg-[#ca8a04] cursor-pointer">Upgrade Plan</button>
|
||
</div>
|
||
<button disabled="true">Disabled Button</button>
|
||
<button>Normal Button</button>
|
||
|
||
<separator direction="horizontal" />
|
||
|
||
<!-- Test CSS Properties -->
|
||
<h2 style="text-center mt-6">🧪 CSS Properties Test</h2>
|
||
<div style="flex flex-col gap-2 justify-center items-center mt-2">
|
||
<div style="bg-[#ef4444] text-white p-4 rounded-lg opacity-75 z-10 cursor-pointer">
|
||
<p>Opacity 75% with cursor pointer and z-index 10 - Text should show pointer cursor, not I-beam</p>
|
||
</div>
|
||
<div style="bg-[#10b981] text-white p-4 rounded-lg opacity-50 z-20 cursor-text">
|
||
<p>Opacity 50% with cursor text and z-index 20 - Text should show I-beam cursor</p>
|
||
</div>
|
||
<div style="bg-[#8b5cf6] text-white p-4 rounded-lg opacity-[0.25] z-[999] cursor-default">
|
||
<p>Custom opacity 0.25 with cursor default and z-index 999 - Text should show arrow cursor</p>
|
||
</div>
|
||
<div style="bg-[#f59e0b] text-white p-2 rounded cursor-move">
|
||
<p>Cursor move - Text should show move cursor</p>
|
||
</div>
|
||
<div style="bg-[#06b6d4] text-white p-2 rounded cursor-crosshair">
|
||
<p>Cursor crosshair - Text should show crosshair cursor</p>
|
||
</div>
|
||
<div style="bg-[#84cc16] text-white p-2 rounded cursor-help">
|
||
<p>Cursor help - Text should show help cursor</p>
|
||
</div>
|
||
<div style="bg-[#ec4899] text-white p-2 rounded cursor-not-allowed">
|
||
<p>Cursor not-allowed - Text should show forbidden cursor</p>
|
||
</div>
|
||
</div>
|
||
|
||
<separator direction="horizontal" />
|
||
|
||
<!-- Test cursor inheritance -->
|
||
<h2 style="text-center mt-6">🖱️ Cursor Inheritance Test</h2>
|
||
<div style="cursor-pointer bg-[#1e293b] p-4 rounded-lg">
|
||
<p>This paragraph is inside a div with cursor-pointer.</p>
|
||
<p>Both paragraphs should show pointer cursor instead of default I-beam.</p>
|
||
<div style="bg-[#334155] p-2 rounded mt-2">
|
||
<p>This nested paragraph should also inherit the pointer cursor.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Border examples -->
|
||
<div style="border p-2 mb-2">border</div>
|
||
<div style="border-2 p-2 mb-2">border-2</div>
|
||
<div style="border-4 p-2 mb-2">border-4</div>
|
||
<div style="border-2 border-red-500 p-2 mb-2">border-2 border-red-500</div>
|
||
<div style="border p-2 mb-2">border-solid</div>
|
||
<div style="border border-dashed p-2 mb-2">border-dashed</div>
|
||
<div style="border border-dotted p-2 mb-2">border-dotted</div>
|
||
<div style="border-none p-2 mb-2">border-none</div>
|
||
<div style="border-t p-2 mb-2">border-t</div>
|
||
<div style="border-r p-2 mb-2">border-r</div>
|
||
<div style="border-b p-2 mb-2">border-b</div>
|
||
<div style="border-l p-2 mb-2">border-l</div>
|
||
<div style="border-t-4 p-2 mb-2">border-t-4</div>
|
||
<div style="border-b-2 p-2 mb-2">border-b-2</div>
|
||
<div style="border-l-6 p-2 mb-2">border-l-6</div>
|
||
<div style="border-t-3 border-green-500 p-2 mb-2">border-t-3 border-green-500</div>
|
||
<div style="border border-white p-2 mb-2">border-white</div>
|
||
<div style="border border-black p-2 mb-2">border-black</div>
|
||
<div style="border border-transparent p-2 mb-2">border-transparent</div>
|
||
<div style="border border-gray-400 p-2 mb-2">border-gray-400</div>
|
||
<div style="border border-slate-700 p-2 mb-2">border-slate-700</div>
|
||
<div style="border border-red-500 p-2 mb-2">border-red-500</div>
|
||
<div style="border border-green-600 p-2 mb-2">border-green-600</div>
|
||
<div style="border border-blue-400 p-2 mb-2">border-blue-400</div>
|
||
<div style="border border-yellow-300 p-2 mb-2">border-yellow-300</div>
|
||
|
||
<select style=\"text-center max-w-5 max-h-32\">
|
||
<option value=\"test1\">Test 1</option>
|
||
<option value=\"test2\" selected=\"true\">Test 2</option>
|
||
<option value=\"test3\">Test 3</option>
|
||
<option value=\"test4\" disabled=\"true\">Test 4</option>
|
||
<option value=\"test5\">Test 5</option>
|
||
</select>
|
||
|
||
<textarea />
|
||
<textarea cols=\"30\" />
|
||
<textarea rows=\"2\" />
|
||
<textarea maxlength=\"20\" />
|
||
<textarea readonly=\"true\">le skibidi le toilet</textarea>
|
||
<textarea disabled=\"true\" value=\"DISABLED\" />
|
||
<textarea placeholder=\"this is a placeholder...\" />
|
||
|
||
<!-- action, method, and type=submit are for when we implement Lua -->
|
||
<form action=\"/submit\" method=\"POST\">
|
||
<span>Name:</span>
|
||
<input type=\"text\" placeholder=\"First name\" value=\"John\" maxlength=\"20\" minlength=\"3\" />
|
||
<span>Email regex:</span>
|
||
<input type=\"text\" placeholder=\"Last name\" value=\"Doe\" pattern=\"^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$\" />
|
||
<span>Smart:</span>
|
||
<input type=\"checkbox\" />
|
||
<input type=\"checkbox\" value=\"true\" />
|
||
|
||
<p>favorite food</p>
|
||
<input type=\"radio\" group=\"food\" />
|
||
<span>Pizza</span>
|
||
<input type=\"radio\" group=\"food\" />
|
||
<span>Berry</span>
|
||
<input type=\"radio\" group=\"food\" />
|
||
<span>Gary</span>
|
||
|
||
<h2>Color</h2>
|
||
<input type=\"color\" value=\"#ff0000\" />
|
||
<h2>Date</h2>
|
||
<input type=\"date\" value=\"2018-07-22\" />
|
||
|
||
<h2>Range Slider</h2>
|
||
<input style=\"max-w-2 max-h-2\" type=\"range\" min=\"0\" max=\"100\" step=\"5\" value=\"50\" />
|
||
|
||
<h2>Number Input</h2>
|
||
<input type=\"number\" min=\"1\" max=\"10\" step=\"0.5\" value=\"5\" placeholder=\"Enter number\" />
|
||
|
||
<h2>File Upload</h2>
|
||
<input type=\"file\" accept=\".txt,.pdf,image/*\" />
|
||
</form>
|
||
<separator direction=\"horizontal\" />
|
||
# Ordered list
|
||
<ol>
|
||
<li>hello gang</li>
|
||
<li>this</li>
|
||
<li>is</li>
|
||
</ol>
|
||
|
||
<ol type=\"zero-lead\">
|
||
<li>hello gang</li>
|
||
<li>this</li>
|
||
<li>is</li>
|
||
<li>a test</li>
|
||
</ol>
|
||
|
||
<ol type=\"lower-alpha\">
|
||
<li>hello gang</li>
|
||
<li>this</li>
|
||
<li>is</li>
|
||
<li>a test</li>
|
||
</ol>
|
||
|
||
<ol type=\"upper-alpha\">
|
||
<li>hello gang</li>
|
||
<li>this</li>
|
||
<li>is</li>
|
||
<li>a test</li>
|
||
</ol>
|
||
|
||
|
||
<ol type=\"lower-roman\">
|
||
<li>hello gang</li>
|
||
<li>this</li>
|
||
<li>is</li>
|
||
<li>a test</li>
|
||
</ol>
|
||
|
||
<ol type=\"upper-roman\">
|
||
<li>hello gang</li>
|
||
<li>this</li>
|
||
<li>is</li>
|
||
<li>a test</li>
|
||
</ol>
|
||
|
||
<ul>
|
||
<li>hello gang</li>
|
||
<li>this</li>
|
||
<li>is</li>
|
||
<li>a test</li>
|
||
</ul>
|
||
|
||
<ul type=\"circle\">
|
||
<li>hello gang</li>
|
||
<li>this</li>
|
||
<li>is</li>
|
||
<li>a test</li>
|
||
</ul>
|
||
<ul type=\"none\">
|
||
<li>hello gang</li>
|
||
<li>this</li>
|
||
<li>is</li>
|
||
<li>a test</li>
|
||
</ul>
|
||
<ul type=\"square\">
|
||
<li>hello gang</li>
|
||
<li>this</li>
|
||
<li>is</li>
|
||
<li>a test</li>
|
||
</ul>
|
||
<img style=\"text-center max-w-24 max-h-24\" src=\"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQMNUPIKabszX0Js_c0kfa4cz_JQYKfGTuBUA&s\" />
|
||
<separator direction=\"vertical\" />
|
||
|
||
<!-- FLEXBOX EXAMPLES -->
|
||
<h2>Flex Row (gap, justify-between, items-center)</h2>
|
||
<div style=\"flex flex-row gap-4 justify-between items-center w-64 h-16 bg-[#f0f0f0]\">
|
||
<span style=\"bg-[#ffaaaa] w-16 h-8 flex items-center justify-center\">A</span>
|
||
<span style=\"bg-[#aaffaa] w-16 h-8 flex items-center justify-center\">B</span>
|
||
<span style=\"bg-[#aaaaff] w-16 h-8 flex items-center justify-center\">C</span>
|
||
</div>
|
||
|
||
<h2>Flex Column (gap, items-center, content-center)</h2>
|
||
<div style=\"flex flex-col gap-2 items-center content-center h-32 w-32 bg-[#e0e0e0]\">
|
||
<span style=\"bg-[#ffaaaa] w-16 h-6 flex items-center justify-center\">1</span>
|
||
<span style=\"bg-[#aaffaa] w-16 h-6 flex items-center justify-center\">2</span>
|
||
<span style=\"bg-[#aaaaff] w-16 h-6 flex items-center justify-center\">3</span>
|
||
</div>
|
||
|
||
<h2>Flex Wrap (row, wrap, gap)</h2>
|
||
<div style=\"flex flex-row flex-wrap gap-2 w-40 bg-[#f8f8f8]\">
|
||
<span style=\"bg-[#ffaaaa] w-16 h-6 flex items-center justify-center\">X</span>
|
||
<span style=\"bg-[#aaffaa] w-16 h-6 flex items-center justify-center\">Y</span>
|
||
<span style=\"bg-[#aaaaff] w-16 h-6 flex items-center justify-center\">Z</span>
|
||
<span style=\"bg-[#ffffaa] w-16 h-6 flex items-center justify-center\">W</span>
|
||
</div>
|
||
|
||
<h2>Flex Grow/Shrink/Basis</h2>
|
||
<div style=\"flex flex-row gap-2 w-64 bg-[#f0f0f0]\">
|
||
<span style=\"bg-[#ffaaaa] flex-grow-1 h-8 flex items-center justify-center\">Grow 1</span>
|
||
<span style=\"bg-[#aaffaa] flex-grow-2 h-8 flex items-center justify-center\">Grow 2</span>
|
||
<span style=\"bg-[#aaaaff] flex-shrink-0 w-8 h-8 flex items-center justify-center\">No Shrink</span>
|
||
</div>
|
||
|
||
<h2>Align Self</h2>
|
||
<div style=\"flex flex-row h-24 bg-[#f0f0f0] items-stretch gap-2 w-64\">
|
||
<span style=\"bg-[#ffaaaa] w-12 h-8 self-start flex items-center justify-center\">Start</span>
|
||
<span style=\"bg-[#aaffaa] w-12 h-8 self-center flex items-center justify-center\">Center</span>
|
||
<span style=\"bg-[#aaaaff] w-12 h-8 self-end flex items-center justify-center\">End</span>
|
||
<span style=\"bg-[#ffffaa] w-12 h-8 self-stretch flex items-center justify-center\">Stretch</span>
|
||
</div>
|
||
</body>""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENT_S = """<head>
|
||
<title>CSS Selector Tests</title>
|
||
<style>
|
||
/* Descendant selectors */
|
||
div p { text-[#663399] }
|
||
.container span { bg-[#ffeeaa] }
|
||
|
||
/* Direct child selectors */
|
||
.outer-div > p { font-bold }
|
||
.parent > button { bg-[#44cc88] }
|
||
|
||
/* Adjacent sibling selectors */
|
||
h1 + p { text-[#ff0000] font-bold }
|
||
h2 + div { bg-[#eeffee] }
|
||
|
||
/* General sibling selectors */
|
||
h1 ~ p { text-[#0000ff] }
|
||
h1 ~ .second-p { text-[#0000ff] }
|
||
h3 ~ span { bg-[#ffdddd] }
|
||
|
||
/* Attribute selectors */
|
||
input[type="text"] { border border-[#cccccc] bg-[#f9f9f9] }
|
||
a[href^="https"] { text-[#008000] font-bold }
|
||
button[disabled] { bg-[#888888] text-[#cccccc] }
|
||
input[placeholder*="email"] { border-2 border-[#0066cc] bg-[#ffffff] }
|
||
div[style$="special"] { bg-[#ffffaa] }
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<h1>CSS Selector Test Page</h1>
|
||
<p>This paragraph should be red and bold (h1 + p)</p>
|
||
<p style="second-p">This paragraph should be blue (h1 ~ p)</p>
|
||
|
||
<h2>Descendant vs Child Selectors</h2>
|
||
<div style="outer-div">
|
||
<p>This paragraph should be purple and bold (div p and .outer-div > p)</p>
|
||
<div>
|
||
<p>This paragraph should be purple but not bold (div p only)</p>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>Attribute Selectors</h3>
|
||
<input type="text" placeholder="Enter your name" />
|
||
<input type="text" placeholder="Enter your email address" />
|
||
<input type="password" placeholder="Enter password" />
|
||
|
||
<br />
|
||
<a href="http://example.com">HTTP Link (normal)</a>
|
||
<br />
|
||
<a href="https://secure.com">HTTPS Link (green and bold)</a>
|
||
|
||
<br />
|
||
<button>Normal Button</button>
|
||
<button disabled="true">Disabled Button (gray)</button>
|
||
|
||
<h3>Sibling Selectors</h3>
|
||
<div style="bg-[#eeffee]">This div should have light green bg (h2 + div)</div>
|
||
<span>This span should have light red bg (h3 ~ span)</span>
|
||
<span>This span should also have light red bg (h3 ~ span)</span>
|
||
|
||
<div style="container">
|
||
<span>This span should have yellow bg (.container span)</span>
|
||
<p>Regular paragraph in container</p>
|
||
</div>
|
||
|
||
<div style="parent">
|
||
<button>This button should be green (.parent > button)</button>
|
||
<div>
|
||
<button>This button should be normal (not direct child)</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="item-special">This div should have yellow bg (class ends with 'special')</div>
|
||
<div style="special-item">This div should be normal</div>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENT3 = """<head>
|
||
<title>Task Manager</title>
|
||
<icon src="https://cdn-icons-png.flaticon.com/512/126/126472.png">
|
||
|
||
<meta name="theme-color" content="#1e1e2f">
|
||
<meta name="description" content="Manage your tasks easily.">
|
||
|
||
<style>
|
||
h1 { text-[#4ade80] text-3xl font-bold }
|
||
p { text-[#94a3b8] text-lg }
|
||
input { border border-[#cbd5e1] px-2 py-1 rounded }
|
||
</style>
|
||
|
||
<script src="logic.lua" />
|
||
</head>
|
||
|
||
<body>
|
||
<h1 style="text-center">📝 My Task Manager</h1>
|
||
<p style="text-center mb-4">Keep track of your to-do list</p>
|
||
|
||
<!-- Task List -->
|
||
<div style="flex flex-col gap-2 w-80 mx-auto bg-[#f8fafc] p-4 rounded">
|
||
<span style="flex justify-between items-center bg-[#e2e8f0] px-2 py-1 rounded">
|
||
<span>✅ Finish homework</span>
|
||
<button style="bg-[#4ade80] text-[#ffffff] hover:bg-[#22c55e]">Delete</button>
|
||
</span>
|
||
<span style="flex justify-between items-center bg-[#e2e8f0] px-2 py-1 rounded">
|
||
<span>✍️ Write blog post</span>
|
||
<button style="bg-[#4ade80] text-[#ffffff] hover:bg-[#22c55e]">Delete</button>
|
||
</span>
|
||
<span style="flex justify-between items-center bg-[#e2e8f0] px-2 py-1 rounded">
|
||
<span>💪 Gym workout</span>
|
||
<button style="bg-[#4ade80] text-[#ffffff] hover:bg-[#22c55e]">Delete</button>
|
||
</span>
|
||
</div>
|
||
|
||
<separator direction="horizontal" />
|
||
|
||
<!-- Add New Task -->
|
||
<h2 style="text-center mt-4">Add a New Task</h2>
|
||
<form action="/add-task" method="POST" style="flex flex-col gap-2 w-80 mx-auto">
|
||
<input type="text" placeholder="Enter task..." minlength="3" required="true" />
|
||
<input type="date" />
|
||
<button type="submit" style="bg-[#4ade80] text-[#ffffff] hover:bg-[#22c55e]">Add Task</button>
|
||
</form>
|
||
|
||
<separator direction="horizontal" />
|
||
|
||
<h2 style="text-center">Task Categories</h2>
|
||
<div style="flex flex-row gap-2 justify-center items-center w-full">
|
||
<span style="bg-[#fef3c7] px-4 py-2 rounded">📚 Study</span>
|
||
<span style="bg-[#d1fae5] px-4 py-2 rounded">💼 Work</span>
|
||
<span style="bg-[#e0e7ff] px-4 py-2 rounded">🏋️ Health</span>
|
||
</div>
|
||
|
||
<form>
|
||
<input type=\"password\" placeholder=\"your password...\" />
|
||
<button type=\"submit\" style=\"bg-[#4CAF50] rounded-lg text-[#FFFFFF]\">Submit</button>
|
||
<button style=\"bg-[#2196F3] rounded-xl text-[#FFFFFF]\">Blue Button</button>
|
||
<button style=\"bg-[#FF5722] rounded-full text-[#FFFFFF]\">Orange Pill</button>
|
||
<button style=\"bg-[#9C27B0] rounded-[20px] text-[#FFFFFF]\">Purple Custom</button>
|
||
<button style=\"bg-[#FFD700] rounded text-[#000000] hover:bg-[#FFA500] hover:text-[#FFFFFF]\">Hover Test</button>
|
||
</form>
|
||
|
||
<h2>Button Style Tests</h2>
|
||
|
||
<button>Normal, no-styling button.</button>
|
||
|
||
<h3>Corner Radius Variants</h3>
|
||
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-none\">No Radius</button>
|
||
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-sm\">Small (2px)</button>
|
||
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded\">Default (4px)</button>
|
||
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-md\">Medium (6px)</button>
|
||
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-lg\">Large (8px)</button>
|
||
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-xl\">Extra Large (12px)</button>
|
||
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-2xl\">2XL (16px)</button>
|
||
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-3xl\">3XL (24px)</button>
|
||
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-full\">Full (Pill)</button>
|
||
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-[30px]\">Custom 30px</button>
|
||
|
||
<h3>Color Combinations</h3>
|
||
<button style=\"bg-[#FF6B6B] text-[#FFFFFF] rounded-lg\">Red Background</button>
|
||
<button style=\"bg-[#4ECDC4] text-[#2C3E50] rounded-lg\">Teal & Dark Text</button>
|
||
<button style=\"bg-[#45B7D1] text-[#FFFFFF] rounded-lg\">Sky Blue</button>
|
||
<button style=\"bg-[#96CEB4] text-[#2C3E50] rounded-lg\">Mint Green</button>
|
||
<button style=\"bg-[#FFEAA7] text-[#2D3436] rounded-lg\">Yellow Cream</button>
|
||
<button style=\"bg-[#DDA0DD] text-[#FFFFFF] rounded-lg\">Plum Purple</button>
|
||
<button style=\"bg-[#98D8C8] text-[#2C3E50] rounded-lg\">Seafoam</button>
|
||
|
||
<h3>Hover Effects</h3>
|
||
<button style=\"bg-[#3498DB] text-[#FFFFFF] rounded-lg hover:bg-[#2980B9] hover:text-[#F8F9FA]\">Blue Hover</button>
|
||
<button style=\"bg-[#E67E22] text-[#FFFFFF] rounded-xl hover:bg-[#D35400] hover:text-[#ECF0F1]\">Orange Hover</button>
|
||
<button style=\"bg-[#9B59B6] text-[#FFFFFF] rounded-full hover:bg-[#8E44AD] hover:text-[#F4F4F4]\">Purple Pill Hover</button>
|
||
<button style=\"bg-[#1ABC9C] text-[#FFFFFF] rounded-2xl hover:bg-[#16A085]\">Turquoise Hover</button>
|
||
|
||
<h3>Advanced Hover Combinations</h3>
|
||
<button style=\"bg-[#34495E] text-[#ECF0F1] rounded hover:bg-[#E74C3C] hover:text-[#FFFFFF]\">Dark to Red</button>
|
||
<button style=\"bg-[#F39C12] text-[#2C3E50] rounded-lg hover:bg-[#27AE60] hover:text-[#FFFFFF]\">Gold to Green</button>
|
||
<button style=\"bg-[#FFFFFF] text-[#2C3E50] rounded-xl hover:bg-[#2C3E50] hover:text-[#FFFFFF]\">Light to Dark</button>
|
||
|
||
<h3>Text Color Focus</h3>
|
||
<button style=\"text-[#E74C3C] rounded-lg\">Red Text Only</button>
|
||
<button style=\"text-[#27AE60] rounded-lg\">Green Text Only</button>
|
||
<button style=\"text-[#3498DB] rounded-lg\">Blue Text Only</button>
|
||
<button style=\"text-[#9B59B6] rounded-full\">Purple Text Pill</button>
|
||
|
||
<h3>Mixed Styles</h3>
|
||
<button style=\"bg-[#FF7675] text-[#FFFFFF] rounded-[15px] hover:bg-[#FD79A8] hover:text-[#2D3436]\">Custom Mix 1</button>
|
||
<button style=\"bg-[#6C5CE7] text-[#DDD] rounded-3xl hover:bg-[#A29BFE] hover:text-[#2D3436]\">Custom Mix 2</button>
|
||
<button style=\"bg-[#00B894] text-[#FFFFFF] rounded-[25px] hover:bg-[#00CEC9] hover:text-[#2D3436]\">Custom Mix 3</button>
|
||
<button style=\"bg-[#0000ff] text-[#FFFFFF] rounded-[25px] hover:bg-[#ff0000] hover:text-[#2D3436]\">Blue normal, red hover</button>
|
||
|
||
<h3>Active State Tests</h3>
|
||
<button style=\"bg-[#3498DB] text-[#FFFFFF] rounded-lg hover:bg-[#2980B9] active:bg-[#1F618D] active:text-[#F8F9FA]\">Blue with Active</button>
|
||
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-xl hover:bg-[#C0392B] active:bg-[#A93226] active:text-[#ECF0F1]\">Red with Active</button>
|
||
<button style=\"bg-[#27AE60] text-[#FFFFFF] rounded-full hover:bg-[#229954] active:bg-[#1E8449] active:text-[#D5DBDB]\">Green Pill Active</button>
|
||
<button style=\"bg-[#F39C12] text-[#2C3E50] rounded hover:bg-[#E67E22] hover:text-[#FFFFFF] active:bg-[#D35400] active:text-[#F7F9FC]\">Gold Multi-State</button>
|
||
<button style=\"bg-[#9B59B6] text-[#FFFFFF] rounded-2xl active:bg-[#7D3C98] active:text-[#E8DAEF]\">Purple Active Only</button>
|
||
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENTvvv = """
|
||
<head>
|
||
<title>Lua API Demo</title>
|
||
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
||
<meta name="theme-color" content="#000080">
|
||
<meta name="description" content="Demonstrating the GURT Lua API">
|
||
|
||
<style>
|
||
body { bg-[#f8f9fa] p-6 }
|
||
h1 { text-[#2563eb] text-2xl font-bold }
|
||
.container { bg-[#ffffff] p-4 rounded-lg shadow-lg }
|
||
.demo-button { bg-[#3b82f6] text-white px-4 py-2 rounded hover:bg-[#2563eb] }
|
||
.fancy { bg-green-500 text-red-500 p-2 rounded-full mt-2 mb-2 text-2xl hover:bg-red-300 hover:text-[#2563eb] }
|
||
</style>
|
||
|
||
<script>
|
||
local typing = gurt.select('#type')
|
||
local mouse = gurt.select('#mouse')
|
||
local btnmouse = gurt.select('#btnmouse')
|
||
|
||
gurt.log('Starting Lua script execution...')
|
||
|
||
gurt.body:on('keypress', function(el)
|
||
typing.text = table.tostring(el)
|
||
end)
|
||
|
||
gurt.body:on('mousemove', function(el)
|
||
mouse.text = table.tostring(el)
|
||
end)
|
||
|
||
-- Test element selection and manipulation
|
||
local heading = gurt.select('#main-heading')
|
||
heading.text = 'Welcome to the New Web!'
|
||
|
||
local button = gurt.select('#demo-button')
|
||
local event_log = gurt.select('#event-log')
|
||
|
||
button:on('mousedown', function()
|
||
print('Mouse down')
|
||
end)
|
||
|
||
button:on('mouseup', function()
|
||
print('Mouse up')
|
||
end)
|
||
|
||
button:on('mouseenter', function()
|
||
print('Mouse enter')
|
||
end)
|
||
|
||
button:on('mouseexit', function()
|
||
print('Mouse exit')
|
||
end)
|
||
|
||
button:on('mousemove', function(el)
|
||
btnmouse.text = table.tostring(el)
|
||
end)
|
||
|
||
if button and event_log then
|
||
local click_count = 0
|
||
|
||
local subscription = button:on('click', function()
|
||
click_count = click_count + 1
|
||
local new_text = 'Button clicked ' .. click_count .. ' time(s)!'
|
||
event_log.text = new_text
|
||
end)
|
||
|
||
heading:on('focusin', function()
|
||
print('oh u flck')
|
||
subscription:unsubscribe()
|
||
end)
|
||
|
||
gurt.log('Event listener attached to button with subscription ID')
|
||
else
|
||
gurt.log('Could not find button or event log element')
|
||
end
|
||
|
||
-- DOM Manipulation Demo
|
||
gurt.log('Testing DOM manipulation...')
|
||
|
||
-- Create a new div with styling
|
||
local new_div = gurt.create('div', { style = 'bg-red-500 p-4 rounded-lg mb-4' })
|
||
|
||
-- Create a paragraph with text
|
||
local new_p = gurt.create('p', {
|
||
style = 'text-white font-bold text-lg',
|
||
text = 'This element was created dynamically with Lua!'
|
||
})
|
||
|
||
-- Append paragraph to div
|
||
new_div:append(new_p)
|
||
|
||
-- Append div to body
|
||
gurt.body:append(new_div)
|
||
|
||
-- Create another element to test removal
|
||
local temp_element = gurt.create('div', {
|
||
style = 'bg-yellow-400 p-2 rounded text-black',
|
||
text = 'This will be removed in 3 seconds...'
|
||
})
|
||
gurt.body:append(temp_element)
|
||
|
||
local test = gurt.setTimeout(function()
|
||
print('removed')
|
||
temp_element:remove()
|
||
end, 3000)
|
||
|
||
-- gurt.clearTimeout(test)
|
||
|
||
local addBtn = gurt.select('#add-class')
|
||
local removeBtn = gurt.select('#remove-class')
|
||
local btnTarget = gurt.select('#btnTarget')
|
||
|
||
addBtn:on('click', function()
|
||
btnTarget.classList:add('fancy')
|
||
-- btnTarget.classList:toggle('fancy')
|
||
print('Class added')
|
||
end)
|
||
|
||
removeBtn:on('click', function()
|
||
btnTarget.classList:remove('fancy')
|
||
print('Class removed')
|
||
end)
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<h1 id="main-heading">Welcome to GURT Lua API Demo</h1>
|
||
|
||
<div style="container">
|
||
<p>This page demonstrates the GURT Lua API in action.</p>
|
||
<div id="demo-button" style="w-40 h-40 bg-red-500 p-4 rounded-lg">Click me to see Lua in action!</div>
|
||
</div>
|
||
|
||
<p id="event-log" style="mt-4 p-4 bg-[#f3f4f6] rounded min-h-24">Click the button</p>
|
||
|
||
<p id="mouse" style="mt-4 p-4 bg-[#f3f4f6] rounded min-h-24">Move your mouse</p>
|
||
|
||
<p id="btnmouse" style="mt-4 p-4 bg-[#f3f4f6] rounded min-h-24">Move mouse over Button</p>
|
||
|
||
<p id="type" style="mt-4 p-4 bg-[#f3f4f6] rounded min-h-24">Type something</p>
|
||
|
||
<div style="mt-6 flex gap-4 items-center">
|
||
<div style="text-lg font-semibold">Style Controls:</div>
|
||
<button id="add-class" style="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700">Add Class</button>
|
||
<button id="remove-class" style="bg-red-600 text-white px-4 py-2 rounded hover:bg-red-700">Remove Class</button>
|
||
</div>
|
||
<button id="btnTarget" style="bg-gray-600">Button</button>
|
||
|
||
</body>""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENT_ADD_REMOVE = """<head>
|
||
<title>Lua List Manipulation Demo</title>
|
||
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
||
<meta name="theme-color" content="#000080">
|
||
<meta name="description" content="Adding and popping list items with GURT Lua API">
|
||
|
||
<style>
|
||
body { bg-[#f8f9fa] p-6 }
|
||
h1 { text-[#2563eb] text-4xl font-bold }
|
||
.container { flex flex-row bg-[#ffffff] p-4 rounded-lg shadow-lg }
|
||
.demo-button { bg-[#3b82f6] text-white px-4 py-2 rounded hover:bg-[#2563eb] cursor-pointer }
|
||
ul { list-disc pl-6 }
|
||
li { text-[#111827] py-1 }
|
||
</style>
|
||
|
||
<script>
|
||
local add_button = gurt.select('#add-button')
|
||
local pop_button = gurt.select('#pop-button')
|
||
local list = gurt.select('#item-list')
|
||
local counter = 1
|
||
|
||
gurt.log('List manipulation script started.')
|
||
|
||
add_button:on('click', function()
|
||
local new_item = gurt.create('li', {
|
||
text = 'Item #' .. counter
|
||
})
|
||
list:append(new_item)
|
||
counter = counter + 1
|
||
end)
|
||
|
||
pop_button:on('click', function()
|
||
local items = list.children
|
||
local last = items[#items]
|
||
if last then
|
||
last:remove()
|
||
counter = math.max(1, counter - 1)
|
||
end
|
||
end)
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<h1 id="main-heading">List Manipulation with Lua</h1>
|
||
|
||
<div style="container">
|
||
<p>Use the buttons below to add or remove items from the list:</p>
|
||
<button id="add-button" style="demo-button inline-block mr-2">Add Item</button>
|
||
<button id="pop-button" style="demo-button inline-block">Pop Item</button>
|
||
</div>
|
||
|
||
<ul id="item-list" style="mt-4 bg-[#f3f4f6] p-4 rounded min-h-24">
|
||
<!-- List items will appear here -->
|
||
</ul>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENT_TWEEN = """<head>
|
||
<title>Tween Animation Demo</title>
|
||
<icon src="https://cdn-icons-png.flaticon.com/512/1828/1828774.png">
|
||
<meta name="theme-color" content="#1a202c">
|
||
<meta name="description" content="Demonstrating Lua Tween animations">
|
||
|
||
<style>
|
||
body { bg-[#0f1629] text-[#ffffff] p-6 font-sans }
|
||
h1 { text-[#60a5fa] text-4xl font-bold text-center mb-6 }
|
||
h2 { text-[#a78bfa] text-2xl font-bold mt-8 mb-4 }
|
||
.container { bg-[#1e293b] p-6 rounded-lg shadow-lg mb-6 }
|
||
.demo-box {
|
||
bg-[#3b82f6]
|
||
w-[100px]
|
||
h-[100px]
|
||
rounded-lg
|
||
flex
|
||
items-center
|
||
justify-center
|
||
text-[#ffffff]
|
||
font-bold
|
||
cursor-pointer
|
||
mb-4
|
||
}
|
||
.control-panel {
|
||
flex
|
||
flex-row
|
||
gap-2
|
||
flex-wrap
|
||
justify-center
|
||
mt-4
|
||
}
|
||
button {
|
||
bg-[#059669]
|
||
text-[#ffffff]
|
||
px-4
|
||
py-2
|
||
rounded
|
||
hover:bg-[#047857]
|
||
active:bg-[#065f46]
|
||
cursor-pointer
|
||
}
|
||
.reset-btn { bg-[#dc2626] hover:bg-[#b91c1c] active:bg-[#991b1b] }
|
||
.warning { text-[#fbbf24] bg-[#451a03] p-4 rounded border-l-4 border-[#f59e0b] }
|
||
</style>
|
||
|
||
<script>
|
||
-- Get references to all demo elements
|
||
local fadeBox = gurt.select('#fade-box')
|
||
local colorBox = gurt.select('#color-box')
|
||
local scaleBox = gurt.select('#scale-box')
|
||
local rotateBox = gurt.select('#rotate-box')
|
||
local moveBox = gurt.select('#move-box')
|
||
local comboBox = gurt.select('#combo-box')
|
||
|
||
gurt.log('Tween animation demo started!')
|
||
|
||
-- Fade Animation
|
||
gurt.select('#fade-btn'):on('click', function()
|
||
fadeBox:createTween():to('opacity', 0):duration(1.0):easing('out'):transition('linear'):play()
|
||
end)
|
||
|
||
gurt.select('#fade-restore-btn'):on('click', function()
|
||
fadeBox:createTween():to('opacity', 1):duration(0.5):easing('in'):transition('linear'):play()
|
||
end)
|
||
|
||
-- Color Animation
|
||
gurt.select('#color-btn'):on('click', function()
|
||
colorBox:createTween():to('backgroundColor', '#ff0000'):duration(1.0):easing('inout'):transition('quad'):play()
|
||
end)
|
||
|
||
gurt.select('#color-restore-btn'):on('click', function()
|
||
colorBox:createTween():to('backgroundColor', '#3b82f6'):duration(1.0):easing('inout'):transition('quad'):play()
|
||
end)
|
||
|
||
-- Scale Animation
|
||
gurt.select('#scale-btn'):on('click', function()
|
||
scaleBox:createTween():to('scale', 1.5):duration(1.0):easing('out'):transition('cubic'):play()
|
||
end)
|
||
|
||
gurt.select('#scale-restore-btn'):on('click', function()
|
||
scaleBox:createTween():to('scale', 1.0):duration(0.8):easing('in'):transition('cubic'):play()
|
||
end)
|
||
|
||
-- Rotation Animation
|
||
gurt.select('#rotate-btn'):on('click', function()
|
||
rotateBox:createTween():to('rotation', 360):duration(2.0):easing('inout'):transition('sine'):play()
|
||
end)
|
||
|
||
gurt.select('#rotate-restore-btn'):on('click', function()
|
||
rotateBox:createTween():to('rotation', 0):duration(1.0):easing('out'):transition('sine'):play()
|
||
end)
|
||
|
||
-- Movement Animation
|
||
gurt.select('#move-btn'):on('click', function()
|
||
moveBox:createTween():to('x', 200):duration(1.5):easing('out'):transition('elastic'):play()
|
||
end)
|
||
|
||
gurt.select('#move-restore-btn'):on('click', function()
|
||
moveBox:createTween():to('x', 0):duration(1.0):easing('in'):transition('elastic'):play()
|
||
end)
|
||
|
||
-- Complex Parallel Animation
|
||
gurt.select('#combo-btn'):on('click', function()
|
||
local tween = comboBox:createTween()
|
||
tween:parallel()
|
||
tween:to('scale', 1.3):duration(1.0):easing('out'):transition('back')
|
||
tween:to('rotation', 180):duration(1.0):easing('out'):transition('sine')
|
||
tween:to('backgroundColor', '#10b981'):duration(1.0):easing('out'):transition('linear')
|
||
tween:play()
|
||
end)
|
||
|
||
-- Complex Chain Animation
|
||
gurt.select('#chain-btn'):on('click', function()
|
||
local tween = comboBox:createTween()
|
||
tween:chain()
|
||
tween:to('x', 150):duration(0.8):easing('out'):transition('bounce')
|
||
tween:to('y', -50):duration(0.8):easing('out'):transition('bounce')
|
||
tween:to('x', 0):duration(0.8):easing('out'):transition('bounce')
|
||
tween:to('y', 0):duration(0.8):easing('out'):transition('bounce')
|
||
tween:play()
|
||
end)
|
||
|
||
-- Reset all animations
|
||
gurt.select('#reset-all-btn'):on('click', function()
|
||
-- Reset all properties to default
|
||
fadeBox:createTween():to('opacity', 1):duration(0.3):play()
|
||
colorBox:createTween():to('backgroundColor', '#3b82f6'):duration(0.3):play()
|
||
scaleBox:createTween():to('scale', 1.0):duration(0.3):play()
|
||
rotateBox:createTween():to('rotation', 0):duration(0.3):play()
|
||
moveBox:createTween():to('x', 0):duration(0.3):play()
|
||
|
||
local combo_tween = comboBox:createTween()
|
||
combo_tween:parallel()
|
||
combo_tween:to('scale', 1.0):duration(0.3)
|
||
combo_tween:to('rotation', 0):duration(0.3)
|
||
combo_tween:to('backgroundColor', '#3b82f6'):duration(0.3)
|
||
combo_tween:to('x', 0):duration(0.3)
|
||
combo_tween:to('y', 0):duration(0.3)
|
||
combo_tween:play()
|
||
end)
|
||
|
||
-- Callback example
|
||
gurt.select('#callback-btn'):on('click', function()
|
||
fadeBox:createTween():to('opacity', 0.3):duration(1.0):easing('inout'):callback(function()
|
||
gurt.log('Fade animation completed!')
|
||
end):play()
|
||
end)
|
||
|
||
-- Loops example
|
||
gurt.select('#steps-btn'):on('click', function()
|
||
scaleBox:createTween():loops(3)
|
||
:to('scale', 2.0):duration(0.5)
|
||
:to('scale', 1.0):duration(0.5)
|
||
:callback(function()
|
||
print('Animation completed!')
|
||
end):play()
|
||
end)
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<h1>🎬 Lua Tween Animation Demo</h1>
|
||
|
||
<div style="warning">
|
||
<p><strong>Note:</strong> This demo showcases the Lua Tween API for smooth animations. Each box demonstrates different animation properties and easing functions.</p>
|
||
</div>
|
||
|
||
<h2>Fade Animation</h2>
|
||
<div style="container">
|
||
<div id="fade-box" style="demo-box">Fade Me</div>
|
||
<div style="control-panel">
|
||
<button id="fade-btn">Fade Out</button>
|
||
<button id="fade-restore-btn">Fade In</button>
|
||
<button id="callback-btn">Fade with Callback</button>
|
||
</div>
|
||
</div>
|
||
|
||
<h2>Color Animation</h2>
|
||
<div style="container">
|
||
<div id="color-box" style="demo-box">Change Color</div>
|
||
<div style="control-panel">
|
||
<button id="color-btn">To Red</button>
|
||
<button id="color-restore-btn">To Blue</button>
|
||
</div>
|
||
</div>
|
||
|
||
<h2>Scale Animation</h2>
|
||
<div style="container">
|
||
<div id="scale-box" style="demo-box">Scale Me</div>
|
||
<div style="control-panel">
|
||
<button id="scale-btn">Scale Up</button>
|
||
<button id="scale-restore-btn">Scale Down</button>
|
||
<button id="steps-btn">Pulse (Loop)</button>
|
||
</div>
|
||
</div>
|
||
|
||
<h2>Rotation Animation</h2>
|
||
<div style="container">
|
||
<div id="rotate-box" style="demo-box">Spin Me</div>
|
||
<div style="control-panel">
|
||
<button id="rotate-btn">Rotate 360°</button>
|
||
<button id="rotate-restore-btn">Reset Rotation</button>
|
||
</div>
|
||
</div>
|
||
|
||
<h2>Movement Animation</h2>
|
||
<div style="container">
|
||
<div id="move-box" style="demo-box">Move Me</div>
|
||
<div style="control-panel">
|
||
<button id="move-btn">Move Right</button>
|
||
<button id="move-restore-btn">Move Back</button>
|
||
</div>
|
||
</div>
|
||
|
||
<h2>Complex Animations</h2>
|
||
<div style="container">
|
||
<div id="combo-box" style="demo-box">Complex</div>
|
||
<div style="control-panel">
|
||
<button id="combo-btn">Parallel Animation</button>
|
||
<button id="chain-btn">Chain Animation</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="control-panel mt-8">
|
||
<button id="reset-all-btn" style="reset-btn">🔄 Reset All Animations</button>
|
||
</div>
|
||
|
||
<div style="container mt-8">
|
||
<h2>Available Tween Methods:</h2>
|
||
<ul style="list-disc pl-6 text-[#d1d5db]">
|
||
<li><strong>element:createTween()</strong> - Create a new tween for the element</li>
|
||
<li><strong>tween:to(property, target_value, duration, easing)</strong> - Animate to a target value</li>
|
||
<li><strong>tween:from(property, start_value, duration, easing)</strong> - Animate from a start value</li>
|
||
<li><strong>tween:parallel()</strong> - Set tween to run animations in parallel</li>
|
||
<li><strong>tween:chain()</strong> - Set tween to run animations in sequence</li>
|
||
<li><strong>tween:steps(count)</strong> - Set number of loops</li>
|
||
<li><strong>tween:callback(function)</strong> - Execute function when tween completes</li>
|
||
<li><strong>tween:play()</strong> - Start the tween animation</li>
|
||
<li><strong>tween:stop()</strong> - Stop the tween animation</li>
|
||
<li><strong>tween:pause()</strong> - Pause the tween animation</li>
|
||
<li><strong>tween:resume()</strong> - Resume the tween animation</li>
|
||
</ul>
|
||
|
||
<h2 style="mt-4">Supported Properties:</h2>
|
||
<ul style="list-disc pl-6 text-[#d1d5db]">
|
||
<li><strong>opacity</strong> - Element transparency (0-1)</li>
|
||
<li><strong>backgroundColor</strong> - Background color (hex/color names)</li>
|
||
<li><strong>color/textColor</strong> - Text color (hex/color names)</li>
|
||
<li><strong>width/height</strong> - Element dimensions (pixels)</li>
|
||
<li><strong>x/y</strong> - Position coordinates (pixels)</li>
|
||
<li><strong>scale</strong> - Element scale factor</li>
|
||
<li><strong>rotation</strong> - Rotation angle (degrees)</li>
|
||
</ul>
|
||
|
||
<h2 style="mt-4">Easing Functions:</h2>
|
||
<ul style="list-disc pl-6 text-[#d1d5db]">
|
||
<li><strong>easeIn</strong> - Slow start, fast end</li>
|
||
<li><strong>easeOut</strong> - Fast start, slow end</li>
|
||
<li><strong>easeInOut</strong> - Slow start and end, fast middle</li>
|
||
<li><strong>easeOutIn</strong> - Fast start and end, slow middle</li>
|
||
</ul>
|
||
</div>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENT_DOM_MANIPULATION = """
|
||
<head>
|
||
<title>DOM Utilities Test</title>
|
||
<style>
|
||
.test-item { bg-[#e0e7ef] text-[#22223b] rounded p-2 mb-2 }
|
||
.highlight { bg-[#ffd700] }
|
||
</style>
|
||
<script>
|
||
local log = gurt.select("#log")
|
||
local function log_msg(msg)
|
||
log.text = log.text .. msg .. "\\n"
|
||
end
|
||
|
||
local parent = gurt.select("#parent")
|
||
local child1 = gurt.select("#child1")
|
||
local child2 = gurt.select("#child2")
|
||
local child3 = gurt.select("#child3")
|
||
print(log)
|
||
-- Show DOM property usage
|
||
log.text = ""
|
||
log_msg("parent of child2: " .. table.tostring(child2.parent))
|
||
log_msg("nextSibling of child2: " .. table.tostring(child2.nextSibling))
|
||
log_msg("previousSibling of child2: " .. table.tostring(child2.previousSibling))
|
||
log_msg("firstChild of parent: " .. table.tostring(parent.firstChild))
|
||
log_msg("lastChild of parent: " .. table.tostring(parent.lastChild))
|
||
|
||
-- Insert Before
|
||
gurt.select("#btn-insert-before"):on("click", function()
|
||
local newDiv = gurt.create("div", { class = "test-item highlight", text = "Inserted Before Child 2" })
|
||
parent:insertBefore(newDiv, child2)
|
||
log_msg("Inserted before child2: " .. newDiv._element_id)
|
||
end)
|
||
|
||
-- Insert After
|
||
gurt.select("#btn-insert-after"):on("click", function()
|
||
local newDiv = gurt.create("div", { class = "test-item highlight", text = "Inserted After Child 2" })
|
||
parent:insertAfter(newDiv, child2)
|
||
log_msg("Inserted after child2: " .. newDiv._element_id)
|
||
end)
|
||
|
||
-- Replace
|
||
gurt.select("#btn-replace"):on("click", function()
|
||
local newDiv = gurt.create("div", { class = "test-item highlight", text = "Replacement for Child 2" })
|
||
parent:replace(newDiv, child2)
|
||
log_msg("Replaced child2 with: " .. newDiv._element_id)
|
||
end)
|
||
|
||
-- Clone
|
||
gurt.select("#btn-clone"):on("click", function()
|
||
local clone = child3:clone(true)
|
||
parent:append(clone)
|
||
log_msg("Cloned child3: " .. clone._element_id)
|
||
end)
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<h1>DOM Utilities Demo</h1>
|
||
<div id="parent" style="bg-[#f8fafc] p-4 rounded flex flex-col gap-2">
|
||
<div class="test-item">Non-interactible</div>
|
||
<div id="child1" class="test-item">Child 1</div>
|
||
<div id="child2" class="test-item">Child 2</div>
|
||
<div id="child3" class="test-item">Child 3</div>
|
||
</div>
|
||
<div style="flex gap-2 mt-4">
|
||
<button id="btn-insert-before">Insert Before Child 2</button>
|
||
<button id="btn-insert-after">Insert After Child 2</button>
|
||
<button id="btn-replace">Replace Child 2</button>
|
||
<button id="btn-clone">Clone Child 3</button>
|
||
</div>
|
||
<p id="log" style="mt-4 text-[#444] text-sm">Test</p>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENTc = """<head>
|
||
<title>Input Events API Demo</title>
|
||
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
||
<meta name="theme-color" content="#059669">
|
||
<meta name="description" content="Demonstrating input element events with GURT Lua API">
|
||
|
||
<style>
|
||
body { bg-[#f0fdf4] p-6 }
|
||
h1 { text-[#059669] text-3xl font-bold text-center }
|
||
h2 { text-[#047857] text-xl font-semibold }
|
||
.container { bg-[#ffffff] p-6 rounded-lg shadow-lg max-w-4xl mx-auto }
|
||
.form-group { flex flex-col gap-2 mb-4 }
|
||
.input-demo { bg-[#f8fafc] p-4 rounded-lg border }
|
||
.event-log { bg-[#1f2937] text-white p-4 rounded-lg font-mono text-sm max-h-64 overflow-auto }
|
||
.form-button { bg-[#10b981] text-white px-4 py-2 rounded hover:bg-[#059669] cursor-pointer }
|
||
.clear-btn { bg-[#ef4444] text-white px-4 py-2 rounded hover:bg-[#dc2626] cursor-pointer }
|
||
</style>
|
||
|
||
<script>
|
||
-- Get the event log element
|
||
local eventLog = gurt.select('#event-log')
|
||
|
||
local function logEvent(elementType, eventType, data)
|
||
local timestamp = Time.format(Time.now(), '%H:%M:%S')
|
||
local message = '[' .. timestamp .. '] ' .. elementType .. ' -> ' .. eventType
|
||
if data then
|
||
message = message .. ': ' .. data
|
||
end
|
||
|
||
print(message)
|
||
end
|
||
|
||
-- Text Input Events
|
||
local textInput = gurt.select('#text-input')
|
||
print('Text input found:', textInput)
|
||
if textInput then
|
||
textInput:on('input', function(e)
|
||
logEvent('Text Input', 'input', e.value)
|
||
end)
|
||
textInput:on('change', function(e)
|
||
logEvent('Text Input', 'change', e.value)
|
||
end)
|
||
textInput:on('focusin', function()
|
||
logEvent('Text Input', 'focusin', nil)
|
||
end)
|
||
textInput:on('focusout', function()
|
||
logEvent('Text Input', 'focusout', nil)
|
||
end)
|
||
else
|
||
print('Text input not found!')
|
||
end
|
||
|
||
-- Email Input Events
|
||
local emailInput = gurt.select('#email-input')
|
||
|
||
emailInput:on('input', function(e)
|
||
logEvent('Email Input', 'input', e.value)
|
||
end)
|
||
emailInput:on('change', function(e)
|
||
logEvent('Email Input', 'change', e.value)
|
||
end)
|
||
|
||
-- Password Input Events
|
||
local passwordInput = gurt.select('#password-input')
|
||
passwordInput:on('input', function(e)
|
||
logEvent('Password Input', 'input', table.tostring(e))
|
||
end)
|
||
passwordInput:on('change', function(e)
|
||
logEvent('Password Input', 'change', table.tostring(e))
|
||
end)
|
||
|
||
-- Number Input Events
|
||
local numberInput = gurt.select('#number-input')
|
||
numberInput:on('change', function(e)
|
||
logEvent('Number Input', 'change', e.value)
|
||
end)
|
||
|
||
-- Range Input Events
|
||
local rangeInput = gurt.select('#range-input')
|
||
rangeInput:on('change', function(e)
|
||
logEvent('Range Input', 'change', e.value)
|
||
end)
|
||
|
||
-- Color Input Events
|
||
local colorInput = gurt.select('#color-input')
|
||
colorInput:on('change', function(e)
|
||
logEvent('Color Input', 'change', e.value)
|
||
end)
|
||
|
||
-- Date Input Events
|
||
local dateInput = gurt.select('#date-input')
|
||
dateInput:on('change', function(e)
|
||
logEvent('Date Input', 'change', e.value)
|
||
end)
|
||
|
||
-- File Input Events
|
||
local fileInput = gurt.select('#file-input')
|
||
fileInput:on('change', function(e)
|
||
if e.dataURL then
|
||
e.dataURL = e.dataURL:sub(1, 100)
|
||
end
|
||
if e.text then
|
||
e.text = e.text:sub(1, 100)
|
||
end
|
||
logEvent('File Input', 'change', table.tostring(e))
|
||
end)
|
||
|
||
-- Checkbox Events
|
||
local checkbox = gurt.select('#checkbox')
|
||
checkbox:on('change', function(e)
|
||
logEvent('Checkbox', 'change', table.tostring(e))
|
||
end)
|
||
|
||
-- Radio Button Events
|
||
local radio1 = gurt.select('#radio1')
|
||
local radio2 = gurt.select('#radio2')
|
||
local radio3 = gurt.select('#radio3')
|
||
|
||
radio1:on('change', function(e)
|
||
logEvent('Radio Button 1', 'change', table.tostring(e))
|
||
end)
|
||
|
||
radio2:on('change', function(e)
|
||
logEvent('Radio Button 2', 'change', table.tostring(e))
|
||
end)
|
||
|
||
radio3:on('change', function(e)
|
||
logEvent('Radio Button 3', 'change', table.tostring(e))
|
||
end)
|
||
|
||
-- Textarea Events
|
||
local textarea = gurt.select('#textarea')
|
||
|
||
textarea:on('input', function(e)
|
||
logEvent('Textarea', 'input', e.value:sub(1, 20) .. '...')
|
||
end)
|
||
textarea:on('change', function(e)
|
||
logEvent('Textarea', 'change', 'Length: ' .. #e.value)
|
||
end)
|
||
|
||
-- Select Events
|
||
local selectElement = gurt.select('#select-element')
|
||
selectElement:on('change', function(e)
|
||
logEvent('Select', 'change', 'Index: ' .. table.tostring(e))
|
||
end)
|
||
|
||
-- Button Events
|
||
local submitBtn = gurt.select('#submit-btn')
|
||
submitBtn:on('click', function()
|
||
logEvent('Submit Button', 'click', nil)
|
||
end)
|
||
submitBtn:on('submit', function(e)
|
||
logEvent('Form', 'submit', table.tostring(e))
|
||
end)
|
||
|
||
-- Clear log button
|
||
local clearBtn = gurt.select('#clear-btn')
|
||
clearBtn:on('click', function()
|
||
eventLog.text = '--- Event Log Cleared ---\\n'
|
||
eventCount = 0
|
||
end)
|
||
|
||
-- Initial log message
|
||
logEvent('System', 'initialized', 'Input events demo ready')
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<h1>🎛️ Input Events API Demo</h1>
|
||
|
||
<div style="container mt-6">
|
||
<div style="flex flex-row gap-6">
|
||
<!-- Input Forms Column -->
|
||
<div style="flex-1">
|
||
<h2>Input Elements</h2>
|
||
|
||
<form id="demo-form">
|
||
<div style="form-group">
|
||
<label>Text Input:</label>
|
||
<input id="text-input" key="username" type="text" placeholder="Type something..." />
|
||
</div>
|
||
|
||
<div style="form-group">
|
||
<label>Email Input:</label>
|
||
<input id="email-input" key="email" type="email" placeholder="Enter email..." />
|
||
</div>
|
||
|
||
<div style="form-group">
|
||
<label>Password Input:</label>
|
||
<input id="password-input" key="password" type="password" placeholder="Enter password..." />
|
||
</div>
|
||
|
||
<div style="form-group">
|
||
<label>Number Input:</label>
|
||
<input id="number-input" key="score" type="number" min="0" max="100" value="50" />
|
||
</div>
|
||
|
||
<div style="form-group">
|
||
<label>Range Input:</label>
|
||
<input id="range-input" key="volume" type="range" min="0" max="100" value="25" />
|
||
</div>
|
||
|
||
<div style="form-group">
|
||
<label>Color Input:</label>
|
||
<input id="color-input" key="favoriteColor" type="color" value="#ff0000" />
|
||
</div>
|
||
|
||
<div style="form-group">
|
||
<label>Date Input:</label>
|
||
<input id="date-input" key="birthDate" type="date" value="2024-01-01" />
|
||
</div>
|
||
|
||
<div style="form-group">
|
||
<label>File Input:</label>
|
||
<input id="file-input" key="attachment" type="file" accept=".txt,.pdf,.png" />
|
||
</div>
|
||
|
||
<div style="form-group">
|
||
<input id="checkbox" key="newsletter" type="checkbox" />
|
||
<p>Checkbox Option</p>
|
||
</div>
|
||
|
||
<div style="form-group">
|
||
<input id="radio1" key="option" type="radio" group="options" value="option1" /><span>Option 1</span>
|
||
<input id="radio2" key="option" type="radio" group="options" value="option2" /><span>Option 2</span>
|
||
<input id="radio3" key="option" type="radio" group="options" value="option3" /><span>Option 3</span>
|
||
</div>
|
||
|
||
<div style="form-group">
|
||
<label>Textarea:</label>
|
||
<textarea id="textarea" key="message" placeholder="Write something longer..." rows="3"></textarea>
|
||
</div>
|
||
|
||
<div style="form-group">
|
||
<label>Select Dropdown:</label>
|
||
<select id="select-element" key="fruit">
|
||
<option value="apple">Apple</option>
|
||
<option value="banana" selected="true">Banana</option>
|
||
<option value="orange">Orange</option>
|
||
<option value="grape">Grape</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div style="flex gap-2">
|
||
<button id="submit-btn" type="submit" style="form-button">Submit Form</button>
|
||
<button id="clear-btn" type="button" style="clear-btn">Clear Log</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- Event Log Column -->
|
||
<div style="flex-1">
|
||
<h2>Event Log</h2>
|
||
<div style="event-log">
|
||
<pre id="event-log">Waiting for events...
|
||
</pre>
|
||
</div>
|
||
|
||
<div style="bg-[#e0f2fe] p-4 rounded-lg mt-4">
|
||
<h3 style="text-[#0277bd] font-semibold mb-2">Available Events:</h3>
|
||
<ul style="text-[#01579b] space-y-1 text-sm">
|
||
<li><strong>input:</strong> Fires as you type (real-time)</li>
|
||
<li><strong>change:</strong> Fires when value changes and element loses focus</li>
|
||
<li><strong>focusin:</strong> Fires when element gains focus</li>
|
||
<li><strong>focusout:</strong> Fires when element loses focus</li>
|
||
<li><strong>click:</strong> Fires when button is clicked</li>
|
||
<li><strong>submit:</strong> Fires when form is submitted (includes form data)</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENT_CLIPBOARD = """<head>
|
||
<title>Network & Clipboard API Demo</title>
|
||
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
||
<meta name="theme-color" content="#059669">
|
||
<meta name="description" content="Demonstrating Network fetching and Clipboard operations">
|
||
|
||
<style>
|
||
body { bg-[#f0fdf4] p-6 }
|
||
h1 { text-[#059669] text-3xl font-bold text-center }
|
||
h2 { text-[#047857] text-xl font-semibold }
|
||
.container { bg-[#ffffff] p-6 rounded-lg shadow-lg max-w-4xl mx-auto }
|
||
.button-group { flex gap-3 justify-center items-center flex-wrap }
|
||
.clipboard-btn { bg-[#10b981] text-white hover:bg-[#059669] p-4 }
|
||
.copy-url-btn { bg-[#8b5cf6] text-white hover:bg-[#7c3aed] }
|
||
</style>
|
||
|
||
<script>
|
||
gurt.log('Script started!')
|
||
|
||
local copyBtn = gurt.select('#copy-text-btn')
|
||
|
||
copyBtn:on('click', function()
|
||
gurt.log('Copy button clicked!')
|
||
Clipboard.write('Hello from GURT!')
|
||
end)
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<h1>Clipboard API</h1>
|
||
|
||
<div style="container mt-6">
|
||
<h2>Clipboard Operations</h2>
|
||
<div style="button-group mb-6">
|
||
<button id="copy-text-btn" style="action-button clipboard-btn">📋 Copy Text</button>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENTx = """<head>
|
||
<title>Signal API Demo</title>
|
||
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
||
<meta name="theme-color" content="#8b5cf6">
|
||
<meta name="description" content="Demonstrating the new Signal API with custom events">
|
||
|
||
<style>
|
||
body { bg-[#f8fafc] p-6 }
|
||
h1 { text-[#8b5cf6] text-3xl font-bold text-center }
|
||
h2 { text-[#6d28d9] text-xl font-semibold }
|
||
.container { bg-[#ffffff] p-6 rounded-lg shadow-lg max-w-4xl mx-auto }
|
||
.button-group { flex gap-3 justify-center items-center flex-wrap }
|
||
.signal-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors }
|
||
.fire-btn { bg-[#10b981] text-white hover:bg-[#059669] }
|
||
.connect-btn { bg-[#3b82f6] text-white hover:bg-[#2563eb] }
|
||
.disconnect-btn { bg-[#ef4444] text-white hover:bg-[#dc2626] }
|
||
.log-area { bg-[#f1f5f9] p-4 rounded-lg min-h-32 font-mono text-sm }
|
||
.status-display { bg-[#ddd6fe] p-3 rounded-md text-[#5b21b6] font-mono }
|
||
.info-box { bg-[#fef3c7] border border-[#f59e0b] p-4 rounded-lg }
|
||
</style>
|
||
|
||
<script>
|
||
-- Create custom signals
|
||
local mySignal = Signal.new()
|
||
local dataSignal = Signal.new()
|
||
local userActionSignal = Signal.new()
|
||
print(".container > div: ", gurt.selectAll('.container > div'))
|
||
print(".container div: ", gurt.selectAll('.container div'))
|
||
print("button[disabled]: ", gurt.selectAll('button[disabled]'))
|
||
print(".container: ", gurt.selectAll('.container'))
|
||
print("#log-area: ", gurt.selectAll('#log-area'))
|
||
-- Get UI elements
|
||
local logArea = gurt.select('#log-area')
|
||
local statusDisplay = gurt.select('#status-display')
|
||
local connectBtn = gurt.select('#connect-btn')
|
||
local disconnectBtn = gurt.select('#disconnect-btn')
|
||
local fireBtn = gurt.select('#fire-btn')
|
||
local fireDataBtn = gurt.select('#fire-data-btn')
|
||
local clearLogBtn = gurt.select('#clear-log-btn')
|
||
|
||
gurt.log('Signal API demo script started.')
|
||
|
||
local logMessages = {}
|
||
local connectionCount = 0
|
||
local activeConnections = {}
|
||
|
||
-- Function to add message to log
|
||
local function addLog(message)
|
||
table.insert(logMessages, Time.format(Time.now(), '%H:%M:%S') .. ' - ' .. message)
|
||
if #logMessages > 20 then
|
||
table.remove(logMessages, 1)
|
||
end
|
||
logArea.text = table.concat(logMessages, '\\n')
|
||
end
|
||
|
||
-- Function to update status
|
||
local function updateStatus()
|
||
statusDisplay.text = 'Active Connections: ' .. #activeConnections .. '\\nTotal Events Fired: ' .. connectionCount
|
||
end
|
||
|
||
-- Signal handlers
|
||
local function onMySignal(arg1, arg2)
|
||
addLog('mySignal fired with args: ' .. (arg1 or 'nil') .. ', ' .. (arg2 or 'nil'))
|
||
end
|
||
|
||
local function onDataSignal(data)
|
||
addLog('dataSignal received: ' .. table.tostring(data))
|
||
end
|
||
|
||
local function onUserAction(action, timestamp)
|
||
addLog('userActionSignal: ' .. action .. ' at ' .. timestamp)
|
||
end
|
||
|
||
-- Connect button
|
||
connectBtn:on('click', function()
|
||
-- Connect multiple handlers to demonstrate multiple connections
|
||
local conn1 = mySignal:connect(onMySignal)
|
||
local conn2 = dataSignal:connect(onDataSignal)
|
||
local conn3 = userActionSignal:connect(onUserAction)
|
||
|
||
table.insert(activeConnections, conn1)
|
||
table.insert(activeConnections, conn2)
|
||
table.insert(activeConnections, conn3)
|
||
|
||
addLog('Connected 3 signal handlers')
|
||
updateStatus()
|
||
end)
|
||
|
||
-- Disconnect button
|
||
disconnectBtn:on('click', function()
|
||
for i = 1, #activeConnections do
|
||
activeConnections[i]:disconnect()
|
||
end
|
||
activeConnections = {}
|
||
addLog('Disconnected all signal handlers')
|
||
updateStatus()
|
||
end)
|
||
|
||
-- Fire simple signal
|
||
fireBtn:on('click', function()
|
||
mySignal:fire('Hello', 123)
|
||
connectionCount = connectionCount + 1
|
||
addLog('Fired mySignal with two arguments')
|
||
updateStatus()
|
||
end)
|
||
|
||
-- Fire data signal
|
||
fireDataBtn:on('click', function()
|
||
local sampleData = {
|
||
user = 'Alice',
|
||
score = math.random(100, 999),
|
||
items = {'sword', 'shield', 'potion'}
|
||
}
|
||
dataSignal:fire(sampleData)
|
||
connectionCount = connectionCount + 1
|
||
addLog('Fired dataSignal with complex data')
|
||
updateStatus()
|
||
end)
|
||
|
||
-- Fire user action signal
|
||
gurt.body:on('keypress', function(keyInfo)
|
||
if #activeConnections > 0 then
|
||
userActionSignal:fire('keypress: ' .. keyInfo.key, Time.format(Time.now(), '%H:%M:%S'))
|
||
connectionCount = connectionCount + 1
|
||
updateStatus()
|
||
end
|
||
end)
|
||
|
||
-- Clear log button
|
||
clearLogBtn:on('click', function()
|
||
logMessages = {}
|
||
logArea.text = 'Log cleared.'
|
||
addLog('Log area cleared')
|
||
end)
|
||
|
||
-- Initialize with some sample connections
|
||
local initialConn = mySignal:connect(function(a, b)
|
||
addLog('Initial handler triggered with: ' .. (a or 'nil') .. ', ' .. (b or 'nil'))
|
||
end)
|
||
table.insert(activeConnections, initialConn)
|
||
|
||
addLog('Signal API demo initialized')
|
||
addLog('Try connecting handlers and firing signals!')
|
||
addLog('Press any key to trigger userActionSignal (when connected)')
|
||
updateStatus()
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<h1>🔔 Signal API Demo</h1>
|
||
|
||
<div style="container mt-6">
|
||
<div style="info-box mb-6">
|
||
<p><strong>Signal API Usage Example:</strong></p>
|
||
<p><code>local mySignal = Signal.new()</code></p>
|
||
<p><code>mySignal:connect(function(arg1, arg2) print("Event fired with: ", arg1, arg2) end)</code></p>
|
||
<p><code>mySignal:fire("Hello", 123)</code></p>
|
||
<p><code>connection:disconnect()</code></p>
|
||
</div>
|
||
|
||
<h2>Controls</h2>
|
||
<div style="button-group mb-6">
|
||
<button id="connect-btn" style="signal-button connect-btn">🔗 Connect Handlers</button>
|
||
<button id="disconnect-btn" style="signal-button disconnect-btn">❌ Disconnect All</button>
|
||
<button id="fire-btn" style="signal-button fire-btn">🔔 Fire Simple Signal</button>
|
||
<button id="fire-data-btn" style="signal-button fire-btn">📊 Fire Data Signal</button>
|
||
<button id="clear-log-btn" style="signal-button">🧹 Clear Log</button>
|
||
</div>
|
||
|
||
<h2>Status</h2>
|
||
<div style="status-display mb-6">
|
||
<pre id="status-display">Loading status...</pre>
|
||
</div>
|
||
|
||
<h2>Event Log</h2>
|
||
<div style="log-area mb-6">
|
||
<pre id="log-area">Initializing...</pre>
|
||
</div>
|
||
|
||
<div style="bg-[#e0f2fe] p-4 rounded-lg">
|
||
<h3 style="text-[#0277bd] font-semibold mb-2">Signal API Features:</h3>
|
||
<ul style="text-[#01579b] space-y-1">
|
||
<li><strong>Signal.new():</strong> Creates a new signal object</li>
|
||
<li><strong>signal:connect(callback):</strong> Connects a callback function and returns a connection object</li>
|
||
<li><strong>signal:fire(...):</strong> Fires the signal with optional arguments</li>
|
||
<li><strong>connection:disconnect():</strong> Disconnects a specific connection</li>
|
||
<li><strong>signal:disconnect():</strong> Disconnects all connections from the signal</li>
|
||
<li><strong>Multiple Connections:</strong> One signal can have multiple connected callbacks</li>
|
||
<li><strong>Argument Passing:</strong> Signals can pass multiple arguments to connected callbacks</li>
|
||
</ul>
|
||
</div>
|
||
<button disabled="true">Test</button>
|
||
<button disabled="true">Test2</button>
|
||
</div>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENTa = """<head>
|
||
<title>Button getAttribute/setAttribute Demo</title>
|
||
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
||
<meta name="theme-color" content="#3b82f6">
|
||
<meta name="description" content="Demonstrating getAttribute and setAttribute with button controls">
|
||
|
||
<style>
|
||
body { bg-[#f8fafc] p-6 }
|
||
h1 { text-[#3b82f6] text-3xl font-bold text-center }
|
||
h2 { text-[#1e40af] text-xl font-semibold }
|
||
.container { bg-[#ffffff] p-6 rounded-lg shadow-lg max-w-4xl mx-auto }
|
||
.button-group { flex gap-3 justify-center items-center flex-wrap }
|
||
.control-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors }
|
||
.enable-btn { bg-[#10b981] text-white hover:bg-[#059669] }
|
||
.disable-btn { bg-[#ef4444] text-white hover:bg-[#dc2626] }
|
||
.toggle-btn { bg-[#8b5cf6] text-white hover:bg-[#7c3aed] }
|
||
.status-btn { bg-[#6b7280] text-white hover:bg-[#4b5563] }
|
||
.demo-buttons { bg-[#f1f5f9] p-4 rounded-lg }
|
||
.status-display { bg-[#e0e7ff] p-3 rounded-md text-[#3730a3] font-mono }
|
||
.info-box { bg-[#fef3c7] border border-[#f59e0b] p-4 rounded-lg }
|
||
.target-button { bg-[#3b82f6] text-white px-6 py-3 rounded-lg font-semibold hover:bg-[#2563eb] }
|
||
.target-button[disabled] { bg-[#9ca3af] text-[#6b7280] cursor-not-allowed }
|
||
</style>
|
||
|
||
<script>
|
||
local targetButton = gurt.select('#target-button')
|
||
local enableBtn = gurt.select('#enable-btn')
|
||
local disableBtn = gurt.select('#disable-btn')
|
||
local toggleBtn = gurt.select('#toggle-btn')
|
||
local statusBtn = gurt.select('#status-btn')
|
||
local statusDisplay = gurt.select('#status-display')
|
||
local infoBox = gurt.select('#info-box')
|
||
local clickCounter = gurt.select('#click-counter')
|
||
|
||
gurt.log('Button attribute demo script started.')
|
||
|
||
local clickCount = 0
|
||
|
||
-- Function to update the status display
|
||
local function updateStatus()
|
||
local disabled = targetButton:getAttribute('disabled')
|
||
local type = targetButton:getAttribute('type')
|
||
local style = targetButton:getAttribute('style')
|
||
local id = targetButton:getAttribute('id')
|
||
local dataValue = targetButton:getAttribute('data-value')
|
||
|
||
local status = 'Status: ' .. (disabled and 'DISABLED' or 'ENABLED') .. '\\n'
|
||
status = status .. 'Type: ' .. (type or 'button') .. '\\n'
|
||
status = status .. 'ID: ' .. (id or 'none') .. '\\n'
|
||
status = status .. 'Data Value: ' .. (dataValue or 'none') .. '\\n'
|
||
status = status .. 'Click Count: ' .. clickCount
|
||
|
||
statusDisplay.text = status
|
||
|
||
-- Update info box with current state
|
||
if disabled then
|
||
infoBox.text = '🔒 Target button is currently DISABLED. It cannot be clicked and appears grayed out.'
|
||
else
|
||
infoBox.text = '✅ Target button is currently ENABLED. Click it to see the counter increase!'
|
||
end
|
||
end
|
||
|
||
-- Target button click handler
|
||
targetButton:on('click', function()
|
||
clickCount = clickCount + 1
|
||
clickCounter.text = 'Button clicked ' .. clickCount .. ' times!'
|
||
gurt.log('Target button clicked! Count:', clickCount)
|
||
updateStatus()
|
||
end)
|
||
|
||
-- Enable button functionality
|
||
enableBtn:on('click', function()
|
||
targetButton:setAttribute('disabled', '') -- Remove disabled attribute
|
||
targetButton:setAttribute('data-value', 'enabled')
|
||
gurt.log('Target button enabled via setAttribute')
|
||
updateStatus()
|
||
end)
|
||
|
||
-- Disable button functionality
|
||
disableBtn:on('click', function()
|
||
targetButton:setAttribute('disabled', 'true')
|
||
targetButton:setAttribute('data-value', 'disabled')
|
||
gurt.log('Target button disabled via setAttribute')
|
||
updateStatus()
|
||
end)
|
||
|
||
-- Toggle button functionality
|
||
toggleBtn:on('click', function()
|
||
local currentlyDisabled = targetButton:getAttribute('disabled')
|
||
|
||
if currentlyDisabled then
|
||
-- Currently disabled, so enable it
|
||
targetButton:setAttribute('disabled', '')
|
||
targetButton:setAttribute('data-value', 'toggled-enabled')
|
||
gurt.log('Target button toggled to enabled state')
|
||
else
|
||
-- Currently enabled, so disable it
|
||
targetButton:setAttribute('disabled', 'true')
|
||
targetButton:setAttribute('data-value', 'toggled-disabled')
|
||
gurt.log('Target button toggled to disabled state')
|
||
end
|
||
|
||
updateStatus()
|
||
end)
|
||
|
||
-- Status check button
|
||
statusBtn:on('click', function()
|
||
local disabled = targetButton:getAttribute('disabled')
|
||
local type = targetButton:getAttribute('type')
|
||
local dataValue = targetButton:getAttribute('data-value')
|
||
|
||
gurt.log('=== BUTTON STATUS CHECK ===')
|
||
gurt.log('Disabled attribute:', disabled or 'not set')
|
||
gurt.log('Type attribute:', type or 'not set')
|
||
gurt.log('Data-value attribute:', dataValue or 'not set')
|
||
gurt.log('Click count:', clickCount)
|
||
gurt.log('===========================')
|
||
|
||
-- Demonstrate style setAttribute
|
||
local randomColors = {'bg-red-500', 'bg-green-500', 'bg-purple-500', 'bg-orange-500', 'bg-pink-500'}
|
||
local randomColor = randomColors[math.random(1, #randomColors)]
|
||
|
||
if not disabled then
|
||
targetButton:setAttribute('style', 'target-button ' .. randomColor .. ' text-white px-6 py-3 rounded-lg font-semibold hover:opacity-75')
|
||
|
||
gurt.setTimeout(function()
|
||
targetButton:setAttribute('style', 'target-button bg-[#3b82f6] text-white px-6 py-3 rounded-lg font-semibold hover:bg-[#2563eb]')
|
||
end, 1000)
|
||
end
|
||
end)
|
||
|
||
-- Initialize status display
|
||
updateStatus()
|
||
|
||
-- Set initial attributes to demonstrate the methods
|
||
targetButton:setAttribute('type', 'button')
|
||
targetButton:setAttribute('data-value', 'initial')
|
||
|
||
-- Update status after setting initial attributes
|
||
gurt.setTimeout(function()
|
||
updateStatus()
|
||
end, 100)
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<h1>🔘 Button getAttribute & setAttribute Demo</h1>
|
||
|
||
<div style="container mt-6">
|
||
<div style="info-box mb-6">
|
||
<p id="info-box">✅ Target button is currently ENABLED. Click it to see the counter increase!</p>
|
||
</div>
|
||
|
||
<h2>Target Button</h2>
|
||
<div style="demo-buttons mb-6 text-center">
|
||
<button id="target-button" style="target-button">🎯 Click Me!</button>
|
||
<p id="click-counter" style="mt-3 text-lg font-semibold text-[#374151]">Button clicked 0 times!</p>
|
||
</div>
|
||
|
||
<h2>Control Buttons</h2>
|
||
<div style="button-group mb-6">
|
||
<button id="enable-btn" style="control-button enable-btn">🟢 Enable Button</button>
|
||
<button id="disable-btn" style="control-button disable-btn">🔴 Disable Button</button>
|
||
<button id="toggle-btn" style="control-button toggle-btn">🔄 Toggle State</button>
|
||
<button id="status-btn" style="control-button status-btn">📊 Check Status</button>
|
||
</div>
|
||
|
||
<h2>Current Attributes</h2>
|
||
<div style="status-display mb-6">
|
||
<pre id="status-display">Loading status...</pre>
|
||
</div>
|
||
|
||
<div style="bg-[#e0f2fe] p-4 rounded-lg">
|
||
<h3 style="text-[#0277bd] font-semibold mb-2">How It Works:</h3>
|
||
<ul style="text-[#01579b] space-y-1">
|
||
<li><strong>Enable:</strong> Uses <code>setAttribute('disabled', '')</code> to remove the disabled attribute</li>
|
||
<li><strong>Disable:</strong> Uses <code>setAttribute('disabled', 'true')</code> to add the disabled attribute</li>
|
||
<li><strong>Toggle:</strong> Uses <code>getAttribute('disabled')</code> to check current state, then toggles it</li>
|
||
<li><strong>Status:</strong> Uses <code>getAttribute()</code> to read multiple attributes and displays them</li>
|
||
<li><strong>Bonus:</strong> Also demonstrates setting custom data attributes and style changes</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENTva = """<head>
|
||
<title>WebSocket API Demo</title>
|
||
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
||
<meta name="theme-color" content="#059669">
|
||
<meta name="description" content="Demonstrating WebSocket real-time communication API">
|
||
|
||
<style>
|
||
body { bg-[#f0fdf4] p-6 }
|
||
h1 { text-[#059669] text-3xl font-bold text-center }
|
||
h2 { text-[#047857] text-xl font-semibold }
|
||
.container { bg-[#ffffff] p-6 rounded-lg shadow-lg max-w-4xl mx-auto }
|
||
.button-group { flex gap-3 justify-center items-center flex-wrap }
|
||
.ws-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors bg-[#10b981] text-white hover:bg-[#059669] }
|
||
.send-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors bg-[#3b82f6] text-white hover:bg-[#2563eb] }
|
||
.disconnect-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors bg-[#ef4444] text-white hover:bg-[#dc2626] }
|
||
.clear-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors bg-[#6b7280] text-white hover:bg-[#4b5563] }
|
||
.log-area { bg-[#f1f5f9] p-4 rounded-lg min-h-32 font-mono text-sm max-h-96 overflow-auto }
|
||
.info-box { bg-[#dbeafe] border border-[#3b82f6] p-4 rounded-lg }
|
||
.input-area { bg-[#f9fafb] p-4 rounded-lg border }
|
||
.status-connected { text-[#059669] font-bold }
|
||
.status-disconnected { text-[#ef4444] font-bold }
|
||
.status-connecting { text-[#f59e0b] font-bold }
|
||
</style>
|
||
|
||
<script>
|
||
-- Get UI elements
|
||
local logArea = gurt.select('#log-area')
|
||
local statusDisplay = gurt.select('#status-display')
|
||
local connectBtn = gurt.select('#connect-btn')
|
||
local disconnectBtn = gurt.select('#disconnect-btn')
|
||
local sendBtn = gurt.select('#send-btn')
|
||
local clearLogBtn = gurt.select('#clear-log-btn')
|
||
local urlInput = gurt.select('#url-input')
|
||
local messageInput = gurt.select('#message-input')
|
||
|
||
gurt.log('WebSocket API demo script started.')
|
||
|
||
local logMessages = {}
|
||
local socket = nil
|
||
local connected = false
|
||
|
||
-- Function to add message to log
|
||
local function addLog(message)
|
||
table.insert(logMessages, Time.format(Time.now(), '%H:%M:%S') .. ' - ' .. message)
|
||
if #logMessages > 50 then
|
||
table.remove(logMessages, 1)
|
||
end
|
||
logArea.text = table.concat(logMessages, '\\n')
|
||
end
|
||
|
||
-- Function to update status display
|
||
local function updateStatus(status, color)
|
||
statusDisplay.text = 'Status: ' .. status
|
||
statusDisplay.style = 'status-' .. color
|
||
end
|
||
|
||
-- Initialize with default values
|
||
urlInput.text = 'wss://echo.websocket.org'
|
||
messageInput.text = 'Hello from Gurted!'
|
||
|
||
-- Connect to WebSocket
|
||
connectBtn:on('click', function()
|
||
local url = urlInput.text
|
||
addLog('Attempting to connect to: ' .. url)
|
||
updateStatus('Connecting...', 'connecting')
|
||
|
||
socket = WebSocket:new(url)
|
||
|
||
socket:on('open', function()
|
||
addLog('✅ Connected to WebSocket server!')
|
||
updateStatus('Connected', 'connected')
|
||
connected = true
|
||
socket:send('Hello from the Gurted web!')
|
||
end)
|
||
|
||
socket:on('message', function(event)
|
||
addLog('📨 Received: ' .. event.data)
|
||
end)
|
||
|
||
socket:on('close', function()
|
||
addLog('❌ Connection closed')
|
||
updateStatus('Disconnected', 'disconnected')
|
||
connected = false
|
||
end)
|
||
|
||
socket:on('error', function(event)
|
||
addLog('🚨 Error: ' .. (event.message or 'Unknown error'))
|
||
updateStatus('Error', 'disconnected')
|
||
connected = false
|
||
end)
|
||
end)
|
||
|
||
-- Disconnect from WebSocket
|
||
disconnectBtn:on('click', function()
|
||
if socket and connected then
|
||
addLog('Disconnecting from WebSocket...')
|
||
socket:close()
|
||
else
|
||
addLog('No active connection to disconnect')
|
||
end
|
||
end)
|
||
|
||
-- Send message
|
||
sendBtn:on('click', function()
|
||
if socket and connected then
|
||
local message = messageInput.text
|
||
if message and message ~= '' then
|
||
socket:send(message)
|
||
addLog('📤 Sent: ' .. message)
|
||
else
|
||
addLog('❌ Cannot send empty message')
|
||
end
|
||
else
|
||
addLog('❌ Not connected to WebSocket server')
|
||
end
|
||
end)
|
||
|
||
-- Clear log button
|
||
clearLogBtn:on('click', function()
|
||
logMessages = {}
|
||
logArea.text = 'Log cleared.'
|
||
addLog('WebSocket API demo ready')
|
||
end)
|
||
|
||
-- Allow Enter key to send messages
|
||
messageInput:on('keypress', function(e)
|
||
if e.key == 'Enter' and socket and connected then
|
||
local message = messageInput.text
|
||
if message and message ~= '' then
|
||
socket:send(message)
|
||
addLog('📤 Sent: ' .. message)
|
||
messageInput.text = ''
|
||
end
|
||
end
|
||
end)
|
||
|
||
-- Initialize
|
||
updateStatus('Disconnected', 'disconnected')
|
||
addLog('WebSocket API demo ready')
|
||
addLog('Enter a WebSocket URL and click Connect to start!')
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<h1>🔌 WebSocket API Demo</h1>
|
||
|
||
<div style="container mt-6">
|
||
<div style="info-box mb-6">
|
||
<h3 style="text-[#1e40af] font-semibold mb-2">WebSocket API Usage:</h3>
|
||
<p><code>local socket = WebSocket:new(url)</code></p>
|
||
<p><code>socket:on('open', function() ... end)</code></p>
|
||
<p><code>socket:on('message', function(event) print(event.data) end)</code></p>
|
||
<p><code>socket:send('Hello Server!')</code></p>
|
||
<p><code>socket:close()</code></p>
|
||
</div>
|
||
|
||
<h2>Connection</h2>
|
||
<div style="input-area mb-6">
|
||
<div style="flex flex-col gap-3">
|
||
<div>
|
||
<label style="block text-sm font-medium mb-1">WebSocket URL:</label>
|
||
<input id="url-input" type="text" style="w-full p-2 border border-gray-300 rounded-md" placeholder="ws://echo.websocket.org" />
|
||
</div>
|
||
<div id="status-display" style="status-disconnected">Status: Disconnected</div>
|
||
<div style="flex gap-2">
|
||
<button id="connect-btn" style="ws-button">🔗 Connect</button>
|
||
<button id="disconnect-btn" style="disconnect-button">❌ Disconnect</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h2>Send Messages</h2>
|
||
<div style="input-area mb-6">
|
||
<div style="flex flex-col gap-3">
|
||
<div>
|
||
<label style="block text-sm font-medium mb-1">Message:</label>
|
||
<input id="message-input" type="text" style="w-full p-2 border border-gray-300 rounded-md" placeholder="Type your message..." />
|
||
</div>
|
||
<div style="flex gap-2">
|
||
<button id="send-btn" style="send-button">📤 Send Message</button>
|
||
<span style="text-sm text-gray-600">Or press Enter to send</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h2>Event Log</h2>
|
||
<div style="button-group mb-3">
|
||
<button id="clear-log-btn" style="clear-button">🧹 Clear Log</button>
|
||
</div>
|
||
<div style="log-area mb-6">
|
||
<pre id="log-area">Initializing...</pre>
|
||
</div>
|
||
|
||
<div style="bg-[#f0f9ff] p-4 rounded-lg">
|
||
<h3 style="text-[#0369a1] font-semibold mb-2">WebSocket Events:</h3>
|
||
<ul style="text-[#075985] space-y-1 text-sm">
|
||
<li><strong>open:</strong> Fired when connection is established</li>
|
||
<li><strong>message:</strong> Fired when a message is received (event.data contains the message)</li>
|
||
<li><strong>close:</strong> Fired when connection is closed</li>
|
||
<li><strong>error:</strong> Fired when an error occurs (event.message contains error info)</li>
|
||
</ul>
|
||
<h3 style="text-[#0369a1] font-semibold mt-4 mb-2">WebSocket Methods:</h3>
|
||
<ul style="text-[#075985] space-y-1 text-sm">
|
||
<li><strong>WebSocket:new(url):</strong> Creates and connects to WebSocket server</li>
|
||
<li><strong>socket:send(message):</strong> Sends a text message to the server</li>
|
||
<li><strong>socket:close():</strong> Closes the connection</li>
|
||
<li><strong>socket:on(event, callback):</strong> Registers event handlers</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENTy = """<head>
|
||
<title>Network & JSON API Demo</title>
|
||
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
||
<meta name="theme-color" content="#0891b2">
|
||
<meta name="description" content="Demonstrating Network fetch() and JSON APIs">
|
||
|
||
<style>
|
||
body { bg-[#ecfdf5] p-6 }
|
||
h1 { text-[#0891b2] text-3xl font-bold text-center }
|
||
h2 { text-[#0f766e] text-xl font-semibold }
|
||
.container { bg-[#ffffff] p-6 rounded-lg shadow-lg max-w-4xl mx-auto }
|
||
.button-group { flex gap-3 justify-center items-center flex-wrap }
|
||
.fetch-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors bg-[#059669] text-white hover:bg-[#047857] }
|
||
.json-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors bg-[#7c3aed] text-white hover:bg-[#6d28d9] }
|
||
.clear-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors bg-[#ef4444] text-white hover:bg-[#dc2626] }
|
||
.response-area { bg-[#f1f5f9] p-4 rounded-lg min-h-32 font-mono text-sm max-h-96 overflow-auto }
|
||
.info-box { bg-[#dbeafe] border border-[#3b82f6] p-4 rounded-lg }
|
||
.input-area { bg-[#f9fafb] p-4 rounded-lg border }
|
||
</style>
|
||
|
||
<script>
|
||
-- Get UI elements
|
||
local responseArea = gurt.select('#response-area')
|
||
local fetchGetBtn = gurt.select('#fetch-get-btn')
|
||
local fetchPostBtn = gurt.select('#fetch-post-btn')
|
||
local jsonEncodeBtn = gurt.select('#json-encode-btn')
|
||
local jsonDecodeBtn = gurt.select('#json-decode-btn')
|
||
local clearLogBtn = gurt.select('#clear-log-btn')
|
||
local urlInput = gurt.select('#url-input')
|
||
local jsonInput = gurt.select('#json-input')
|
||
|
||
gurt.log('Network & JSON API demo script started.')
|
||
|
||
local logMessages = {}
|
||
|
||
-- Function to add message to log
|
||
local function addLog(message)
|
||
table.insert(logMessages, Time.format(Time.now(), '%H:%M:%S') .. ' - ' .. message)
|
||
if #logMessages > 50 then
|
||
table.remove(logMessages, 1)
|
||
end
|
||
responseArea.text = table.concat(logMessages, '\\n')
|
||
end
|
||
|
||
-- Initialize with default values
|
||
urlInput.text = 'https://jsonplaceholder.typicode.com/posts/1'
|
||
jsonInput.text = JSON.stringify({
|
||
name = 'Alice Johnson',
|
||
age = 28,
|
||
hobbies = {'reading', 'coding', 'gaming'},
|
||
active = true,
|
||
score = 95.5
|
||
})
|
||
|
||
-- GET Request Test
|
||
fetchGetBtn:on('click', function()
|
||
local url = urlInput.text
|
||
addLog('Making GET request to: ' .. url)
|
||
|
||
local response = fetch(url)
|
||
|
||
addLog('Response Status: ' .. response.status .. ' ' .. response.statusText)
|
||
addLog('Response Headers: ' .. JSON.stringify(response.headers))
|
||
|
||
if response:ok() then
|
||
local responseText = response:text()
|
||
addLog('Response Body: ' .. responseText:sub(1, 200) .. (responseText:len() > 200 and '...' or ''))
|
||
|
||
-- Try to parse as JSON
|
||
local jsonData = response:json()
|
||
if jsonData then
|
||
addLog('Parsed JSON successfully')
|
||
end
|
||
else
|
||
addLog('Request failed with status: ' .. response.status)
|
||
end
|
||
end)
|
||
|
||
-- POST Request Test
|
||
fetchPostBtn:on('click', function()
|
||
local url = 'https://jsonplaceholder.typicode.com/posts'
|
||
local postData = {
|
||
title = 'Test Post from GURT',
|
||
body = 'This is a test post created using the GURT Network API',
|
||
userId = 1
|
||
}
|
||
|
||
addLog('Making POST request to: ' .. url)
|
||
addLog('POST Data: ' .. JSON.stringify(postData))
|
||
|
||
local response = fetch(url, {
|
||
method = 'POST',
|
||
headers = {
|
||
['Content-Type'] = 'application/json'
|
||
},
|
||
body = JSON.stringify(postData)
|
||
})
|
||
|
||
addLog('Response Status: ' .. response.status .. ' ' .. response.statusText)
|
||
|
||
if response:ok() then
|
||
local responseText = response:text()
|
||
addLog('Created Resource: ' .. responseText)
|
||
else
|
||
addLog('POST request failed with status: ' .. response.status)
|
||
end
|
||
end)
|
||
|
||
-- JSON Encode Test
|
||
jsonEncodeBtn:on('click', function()
|
||
local inputText = jsonInput.text
|
||
addLog('Encoding text to JSON: ' .. inputText:sub(1, 100) .. (inputText:len() > 100 and '...' or ''))
|
||
|
||
-- Try to parse the input as Lua data first
|
||
local success, data = pcall(function()
|
||
-- Simple data structure for demo
|
||
return {
|
||
message = inputText,
|
||
timestamp = Time.now(),
|
||
random = math.random(1, 100),
|
||
nested = {
|
||
array = {1, 2, 3},
|
||
bool = true
|
||
}
|
||
}
|
||
end)
|
||
|
||
if success then
|
||
local jsonString = JSON.stringify(data)
|
||
addLog('JSON Encoded: ' .. jsonString)
|
||
else
|
||
addLog('Error creating test data for encoding')
|
||
end
|
||
end)
|
||
|
||
-- JSON Decode Test
|
||
jsonDecodeBtn:on('click', function()
|
||
local jsonText = jsonInput.text
|
||
addLog('Decoding JSON: ' .. jsonText:sub(1, 100) .. (jsonText:len() > 100 and '...' or ''))
|
||
|
||
local data, error = JSON.parse(jsonText)
|
||
|
||
if data then
|
||
addLog('JSON Decoded successfully!')
|
||
addLog('Data type: ' .. type(data))
|
||
if type(data) == 'table' then
|
||
local keys = {}
|
||
for k, v in pairs(data) do
|
||
table.insert(keys, k .. ':' .. type(v))
|
||
end
|
||
addLog('Keys: ' .. table.concat(keys, ', '))
|
||
end
|
||
addLog('Stringified back: ' .. JSON.stringify(data))
|
||
else
|
||
addLog('JSON Decode Error: ' .. (error or 'Unknown error'))
|
||
end
|
||
end)
|
||
|
||
-- Clear log button
|
||
clearLogBtn:on('click', function()
|
||
logMessages = {}
|
||
responseArea.text = 'Log cleared.'
|
||
addLog('Network & JSON API demo ready')
|
||
end)
|
||
|
||
-- Initialize
|
||
addLog('Network & JSON API demo ready')
|
||
addLog('Try the buttons above to test network requests and JSON operations!')
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<h1>🌐 Network & JSON API Demo</h1>
|
||
|
||
<div style="container mt-6">
|
||
<div style="info-box mb-6">
|
||
<h3 style="text-[#1e40af] font-semibold mb-2">API Examples:</h3>
|
||
<p><strong>Network:</strong> <code>fetch(url, {method: "POST", headers: {...}, body: "..."})</code></p>
|
||
<p><strong>JSON:</strong> <code>JSON.stringify(data)</code> and <code>JSON.parse(jsonString)</code></p>
|
||
</div>
|
||
|
||
<h2>Input Controls</h2>
|
||
<div style="input-area mb-6">
|
||
<div style="flex flex-col gap-3">
|
||
<div>
|
||
<label style="block text-sm font-medium mb-1">Test URL:</label>
|
||
<input id="url-input" type="text" style="w-full p-2 border border-gray-300 rounded-md" placeholder="Enter API URL..." />
|
||
</div>
|
||
<div>
|
||
<label style="block text-sm font-medium mb-1">JSON Data:</label>
|
||
<textarea id="json-input" style="w-full p-2 border border-gray-300 rounded-md" rows="3" placeholder="Enter JSON data..."></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h2>Network Tests</h2>
|
||
<div style="button-group mb-6">
|
||
<button id="fetch-get-btn" style="fetch-button">🔍 GET Request</button>
|
||
<button id="fetch-post-btn" style="fetch-button">📤 POST Request</button>
|
||
</div>
|
||
|
||
<h2>JSON Tests</h2>
|
||
<div style="button-group mb-6">
|
||
<button id="json-encode-btn" style="json-button">📝 JSON Encode</button>
|
||
<button id="json-decode-btn" style="json-button">📖 JSON Decode</button>
|
||
</div>
|
||
|
||
<div style="button-group mb-6">
|
||
<button id="clear-log-btn" style="clear-button">🧹 Clear Log</button>
|
||
</div>
|
||
|
||
<h2>Response Log</h2>
|
||
<div style="response-area mb-6">
|
||
<pre id="response-area">Initializing...</pre>
|
||
</div>
|
||
|
||
<div style="bg-[#f0f9ff] p-4 rounded-lg">
|
||
<h3 style="text-[#0369a1] font-semibold mb-2">Network API Features:</h3>
|
||
<ul style="text-[#075985] space-y-1 text-sm">
|
||
<li><strong>fetch(url, options):</strong> Makes HTTP requests with support for all methods</li>
|
||
<li><strong>Response methods:</strong> text(), json(), ok() for processing responses</li>
|
||
<li><strong>Headers & Body:</strong> Full control over request headers and body content</li>
|
||
<li><strong>Status & StatusText:</strong> Access to HTTP response status information</li>
|
||
</ul>
|
||
<h3 style="text-[#0369a1] font-semibold mt-4 mb-2">JSON API Features:</h3>
|
||
<ul style="text-[#075985] space-y-1 text-sm">
|
||
<li><strong>JSON.stringify():</strong> Alias for encode (browser compatibility)</li>
|
||
<li><strong>JSON.parse():</strong> Alias for decode (browser compatibility)</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
var HTML_CONTENTyea = """<head>
|
||
<title>setInterval & Network Image Demo</title>
|
||
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
||
<meta name="theme-color" content="#7c3aed">
|
||
<meta name="description" content="Testing setInterval/clearInterval and network image loading with binary data">
|
||
<style>
|
||
body { bg-[#f8fafc] p-6 }
|
||
h1 { text-[#7c3aed] text-3xl font-bold text-center }
|
||
h2 { text-[#6d28d9] text-xl font-semibold }
|
||
.container { bg-[#ffffff] p-6 rounded-lg shadow-lg max-w-4xl mx-auto }
|
||
.button-group { flex gap-3 justify-center items-center flex-wrap }
|
||
.control-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors bg-[#7c3aed] text-white hover:bg-[#6d28d9] }
|
||
.danger-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors bg-[#ef4444] text-white hover:bg-[#dc2626] }
|
||
.success-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors bg-[#059669] text-white hover:bg-[#047857] }
|
||
.log-area { bg-[#f1f5f9] p-4 rounded-lg min-h-32 font-mono text-sm max-h-96 overflow-auto }
|
||
.image-container { text-center p-4 border-2 border-dashed border-[#cbd5e1] rounded-lg }
|
||
.counter { text-[#7c3aed] text-6xl font-bold text-center p-4 }
|
||
.info-box { bg-[#ede9fe] border border-[#7c3aed] p-4 rounded-lg }
|
||
</style>
|
||
<script>
|
||
-- Get UI elements
|
||
local logArea = gurt.select('#log-area')
|
||
local counterDisplay = gurt.select('#counter')
|
||
local startIntervalBtn = gurt.select('#start-interval-btn')
|
||
local stopIntervalBtn = gurt.select('#stop-interval-btn')
|
||
local loadImageBtn = gurt.select('#load-image-btn')
|
||
local imageContainer = gurt.select('#image-container')
|
||
|
||
gurt.log('setInterval & Network Image demo script started.')
|
||
|
||
local logMessages = {}
|
||
local counter = 0
|
||
local intervalId = nil
|
||
|
||
-- Function to add message to log
|
||
local function addLog(message)
|
||
table.insert(logMessages, Time.format(Time.now(), '%H:%M:%S.%f'):sub(1, 12) .. ' - ' .. message)
|
||
if #logMessages > 30 then
|
||
table.remove(logMessages, 1)
|
||
end
|
||
logArea.text = table.concat(logMessages, '\\n')
|
||
end
|
||
|
||
-- Update counter display
|
||
local function updateCounter()
|
||
counterDisplay.text = tostring(counter)
|
||
end
|
||
|
||
-- Start interval button
|
||
startIntervalBtn:on('click', function()
|
||
if intervalId then
|
||
addLog('❌ Interval already running (ID: ' .. intervalId .. ')')
|
||
return
|
||
end
|
||
|
||
counter = 0
|
||
updateCounter()
|
||
|
||
intervalId = gurt.setInterval(function()
|
||
counter = counter + 1
|
||
updateCounter()
|
||
addLog('⏱️ Counter updated to: ' .. counter)
|
||
end, 500) -- Every 500ms
|
||
|
||
addLog('✅ Interval started (ID: ' .. intervalId .. ')')
|
||
end)
|
||
|
||
-- Stop interval button
|
||
stopIntervalBtn:on('click', function()
|
||
if not intervalId then
|
||
addLog('❌ No interval to stop')
|
||
return
|
||
end
|
||
|
||
gurt.clearInterval(intervalId)
|
||
addLog('🛑 Interval stopped (ID: ' .. intervalId .. ')')
|
||
intervalId = nil
|
||
end)
|
||
|
||
-- Network image loading
|
||
loadImageBtn:on('click', function()
|
||
addLog('🔄 Starting random image fetch...')
|
||
imageContainer.text = 'Loading image...'
|
||
|
||
-- Use a random image service that returns binary data
|
||
local randomImageUrl = 'https://picsum.photos/300/200?random=' .. math.floor(Time.now() * 1000)
|
||
|
||
addLog('📡 Fetching: ' .. randomImageUrl)
|
||
|
||
local response = fetch(randomImageUrl)
|
||
|
||
-- Handle both success and redirect cases (302 is common for image services)
|
||
if response:ok() or response.status == 302 then
|
||
addLog('✅ Image fetch response received (Status: ' .. response.status .. ')')
|
||
addLog('📊 Content-Type: ' .. (response.headers['content-type'] or 'unknown'))
|
||
addLog('📏 Content-Length: ' .. (response.headers['content-length'] or 'unknown'))
|
||
|
||
-- For image services, we can often use the original URL directly
|
||
-- since the browser/engine handles redirects automatically
|
||
local imageElement = gurt.create('img', {
|
||
src = randomImageUrl,
|
||
style = 'max-w-[300px] max-h-[200px] rounded-lg shadow-md'
|
||
})
|
||
|
||
-- Clear container and append new image
|
||
imageContainer.text = ''
|
||
imageContainer:append(imageElement)
|
||
|
||
addLog('🖼️ Image element created and appended')
|
||
addLog('💡 Note: Image service may use redirects (302), but img tag handles this')
|
||
else
|
||
addLog('❌ Image fetch failed: ' .. response.status .. ' ' .. (response.statusText or 'Unknown'))
|
||
imageContainer.text = 'Failed to load image'
|
||
end
|
||
end)
|
||
|
||
-- Initialize
|
||
updateCounter()
|
||
addLog('🚀 Demo ready!')
|
||
addLog('💡 Click "Start Interval" to begin counter')
|
||
addLog('🖼️ Click "Load Random Image" to test binary data handling')
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<h1>⏰ setInterval & 🖼️ Network Image Demo</h1>
|
||
|
||
<div style="container mt-6">
|
||
<div style="info-box mb-6">
|
||
<h3 style="text-[#6d28d9] font-semibold mb-2">Testing Features:</h3>
|
||
<p><strong>Intervals:</strong> <code>gurt.setInterval(callback, delay)</code> and <code>gurt.clearInterval(id)</code></p>
|
||
<p><strong>Network Images:</strong> <code>fetch()</code> with binary data and dynamic <code><img></code> creation</p>
|
||
</div>
|
||
|
||
<div style="counter mb-6" id="counter">0</div>
|
||
|
||
<h2>Interval Controls</h2>
|
||
<div style="button-group mb-6">
|
||
<button id="start-interval-btn" style="control-button">▶️ Start Interval</button>
|
||
<button id="stop-interval-btn" style="danger-button">⏹️ Stop Interval</button>
|
||
</div>
|
||
|
||
<h2>Network Image Test</h2>
|
||
<div style="button-group mb-6">
|
||
<button id="load-image-btn" style="success-button">🖼️ Load Random Image</button>
|
||
</div>
|
||
|
||
<div id="image-container" style="image-container mb-6">
|
||
<p style="text-[#64748b]">Click "Load Random Image" to test binary data fetching</p>
|
||
</div>
|
||
|
||
<h2>Activity Log</h2>
|
||
<div style="log-area mb-6">
|
||
<pre id="log-area">Initializing...</pre>
|
||
</div>
|
||
|
||
<div style="bg-[#f3f4f6] p-4 rounded-lg">
|
||
<h3 style="text-[#374151] font-semibold mb-2">Implementation Notes:</h3>
|
||
<ul style="text-[#4b5563] space-y-1 text-sm">
|
||
<li><strong>setInterval:</strong> Creates repeating timers (one_shot = false)</li>
|
||
<li><strong>clearInterval:</strong> Stops and cleans up interval timers</li>
|
||
<li><strong>Binary Data:</strong> fetch() handles binary image data seamlessly</li>
|
||
<li><strong>Dynamic DOM:</strong> Images created and appended programmatically</li>
|
||
<li><strong>Random Images:</strong> Picsum service provides different images each time</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENT = """<head>
|
||
<title>Object-Fit CSS Demo</title>
|
||
<icon src="https://picsum.photos/32/32?random=1">
|
||
<meta name="theme-color" content="#0ea5e9">
|
||
<meta name="description" content="Demonstrating object-fit CSS properties for images">
|
||
<style>
|
||
body { bg-[#f1f5f9] p-8 }
|
||
h1 { text-[#0ea5e9] text-4xl font-bold text-center mb-8 }
|
||
h2 { text-[#0369a1] text-2xl font-semibold mb-4 }
|
||
.demo-grid { flex flex-wrap gap-6 justify-center }
|
||
.demo-item { bg-white p-6 rounded-xl shadow-lg }
|
||
.image-container { w-[300px] h-[200px] border-2 border-[#cbd5e1] rounded-lg overflow-hidden mb-4 }
|
||
.code-block { bg-[#1e293b] text-[#e2e8f0] p-3 rounded font-mono text-sm }
|
||
.description { text-[#475569] text-sm mb-2 }
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<h1>🖼️ Object-Fit CSS Demonstration</h1>
|
||
|
||
<div style="demo-grid">
|
||
<!-- Object-fit: none (STRETCH_KEEP) -->
|
||
<div style="demo-item">
|
||
<h2>object-none</h2>
|
||
<div style="description">Image keeps original size, may overflow container</div>
|
||
<div style="image-container">
|
||
<img src="https://picsum.photos/400/700?random=1" style="w-full h-full object-none" />
|
||
</div>
|
||
<div style="code-block">object-none</div>
|
||
</div>
|
||
|
||
<!-- Object-fit: fill (STRETCH_SCALE) -->
|
||
<div style="demo-item">
|
||
<h2>object-fill</h2>
|
||
<div style="description">Image fills container, may distort aspect ratio</div>
|
||
<div style="image-container">
|
||
<img src="https://picsum.photos/500/600?random=2" style="w-full h-full object-fill" />
|
||
</div>
|
||
<div style="code-block">object-fill</div>
|
||
</div>
|
||
|
||
<!-- Object-fit: contain (STRETCH_KEEP_ASPECT) -->
|
||
<div style="demo-item">
|
||
<h2>object-contain</h2>
|
||
<div style="description">Image fits inside container while preserving aspect ratio</div>
|
||
<div style="image-container">
|
||
<img src="https://picsum.photos/700/600?random=3" style="w-full h-full object-contain" />
|
||
</div>
|
||
<div style="code-block">object-contain</div>
|
||
</div>
|
||
|
||
<!-- Object-fit: cover (STRETCH_KEEP_ASPECT_COVERED) -->
|
||
<div style="demo-item">
|
||
<h2>object-cover</h2>
|
||
<div style="description">Image covers entire container while preserving aspect ratio</div>
|
||
<div style="image-container">
|
||
<img src="https://picsum.photos/200/300?random=4" style="w-full h-full object-cover" />
|
||
</div>
|
||
<div style="code-block">object-cover</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="bg-white p-6 rounded-xl shadow-lg mt-8 max-w-4xl mx-auto">
|
||
<h2>📝 Object-fit Property Mapping</h2>
|
||
<div style="text-[#475569]">
|
||
<p><strong>object-none:</strong> Godot's STRETCH_KEEP - Image keeps original dimensions</p>
|
||
<p><strong>object-fill:</strong> Godot's STRETCH_SCALE - Image stretches to fill container</p>
|
||
<p><strong>object-contain:</strong> Godot's STRETCH_KEEP_ASPECT - Image fits inside with preserved aspect ratio</p>
|
||
<p><strong>object-cover:</strong> Godot's STRETCH_KEEP_ASPECT_COVERED - Image covers container with preserved aspect ratio</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
var HTML_CONTENT_TRANSFORM_TEST = """<head>
|
||
<title>Transform CSS Demo - Scale & Rotation</title>
|
||
<icon src="https://picsum.photos/32/32?random=1">
|
||
<meta name="theme-color" content="#8b5cf6">
|
||
<meta name="description" content="Testing scale and rotation CSS utilities">
|
||
<style>
|
||
body { bg-[#f8fafc] p-8 }
|
||
h1 { text-[#8b5cf6] text-4xl font-bold text-center mb-8 }
|
||
h2 { text-[#7c3aed] text-2xl font-semibold mb-4 }
|
||
.demo-grid { flex flex-wrap gap-6 justify-center }
|
||
.demo-item { bg-white p-6 rounded-xl shadow-lg text-center }
|
||
.demo-box { w-[100px] h-[100px] bg-[#3b82f6] text-white text-xl font-bold rounded-lg flex items-center justify-center mb-4 mx-auto }
|
||
.code-block { bg-[#1e293b] text-[#e2e8f0] p-3 rounded font-mono text-sm }
|
||
.description { text-[#64748b] text-sm mb-3 }
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<h1>🔄 Scale & Rotation CSS Demonstration</h1>
|
||
|
||
<div style="demo-grid">
|
||
<!-- Normal (no transform) -->
|
||
<div style="demo-item">
|
||
<h2>Normal</h2>
|
||
<div style="description">No transform applied</div>
|
||
<div style="demo-box">Box</div>
|
||
<div style="code-block">No transform</div>
|
||
</div>
|
||
|
||
<!-- Scale 50% -->
|
||
<div style="demo-item">
|
||
<h2>Scale 50%</h2>
|
||
<div style="description">Scaled to 50% size</div>
|
||
<div style="demo-box scale-50">Box</div>
|
||
<div style="code-block">scale-50</div>
|
||
</div>
|
||
|
||
<!-- Scale 150% -->
|
||
<div style="demo-item">
|
||
<h2>Scale 150%</h2>
|
||
<div style="description">Scaled to 150% size</div>
|
||
<div style="demo-box scale-150">Box</div>
|
||
<div style="code-block">scale-150</div>
|
||
</div>
|
||
|
||
<!-- Scale X-axis only -->
|
||
<div style="demo-item">
|
||
<h2>Scale X 75%</h2>
|
||
<div style="description">X-axis scaled to 75%</div>
|
||
<div style="demo-box scale-x-75">Box</div>
|
||
<div style="code-block">scale-x-75</div>
|
||
</div>
|
||
|
||
<!-- Scale Y-axis only -->
|
||
<div style="demo-item">
|
||
<h2>Scale Y 125%</h2>
|
||
<div style="description">Y-axis scaled to 125%</div>
|
||
<div style="demo-box scale-y-125">Box</div>
|
||
<div style="code-block">scale-y-125</div>
|
||
</div>
|
||
|
||
<!-- Custom scale with bracket notation -->
|
||
<div style="demo-item">
|
||
<h2>Custom Scale</h2>
|
||
<div style="description">Custom scale value 1.7</div>
|
||
<div style="demo-box scale-[170]">Box</div>
|
||
<div style="code-block">scale-[170]</div>
|
||
</div>
|
||
|
||
<!-- Rotate 45 degrees -->
|
||
<div style="demo-item">
|
||
<h2>Rotate 45°</h2>
|
||
<div style="description">Rotated 45 degrees</div>
|
||
<div style="demo-box rotate-45">Box</div>
|
||
<div style="code-block">rotate-45</div>
|
||
</div>
|
||
|
||
<!-- Rotate 90 degrees -->
|
||
<div style="demo-item">
|
||
<h2>Rotate 90°</h2>
|
||
<div style="description">Rotated 90 degrees</div>
|
||
<div style="demo-box rotate-90">Box</div>
|
||
<div style="code-block">rotate-90</div>
|
||
</div>
|
||
|
||
<!-- Custom rotation with bracket notation -->
|
||
<div style="demo-item">
|
||
<h2>Custom Rotate</h2>
|
||
<div style="description">Custom rotation 30deg</div>
|
||
<div style="demo-box rotate-[30deg]">Box</div>
|
||
<div style="code-block">rotate-[30deg]</div>
|
||
</div>
|
||
|
||
<!-- Combined scale and rotation -->
|
||
<div style="demo-item">
|
||
<h2>Scale + Rotate</h2>
|
||
<div style="description">Scale 125% and rotate 45°</div>
|
||
<div style="demo-box scale-125 rotate-45">Box</div>
|
||
<div style="code-block">scale-125 rotate-45</div>
|
||
</div>
|
||
|
||
<!-- Rotation in radians -->
|
||
<div style="demo-item">
|
||
<h2>Radians</h2>
|
||
<div style="description">Rotation using radians</div>
|
||
<div style="demo-box rotate-[1.57rad]">Box</div>
|
||
<div style="code-block">rotate-[1.57rad]</div>
|
||
</div>
|
||
|
||
<!-- Hover effects with transforms -->
|
||
<div style="demo-item">
|
||
<h2>Hover Effect</h2>
|
||
<div style="description">Hover to see scale effect</div>
|
||
<div style="demo-box hover:scale-110 transition hover:rotate-45">Box</div>
|
||
<div style="code-block">hover:scale-110</div>
|
||
</div>
|
||
</div>
|
||
|
||
<button style="hover:scale-110 transition">Button</button>
|
||
|
||
<div style="bg-white p-6 rounded-xl shadow-lg mt-8 max-w-4xl mx-auto">
|
||
<h2>📝 Transform Utility Reference</h2>
|
||
<div style="text-[#475569]">
|
||
<p><strong>Scale utilities:</strong> scale-{value}, scale-x-{value}, scale-y-{value}</p>
|
||
<p><strong>Named values:</strong> 0, 50, 75, 90, 95, 100, 105, 110, 125, 150, 200</p>
|
||
<p><strong>Custom values:</strong> scale-[{number}] where number is percentage (100 = 1.0)</p>
|
||
<p><strong>Rotation utilities:</strong> rotate-{degrees}, rotate-x-{degrees}, rotate-y-{degrees}</p>
|
||
<p><strong>Named degrees:</strong> 0, 1, 2, 3, 6, 12, 45, 90, 180, 270</p>
|
||
<p><strong>Custom rotations:</strong> rotate-[{value}deg], rotate-[{value}rad], rotate-[{value}turn]</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
""".to_utf8_buffer()
|
||
|
||
# Set the active HTML content to use the transform demo
|
||
func _ready():
|
||
HTML_CONTENT = HTML_CONTENT_TRANSFORM_TEST
|