Skip to content

Commit 89bf2bb

Browse files
committed
Apply keebforge updates and professional dark/light theme
1 parent 265013b commit 89bf2bb

5 files changed

Lines changed: 457 additions & 172 deletions

File tree

app/static/index.html

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,24 @@
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
66
<title>KB Plate Validator & Generator</title>
7-
<link rel="stylesheet" href="static/style.css?v=6">
7+
<link rel="stylesheet" href="static/style.css?v=7">
88
</head>
99
<body>
10-
<div class="container">
10+
<div class="container" style="position: relative;">
11+
<button id="theme-toggle" class="theme-toggle" aria-label="Toggle Theme">
12+
<svg id="theme-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
13+
<!-- Default to moon icon since it's dark mode default -->
14+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
15+
</svg>
16+
</button>
1117
<header>
1218
<h1>KB Plate Validator</h1>
1319
<p>Generate SendCutSend-ready keyboard plates from KLE and KiCad files.</p>
1420
</header>
1521

1622
<main>
1723
<div class="tabs">
18-
<button class="tab-btn" data-tab="kle" id="tab-kle" class="active">KLE Mode (No PCB)</button>
24+
<button class="tab-btn active" data-tab="kle" id="tab-kle">KLE Mode</button>
1925
<button class="tab-btn" data-tab="pcb" id="tab-pcb">PCB Mode</button>
2026
<button class="tab-btn" data-tab="convert" id="tab-convert">DXF Converter</button>
2127
</div>
@@ -24,17 +30,17 @@ <h1>KB Plate Validator</h1>
2430
<section id="pcb-section" class="tab-content active">
2531
<div class="form-group">
2632
<label>KLE JSON Layout <span class="required">*</span></label>
27-
<div class="input-toggle" style="margin-bottom: 0.5rem;">
28-
<label style="display: inline-block; font-weight: normal; margin-right: 1rem;">
33+
<div class="input-toggle">
34+
<label>
2935
<input type="radio" name="kle_input_mode" value="text" checked> Paste Raw JSON
3036
</label>
31-
<label style="display: inline-block; font-weight: normal;">
37+
<label>
3238
<input type="radio" name="kle_input_mode" value="file"> Upload File
3339
</label>
3440
</div>
3541

3642
<div id="kle-text-input">
37-
<textarea id="kle_text" name="kle_text" rows="6" style="width: 100%; padding: 0.5rem; border: 1px solid var(--border-color); border-radius: 6px; font-family: monospace;" placeholder='[&#10; ["Esc","Q","W","E","R","T","Y","U","I","O","P","{","}","|"]&#10;]'></textarea>
43+
<textarea id="kle_text" name="kle_text" rows="6" placeholder='[&#10; ["Esc","Q","W","E","R","T","Y","U","I","O","P","{","}","|"]&#10;]'></textarea>
3844
</div>
3945

4046
<div id="kle-file-input" class="hidden">
@@ -65,9 +71,9 @@ <h1>KB Plate Validator</h1>
6571
<label for="pcb_dy">PCB Y Offset (mm)</label>
6672
<input type="number" id="pcb_dy" name="pcb_dy" value="0.0" step="0.1">
6773
</div>
68-
<div class="form-group" style="display: flex; align-items: center; padding-top: 1.5rem;">
69-
<input type="checkbox" id="no_auto_align" name="no_auto_align" style="width: auto; margin-right: 0.5rem;">
70-
<label for="no_auto_align" style="margin-bottom: 0; cursor: pointer;">Disable Auto-Align</label>
74+
<div class="form-group checkbox-group" style="align-self: center;">
75+
<input type="checkbox" id="no_auto_align" name="no_auto_align">
76+
<label for="no_auto_align">Disable Auto-Align</label>
7177
</div>
7278
</div>
7379
</div>
@@ -81,7 +87,7 @@ <h1>KB Plate Validator</h1>
8187
<input type="file" id="dxf_file" name="dxf_file" accept=".dxf">
8288
</div>
8389
<p class="file-name" id="dxf-name"></p>
84-
<div class="notice" style="margin-top: 1rem;">
90+
<div class="notice">
8591
<strong>Note:</strong> Works with any DXF. If standard layers exist
8692
(<code>PLATE_OUTLINE</code>, <code>SWITCH_CUTOUTS</code>,
8793
<code>STAB_CUTOUTS</code>, <code>PCB_SCREW_HOLES</code>) they are used.
@@ -90,24 +96,24 @@ <h1>KB Plate Validator</h1>
9096
</div>
9197
</div>
9298
<div class="actions">
93-
<button type="button" class="primary-btn" id="convert-btn" style="background-color: #059669;">Convert DXF</button>
99+
<button type="button" class="primary-btn btn-secondary" id="convert-btn">Convert DXF</button>
94100
</div>
95101
</section>
96102

