mirror of
https://github.com/myronblair/jarvis
synced 2026-06-30 17:50:23 -05:00
128 lines
7.3 KiB
HTML
128 lines
7.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8"/>
|
|
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
|
<title>JARVIS — Authentication</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
|
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;700;900&family=Share+Tech+Mono&display=swap" rel="stylesheet"/>
|
|
<style>
|
|
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
|
:root{
|
|
--bg:#000810;--cyan:#00d4ff;--cyan2:#00a8cc;--orange:#ff6600;--red:#ff2244;
|
|
--dim:rgba(0,212,255,0.4);--text:#c8e6ff;--text-dim:rgba(200,230,255,0.5);
|
|
--panel-border:rgba(0,212,255,0.2);--grid:rgba(0,180,255,0.07);--r:8px;
|
|
}
|
|
html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);color:var(--text);font-family:'Share Tech Mono',monospace}
|
|
body::before{content:'';position:fixed;inset:0;background-image:linear-gradient(var(--grid) 1px,transparent 1px),linear-gradient(90deg,var(--grid) 1px,transparent 1px);background-size:40px 40px;z-index:0;pointer-events:none}
|
|
body::after{content:'';position:fixed;inset:0;background:radial-gradient(ellipse at 50% 50%,rgba(0,80,160,0.08) 0%,transparent 70%);z-index:0;pointer-events:none}
|
|
.scanlines{position:fixed;inset:0;z-index:1;pointer-events:none;background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,0,0,0.03) 2px,rgba(0,0,0,0.03) 4px);animation:scanMove 8s linear infinite}
|
|
@keyframes scanMove{0%{background-position:0 0}100%{background-position:0 100%}}
|
|
#screen{position:fixed;inset:0;z-index:10;display:flex;align-items:center;justify-content:center;flex-direction:column;background:var(--bg)}
|
|
.reactor{width:160px;height:160px;position:relative;margin-bottom:40px}
|
|
.reactor .ring{position:absolute;border-radius:50%;border:2px solid var(--cyan);top:50%;left:50%;transform:translate(-50%,-50%);box-shadow:0 0 8px var(--cyan),inset 0 0 8px rgba(0,212,255,0.1);animation:spinRing var(--spd,4s) linear infinite}
|
|
.reactor .r1{width:160px;height:160px;--spd:8s;border-color:rgba(0,212,255,0.3)}
|
|
.reactor .r2{width:130px;height:130px;--spd:6s;animation-direction:reverse}
|
|
.reactor .r3{width:100px;height:100px;--spd:4s;border-color:var(--orange);box-shadow:0 0 12px var(--orange)}
|
|
.reactor .r4{width:70px;height:70px;--spd:3s;animation-direction:reverse}
|
|
.reactor .core{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:40px;height:40px;border-radius:50%;background:radial-gradient(circle,#fff 0%,var(--cyan) 40%,var(--cyan2) 70%,transparent 100%);box-shadow:0 0 20px var(--cyan),0 0 40px var(--cyan),0 0 80px rgba(0,212,255,0.3);animation:corePulse 2s ease-in-out infinite}
|
|
.reactor .ticks{position:absolute;inset:0;border-radius:50%}
|
|
.reactor .ticks::before,.reactor .ticks::after{content:'';position:absolute;background:var(--cyan);opacity:0.5}
|
|
.reactor .ticks::before{left:50%;top:0;width:1px;height:12px;transform:translateX(-50%)}
|
|
.reactor .ticks::after{left:0;top:50%;height:1px;width:12px;transform:translateY(-50%)}
|
|
@keyframes spinRing{from{transform:translate(-50%,-50%) rotate(0deg)}to{transform:translate(-50%,-50%) rotate(360deg)}}
|
|
@keyframes corePulse{0%,100%{opacity:0.8;transform:translate(-50%,-50%) scale(1)}50%{opacity:1;transform:translate(-50%,-50%) scale(1.1)}}
|
|
h1{font-family:'Orbitron',monospace;font-size:2.5rem;font-weight:900;letter-spacing:8px;color:var(--cyan);text-shadow:0 0 20px var(--cyan),0 0 40px rgba(0,212,255,0.4);margin-bottom:8px}
|
|
p.sub{color:var(--text-dim);font-size:0.85rem;letter-spacing:4px;text-transform:uppercase;margin-bottom:40px}
|
|
.form{display:flex;flex-direction:column;gap:14px;width:320px}
|
|
.form input{background:rgba(0,212,255,0.05);border:1px solid var(--panel-border);border-radius:var(--r);padding:12px 16px;color:var(--cyan);font-family:'Share Tech Mono',monospace;font-size:0.95rem;outline:none;transition:border-color .2s,box-shadow .2s;letter-spacing:1px;width:100%}
|
|
.form input:focus{border-color:var(--cyan);box-shadow:0 0 12px rgba(0,212,255,0.2)}
|
|
.form input::placeholder{color:var(--dim);letter-spacing:1px}
|
|
.form button{background:linear-gradient(135deg,rgba(0,212,255,0.15),rgba(0,212,255,0.05));border:1px solid var(--cyan);border-radius:var(--r);padding:14px;color:var(--cyan);font-family:'Orbitron',monospace;font-size:0.8rem;font-weight:700;letter-spacing:3px;text-transform:uppercase;cursor:pointer;transition:all .2s;box-shadow:0 0 12px rgba(0,212,255,0.1)}
|
|
.form button:hover:not(:disabled){background:rgba(0,212,255,0.2);box-shadow:0 0 20px rgba(0,212,255,0.3)}
|
|
.form button:disabled{opacity:0.5;cursor:default}
|
|
#loginError{color:var(--red);font-size:0.85rem;text-align:center;letter-spacing:1px;min-height:20px}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="scanlines"></div>
|
|
<div id="screen">
|
|
<div class="reactor">
|
|
<div class="ring r1"></div>
|
|
<div class="ring r2"></div>
|
|
<div class="ring r3"></div>
|
|
<div class="ring r4"></div>
|
|
<div class="core"></div>
|
|
<div class="ticks"></div>
|
|
</div>
|
|
<h1>JARVIS</h1>
|
|
<p class="sub">Just A Rather Very Intelligent System</p>
|
|
<div class="form">
|
|
<input type="text" id="lu" placeholder="IDENTIFICATION" autocomplete="username" value="myron"/>
|
|
<input type="password" id="lp" placeholder="ACCESS CODE" autocomplete="current-password"/>
|
|
<button type="button" id="loginBtn">INITIALIZE SYSTEM</button>
|
|
<div id="loginError"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Script is AFTER the elements so DOM is ready when it runs.
|
|
data-cfasync="false" tells Rocket Loader not to defer this block.
|
|
addEventListener is used (not onclick=) so Rocket Loader cannot inject guards. -->
|
|
<script data-cfasync="false">
|
|
(function() {
|
|
// Redirect if already authenticated
|
|
if (sessionStorage.getItem('jarvis_token')) {
|
|
window.location.replace('/');
|
|
return;
|
|
}
|
|
|
|
var btn = document.getElementById('loginBtn');
|
|
var luEl = document.getElementById('lu');
|
|
var lpEl = document.getElementById('lp');
|
|
var errEl = document.getElementById('loginError');
|
|
|
|
function doLogin() {
|
|
var user = luEl.value.trim();
|
|
var pass = lpEl.value;
|
|
if (!user || !pass) { errEl.textContent = 'ENTER CREDENTIALS'; return; }
|
|
btn.disabled = true;
|
|
btn.textContent = 'INITIALIZING...';
|
|
errEl.textContent = '';
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('POST', '/api/auth', true);
|
|
xhr.setRequestHeader('Content-Type', 'application/json');
|
|
xhr.onload = function() {
|
|
try {
|
|
var data = JSON.parse(xhr.responseText);
|
|
if (data.success) {
|
|
sessionStorage.setItem('jarvis_token', data.token);
|
|
sessionStorage.setItem('jarvis_user', data.display_name);
|
|
window.location.replace('/');
|
|
} else {
|
|
errEl.textContent = 'ACCESS DENIED';
|
|
btn.disabled = false;
|
|
btn.textContent = 'INITIALIZE SYSTEM';
|
|
}
|
|
} catch(e) {
|
|
errEl.textContent = 'SERVER ERROR';
|
|
btn.disabled = false;
|
|
btn.textContent = 'INITIALIZE SYSTEM';
|
|
}
|
|
};
|
|
xhr.onerror = function() {
|
|
errEl.textContent = 'CONNECTION FAILED';
|
|
btn.disabled = false;
|
|
btn.textContent = 'INITIALIZE SYSTEM';
|
|
};
|
|
xhr.send(JSON.stringify({ username: user, password: pass }));
|
|
}
|
|
|
|
btn.addEventListener('click', doLogin);
|
|
lpEl.addEventListener('keydown', function(e) { if (e.key === 'Enter') doLogin(); });
|
|
luEl.addEventListener('keydown', function(e) { if (e.key === 'Enter') lpEl.focus(); });
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|