mirror of
https://github.com/sol1/rustguac.git
synced 2026-09-10 09:35:45 +00:00
67101e27ce
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
224 lines
9.1 KiB
HTML
224 lines
9.1 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>rustguac - Docs</title>
|
|
<style>
|
|
:root { --primary: #e94560; --primary-hover: #c73652; --accent: #5bc0be; --accent-hover: #4aa3a1; --bg: #1a1a2e; --surface: #16213e; --input: #0f3460; --text: #e0e0e0; --text-muted: #aaa; --border: #333; }
|
|
* { box-sizing: border-box; }
|
|
body { font-family: monospace; background: var(--bg); color: var(--text); padding: 2em; font-size: 18px; margin: 0; }
|
|
h1 { color: var(--primary); }
|
|
nav { margin-bottom: 1.5em; font-size: 0.95em; }
|
|
nav a { margin-right: 1.5em; text-decoration: none; color: var(--accent); }
|
|
nav a:hover { text-decoration: underline; }
|
|
nav .active { color: var(--primary); font-weight: bold; }
|
|
nav .logout { color: #888; float: right; cursor: pointer; }
|
|
nav .logout:hover { color: var(--primary); }
|
|
|
|
/* Layout */
|
|
.docs-layout { display: flex; min-height: calc(100vh - 140px); border-top: 1px solid var(--border); margin-top: 1em; }
|
|
|
|
/* Sidebar */
|
|
.sidebar {
|
|
width: 220px;
|
|
min-width: 220px;
|
|
border-right: 1px solid var(--border);
|
|
padding: 1em 0;
|
|
overflow-y: auto;
|
|
}
|
|
.sidebar a {
|
|
display: block;
|
|
padding: 0.5em 1.2em;
|
|
color: var(--text-muted);
|
|
text-decoration: none;
|
|
font-size: 0.9em;
|
|
border-left: 3px solid transparent;
|
|
}
|
|
.sidebar a:hover { color: var(--text); background: var(--surface); }
|
|
.sidebar a.active {
|
|
color: var(--primary);
|
|
border-left-color: var(--primary);
|
|
background: var(--surface);
|
|
font-weight: bold;
|
|
}
|
|
|
|
/* Content area */
|
|
.content {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 2em 2.5em;
|
|
max-width: 900px;
|
|
}
|
|
.content h1 { color: var(--primary); font-size: 1.5em; margin-bottom: 0.8em; }
|
|
.content h2 { color: var(--primary); font-size: 1.15em; margin-top: 2em; margin-bottom: 0.5em; border-bottom: 1px solid var(--border); padding-bottom: 0.3em; }
|
|
.content h3 { color: var(--accent); font-size: 1em; margin-top: 1.5em; margin-bottom: 0.4em; }
|
|
.content h4 { color: var(--accent); font-size: 0.95em; margin-top: 1.2em; margin-bottom: 0.3em; }
|
|
.content p { margin: 0.6em 0; line-height: 1.6; }
|
|
.content ul, .content ol { margin: 0.5em 0 0.5em 1.5em; line-height: 1.6; }
|
|
.content li { margin: 0.2em 0; }
|
|
.content a { color: var(--accent); }
|
|
.content a:hover { text-decoration: underline; }
|
|
.content code {
|
|
background: var(--surface);
|
|
padding: 0.15em 0.4em;
|
|
border-radius: 3px;
|
|
font-size: 0.9em;
|
|
}
|
|
.content pre {
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
padding: 1em;
|
|
border-radius: 6px;
|
|
overflow-x: auto;
|
|
line-height: 1.5;
|
|
margin: 0.8em 0;
|
|
}
|
|
.content pre code {
|
|
background: none;
|
|
padding: 0;
|
|
border-radius: 0;
|
|
font-size: 0.85em;
|
|
}
|
|
.content table { border-collapse: collapse; width: 100%; margin: 0.8em 0; }
|
|
.content th, .content td { text-align: left; padding: 0.4em 0.8em; border-bottom: 1px solid var(--border); }
|
|
.content th { color: var(--text-muted); font-size: 0.85em; }
|
|
.content blockquote {
|
|
border-left: 3px solid var(--accent);
|
|
margin: 0.8em 0;
|
|
padding: 0.4em 1em;
|
|
color: var(--text-muted);
|
|
}
|
|
.content hr { border: none; border-top: 1px solid var(--border); margin: 2em 0; }
|
|
|
|
.loading { padding: 2em; color: var(--text-muted); }
|
|
|
|
@media (max-width: 700px) {
|
|
.sidebar { width: 160px; min-width: 160px; }
|
|
.content { padding: 1em; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<img id="site-logo" src="/logo.svg" style="max-height:40px;vertical-align:middle;margin-right:0.5em" alt=""><h1 style="display:inline;vertical-align:middle">rustguac</h1>
|
|
<nav>
|
|
<a href="/addressbook.html">Address Book</a>
|
|
<a href="/sessions.html" id="sessions-link">Sessions</a>
|
|
<a href="/recordings.html">Recordings</a>
|
|
<a href="/docs.html" class="active">Docs</a>
|
|
<a href="/admin.html" id="admin-link" style="display:none">Admin</a>
|
|
<span class="logout" id="logout-btn">logout</span>
|
|
</nav>
|
|
|
|
<div class="docs-layout">
|
|
<div class="sidebar" id="sidebar"></div>
|
|
<div class="content" id="content">
|
|
<div class="loading">Loading documentation...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
var docs = [];
|
|
var sidebar = document.getElementById('sidebar');
|
|
var content = document.getElementById('content');
|
|
|
|
function showSection(slug) {
|
|
var doc = docs.find(function(d) { return d.slug === slug; });
|
|
if (!doc && docs.length) doc = docs[0];
|
|
if (!doc) return;
|
|
|
|
content.innerHTML = doc.html;
|
|
|
|
// Update sidebar active state
|
|
var links = sidebar.querySelectorAll('a');
|
|
for (var i = 0; i < links.length; i++) {
|
|
links[i].classList.toggle('active', links[i].dataset.slug === doc.slug);
|
|
}
|
|
|
|
// Update hash without triggering hashchange
|
|
if (location.hash !== '#' + doc.slug) {
|
|
history.replaceState(null, '', '#' + doc.slug);
|
|
}
|
|
|
|
content.scrollTop = 0;
|
|
}
|
|
|
|
function getSlugFromHash() {
|
|
return location.hash ? location.hash.substring(1) : '';
|
|
}
|
|
|
|
// Load docs from API
|
|
fetch('/api/docs')
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
docs = data;
|
|
|
|
// Build sidebar
|
|
var html = '';
|
|
for (var i = 0; i < docs.length; i++) {
|
|
html += '<a href="#' + docs[i].slug + '" data-slug="' + docs[i].slug + '">' + docs[i].title + '</a>';
|
|
}
|
|
sidebar.innerHTML = html;
|
|
|
|
// Click handler for sidebar links
|
|
sidebar.addEventListener('click', function(e) {
|
|
var a = e.target.closest('a');
|
|
if (!a) return;
|
|
e.preventDefault();
|
|
var slug = a.dataset.slug;
|
|
history.pushState(null, '', '#' + slug);
|
|
showSection(slug);
|
|
});
|
|
|
|
// Show initial section from hash or first
|
|
showSection(getSlugFromHash() || docs[0].slug);
|
|
})
|
|
.catch(function() {
|
|
content.innerHTML = '<div class="loading">Failed to load documentation.</div>';
|
|
});
|
|
|
|
// Handle browser back/forward
|
|
window.addEventListener('popstate', function() {
|
|
showSection(getSlugFromHash());
|
|
});
|
|
|
|
// Theme and auth
|
|
function applyTheme(theme) {
|
|
if (!theme) return;
|
|
var props = {primary_color:'--primary',primary_hover:'--primary-hover',accent_color:'--accent',accent_hover:'--accent-hover',bg_color:'--bg',surface_color:'--surface',input_color:'--input',text_color:'--text',text_muted:'--text-muted',border_color:'--border'};
|
|
var r = document.documentElement.style;
|
|
for (var k in props) { if (theme[k]) r.setProperty(props[k], theme[k]); }
|
|
if (theme.logo_url) { var logo = document.getElementById('site-logo'); if (logo) { logo.src = theme.logo_url; logo.style.display = ''; } }
|
|
}
|
|
fetch('/api/auth/status').then(function(r){return r.json()}).then(function(d){
|
|
if(d.site_title){document.title=d.site_title+' - Docs';document.querySelector('h1').textContent=d.site_title;}
|
|
applyTheme(d.theme);
|
|
});
|
|
var apiKey = sessionStorage.getItem('rustguac_api_key');
|
|
var roleLevel = { admin: 4, poweruser: 3, operator: 2, viewer: 1 };
|
|
if (apiKey) {
|
|
document.getElementById('admin-link').style.display = '';
|
|
} else {
|
|
fetch('/api/me', { credentials: 'same-origin' })
|
|
.then(function(res) {
|
|
if (!res.ok) { window.location.href = '/'; return; }
|
|
return res.json();
|
|
})
|
|
.then(function(data) {
|
|
if (!data) return;
|
|
if (data.role === 'admin') document.getElementById('admin-link').style.display = '';
|
|
var level = roleLevel[data.role] || 0;
|
|
if (level < 3) {
|
|
document.getElementById('sessions-link').style.display = 'none';
|
|
}
|
|
})
|
|
.catch(function() { window.location.href = '/'; });
|
|
}
|
|
document.getElementById('logout-btn').addEventListener('click', function() {
|
|
sessionStorage.removeItem('rustguac_api_key');
|
|
fetch('/auth/logout', { credentials: 'same-origin' })
|
|
.finally(function() { window.location.href = '/'; });
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|