97103
<section class="options-section">
98104
<h3>Generation Formats</h3>
99-
<div class="options-grid" style="grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));">
100-
<div class="form-group" style="display: flex; align-items: center;">
101-
<input type="checkbox" id="gen_dxf" name="gen_dxf" checked style="width: auto; margin-right: 0.5rem;">
102-
<label for="gen_dxf" style="margin-bottom: 0; cursor: pointer;">DXF (Laser)</label>
105+
<div class="options-grid">
106+
<div class="checkbox-group">
107+
<input type="checkbox" id="gen_dxf" name="gen_dxf" checked>
108+
<label for="gen_dxf">DXF (Laser)</label>
103109
</div>
104-
<div class="form-group" style="display: flex; align-items: center;">
105-
<input type="checkbox" id="gen_gerber" name="gen_gerber" checked style="width: auto; margin-right: 0.5rem;">
106-
<label for="gen_gerber" style="margin-bottom: 0; cursor: pointer;">Gerber (JLCPCB)</label>
110+
<div class="checkbox-group">
111+
<input type="checkbox" id="gen_gerber" name="gen_gerber" checked>
112+
<label for="gen_gerber">Gerber (JLCPCB)</label>
107113
</div>
108-
<div class="form-group" style="display: flex; align-items: center;">
109-
<input type="checkbox" id="gen_stl" name="gen_stl" checked style="width: auto; margin-right: 0.5rem;">
110-
<label for="gen_stl" style="margin-bottom: 0; cursor: pointer;">STL (3D Print)</label>
114+
<div class="checkbox-group">
115+
<input type="checkbox" id="gen_stl" name="gen_stl" checked>
116+
<label for="gen_stl">STL (3D Print)</label>
111117
</div>
112118
</div>
113119
</section>
@@ -156,7 +162,7 @@ <h3>Plate Options</h3>
156162
</div>
157163

158164
<div id="kle-options">
159-
<h3>KLE Mounting Options</h3>
165+
<h3 style="margin-top: 1.5rem;">KLE Mounting Options</h3>
160166
<div class="options-grid">
161167
<div class="form-group">
162168
<label for="screw_preset">Screw Preset</label>
@@ -168,19 +174,22 @@ <h3>KLE Mounting Options</h3>
168174
<option value="grid3x2">Grid 3x2</option>
169175
<option value="grid4x2">Grid 4x2</option>
170176
<option value="between_rows">Between Rows</option>
177+
<option value="snap">Intelligent Snap (Auto Brace)</option>
178+
<option value="gh60">GH60 standard</option>
179+
<option value="skyway96">Skyway96 standard</option>
171180
</select>
172181
</div>
173182
<div class="form-group">
174183
<label for="screw_inset">Screw Inset (mm)</label>
175184
<input type="number" id="screw_inset" name="screw_inset" value="5.0" step="0.5">
176185
</div>
177-
<div class="form-group" style="display: flex; align-items: center; padding-top: 1.5rem;">
178-
<input type="checkbox" id="split" name="split" style="width: auto; margin-right: 0.5rem;">
179-
<label for="split" style="margin-bottom: 0; cursor: pointer;">Split Plates (Ergo/Alice)</label>
186+
<div class="form-group checkbox-group" style="align-self: center;">
187+
<input type="checkbox" id="split" name="split">
188+
<label for="split">Split Plates (Ergo/Alice)</label>
180189
</div>
181-
<div class="form-group" style="display: flex; align-items: center; padding-top: 1.5rem;">
182-
<input type="checkbox" id="puzzle_split" name="puzzle_split" style="width: auto; margin-right: 0.5rem;">
183-
<label for="puzzle_split" style="margin-bottom: 0; cursor: pointer;">Hole-Aware Puzzle Split (for 3D Printing)</label>
190+
<div class="form-group checkbox-group" style="align-self: center;">
191+
<input type="checkbox" id="puzzle_split" name="puzzle_split">
192+
<label for="puzzle_split">Hole-Aware Puzzle Split</label>
184193
</div>
185194
</div>
186195
</div>
@@ -199,20 +208,20 @@ <h3>KLE Mounting Options</h3>
199208
<div id="results">
200209
<h3 id="results-title">Output Files</h3>
201210
<div class="stats-grid">
202-
<div class="stat"><span class="label">Keys:</span> <span id="stat-keys">-</span></div>
203-
<div class="stat"><span class="label">Dimensions:</span> <span id="stat-dims">-</span></div>
204-
<div class="stat"><span class="label">Screws:</span> <span id="stat-screws">-</span></div>
211+
<div class="stat"><span class="label">Keys</span> <span id="stat-keys">-</span></div>
212+
<div class="stat"><span class="label">Dimensions</span> <span id="stat-dims">-</span></div>
213+
<div class="stat"><span class="label">Screws</span> <span id="stat-screws">-</span></div>
205214
</div>
206215

