Files
M1730-Scale/web/templates/index.html
T
adebaumann 9e7223a1f5 Add web SVG generator, container, and Kubernetes manifests
- Flask app (web/) generates M1730 scale SVGs from a form; embeds
  GOST typ A font as base64 so output is self-contained
- Dockerfile builds the app into git.baumann.gr/adebaumann/m1730-generator
- k8s/ deploys as a ClusterIP service for NPM to proxy at
  works.adebaumann.com/M1730-generator/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-12 00:29:55 +02:00

214 lines
5.6 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">
<title>M1730 Scale Generator</title>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: system-ui, sans-serif;
background: #f4f4f5;
color: #222;
min-height: 100vh;
padding: 2rem 1.5rem;
}
.container { max-width: 840px; margin: 0 auto; }
h1 { font-size: 1.3rem; font-weight: 600; margin-bottom: 1.5rem; }
.card {
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem 2rem;
}
@media (max-width: 560px) { .grid { grid-template-columns: 1fr; } }
label {
display: flex;
flex-direction: column;
gap: 0.3rem;
font-size: 0.88rem;
font-weight: 600;
}
label small { font-weight: normal; color: #666; font-size: 0.8rem; }
input[type="text"],
input[type="number"] {
padding: 0.4rem 0.65rem;
border: 1px solid #bbb;
border-radius: 4px;
font-size: 0.95rem;
width: 100%;
transition: border-color 0.15s;
}
input:focus { outline: 2px solid #0070f3; outline-offset: 1px; border-color: transparent; }
.actions {
grid-column: 1 / -1;
display: flex;
gap: 0.75rem;
align-items: center;
margin-top: 0.5rem;
}
button {
padding: 0.45rem 1.2rem;
font-size: 0.9rem;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: 500;
}
#btn-generate { background: #0070f3; color: #fff; }
#btn-generate:hover { background: #005fd4; }
#btn-download { background: #e5e5e5; color: #222; }
#btn-download:hover:not(:disabled) { background: #d4d4d4; }
#btn-download:disabled { opacity: 0.45; cursor: not-allowed; }
#status { font-size: 0.82rem; color: #888; }
.preview-card {
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
padding: 1.5rem;
}
.preview-label {
font-size: 0.8rem;
font-weight: 600;
color: #888;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 1rem;
}
#preview svg { width: 100%; height: auto; display: block; }
#preview-placeholder { font-size: 0.9rem; color: #aaa; }
</style>
</head>
<body>
<div class="container">
<h1>M1730 Scale Generator</h1>
<div class="card">
<form id="form" class="grid">
<label>
Unit
<small>Large letter left of scale</small>
<input name="unit" type="text" value="%" required>
</label>
<label>
Range label
<small>Small text in the strip (e.g. 5mA, 10V)</small>
<input name="range_label" type="text" value="5mA" required>
</label>
<label>
Min value
<small>Value at the left (zero) end</small>
<input name="min" type="number" step="any" value="0" required>
</label>
<label>
Max value
<small>Value at the right end</small>
<input name="max" type="number" step="any" value="100" required>
</label>
<label>
Major tick intervals
<small>Number of divisions (e.g. 10 → 0, 10, 20 … 100)</small>
<input name="big_ticks" type="number" min="1" max="50" value="10" required>
</label>
<label>
Minor ticks per interval
<small>Small ticks between each major pair</small>
<input name="small_ticks" type="number" min="0" max="20" value="4" required>
</label>
<label>
Number of labels
<small>Numeric values to print; best when (count1) divides intervals</small>
<input name="label_count" type="number" min="2" value="6" required>
</label>
<div class="actions">
<button type="submit" id="btn-generate">Generate</button>
<button type="button" id="btn-download" disabled>Download SVG</button>
<span id="status"></span>
</div>
</form>
</div>
<div class="preview-card">
<div class="preview-label">Preview</div>
<div id="preview">
<p id="preview-placeholder">Fill in the form and click Generate.</p>
</div>
</div>
</div>
<script>
let lastSvg = '';
async function doGenerate() {
const status = document.getElementById('status');
status.textContent = 'Generating…';
try {
const resp = await fetch('generate', {
method: 'POST',
body: new FormData(document.getElementById('form')),
});
if (!resp.ok) throw new Error(await resp.text());
lastSvg = await resp.text();
document.getElementById('preview').innerHTML = lastSvg;
document.getElementById('btn-download').disabled = false;
status.textContent = '';
} catch (err) {
status.textContent = 'Error: ' + err.message;
}
}
document.getElementById('form').addEventListener('submit', e => {
e.preventDefault();
doGenerate();
});
document.getElementById('btn-download').addEventListener('click', () => {
if (!lastSvg) return;
const a = Object.assign(document.createElement('a'), {
href: URL.createObjectURL(new Blob([lastSvg], { type: 'image/svg+xml' })),
download: 'M1730-Scale.svg',
});
a.click();
URL.revokeObjectURL(a.href);
});
// Show default scale on load
doGenerate();
</script>
</body>
</html>