This repository has been archived on 2026-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
2025-11-10 15:08:25 +01:00

305 lines
8.5 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>nymea EV Dash</title>
<style>
:root {
--primary-color: #0050a0;
--secondary-color: #00a0e0;
--accent-color: #f4b400;
--surface-color: #ffffff;
--background-color: #f5f7fa;
--text-color: #1f2d3d;
--muted-text-color: #566b84;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: "Segoe UI", Roboto, sans-serif;
background: var(--background-color);
color: var(--text-color);
min-height: 100vh;
display: flex;
flex-direction: column;
}
header {
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: #ffffff;
padding: 2.5rem 1.5rem 2rem;
text-align: center;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}
header h1 {
margin: 0 0 0.5rem;
font-weight: 600;
letter-spacing: 0.02em;
}
header p {
margin: 0;
}
main {
flex: 1;
width: min(960px, 92vw);
margin: 2rem auto 3rem;
display: grid;
gap: 1.5rem;
}
.card {
background: var(--surface-color);
border-radius: 14px;
padding: 1.5rem;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.06);
}
.card h2 {
margin-top: 0;
font-size: 1.25rem;
}
.status-indicator {
display: inline-flex;
align-items: center;
gap: 0.75rem;
font-weight: 600;
}
.status-dot {
width: 14px;
height: 14px;
border-radius: 50%;
background-color: #d3dce6;
transition: background-color 0.3s ease;
}
.status-dot.connecting {
background-color: #f4b400;
}
.status-dot.connected {
background-color: #2ecc71;
}
.status-dot.authenticating {
background-color: #8e44ad;
}
.status-dot.error {
background-color: #e74c3c;
}
.grid-two-column {
display: grid;
gap: 1.5rem;
}
@media (min-width: 900px) {
.grid-two-column {
grid-template-columns: 1fr 1fr;
}
}
pre {
margin: 0;
background: #f8fafc;
border-radius: 10px;
padding: 1rem;
overflow-x: auto;
font-size: 0.95rem;
}
code {
font-family: "Fira Code", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
}
footer {
text-align: center;
padding: 1.25rem 1rem;
background: #ffffff;
border-top: 1px solid #d3dce6;
font-size: 0.9rem;
color: var(--muted-text-color);
}
/* Login overlay */
.overlay {
position: fixed;
inset: 0;
background: rgba(31, 45, 61, 0.65);
display: flex;
align-items: center;
justify-content: center;
padding: 1.5rem;
transition: opacity 0.3s ease;
}
.overlay.hidden {
visibility: hidden;
opacity: 0;
pointer-events: none;
}
.login-panel {
background: var(--surface-color);
width: min(420px, 100%);
border-radius: 16px;
padding: 2rem;
box-shadow: 0 24px 48px rgba(0, 0, 0, 0.18);
}
.login-panel h2 {
margin: 0 0 0.5rem;
font-size: 1.5rem;
}
.login-panel p {
margin: 0;
color: var(--muted-text-color);
}
form {
margin-top: 1.5rem;
display: grid;
gap: 1rem;
}
label {
display: grid;
gap: 0.35rem;
font-weight: 600;
}
input[type="text"],
input[type="password"] {
border-radius: 10px;
border: 1px solid #d3dce6;
padding: 0.75rem 1rem;
font-size: 1rem;
background: #f9fbfd;
color: var(--text-color);
}
input[type="text"]:focus,
input[type="password"]:focus {
outline: none;
border-color: var(--secondary-color);
box-shadow: 0 0 0 3px rgba(0, 160, 224, 0.2);
}
button {
border: none;
border-radius: 999px;
padding: 0.75rem 1.5rem;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
justify-self: start;
transition: transform 0.12s ease, box-shadow 0.12s ease;
}
button.primary {
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: #ffffff;
box-shadow: 0 10px 24px rgba(0, 80, 160, 0.26);
}
button.primary:disabled {
opacity: 0.65;
cursor: progress;
box-shadow: none;
}
button.primary:not(:disabled):hover {
transform: translateY(-1px);
box-shadow: 0 16px 32px rgba(0, 80, 160, 0.28);
}
.error-message {
background: rgba(231, 76, 60, 0.08);
border: 1px solid rgba(231, 76, 60, 0.18);
color: #c0392b;
border-radius: 10px;
padding: 0.75rem 1rem;
}
.helper-text {
font-size: 0.9rem;
color: var(--muted-text-color);
}
.hidden {
display: none !important;
}
</style>
</head>
<body>
<header>
<h1>nymea EV Dash</h1>
<p class="status-indicator">
<span id="statusDot" class="status-dot connecting" aria-hidden="true"></span>
<span id="connectionStatus">Awaiting login…</span>
</p>
</header>
<main>
<section class="card" aria-live="polite">
<h2>Connection</h2>
<p id="sessionSummary" class="helper-text">Please sign in to start the WebSocket session.</p>
</section>
<section class="card">
<h2>API Contract</h2>
<p class="helper-text">All requests follow the structure below. Use <code>app.sendAction(action, payload)</code> from the browser console after authentication.</p>
<div class="grid-two-column">
<div>
<h3>Request template</h3>
<pre id="requestTemplate"></pre>
</div>
<div>
<h3>Responses</h3>
<pre id="responseTemplate"></pre>
</div>
</div>
</section>
<section class="card" aria-live="polite">
<h2>Last message</h2>
<pre id="incomingMessage">No messages received yet.</pre>
</section>
</main>
<div id="loginOverlay" class="overlay" role="dialog" aria-modal="true" aria-labelledby="loginTitle">
<div class="login-panel">
<h2 id="loginTitle">Sign in</h2>
<p>Authenticate with your nymea credentials to obtain a session token for the dashboard.</p>
<div id="loginError" class="error-message hidden" role="alert"></div>
<form id="loginForm" autocomplete="on">
<label for="username">Username
<input type="text" id="username" name="username" autocomplete="username" required placeholder="nymea user">
</label>
<label for="password">Password
<input type="password" id="password" name="password" autocomplete="current-password" required placeholder="••••••••">
</label>
<p class="helper-text">Tokens remain valid for one hour. Reloading the dashboard reuses an active session automatically.</p>
<button type="submit" id="loginButton" class="primary">Sign in</button>
</form>
</div>
</div>
<footer>
<span id="appVersion">nymea EV Dash</span> · &copy; 20132025 nymea GmbH. All rights reserved.
</footer>
<script src="app.js"></script>
</body>
</html>