207-
<div id="preview-container" style="margin: 2rem 0; text-align: center; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 1rem; overflow: auto; max-height: 400px; min-height: 80px;">
208-
<p style="padding: 2rem; color: var(--text-muted);">Preview appears after generation.</p>
216+
<div id="preview-container">
217+
<p style="color: var(--text-muted); font-weight: 500;">Preview appears after generation.</p>
209218
</div>
210219

211220
<div id="validation-notice" class="notice hidden"></div>
212-
<div class="download-buttons" style="display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap;">
213-
<a href="#" id="download-link" class="primary-btn btn-disabled">Download DXF</a>
214-
<a href="#" id="download-gerber" class="primary-btn btn-disabled" style="background-color: #059669;">Download Gerber (JLCPCB)</a>
215-
<a href="#" id="download-stl" class="primary-btn btn-disabled" style="background-color: #7c3aed;">Download 3D (STL)</a>
221+
<div class="download-buttons">
222+
<a href="#" id="download-link" class="primary-btn btn-secondary btn-disabled">Download DXF</a>
223+
<a href="#" id="download-gerber" class="primary-btn btn-secondary btn-disabled">Download Gerber</a>
224+
<a href="#" id="download-stl" class="primary-btn btn-secondary btn-disabled">Download STL</a>
216225
</div>
217226
</div>
218227

@@ -224,6 +233,6 @@ <h3 id="results-title">Output Files</h3>
224233
</footer>
225234
</div>
226235

227-
<script src="static/script.js?v=6"></script>
236+
<script src="static/script.js?v=7"></script>
228237
</body>
229238
</html>

app/static/script.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,31 @@
11
document.addEventListener('DOMContentLoaded', () => {
2+
// Theme handling
3+
const htmlEl = document.documentElement;
4+
const themeToggleBtn = document.getElementById('theme-toggle');
5+
const themeIcon = document.getElementById('theme-icon');
6+
7+
const moonIcon = '<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>';
8+
const sunIcon = '<circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>';
9+
10+
// Default to dark theme if not set
11+
let currentTheme = localStorage.getItem('theme') || 'dark';
12+
if (currentTheme === 'light') {
13+
htmlEl.setAttribute('data-theme', 'light');
14+
themeIcon.innerHTML = sunIcon;
15+
}
16+
17+
themeToggleBtn.addEventListener('click', () => {
18+
if (htmlEl.getAttribute('data-theme') === 'light') {
19+
htmlEl.removeAttribute('data-theme');
20+
localStorage.setItem('theme', 'dark');
21+
themeIcon.innerHTML = moonIcon;
22+
} else {
23+
htmlEl.setAttribute('data-theme', 'light');
24+
localStorage.setItem('theme', 'light');
25+
themeIcon.innerHTML = sunIcon;
26+
}
27+
});
28+
229
const form = document.getElementById('plate-form');
330
const tabBtns = document.querySelectorAll('.tab-btn');
431
const kleInput = document.getElementById('kle_file');

0 commit comments

Comments
 (0)