feat: replace Watchtower theme with OIDC professional design

- Remove Watchtower theme CSS files (tokens_watchtower.css, theme_watchtower.css)
- Add OIDC styles.css (professional IT asset management design)
- Add dark mode toggle button (moon/sun icon)
- Remove custom CSS in favor of OIDC styles.css
- Add dark mode persistence with localStorage
- Remove bg-noise div (Watchtower-specific)
- Wrap content in .container div for OIDC layout

Benefits:
- Professional gradient header
- Light/Dark mode toggle
- Better color palette for readability
- Consistent with homelab-service-oidc design

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-30 12:32:57 +01:00
parent 73ade70f16
commit 49adf77808
5 changed files with 754 additions and 294 deletions

View File

@ -4,99 +4,21 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Safe Kiddo Control</title>
<link rel="stylesheet" href="/static/tokens_watchtower.css" />
<link rel="stylesheet" href="/static/theme_watchtower.css" />
<link rel="stylesheet" href="/static/styles.css" />
<script src="https://unpkg.com/lucide@latest"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { max-width: 1400px; margin: auto; padding: 2rem; font-family: var(--font-ui); }
/* Header */
header { background: var(--color-surface); padding: 2rem; border-radius: var(--radius-md); margin-bottom: 2rem; border: 1px solid var(--color-border); border-left: 4px solid var(--color-accent); display: flex; justify-content: space-between; align-items: center; }
header h1 { color: var(--color-accent); margin: 0; font-size: 1.75rem; text-transform: uppercase; letter-spacing: 0.05em; display: flex; align-items: center; gap: 0.75rem; }
header .user-info { color: var(--color-text-muted); font-size: 0.875rem; }
/* Metrics Dashboard */
.metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; margin-bottom: 2rem; }
.metric-card { background: var(--color-surface); padding: 1.5rem; border-radius: var(--radius-md); border: 1px solid var(--color-border); border-left: 3px solid var(--color-accent); transition: all 0.2s; }
.metric-card:hover { transform: translateY(-2px); box-shadow: 0 0 20px rgba(0, 224, 143, 0.15); }
.metric-card .label { color: var(--color-text-muted); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 0.5rem; display: flex; align-items: center; gap: 0.5rem; }
.metric-card .value { color: var(--color-accent); font-size: 2rem; font-weight: 700; }
.metric-card.warning { border-left-color: var(--color-warning); }
.metric-card.warning .value { color: var(--color-warning); }
.metric-card.error { border-left-color: var(--color-error); }
.metric-card.error .value { color: var(--color-error); }
/* Sections */
section { background: var(--color-surface); padding: 1.5rem; border-radius: var(--radius-md); margin-bottom: 1.5rem; border: 1px solid var(--color-border); }
section h3 { color: var(--color-accent); text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.875rem; margin-bottom: 1rem; border-bottom: 1px solid var(--color-border); padding-bottom: 0.5rem; display: flex; align-items: center; gap: 0.5rem; }
/* User Table */
.user-table { width: 100%; border-collapse: separate; border-spacing: 0 0.5rem; }
.user-table thead th { text-align: left; color: var(--color-text-muted); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.1em; padding: 0.5rem 1rem; border-bottom: 1px solid var(--color-border); }
.user-table tbody tr { background: rgba(10, 14, 20, 0.4); transition: all 0.2s; }
.user-table tbody tr:hover { background: rgba(10, 14, 20, 0.6); transform: scale(1.01); }
.user-table tbody td { padding: 1rem; border-top: 1px solid rgba(255, 255, 255, 0.05); }
.user-table tbody td:first-child { border-top-left-radius: var(--radius-sm); border-bottom-left-radius: var(--radius-sm); }
.user-table tbody td:last-child { border-top-right-radius: var(--radius-sm); border-bottom-right-radius: var(--radius-sm); }
/* Status Badges */
.badge { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.35rem 0.75rem; border-radius: 999px; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; }
.badge.success { background: rgba(0, 224, 143, 0.15); color: var(--color-success); border: 1px solid var(--color-success); }
.badge.warning { background: rgba(255, 180, 84, 0.15); color: var(--color-warning); border: 1px solid var(--color-warning); }
.badge.error { background: rgba(255, 94, 94, 0.15); color: var(--color-error); border: 1px solid var(--color-error); }
.badge.neutral { background: rgba(255, 255, 255, 0.05); color: var(--color-text-muted); border: 1px solid rgba(255, 255, 255, 0.1); }
/* Buttons */
button { padding: 0.75rem 1.5rem; background: var(--color-accent); color: #081015; border: none; border-radius: 999px; cursor: pointer; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; transition: all 0.2s; display: inline-flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; }
button:hover:not(:disabled) { box-shadow: 0 0 20px var(--wt-glow); transform: translateY(-2px); }
button:disabled { opacity: 0.5; cursor: not-allowed; }
button.secondary { background: transparent; border: 1px solid var(--color-accent); color: var(--color-accent); }
button.secondary:hover:not(:disabled) { background: rgba(0, 224, 143, 0.1); }
button.danger { background: var(--color-error); color: #1b0d0d; }
button.small { padding: 0.5rem 1rem; font-size: 0.75rem; }
/* Forms */
.form-group { margin-bottom: 1rem; }
label { display: block; margin-bottom: 0.5rem; color: var(--color-text-muted); font-size: 0.875rem; text-transform: uppercase; letter-spacing: 0.05em; }
input, select, textarea { background: rgba(10, 14, 20, 0.6); border: 1px solid rgba(255, 255, 255, 0.15); color: var(--color-text); padding: 0.75rem; border-radius: var(--radius-sm); width: 100%; font-family: inherit; transition: all 0.2s; }
input:focus, select:focus, textarea:focus { border-color: var(--color-accent); box-shadow: 0 0 15px var(--wt-glow); outline: none; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; }
/* Toast Notifications */
.toast-container { position: fixed; top: 2rem; right: 2rem; z-index: 1000; display: flex; flex-direction: column; gap: 1rem; max-width: 400px; }
.toast { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: 1rem 1.5rem; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); animation: slideIn 0.3s ease; display: flex; align-items: center; gap: 1rem; }
.toast.success { border-left: 4px solid var(--color-success); }
.toast.error { border-left: 4px solid var(--color-error); }
.toast.warning { border-left: 4px solid var(--color-warning); }
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
/* Loading Spinner */
.spinner { border: 3px solid rgba(255, 255, 255, 0.1); border-top-color: var(--color-accent); border-radius: 50%; width: 20px; height: 20px; animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* Modal */
.modal { display: none; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.8); backdrop-filter: blur(4px); align-items: center; justify-content: center; z-index: 999; }
.modal.active { display: flex; }
.modal-content { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: 2rem; max-width: 500px; width: 90%; box-shadow: 0 20px 40px rgba(0, 0, 0, 0.7); }
.modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; }
.modal-header h3 { color: var(--color-accent); margin: 0; }
.modal-actions { display: flex; gap: 1rem; justify-content: flex-end; margin-top: 1.5rem; }
/* Details/Accordion */
details { margin-top: 1rem; background: rgba(10, 14, 20, 0.3); padding: 1rem; border-radius: var(--radius-sm); border: 1px solid rgba(255, 255, 255, 0.05); }
summary { cursor: pointer; color: var(--color-accent); font-weight: 600; user-select: none; display: flex; align-items: center; gap: 0.5rem; }
/* Utility */
.hidden { display: none; }
.text-muted { color: var(--color-text-muted); }
.text-center { text-align: center; }
.mt-1 { margin-top: 1rem; }
.mb-1 { margin-bottom: 1rem; }
</style>
</head>
<body>
<div class="bg-noise"></div>
<!-- Dark Mode Toggle -->
<button class="theme-toggle" onclick="toggleTheme()" aria-label="Toggle dark mode">
<svg class="moon-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z" />
</svg>
<svg class="sun-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z" />
</svg>
</button>
<div class="container">
<!-- Header -->
<header>
@ -678,6 +600,18 @@
// Initialize
checkSession();
checkOidcStatus();
// Dark Mode Toggle
function toggleTheme() {
document.body.classList.toggle('dark-mode');
localStorage.setItem('darkMode', document.body.classList.contains('dark-mode'));
}
// Load dark mode preference
if (localStorage.getItem('darkMode') === 'true') {
document.body.classList.add('dark-mode');
}
</script>
</div>
</body>
</html>