@vitronai/alethia 0.3.8 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -11
- package/demo/README.md +58 -35
- package/demo/admin-panel.html +1 -1
- package/demo/agent-oversight.html +237 -0
- package/demo/crypto-readiness.html +237 -0
- package/demo/ea1-stress-test.html +200 -0
- package/demo/financial-dashboard.html +1 -1
- package/demo/incident-response.html +267 -0
- package/demo/nist-compliance.html +129 -0
- package/demo/threat-intel.html +301 -0
- package/demo/wcag-audit.html +113 -0
- package/dist/index.js +25 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/demo/cookie-banner.html +0 -66
- package/demo/ecommerce.html +0 -88
- package/demo/form-validation.html +0 -113
- package/demo/signup-form.html +0 -70
- package/demo/spa-loading.html +0 -64
- package/demo/todo-app.html +0 -51
package/demo/cookie-banner.html
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<title>Blog Post</title>
|
|
5
|
-
<style>
|
|
6
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
-
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; padding: 2rem; }
|
|
8
|
-
h1 { font-size: 1.8rem; margin-bottom: 0.5rem; }
|
|
9
|
-
.meta { color: #64748b; margin-bottom: 1.5rem; font-size: 0.9rem; }
|
|
10
|
-
article { max-width: 640px; line-height: 1.7; }
|
|
11
|
-
article p { margin-bottom: 1rem; color: #cbd5e1; }
|
|
12
|
-
.cookie-banner { position: fixed; bottom: 0; left: 0; right: 0; background: #1e293b; border-top: 1px solid #334155; padding: 1rem 2rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem; z-index: 100; }
|
|
13
|
-
.cookie-banner p { color: #94a3b8; font-size: 0.9rem; margin: 0; }
|
|
14
|
-
.cookie-banner button { padding: 0.5rem 1.2rem; border-radius: 8px; border: none; font-weight: 600; cursor: pointer; }
|
|
15
|
-
.accept-btn { background: #3b82f6; color: white; }
|
|
16
|
-
.decline-btn { background: #334155; color: #94a3b8; }
|
|
17
|
-
.hidden { display: none; }
|
|
18
|
-
.newsletter { border: 1px solid #334155; border-radius: 12px; padding: 1.2rem; background: #1e293b; margin-top: 2rem; }
|
|
19
|
-
.newsletter h3 { margin-bottom: 0.5rem; }
|
|
20
|
-
.newsletter input { padding: 0.5rem; border-radius: 6px; border: 1px solid #334155; background: #0f172a; color: #e2e8f0; margin-right: 0.5rem; }
|
|
21
|
-
.newsletter button { padding: 0.5rem 1rem; border-radius: 6px; border: none; background: #3b82f6; color: white; cursor: pointer; }
|
|
22
|
-
.subscribed { color: #34d399; font-weight: 600; display: none; }
|
|
23
|
-
</style>
|
|
24
|
-
</head>
|
|
25
|
-
<body>
|
|
26
|
-
<article>
|
|
27
|
-
<h1>Why Zero-IPC Matters for AI Agents</h1>
|
|
28
|
-
<p class="meta">April 10, 2026 · 5 min read</p>
|
|
29
|
-
<p>When an AI agent generates code and needs to verify it works, every millisecond of automation latency compounds. CDP-based tools add ~580ms of marshalling tax per assertion.</p>
|
|
30
|
-
<p>Zero-IPC eliminates the process boundary between the automation driver and the DOM. The driver touches the DOM the same way the page's own JavaScript does — synchronously, in-process, with no serialization overhead.</p>
|
|
31
|
-
<p>The result: ~13ms per step instead of ~580ms. That's not an optimization — it's a different architecture.</p>
|
|
32
|
-
<div class="newsletter">
|
|
33
|
-
<h3>Subscribe to updates</h3>
|
|
34
|
-
<div id="subscribe-form">
|
|
35
|
-
<input id="email" type="email" placeholder="you@example.com" aria-label="Email address" />
|
|
36
|
-
<button id="subscribe-btn" type="button">Subscribe</button>
|
|
37
|
-
</div>
|
|
38
|
-
<p id="subscribed" class="subscribed">Subscribed! Check your inbox.</p>
|
|
39
|
-
</div>
|
|
40
|
-
</article>
|
|
41
|
-
|
|
42
|
-
<div id="cookie-banner" class="cookie-banner">
|
|
43
|
-
<p>We use cookies to improve your experience. No tracking, no ads.</p>
|
|
44
|
-
<div>
|
|
45
|
-
<button class="decline-btn" id="decline-cookies" type="button">Decline</button>
|
|
46
|
-
<button class="accept-btn" id="accept-cookies" type="button">Accept</button>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
<script>
|
|
51
|
-
document.getElementById('accept-cookies').addEventListener('click', function() {
|
|
52
|
-
document.getElementById('cookie-banner').classList.add('hidden');
|
|
53
|
-
});
|
|
54
|
-
document.getElementById('decline-cookies').addEventListener('click', function() {
|
|
55
|
-
document.getElementById('cookie-banner').classList.add('hidden');
|
|
56
|
-
});
|
|
57
|
-
document.getElementById('subscribe-btn').addEventListener('click', function() {
|
|
58
|
-
var email = document.getElementById('email').value;
|
|
59
|
-
if (email && email.includes('@')) {
|
|
60
|
-
document.getElementById('subscribe-form').style.display = 'none';
|
|
61
|
-
document.getElementById('subscribed').style.display = 'block';
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
</script>
|
|
65
|
-
</body>
|
|
66
|
-
</html>
|
package/demo/ecommerce.html
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<title>Acme Store</title>
|
|
5
|
-
<style>
|
|
6
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
-
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; padding: 2rem; }
|
|
8
|
-
h1 { font-size: 1.8rem; margin-bottom: 1.5rem; }
|
|
9
|
-
.products { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 2rem; }
|
|
10
|
-
.product { border: 1px solid #334155; border-radius: 12px; padding: 1.2rem; background: #1e293b; }
|
|
11
|
-
.product h2 { font-size: 1.1rem; margin-bottom: 0.4rem; }
|
|
12
|
-
.product .price { color: #34d399; font-weight: 700; font-size: 1.2rem; }
|
|
13
|
-
.product p { color: #94a3b8; font-size: 0.9rem; margin: 0.4rem 0; }
|
|
14
|
-
button { padding: 0.6rem 1rem; border-radius: 8px; border: none; background: #3b82f6; color: white; font-weight: 600; cursor: pointer; margin-top: 0.5rem; }
|
|
15
|
-
button:hover { background: #2563eb; }
|
|
16
|
-
button:disabled { background: #475569; cursor: not-allowed; }
|
|
17
|
-
.cart { border: 1px solid #334155; border-radius: 12px; padding: 1.2rem; background: #1e293b; max-width: 400px; }
|
|
18
|
-
.cart h2 { margin-bottom: 0.8rem; }
|
|
19
|
-
.cart ul { list-style: none; }
|
|
20
|
-
.cart li { padding: 0.4rem 0; border-bottom: 1px solid #0f172a; display: flex; justify-content: space-between; }
|
|
21
|
-
.cart-total { margin-top: 0.8rem; font-weight: 700; font-size: 1.1rem; color: #34d399; }
|
|
22
|
-
.cart-empty { color: #64748b; }
|
|
23
|
-
.checkout-btn { background: #ef4444; width: 100%; margin-top: 0.8rem; }
|
|
24
|
-
.success { display: none; color: #34d399; font-size: 1.2rem; font-weight: 700; margin-top: 1rem; }
|
|
25
|
-
</style>
|
|
26
|
-
</head>
|
|
27
|
-
<body>
|
|
28
|
-
<h1>Acme Store</h1>
|
|
29
|
-
<div class="products">
|
|
30
|
-
<div class="product">
|
|
31
|
-
<h2>Wireless Keyboard</h2>
|
|
32
|
-
<p>Mechanical, RGB backlit</p>
|
|
33
|
-
<span class="price">$79</span>
|
|
34
|
-
<br/>
|
|
35
|
-
<button onclick="addToCart('Wireless Keyboard', 79)">Add to Cart</button>
|
|
36
|
-
</div>
|
|
37
|
-
<div class="product">
|
|
38
|
-
<h2>USB-C Hub</h2>
|
|
39
|
-
<p>7-port, 100W passthrough</p>
|
|
40
|
-
<span class="price">$45</span>
|
|
41
|
-
<br/>
|
|
42
|
-
<button onclick="addToCart('USB-C Hub', 45)">Add to Cart</button>
|
|
43
|
-
</div>
|
|
44
|
-
<div class="product">
|
|
45
|
-
<h2>Monitor Stand</h2>
|
|
46
|
-
<p>Adjustable, aluminum</p>
|
|
47
|
-
<span class="price">$120</span>
|
|
48
|
-
<br/>
|
|
49
|
-
<button onclick="addToCart('Monitor Stand', 120)">Add to Cart</button>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
<div class="cart">
|
|
53
|
-
<h2>Cart</h2>
|
|
54
|
-
<ul id="cart-items"><li class="cart-empty">Your cart is empty</li></ul>
|
|
55
|
-
<p id="cart-total" class="cart-total"></p>
|
|
56
|
-
<button class="checkout-btn" id="checkout-btn" onclick="checkout()" disabled>Complete Purchase</button>
|
|
57
|
-
</div>
|
|
58
|
-
<p id="success" class="success" role="alert">Order confirmed! Thank you for your purchase.</p>
|
|
59
|
-
<script>
|
|
60
|
-
const cart = [];
|
|
61
|
-
function addToCart(name, price) {
|
|
62
|
-
cart.push({ name, price });
|
|
63
|
-
renderCart();
|
|
64
|
-
}
|
|
65
|
-
function renderCart() {
|
|
66
|
-
const list = document.getElementById('cart-items');
|
|
67
|
-
const total = document.getElementById('cart-total');
|
|
68
|
-
const btn = document.getElementById('checkout-btn');
|
|
69
|
-
if (cart.length === 0) {
|
|
70
|
-
list.innerHTML = '<li class="cart-empty">Your cart is empty</li>';
|
|
71
|
-
total.textContent = '';
|
|
72
|
-
btn.disabled = true;
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
list.innerHTML = cart.map(item => '<li><span>' + item.name + '</span><span>$' + item.price + '</span></li>').join('');
|
|
76
|
-
const sum = cart.reduce((s, i) => s + i.price, 0);
|
|
77
|
-
total.textContent = 'Total: $' + sum;
|
|
78
|
-
btn.disabled = false;
|
|
79
|
-
}
|
|
80
|
-
function checkout() {
|
|
81
|
-
document.getElementById('success').style.display = 'block';
|
|
82
|
-
document.getElementById('checkout-btn').disabled = true;
|
|
83
|
-
document.getElementById('checkout-btn').textContent = 'Purchased';
|
|
84
|
-
document.title = 'Order Confirmed — Acme Store';
|
|
85
|
-
}
|
|
86
|
-
</script>
|
|
87
|
-
</body>
|
|
88
|
-
</html>
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<title>Contact Form</title>
|
|
5
|
-
<style>
|
|
6
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
-
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
8
|
-
.container { width: 400px; }
|
|
9
|
-
h1 { font-size: 1.8rem; margin-bottom: 1.2rem; }
|
|
10
|
-
form { display: flex; flex-direction: column; gap: 0.8rem; }
|
|
11
|
-
label { font-size: 0.9rem; color: #94a3b8; }
|
|
12
|
-
input, textarea, select { padding: 0.7rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #e2e8f0; font-size: 1rem; font-family: inherit; }
|
|
13
|
-
input::placeholder, textarea::placeholder { color: #64748b; }
|
|
14
|
-
input.invalid, textarea.invalid, select.invalid { border-color: #f87171; }
|
|
15
|
-
.field-error { color: #f87171; font-size: 0.8rem; display: none; }
|
|
16
|
-
.field-error.visible { display: block; }
|
|
17
|
-
textarea { resize: vertical; min-height: 80px; }
|
|
18
|
-
button { padding: 0.75rem; border-radius: 8px; border: none; background: #3b82f6; color: white; font-size: 1rem; font-weight: 600; cursor: pointer; }
|
|
19
|
-
button:hover { background: #2563eb; }
|
|
20
|
-
button:disabled { background: #475569; cursor: not-allowed; }
|
|
21
|
-
.success { display: none; text-align: center; }
|
|
22
|
-
.success h2 { color: #34d399; margin-bottom: 0.5rem; }
|
|
23
|
-
.success p { color: #94a3b8; }
|
|
24
|
-
.char-count { font-size: 0.8rem; color: #64748b; text-align: right; }
|
|
25
|
-
</style>
|
|
26
|
-
</head>
|
|
27
|
-
<body>
|
|
28
|
-
<div class="container">
|
|
29
|
-
<div id="form-container">
|
|
30
|
-
<h1>Contact Us</h1>
|
|
31
|
-
<form id="contact-form" onsubmit="return false;">
|
|
32
|
-
<div>
|
|
33
|
-
<label for="name">Full Name</label>
|
|
34
|
-
<input id="name" placeholder="Jane Doe" aria-label="Full name" />
|
|
35
|
-
<p id="name-error" class="field-error" role="alert">Name is required</p>
|
|
36
|
-
</div>
|
|
37
|
-
<div>
|
|
38
|
-
<label for="contact-email">Email</label>
|
|
39
|
-
<input id="contact-email" type="email" placeholder="jane@example.com" aria-label="Email" />
|
|
40
|
-
<p id="email-error" class="field-error" role="alert">Please enter a valid email</p>
|
|
41
|
-
</div>
|
|
42
|
-
<div>
|
|
43
|
-
<label for="subject">Subject</label>
|
|
44
|
-
<select id="subject" aria-label="Subject">
|
|
45
|
-
<option value="">Select a topic...</option>
|
|
46
|
-
<option value="general">General inquiry</option>
|
|
47
|
-
<option value="support">Technical support</option>
|
|
48
|
-
<option value="partnership">Partnership</option>
|
|
49
|
-
<option value="licensing">Licensing</option>
|
|
50
|
-
</select>
|
|
51
|
-
<p id="subject-error" class="field-error" role="alert">Please select a subject</p>
|
|
52
|
-
</div>
|
|
53
|
-
<div>
|
|
54
|
-
<label for="message">Message</label>
|
|
55
|
-
<textarea id="message" placeholder="Tell us what's on your mind..." aria-label="Message"></textarea>
|
|
56
|
-
<p class="char-count"><span id="char-count">0</span>/500</p>
|
|
57
|
-
<p id="message-error" class="field-error" role="alert">Message must be at least 10 characters</p>
|
|
58
|
-
</div>
|
|
59
|
-
<button type="button" id="submit-btn">Send Message</button>
|
|
60
|
-
</form>
|
|
61
|
-
</div>
|
|
62
|
-
<div id="success" class="success">
|
|
63
|
-
<h2>Message Sent!</h2>
|
|
64
|
-
<p>Thanks for reaching out. We'll get back to you within 24 hours.</p>
|
|
65
|
-
</div>
|
|
66
|
-
</div>
|
|
67
|
-
<script>
|
|
68
|
-
var messageEl = document.getElementById('message');
|
|
69
|
-
var charCount = document.getElementById('char-count');
|
|
70
|
-
messageEl.addEventListener('input', function() {
|
|
71
|
-
charCount.textContent = messageEl.value.length;
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
document.getElementById('submit-btn').addEventListener('click', function() {
|
|
75
|
-
var name = document.getElementById('name');
|
|
76
|
-
var email = document.getElementById('contact-email');
|
|
77
|
-
var subject = document.getElementById('subject');
|
|
78
|
-
var message = document.getElementById('message');
|
|
79
|
-
var valid = true;
|
|
80
|
-
|
|
81
|
-
// Reset
|
|
82
|
-
[name, email, subject, message].forEach(function(el) { el.classList.remove('invalid'); });
|
|
83
|
-
document.querySelectorAll('.field-error').forEach(function(el) { el.classList.remove('visible'); });
|
|
84
|
-
|
|
85
|
-
if (!name.value.trim()) {
|
|
86
|
-
name.classList.add('invalid');
|
|
87
|
-
document.getElementById('name-error').classList.add('visible');
|
|
88
|
-
valid = false;
|
|
89
|
-
}
|
|
90
|
-
if (!email.value.trim() || !email.value.includes('@')) {
|
|
91
|
-
email.classList.add('invalid');
|
|
92
|
-
document.getElementById('email-error').classList.add('visible');
|
|
93
|
-
valid = false;
|
|
94
|
-
}
|
|
95
|
-
if (!subject.value) {
|
|
96
|
-
subject.classList.add('invalid');
|
|
97
|
-
document.getElementById('subject-error').classList.add('visible');
|
|
98
|
-
valid = false;
|
|
99
|
-
}
|
|
100
|
-
if (message.value.trim().length < 10) {
|
|
101
|
-
message.classList.add('invalid');
|
|
102
|
-
document.getElementById('message-error').classList.add('visible');
|
|
103
|
-
valid = false;
|
|
104
|
-
}
|
|
105
|
-
if (valid) {
|
|
106
|
-
document.getElementById('form-container').style.display = 'none';
|
|
107
|
-
document.getElementById('success').style.display = 'block';
|
|
108
|
-
document.title = 'Message Sent — Contact';
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
</script>
|
|
112
|
-
</body>
|
|
113
|
-
</html>
|
package/demo/signup-form.html
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<title>Acme Dashboard</title>
|
|
5
|
-
<style>
|
|
6
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
-
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
8
|
-
.container { width: 360px; }
|
|
9
|
-
h1 { font-size: 1.8rem; margin-bottom: 1.2rem; }
|
|
10
|
-
form { display: flex; flex-direction: column; gap: 0.8rem; }
|
|
11
|
-
input { padding: 0.7rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #e2e8f0; font-size: 1rem; }
|
|
12
|
-
input::placeholder { color: #64748b; }
|
|
13
|
-
button { padding: 0.75rem; border-radius: 8px; border: none; background: #3b82f6; color: white; font-size: 1rem; font-weight: 600; cursor: pointer; }
|
|
14
|
-
button:hover { background: #2563eb; }
|
|
15
|
-
.error { color: #f87171; font-size: 0.9rem; display: none; }
|
|
16
|
-
.error.visible { display: block; }
|
|
17
|
-
#dashboard { display: none; }
|
|
18
|
-
#dashboard h1 { color: #34d399; }
|
|
19
|
-
#dashboard ul { list-style: none; margin-top: 1rem; }
|
|
20
|
-
#dashboard li { padding: 0.5rem 0; border-bottom: 1px solid #1e293b; }
|
|
21
|
-
#dashboard button { background: #ef4444; margin-top: 1rem; }
|
|
22
|
-
</style>
|
|
23
|
-
</head>
|
|
24
|
-
<body>
|
|
25
|
-
<div class="container">
|
|
26
|
-
<div id="login">
|
|
27
|
-
<h1>Sign In</h1>
|
|
28
|
-
<div id="error" class="error" role="alert">Please fill in all fields</div>
|
|
29
|
-
<form onsubmit="return false;">
|
|
30
|
-
<input id="email" type="email" placeholder="Email" aria-label="Email" />
|
|
31
|
-
<input id="password" type="password" placeholder="Password" aria-label="Password" />
|
|
32
|
-
<button type="button" id="signin-btn">Sign In</button>
|
|
33
|
-
</form>
|
|
34
|
-
</div>
|
|
35
|
-
<div id="dashboard">
|
|
36
|
-
<h1>Welcome back!</h1>
|
|
37
|
-
<p id="user-greeting"></p>
|
|
38
|
-
<ul id="tasks">
|
|
39
|
-
<li>Deploy v2.1</li>
|
|
40
|
-
<li>Review PR #42</li>
|
|
41
|
-
<li>Update docs</li>
|
|
42
|
-
</ul>
|
|
43
|
-
<button type="button" id="logout-btn">Sign Out</button>
|
|
44
|
-
</div>
|
|
45
|
-
</div>
|
|
46
|
-
<script>
|
|
47
|
-
document.getElementById('signin-btn').addEventListener('click', function() {
|
|
48
|
-
var email = document.getElementById('email').value;
|
|
49
|
-
var password = document.getElementById('password').value;
|
|
50
|
-
var error = document.getElementById('error');
|
|
51
|
-
if (!email || !password) {
|
|
52
|
-
error.classList.add('visible');
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
error.classList.remove('visible');
|
|
56
|
-
document.getElementById('login').style.display = 'none';
|
|
57
|
-
document.getElementById('dashboard').style.display = 'block';
|
|
58
|
-
document.getElementById('user-greeting').textContent = 'Logged in as ' + email;
|
|
59
|
-
document.title = 'Dashboard — Acme';
|
|
60
|
-
});
|
|
61
|
-
document.getElementById('logout-btn').addEventListener('click', function() {
|
|
62
|
-
document.getElementById('login').style.display = 'block';
|
|
63
|
-
document.getElementById('dashboard').style.display = 'none';
|
|
64
|
-
document.getElementById('email').value = '';
|
|
65
|
-
document.getElementById('password').value = '';
|
|
66
|
-
document.title = 'Acme Dashboard';
|
|
67
|
-
});
|
|
68
|
-
</script>
|
|
69
|
-
</body>
|
|
70
|
-
</html>
|
package/demo/spa-loading.html
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<title>SPA Dashboard</title>
|
|
5
|
-
<style>
|
|
6
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
-
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
8
|
-
.container { width: 480px; }
|
|
9
|
-
h1 { font-size: 1.8rem; margin-bottom: 1rem; }
|
|
10
|
-
.spinner { display: inline-block; width: 20px; height: 20px; border: 3px solid #334155; border-top-color: #3b82f6; border-radius: 50%; animation: spin 0.8s linear infinite; margin-right: 0.5rem; vertical-align: middle; }
|
|
11
|
-
@keyframes spin { to { transform: rotate(360deg); } }
|
|
12
|
-
.loading { color: #94a3b8; margin-bottom: 1rem; }
|
|
13
|
-
.card { border: 1px solid #334155; border-radius: 12px; padding: 1.2rem; background: #1e293b; margin-bottom: 0.8rem; }
|
|
14
|
-
.card h3 { margin-bottom: 0.4rem; }
|
|
15
|
-
.card p { color: #94a3b8; font-size: 0.9rem; }
|
|
16
|
-
.stats { display: flex; gap: 1rem; margin-top: 1rem; }
|
|
17
|
-
.stat { text-align: center; }
|
|
18
|
-
.stat-value { font-size: 2rem; font-weight: 700; color: #3b82f6; }
|
|
19
|
-
.stat-label { font-size: 0.8rem; color: #64748b; }
|
|
20
|
-
#content { display: none; }
|
|
21
|
-
</style>
|
|
22
|
-
</head>
|
|
23
|
-
<body>
|
|
24
|
-
<div class="container">
|
|
25
|
-
<h1>Analytics Dashboard</h1>
|
|
26
|
-
<div id="loading" class="loading" aria-busy="true">
|
|
27
|
-
<span class="spinner"></span>Loading dashboard data...
|
|
28
|
-
</div>
|
|
29
|
-
<div id="content">
|
|
30
|
-
<div class="stats">
|
|
31
|
-
<div class="stat">
|
|
32
|
-
<div class="stat-value">1,247</div>
|
|
33
|
-
<div class="stat-label">Users</div>
|
|
34
|
-
</div>
|
|
35
|
-
<div class="stat">
|
|
36
|
-
<div class="stat-value">89%</div>
|
|
37
|
-
<div class="stat-label">Uptime</div>
|
|
38
|
-
</div>
|
|
39
|
-
<div class="stat">
|
|
40
|
-
<div class="stat-value">3.2s</div>
|
|
41
|
-
<div class="stat-label">Avg Response</div>
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
44
|
-
<div class="card">
|
|
45
|
-
<h3>Recent Activity</h3>
|
|
46
|
-
<p>12 deployments this week. Last deploy: 2 hours ago.</p>
|
|
47
|
-
</div>
|
|
48
|
-
<div class="card">
|
|
49
|
-
<h3>Alerts</h3>
|
|
50
|
-
<p>No active alerts. All systems operational.</p>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
|
-
<script>
|
|
55
|
-
// Simulate async data loading — 2 second delay
|
|
56
|
-
setTimeout(function() {
|
|
57
|
-
document.getElementById('loading').style.display = 'none';
|
|
58
|
-
document.getElementById('loading').setAttribute('aria-busy', 'false');
|
|
59
|
-
document.getElementById('content').style.display = 'block';
|
|
60
|
-
document.title = 'Analytics Dashboard — Loaded';
|
|
61
|
-
}, 2000);
|
|
62
|
-
</script>
|
|
63
|
-
</body>
|
|
64
|
-
</html>
|
package/demo/todo-app.html
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<title>Todo App</title>
|
|
5
|
-
<style>
|
|
6
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
-
body { font-family: -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
8
|
-
.container { width: 400px; }
|
|
9
|
-
h1 { font-size: 1.8rem; margin-bottom: 1.2rem; }
|
|
10
|
-
.add-row { display: flex; gap: 0.5rem; margin-bottom: 1rem; }
|
|
11
|
-
input { flex: 1; padding: 0.7rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #e2e8f0; font-size: 1rem; }
|
|
12
|
-
input::placeholder { color: #64748b; }
|
|
13
|
-
button { padding: 0.7rem 1.2rem; border-radius: 8px; border: none; background: #3b82f6; color: white; font-size: 1rem; font-weight: 600; cursor: pointer; }
|
|
14
|
-
button:hover { background: #2563eb; }
|
|
15
|
-
ul { list-style: none; }
|
|
16
|
-
li { display: flex; justify-content: space-between; align-items: center; padding: 0.6rem 0; border-bottom: 1px solid #1e293b; }
|
|
17
|
-
.delete-btn { background: #ef4444; padding: 0.3rem 0.6rem; font-size: 0.85rem; }
|
|
18
|
-
.count { color: #94a3b8; font-size: 0.9rem; margin-top: 0.8rem; }
|
|
19
|
-
</style>
|
|
20
|
-
</head>
|
|
21
|
-
<body>
|
|
22
|
-
<div class="container">
|
|
23
|
-
<h1>Todo List</h1>
|
|
24
|
-
<div class="add-row">
|
|
25
|
-
<input id="todo-input" placeholder="Add a task..." aria-label="New task" />
|
|
26
|
-
<button type="button" onclick="addTodo()">Add</button>
|
|
27
|
-
</div>
|
|
28
|
-
<ul id="todo-list"></ul>
|
|
29
|
-
<p id="count" class="count"></p>
|
|
30
|
-
</div>
|
|
31
|
-
<script>
|
|
32
|
-
function updateCount() {
|
|
33
|
-
const items = document.querySelectorAll('#todo-list li');
|
|
34
|
-
document.getElementById('count').textContent = items.length + ' item' + (items.length !== 1 ? 's' : '');
|
|
35
|
-
}
|
|
36
|
-
function addTodo() {
|
|
37
|
-
const input = document.getElementById('todo-input');
|
|
38
|
-
const text = input.value.trim();
|
|
39
|
-
if (!text) return;
|
|
40
|
-
const li = document.createElement('li');
|
|
41
|
-
li.innerHTML = '<span>' + text + '</span><button class="delete-btn" onclick="this.parentElement.remove(); updateCount()">Delete</button>';
|
|
42
|
-
document.getElementById('todo-list').appendChild(li);
|
|
43
|
-
input.value = '';
|
|
44
|
-
updateCount();
|
|
45
|
-
}
|
|
46
|
-
document.getElementById('todo-input').addEventListener('keydown', function(e) {
|
|
47
|
-
if (e.key === 'Enter') addTodo();
|
|
48
|
-
});
|
|
49
|
-
</script>
|
|
50
|
-
</body>
|
|
51
|
-
</html>
|