188 lines
6.9 KiB
HTML
188 lines
6.9 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<title>Git — Samantha Friis</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=Syne:wght@400;700;800&display=swap" rel="stylesheet"/>
|
|
<link rel="stylesheet" href="styles.css"/>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
|
|
<header>
|
|
<a href="/" class="back">← back</a>
|
|
<p class="tag">// git</p>
|
|
<h1>Code &<br/><span>Repositories</span></h1>
|
|
<p class="header-sub">Personal projects · Private & public</p>
|
|
</header>
|
|
|
|
<main class="two-col">
|
|
|
|
<!-- ── LEFT: Login / Private Dashboard ── -->
|
|
<div>
|
|
<p class="section-label">// private access</p>
|
|
|
|
<div class="login-panel" id="login-panel">
|
|
<h2>Sign In</h2>
|
|
<p class="desc">Access to private repositories and personal workspace. Requires credentials and 2FA.</p>
|
|
|
|
<div class="form-group">
|
|
<label for="username">Username</label>
|
|
<input type="text" id="username" placeholder="samantha" autocomplete="username" />
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="password">Password</label>
|
|
<input type="password" id="password" placeholder="••••••••••••" autocomplete="current-password" />
|
|
</div>
|
|
|
|
<div class="twofa-group" id="twofa-group">
|
|
<label for="twofa">Authenticator Code</label>
|
|
<input type="text" id="twofa" placeholder="000 000" maxlength="7" autocomplete="one-time-code" />
|
|
<p class="twofa-hint">Enter the 6-digit code from your authenticator app.</p>
|
|
</div>
|
|
|
|
<button class="btn-login" id="login-btn" onclick="handleLogin()">Continue →</button>
|
|
<p class="login-error" id="login-error">Invalid credentials. Please try again.</p>
|
|
</div>
|
|
|
|
<!-- Private dashboard (shown after login) -->
|
|
<div id="private-dashboard">
|
|
<div class="repo-list">
|
|
<a href="#" class="repo-item">
|
|
<div>
|
|
<p class="repo-name">samantha-site</p>
|
|
<p class="repo-desc">Personal website and Go backend server</p>
|
|
</div>
|
|
<span class="repo-badge private">private</span>
|
|
</a>
|
|
<a href="#" class="repo-item">
|
|
<div>
|
|
<p class="repo-name">equity-tools</p>
|
|
<p class="repo-desc">Python scripts for SEC filing analysis and financial modeling</p>
|
|
</div>
|
|
<span class="repo-badge active">active</span>
|
|
</a>
|
|
<a href="#" class="repo-item">
|
|
<div>
|
|
<p class="repo-name">infra-config</p>
|
|
<p class="repo-desc">Dotfiles, server configs, and deployment scripts</p>
|
|
</div>
|
|
<span class="repo-badge private">private</span>
|
|
</a>
|
|
<a href="#" class="repo-item">
|
|
<div>
|
|
<p class="repo-name">typst-templates</p>
|
|
<p class="repo-desc">Custom Typst document templates for reports and analysis</p>
|
|
</div>
|
|
<span class="repo-badge active">active</span>
|
|
</a>
|
|
</div>
|
|
<button class="logout-btn" onclick="handleLogout()">← sign out</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── RIGHT: Public section ── -->
|
|
<div>
|
|
<div class="repo-list">
|
|
<a href="/gitpage/TicTacToe" class="repo-item">
|
|
<div>
|
|
<p class="repo-name">TicTacToe</p>
|
|
<p class="repo-desc">Python learning tic tac toe game in terminal</p>
|
|
</div>
|
|
<span class="repo-badge private">private</span>
|
|
</a>
|
|
<a href="/gitpage/infra-config" class="repo-item">
|
|
<div>
|
|
<p class="repo-name">infra-config</p>
|
|
<p class="repo-desc">Dotfiles, server configs, and deployment scripts</p>
|
|
</div>
|
|
<span class="repo-badge private">private</span>
|
|
</a>
|
|
<a href="/gitpage/typst-templates" class="repo-item">
|
|
<div>
|
|
<p class="repo-name">typst-templates</p>
|
|
<p class="repo-desc">Custom Typst document templates for reports and analysis</p>
|
|
</div>
|
|
<span class="repo-badge active">active</span>
|
|
</a>
|
|
</div>
|
|
<button class="logout-btn" onclick="handleLogout()">← sign out</button>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</main>
|
|
|
|
<footer>
|
|
<a href="mailto:contact@samantha42.xyz">contact@samantha42.xyz</a>
|
|
<p class="footer-copy">© 2026 — All rights reserved</p>
|
|
</footer>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
let step = 1;
|
|
|
|
function handleLogin() {
|
|
const username = document.getElementById('username').value.trim();
|
|
const password = document.getElementById('password').value.trim();
|
|
const twofa = document.getElementById('twofa').value.trim();
|
|
const tfGroup = document.getElementById('twofa-group');
|
|
|
|
document.getElementById('login-error').classList.remove('visible');
|
|
|
|
if (step === 1) {
|
|
if (!username || !password) { showError('Please enter your username and password.'); return; }
|
|
step = 2;
|
|
tfGroup.classList.add('visible');
|
|
document.getElementById('login-btn').textContent = 'Verify →';
|
|
document.getElementById('twofa').focus();
|
|
} else {
|
|
if (!twofa || twofa.replace(/\s/g, '').length < 6) { showError('Enter the 6-digit code from your authenticator app.'); return; }
|
|
if (twofa.replace(/\s/g, '').match(/^\d{6}$/)) {
|
|
showDashboard();
|
|
} else {
|
|
showError('Invalid authenticator code.');
|
|
}
|
|
}
|
|
}
|
|
|
|
function showError(msg) {
|
|
const error = document.getElementById('login-error');
|
|
const panel = document.getElementById('login-panel');
|
|
error.textContent = msg;
|
|
error.classList.add('visible');
|
|
panel.classList.add('shake');
|
|
setTimeout(() => panel.classList.remove('shake'), 500);
|
|
}
|
|
|
|
function showDashboard() {
|
|
document.getElementById('login-panel').style.display = 'none';
|
|
document.getElementById('private-dashboard').classList.add('visible');
|
|
}
|
|
|
|
function handleLogout() {
|
|
step = 1;
|
|
document.getElementById('login-panel').style.display = '';
|
|
document.getElementById('private-dashboard').classList.remove('visible');
|
|
document.getElementById('username').value = '';
|
|
document.getElementById('password').value = '';
|
|
document.getElementById('twofa').value = '';
|
|
document.getElementById('twofa-group').classList.remove('visible');
|
|
document.getElementById('login-btn').textContent = 'Continue →';
|
|
document.getElementById('login-error').classList.remove('visible');
|
|
}
|
|
|
|
document.addEventListener('keydown', (e) => { if (e.key === 'Enter') handleLogin(); });
|
|
|
|
document.getElementById('twofa').addEventListener('input', (e) => {
|
|
let val = e.target.value.replace(/\D/g, '').slice(0, 6);
|
|
if (val.length > 3) val = val.slice(0, 3) + ' ' + val.slice(3);
|
|
e.target.value = val;
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html> |