Redesign: amber-phosphor terminal aesthetic (Departure Mono)
Browse files- index.html +417 -415
index.html
CHANGED
|
@@ -1,415 +1,417 @@
|
|
| 1 |
-
<title>Engineering Activity Tracker</title>
|
| 2 |
-
<meta name="description" content="Interactive engineering activity tracker demo" />
|
| 3 |
-
<
|
| 4 |
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
:
|
| 8 |
-
--
|
| 9 |
-
--
|
| 10 |
-
--
|
| 11 |
-
--
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
--
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
background
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
}
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
.
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
.
|
| 40 |
-
.top-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
.
|
| 44 |
-
.
|
| 45 |
-
.
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
/
|
| 50 |
-
.
|
| 51 |
-
.
|
| 52 |
-
.
|
| 53 |
-
.
|
| 54 |
-
|
| 55 |
-
.
|
| 56 |
-
.kpi
|
| 57 |
-
.kpi
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
.
|
| 61 |
-
.
|
| 62 |
-
.
|
| 63 |
-
|
| 64 |
-
.
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
.
|
| 69 |
-
.
|
| 70 |
-
|
| 71 |
-
.
|
| 72 |
-
.bar-
|
| 73 |
-
.bar
|
| 74 |
-
.
|
| 75 |
-
.
|
| 76 |
-
.
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
.
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
select{
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
.
|
| 96 |
-
.
|
| 97 |
-
.
|
| 98 |
-
.
|
| 99 |
-
.
|
| 100 |
-
.st-
|
| 101 |
-
.
|
| 102 |
-
.
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
.
|
| 106 |
-
|
| 107 |
-
.
|
| 108 |
-
|
| 109 |
-
.
|
| 110 |
-
|
| 111 |
-
.
|
| 112 |
-
.btn
|
| 113 |
-
.btn
|
| 114 |
-
.
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
.
|
| 119 |
-
.ex
|
| 120 |
-
.ex
|
| 121 |
-
.ex
|
| 122 |
-
.ex
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
footer
|
| 126 |
-
footer
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
.overlay{position:fixed;inset:0;background:rgba(
|
| 130 |
-
.overlay[hidden]{display:none}
|
| 131 |
-
.dialog{background:var(--
|
| 132 |
-
.dialog-h{display:flex;align-items:center;justify-content:space-between;padding:
|
| 133 |
-
.dialog-h h2{font-size:
|
| 134 |
-
.dialog-b{padding:
|
| 135 |
-
.dialog-f{display:flex;justify-content:flex-end;gap:10px;padding:
|
| 136 |
-
.x{border:1px solid var(--line-2);background:var(--
|
| 137 |
-
.
|
| 138 |
-
.
|
| 139 |
-
.toast
|
| 140 |
-
.
|
| 141 |
-
.tip
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
@media (
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
</
|
| 157 |
-
|
| 158 |
-
<
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
<p>
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
<
|
| 166 |
-
|
| 167 |
-
<section class="section
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
<
|
| 173 |
-
|
| 174 |
-
<section class="section">
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
<
|
| 180 |
-
<select id="
|
| 181 |
-
<
|
| 182 |
-
<
|
| 183 |
-
<
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
<section
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
<
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
<div class="ex"><h3><span class="g"
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
</
|
| 208 |
-
|
| 209 |
-
<
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
<
|
| 213 |
-
|
| 214 |
-
<div
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
<div class="frow"><label for="
|
| 221 |
-
<div class="frow"><label for="
|
| 222 |
-
<div class="frow
|
| 223 |
-
<div class="frow"><label for="
|
| 224 |
-
<div class="frow"><label for="
|
| 225 |
-
<div class="frow"><label for="
|
| 226 |
-
<div class="frow"><label for="
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
<
|
| 231 |
-
|
| 232 |
-
<div
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
<div class="frow
|
| 239 |
-
<div class="frow"><label for="
|
| 240 |
-
<div class="frow"><label for="
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
<
|
| 245 |
-
|
| 246 |
-
<div
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
<
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
const
|
| 254 |
-
const
|
| 255 |
-
const
|
| 256 |
-
const
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
mk("2026-06-
|
| 264 |
-
mk("2026-
|
| 265 |
-
mk("2026-
|
| 266 |
-
mk("2026-07-
|
| 267 |
-
mk("2026-07-
|
| 268 |
-
mk("2026-
|
| 269 |
-
mk("2026-
|
| 270 |
-
mk("2026-08-
|
| 271 |
-
mk("2026-08-
|
| 272 |
-
mk("2026-08-
|
| 273 |
-
mk("2026-08-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
{num:"P-
|
| 279 |
-
{num:"P-
|
| 280 |
-
|
| 281 |
-
}
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
const
|
| 290 |
-
const
|
| 291 |
-
const
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
function
|
| 295 |
-
|
| 296 |
-
function
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
const
|
| 300 |
-
const
|
| 301 |
-
const
|
| 302 |
-
const
|
| 303 |
-
const
|
| 304 |
-
const
|
| 305 |
-
const
|
| 306 |
-
const
|
| 307 |
-
const
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
{lab:"
|
| 316 |
-
{lab:"
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
const
|
| 336 |
-
|
| 337 |
-
const
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
}
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
const
|
| 349 |
-
|
| 350 |
-
body
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
<td>${esc(e
|
| 354 |
-
<td class="
|
| 355 |
-
<td><span class="
|
| 356 |
-
<td
|
| 357 |
-
|
| 358 |
-
}
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
body
|
| 364 |
-
}
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
const
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
$("#
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
const
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
if(!e.
|
| 393 |
-
if(!e.
|
| 394 |
-
if(
|
| 395 |
-
if(e.
|
| 396 |
-
if(e.hours
|
| 397 |
-
if(e.
|
| 398 |
-
return
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
if(
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
function
|
| 413 |
-
|
| 414 |
-
refreshOptions();
|
| 415 |
-
|
|
|
|
|
|
|
|
|
| 1 |
+
<title>Engineering Activity Tracker</title>
|
| 2 |
+
<meta name="description" content="Interactive engineering activity tracker demo" />
|
| 3 |
+
<style>
|
| 4 |
+
@font-face{font-family:'Departure Mono';src:url(data:font/woff2;base64,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) format('woff2');font-weight:400;font-style:normal;font-display:swap}
|
| 5 |
+
:root{
|
| 6 |
+
--bg:#100d09; --panel:#181410; --panel-2:#1e1913;
|
| 7 |
+
--ink:#ecdcc0; --ink-2:#b7a688; --muted:#7c7057; --line:#2c2519; --line-2:#443a29;
|
| 8 |
+
--amber:#ffb000; --amber-b:#ffcc4d; --amber-dim:#9a7a2a; --amber-wash:rgba(255,176,0,.10);
|
| 9 |
+
--green:#5fd97a; --red:#ff5c47; --defer:#9a8f78;
|
| 10 |
+
--glow:0 0 7px rgba(255,176,0,.45);
|
| 11 |
+
--mono:'Departure Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;
|
| 12 |
+
}
|
| 13 |
+
*{box-sizing:border-box}
|
| 14 |
+
html{scroll-behavior:smooth}
|
| 15 |
+
body{
|
| 16 |
+
margin:0; background:var(--bg); color:var(--ink);
|
| 17 |
+
font-family:var(--mono); font-size:14px; line-height:1.6;
|
| 18 |
+
background-image:radial-gradient(130% 90% at 50% -20%, rgba(255,176,0,.07), rgba(255,176,0,0) 55%);
|
| 19 |
+
background-attachment:fixed;
|
| 20 |
+
}
|
| 21 |
+
.crt{position:fixed;inset:0;z-index:9999;pointer-events:none;opacity:.7;
|
| 22 |
+
background:repeating-linear-gradient(to bottom, rgba(0,0,0,0) 0 2px, rgba(0,0,0,.16) 3px 3px)}
|
| 23 |
+
.crt::after{content:"";position:absolute;inset:0;box-shadow:inset 0 0 180px rgba(0,0,0,.55)}
|
| 24 |
+
h1,h2,h3{margin:0;font-family:var(--mono);font-weight:400;letter-spacing:.01em}
|
| 25 |
+
button{font-family:inherit;cursor:pointer}
|
| 26 |
+
a{color:var(--amber-b)}
|
| 27 |
+
::selection{background:var(--amber);color:var(--bg)}
|
| 28 |
+
:focus-visible{outline:1px solid var(--amber);outline-offset:2px}
|
| 29 |
+
.wrap{max-width:1160px;margin:0 auto;padding:0 22px}
|
| 30 |
+
|
| 31 |
+
@keyframes boot{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
|
| 32 |
+
main>*{animation:boot .5s both}
|
| 33 |
+
main>*:nth-child(1){animation-delay:.04s} main>*:nth-child(2){animation-delay:.12s}
|
| 34 |
+
main>*:nth-child(3){animation-delay:.20s} main>*:nth-child(4){animation-delay:.28s}
|
| 35 |
+
main>*:nth-child(5){animation-delay:.36s} main>*:nth-child(6){animation-delay:.44s}
|
| 36 |
+
.cursor{display:inline-block;width:.55em;height:1em;background:var(--amber);vertical-align:-2px;box-shadow:var(--glow);animation:blink 1.1s steps(1) infinite}
|
| 37 |
+
@keyframes blink{50%{opacity:0}}
|
| 38 |
+
|
| 39 |
+
.top{border-bottom:1px solid var(--line);background:rgba(16,13,9,.82);backdrop-filter:blur(6px);position:sticky;top:0;z-index:30}
|
| 40 |
+
.top-in{display:flex;align-items:center;gap:13px;height:64px}
|
| 41 |
+
.mark{width:34px;height:34px;flex:none;border:1px solid var(--amber);display:grid;place-items:center;color:var(--amber);box-shadow:var(--glow),inset 0 0 8px rgba(255,176,0,.12)}
|
| 42 |
+
.mark svg{width:19px;height:19px}
|
| 43 |
+
.name{font-size:16px;color:var(--amber);text-shadow:var(--glow);letter-spacing:.02em}
|
| 44 |
+
.spec{font-size:11px;color:var(--ink-2);margin-top:2px}
|
| 45 |
+
.top-tag{margin-left:auto;font-size:11px;color:var(--green);border:1px solid var(--line-2);padding:4px 10px;letter-spacing:.08em}
|
| 46 |
+
|
| 47 |
+
main{padding:26px 0 72px}
|
| 48 |
+
.eyebrow{font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--amber-dim);display:flex;align-items:center;gap:12px;margin:0 0 14px}
|
| 49 |
+
.eyebrow::before{content:"//";color:var(--amber);opacity:.7}
|
| 50 |
+
.eyebrow::after{content:"";height:1px;flex:1;background:var(--line)}
|
| 51 |
+
.intro h1{font-size:24px;color:var(--ink)}
|
| 52 |
+
.intro p{color:var(--ink-2);max-width:70ch;margin:8px 0 0}
|
| 53 |
+
.section{margin-top:34px}
|
| 54 |
+
|
| 55 |
+
.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
|
| 56 |
+
.kpi{background:var(--panel);border:1px solid var(--line);border-top:2px solid var(--amber);padding:14px 16px}
|
| 57 |
+
.kpi.k-crit{border-top-color:var(--red)} .kpi.k-amber{border-top-color:var(--amber)}
|
| 58 |
+
.kpi .lab{font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
|
| 59 |
+
.kpi .val{font-size:30px;line-height:1.05;margin-top:8px;color:var(--amber);text-shadow:var(--glow);font-variant-numeric:tabular-nums}
|
| 60 |
+
.kpi.k-crit .val{color:var(--red);text-shadow:0 0 7px rgba(255,92,71,.4)}
|
| 61 |
+
.kpi .val .u{font-size:14px;color:var(--muted);text-shadow:none;margin-left:2px}
|
| 62 |
+
.kpi .meta{font-size:12px;color:var(--ink-2);margin-top:5px}
|
| 63 |
+
|
| 64 |
+
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
|
| 65 |
+
.panel{background:var(--panel);border:1px solid var(--line);padding:16px 18px 14px;position:relative}
|
| 66 |
+
.panel::before{content:"";position:absolute;top:-1px;left:-1px;width:9px;height:9px;border-top:2px solid var(--amber);border-left:2px solid var(--amber)}
|
| 67 |
+
.panel-h{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:12px}
|
| 68 |
+
.panel-h h2{font-size:14px;color:var(--ink);letter-spacing:.02em}
|
| 69 |
+
.panel-h .note{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.1em}
|
| 70 |
+
|
| 71 |
+
svg.chart{width:100%;height:auto;display:block;font-family:var(--mono)}
|
| 72 |
+
.bar-lab{fill:var(--ink-2);font-size:12px}
|
| 73 |
+
.bar-val{fill:var(--amber-b);font-size:12px;font-variant-numeric:tabular-nums}
|
| 74 |
+
.bar-track{fill:rgba(255,176,0,.06)}
|
| 75 |
+
.bar-fill{fill:var(--amber);filter:drop-shadow(0 0 3px rgba(255,176,0,.55))}
|
| 76 |
+
.bar-fill.alt{fill:var(--green);filter:drop-shadow(0 0 3px rgba(95,217,122,.5))}
|
| 77 |
+
.bar g:hover .bar-fill{fill:var(--amber-b)}
|
| 78 |
+
.month-lab{fill:var(--muted);font-size:11px}
|
| 79 |
+
.empty{padding:26px;text-align:center;color:var(--muted);font-size:13px}
|
| 80 |
+
|
| 81 |
+
.toolbar{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:12px}
|
| 82 |
+
input,select{font-family:inherit;font-size:13px;color:var(--ink);background:var(--bg);border:1px solid var(--line-2);padding:8px 11px;width:100%}
|
| 83 |
+
input::placeholder{color:var(--muted)}
|
| 84 |
+
input:focus,select:focus{border-color:var(--amber);outline:none;box-shadow:0 0 0 1px var(--amber-wash)}
|
| 85 |
+
select{appearance:none;padding-right:26px}
|
| 86 |
+
.search{min-width:230px}
|
| 87 |
+
.spacer{flex:1}
|
| 88 |
+
.tscroll{overflow-x:auto;border:1px solid var(--line);background:var(--panel)}
|
| 89 |
+
table{width:100%;border-collapse:collapse;font-size:13px;min-width:900px}
|
| 90 |
+
thead th{text-align:left;padding:10px 13px;font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--amber-dim);border-bottom:1px solid var(--line-2);background:var(--panel-2);position:sticky;top:0}
|
| 91 |
+
th.num,td.num{text-align:right;font-variant-numeric:tabular-nums}
|
| 92 |
+
tbody td{padding:9px 13px;border-bottom:1px solid var(--line);vertical-align:top}
|
| 93 |
+
tbody tr:last-child td{border-bottom:0}
|
| 94 |
+
tbody tr:hover td{background:var(--amber-wash)}
|
| 95 |
+
.mono{font-size:12.5px}
|
| 96 |
+
.blocker{display:block;margin-top:3px;font-size:12px;color:var(--red)}
|
| 97 |
+
.chip{display:inline-flex;align-items:center;font-size:11.5px;padding:1px 8px;border:1px solid var(--line-2);color:var(--ink-2);white-space:nowrap}
|
| 98 |
+
.pill{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;padding:1px 9px;border:1px solid;white-space:nowrap}
|
| 99 |
+
.pill .dot{width:6px;height:6px;border-radius:50%}
|
| 100 |
+
.st-done{color:var(--green);border-color:rgba(95,217,122,.4)} .st-done .dot{background:var(--green);box-shadow:0 0 5px var(--green)}
|
| 101 |
+
.st-prog{color:var(--amber);border-color:rgba(255,176,0,.4)} .st-prog .dot{background:var(--amber);box-shadow:var(--glow)}
|
| 102 |
+
.st-block{color:var(--red);border-color:rgba(255,92,71,.45)} .st-block .dot{background:var(--red);box-shadow:0 0 5px var(--red)}
|
| 103 |
+
.st-defer{color:var(--defer);border-color:var(--line-2)} .st-defer .dot{background:var(--defer)}
|
| 104 |
+
.rowbtn{border:1px solid var(--line-2);background:transparent;color:var(--ink-2);padding:3px 9px;font-size:12px;font-family:inherit}
|
| 105 |
+
.rowbtn:hover{border-color:var(--red);color:var(--red)}
|
| 106 |
+
|
| 107 |
+
.card{background:var(--panel);border:1px solid var(--line);padding:16px 18px}
|
| 108 |
+
.f2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
|
| 109 |
+
.frow{display:flex;flex-direction:column;gap:5px;margin-bottom:11px}
|
| 110 |
+
label{font-size:12px;color:var(--ink-2)}
|
| 111 |
+
.hint{color:var(--muted)}
|
| 112 |
+
.btn{border:1px solid var(--amber);background:transparent;color:var(--amber);padding:8px 15px;font-size:13px;font-family:inherit;letter-spacing:.02em}
|
| 113 |
+
.btn:hover{background:var(--amber);color:var(--bg);box-shadow:var(--glow)}
|
| 114 |
+
.btn-ghost{border-color:var(--line-2);color:var(--ink-2)}
|
| 115 |
+
.btn-ghost:hover{border-color:var(--amber);color:var(--amber);background:transparent;box-shadow:none}
|
| 116 |
+
.err{font-size:12px;color:var(--red);min-height:1px}
|
| 117 |
+
|
| 118 |
+
.exports{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
|
| 119 |
+
.ex{background:var(--panel);border:1px solid var(--line);padding:14px 16px}
|
| 120 |
+
.ex h3{font-size:13.5px;display:flex;align-items:center;gap:9px;color:var(--ink)}
|
| 121 |
+
.ex .g{width:32px;height:24px;display:grid;place-items:center;color:var(--amber)!important;background:var(--panel-2)!important;border:1px solid var(--line-2);font-size:11px;flex:none}
|
| 122 |
+
.ex p{margin:9px 0 9px;font-size:12px;color:var(--ink-2)}
|
| 123 |
+
.ex code{font-size:11.5px;background:var(--bg);border:1px solid var(--line-2);padding:2px 6px;color:var(--amber-b)}
|
| 124 |
+
|
| 125 |
+
footer{border-top:1px solid var(--line);margin-top:50px;padding:22px 0 44px;color:var(--muted);font-size:12px}
|
| 126 |
+
footer .wrap{display:flex;flex-wrap:wrap;gap:6px 18px;align-items:center}
|
| 127 |
+
footer b{color:var(--ink-2)}
|
| 128 |
+
|
| 129 |
+
.overlay{position:fixed;inset:0;background:rgba(8,6,3,.66);backdrop-filter:blur(2px);display:grid;place-items:center;padding:20px;z-index:100}
|
| 130 |
+
.overlay[hidden]{display:none}
|
| 131 |
+
.dialog{background:var(--panel);border:1px solid var(--amber);box-shadow:0 0 40px rgba(255,176,0,.12),0 24px 60px rgba(0,0,0,.6);width:min(560px,100%);max-height:92vh;overflow:auto}
|
| 132 |
+
.dialog-h{display:flex;align-items:center;justify-content:space-between;padding:15px 18px;border-bottom:1px solid var(--line-2);position:sticky;top:0;background:var(--panel)}
|
| 133 |
+
.dialog-h h2{font-size:15px;color:var(--amber)}
|
| 134 |
+
.dialog-b{padding:16px 18px}
|
| 135 |
+
.dialog-f{display:flex;justify-content:flex-end;gap:10px;padding:14px 18px;border-top:1px solid var(--line-2)}
|
| 136 |
+
.x{border:1px solid var(--line-2);background:transparent;color:var(--ink-2);padding:6px;display:grid;place-items:center}
|
| 137 |
+
.x:hover{border-color:var(--amber);color:var(--amber)}
|
| 138 |
+
.full{grid-column:1/-1}
|
| 139 |
+
.toast{position:fixed;left:50%;bottom:26px;transform:translateX(-50%) translateY(18px);background:var(--bg);border:1px solid var(--amber);color:var(--amber);padding:10px 18px;font-size:13px;box-shadow:var(--glow);opacity:0;transition:opacity .2s,transform .2s;pointer-events:none;z-index:200}
|
| 140 |
+
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
|
| 141 |
+
.tip{position:fixed;z-index:300;pointer-events:none;background:var(--bg);border:1px solid var(--amber);color:var(--ink);font-size:12px;padding:5px 9px;box-shadow:var(--glow);opacity:0;transition:opacity .1s;white-space:nowrap}
|
| 142 |
+
.tip b{color:var(--amber)}
|
| 143 |
+
|
| 144 |
+
@media (max-width:880px){.kpis{grid-template-columns:repeat(2,1fr)}.grid2{grid-template-columns:1fr}.exports{grid-template-columns:1fr}.f2{grid-template-columns:1fr}}
|
| 145 |
+
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important;scroll-behavior:auto}}
|
| 146 |
+
</style>
|
| 147 |
+
|
| 148 |
+
<div class="crt" aria-hidden="true"></div>
|
| 149 |
+
<header class="top">
|
| 150 |
+
<div class="wrap top-in">
|
| 151 |
+
<div class="mark" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v18h18"/><path d="M7 14l3-3 3 2 4-6"/></svg></div>
|
| 152 |
+
<div>
|
| 153 |
+
<div class="name">Engineering Activity Tracker</div>
|
| 154 |
+
<div class="spec">magna@eng-tracker:~$ ./tracker --live <span class="cursor"></span></div>
|
| 155 |
+
</div>
|
| 156 |
+
<span class="top-tag">● LIVE</span>
|
| 157 |
+
</div>
|
| 158 |
+
</header>
|
| 159 |
+
|
| 160 |
+
<main class="wrap">
|
| 161 |
+
<div class="intro">
|
| 162 |
+
<p class="eyebrow">This week · <span id="weekRange"></span></p>
|
| 163 |
+
<h1>Day-to-day engineering, logged and rolled up</h1>
|
| 164 |
+
<p>A working demo of the tracker: log activities, watch the totals and charts recompute, and keep an eye on hours by project, hours by category, and open blockers. The full tool writes a styled Excel workbook and exports Word and PowerPoint from the same data.</p>
|
| 165 |
+
</div>
|
| 166 |
+
|
| 167 |
+
<section class="section kpis" id="kpis" aria-label="Key metrics"></section>
|
| 168 |
+
|
| 169 |
+
<section class="section grid2">
|
| 170 |
+
<div class="panel"><div class="panel-h"><h2>Hours by Project</h2><span class="note">ranked</span></div><div id="projChart"></div></div>
|
| 171 |
+
<div class="panel"><div class="panel-h"><h2>Hours by Category</h2><span class="note">ranked</span></div><div id="catChart"></div></div>
|
| 172 |
+
</section>
|
| 173 |
+
|
| 174 |
+
<section class="section panel"><div class="panel-h"><h2>Hours by Month</h2><span class="note">rollup</span></div><div id="monthChart"></div></section>
|
| 175 |
+
|
| 176 |
+
<section class="section">
|
| 177 |
+
<p class="eyebrow">Daily Log</p>
|
| 178 |
+
<div class="toolbar">
|
| 179 |
+
<div><input class="search" id="search" type="search" placeholder="Search description, engineer, ticket..." aria-label="Search the log" /></div>
|
| 180 |
+
<select id="fCat" aria-label="Filter by category"><option value="">All categories</option></select>
|
| 181 |
+
<select id="fProj" aria-label="Filter by project"><option value="">All projects</option></select>
|
| 182 |
+
<select id="fStatus" aria-label="Filter by status"><option value="">All statuses</option></select>
|
| 183 |
+
<div class="spacer"></div>
|
| 184 |
+
<button class="btn btn-ghost" id="resetBtn">Reset</button>
|
| 185 |
+
<button class="btn" id="addBtn">+ Add entry</button>
|
| 186 |
+
</div>
|
| 187 |
+
<div class="tscroll"><table>
|
| 188 |
+
<thead><tr><th>Log ID</th><th>Date</th><th>Engineer</th><th>Project</th><th>Category</th><th>Description</th><th class="num">Hours</th><th>Status</th><th></th></tr></thead>
|
| 189 |
+
<tbody id="logBody"></tbody>
|
| 190 |
+
</table></div>
|
| 191 |
+
</section>
|
| 192 |
+
|
| 193 |
+
<section class="section grid2">
|
| 194 |
+
<div class="panel">
|
| 195 |
+
<div class="panel-h"><h2>Part Costs</h2><button class="btn btn-ghost" id="addPartBtn" style="padding:6px 11px;font-size:12.5px">+ Part</button></div>
|
| 196 |
+
<div class="tscroll" style="border:0">
|
| 197 |
+
<table style="min-width:520px"><thead><tr><th>Part #</th><th>Description</th><th>Project</th><th class="num">Unit</th><th class="num">Qty</th><th class="num">Total</th></tr></thead><tbody id="partsBody"></tbody></table>
|
| 198 |
+
</div>
|
| 199 |
+
</div>
|
| 200 |
+
<div class="panel">
|
| 201 |
+
<div class="panel-h"><h2>From the installed tool</h2></div>
|
| 202 |
+
<div class="exports" style="grid-template-columns:1fr;gap:11px">
|
| 203 |
+
<div class="ex"><h3><span class="g">XLS</span> Excel workbook</h3><p>Styled Daily_Log table with native date cells, currency formats, and status conditional formatting, plus dashboard formulas and native charts.</p><code>eng-tracker init</code></div>
|
| 204 |
+
<div class="ex"><h3><span class="g">DOC</span> Word report</h3><p>A weekly report for management: totals, breakdowns, blockers, part costs.</p><code>eng-tracker report</code></div>
|
| 205 |
+
<div class="ex"><h3><span class="g">PPT</span> PowerPoint deck</h3><p>A status deck with KPI slides and native charts.</p><code>eng-tracker deck</code></div>
|
| 206 |
+
</div>
|
| 207 |
+
</div>
|
| 208 |
+
</section>
|
| 209 |
+
</main>
|
| 210 |
+
|
| 211 |
+
<footer><div class="wrap">
|
| 212 |
+
<span>Interactive demo. Entries you add are saved in this browser only.</span>
|
| 213 |
+
<span><b>Stack:</b> Python, openpyxl, pandas, pydantic, Typer, Flask.</span>
|
| 214 |
+
</div></footer>
|
| 215 |
+
|
| 216 |
+
<div class="overlay" id="entryModal" hidden><div class="dialog" role="dialog" aria-modal="true" aria-labelledby="et">
|
| 217 |
+
<div class="dialog-h"><h2 id="et">Add log entry</h2><button class="x" data-close aria-label="Close"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg></button></div>
|
| 218 |
+
<form id="entryForm" novalidate>
|
| 219 |
+
<div class="dialog-b"><div class="f2">
|
| 220 |
+
<div class="frow"><label for="e_eng">Engineer</label><input id="e_eng" required /></div>
|
| 221 |
+
<div class="frow"><label for="e_date">Date</label><input id="e_date" type="date" required /></div>
|
| 222 |
+
<div class="frow"><label for="e_proj">Project</label><input id="e_proj" list="projList" required /><datalist id="projList"></datalist></div>
|
| 223 |
+
<div class="frow"><label for="e_cat">Category</label><select id="e_cat"></select></div>
|
| 224 |
+
<div class="frow full"><label for="e_desc">Description</label><input id="e_desc" required placeholder="What did you work on?" /></div>
|
| 225 |
+
<div class="frow"><label for="e_hours">Hours <span class="hint">(0.25 to 16)</span></label><input id="e_hours" type="number" step="0.25" min="0.25" max="16" required /></div>
|
| 226 |
+
<div class="frow"><label for="e_stat">Status</label><select id="e_stat"></select></div>
|
| 227 |
+
<div class="frow"><label for="e_ticket">Ticket <span class="hint">(optional)</span></label><input id="e_ticket" placeholder="JIRA-123" /></div>
|
| 228 |
+
<div class="frow"><label for="e_block">Blocker <span class="hint">(if Blocked)</span></label><input id="e_block" /></div>
|
| 229 |
+
</div><p class="err" id="formErr"></p></div>
|
| 230 |
+
<div class="dialog-f"><button type="button" class="btn btn-ghost" data-close>Cancel</button><button type="submit" class="btn">Add entry</button></div>
|
| 231 |
+
</form>
|
| 232 |
+
</div></div>
|
| 233 |
+
|
| 234 |
+
<div class="overlay" id="partModal" hidden><div class="dialog" role="dialog" aria-modal="true" aria-labelledby="pt" style="width:min(460px,100%)">
|
| 235 |
+
<div class="dialog-h"><h2 id="pt">Add part</h2><button class="x" data-close aria-label="Close"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg></button></div>
|
| 236 |
+
<form id="partForm" novalidate>
|
| 237 |
+
<div class="dialog-b"><div class="f2">
|
| 238 |
+
<div class="frow"><label for="p_num">Part number</label><input id="p_num" required placeholder="P-1001" /></div>
|
| 239 |
+
<div class="frow"><label for="p_proj">Project</label><input id="p_proj" list="projList" required /></div>
|
| 240 |
+
<div class="frow full"><label for="p_desc">Description</label><input id="p_desc" required /></div>
|
| 241 |
+
<div class="frow"><label for="p_cost">Unit cost</label><input id="p_cost" type="number" step="0.01" min="0" required /></div>
|
| 242 |
+
<div class="frow"><label for="p_qty">Quantity</label><input id="p_qty" type="number" step="1" min="1" required /></div>
|
| 243 |
+
</div><p class="err" id="partErr"></p></div>
|
| 244 |
+
<div class="dialog-f"><button type="button" class="btn btn-ghost" data-close>Cancel</button><button type="submit" class="btn">Add part</button></div>
|
| 245 |
+
</form>
|
| 246 |
+
</div></div>
|
| 247 |
+
|
| 248 |
+
<div class="toast" id="toast" role="status"></div>
|
| 249 |
+
<div class="tip" id="tip"></div>
|
| 250 |
+
|
| 251 |
+
<script>
|
| 252 |
+
"use strict";
|
| 253 |
+
const CATEGORIES=["Feature","Bugfix","Architecture","Code Review","DevOps","Support","Meeting"];
|
| 254 |
+
const STATUSES=["Done","In Progress","Blocked","Deferred"];
|
| 255 |
+
const BASE_PROJECTS=["Body Exteriors","Battery Enclosure","Seating Systems","Powertrain","ADAS Cameras","Exterior Mirrors","Internal"];
|
| 256 |
+
const STATUS_CLASS={"Done":"st-done","In Progress":"st-prog","Blocked":"st-block","Deferred":"st-defer"};
|
| 257 |
+
const LS_KEY="eng-tracker-state-v3";
|
| 258 |
+
const TODAY="2026-08-31";
|
| 259 |
+
|
| 260 |
+
function mk(date,eng,proj,cat,desc,hrs,status,ticket,blocker){return{date,engineer:eng,project:proj,category:cat,description:desc,hours:hrs,status,ticket:ticket||"",blocker:blocker||""};}
|
| 261 |
+
const SEED={
|
| 262 |
+
entries:[
|
| 263 |
+
mk("2026-06-12","A. Rivera","Body Exteriors","Architecture","Liftgate fixture concept review",4.0,"Done",""),
|
| 264 |
+
mk("2026-06-20","A. Rivera","Battery Enclosure","Feature","Coolant bracket rev A model",6.0,"Done","BAT-180"),
|
| 265 |
+
mk("2026-06-27","A. Rivera","Seating Systems","Bugfix","Weld sequence correction",2.5,"Done",""),
|
| 266 |
+
mk("2026-07-08","A. Rivera","ADAS Cameras","Feature","Front-camera bracket tolerance study",5.0,"Done","ADAS-77"),
|
| 267 |
+
mk("2026-07-15","A. Rivera","Powertrain","Code Review","Supplier BOM cost review",2.0,"Done","PR-64"),
|
| 268 |
+
mk("2026-07-22","A. Rivera","Internal","Meeting","Monthly production review",1.5,"Done",""),
|
| 269 |
+
mk("2026-07-29","A. Rivera","Exterior Mirrors","Support","Line support for mirror actuator",3.0,"Done",""),
|
| 270 |
+
mk("2026-08-05","A. Rivera","Body Exteriors","DevOps","Set up shared tracker template",2.5,"Done",""),
|
| 271 |
+
mk("2026-08-12","A. Rivera","Battery Enclosure","Feature","Coolant bracket rev B model",6.0,"Done","BAT-214"),
|
| 272 |
+
mk("2026-08-19","A. Rivera","ADAS Cameras","Bugfix","Camera mount spec correction",1.5,"Done",""),
|
| 273 |
+
mk("2026-08-25","A. Rivera","Body Exteriors","Feature","Part-cost rollup for closure hardware",5.0,"In Progress",""),
|
| 274 |
+
mk("2026-08-27","A. Rivera","Seating Systems","Support","Weld matrix walkthrough with techs",1.25,"Done",""),
|
| 275 |
+
mk("2026-08-31","A. Rivera","Seating Systems","Bugfix","Root-cause stamping burr on seat bracket",3.0,"Blocked","","Waiting on CMM time to confirm the dimension"),
|
| 276 |
+
],
|
| 277 |
+
parts:[
|
| 278 |
+
{num:"P-1042",desc:"Front-camera bracket",proj:"ADAS Cameras",cost:42.50,qty:4},
|
| 279 |
+
{num:"P-2210",desc:"Coolant bracket, rev B",proj:"Battery Enclosure",cost:8.75,qty:12},
|
| 280 |
+
{num:"P-3001",desc:"Liftgate seal clip",proj:"Body Exteriors",cost:0.42,qty:250},
|
| 281 |
+
{num:"P-5567",desc:"Weld fixture pin",proj:"Seating Systems",cost:15.00,qty:6},
|
| 282 |
+
],
|
| 283 |
+
};
|
| 284 |
+
|
| 285 |
+
let state=load();
|
| 286 |
+
function load(){try{const r=localStorage.getItem(LS_KEY);if(r)return JSON.parse(r);}catch(e){}return JSON.parse(JSON.stringify(SEED));}
|
| 287 |
+
function save(){try{localStorage.setItem(LS_KEY,JSON.stringify(state));}catch(e){}}
|
| 288 |
+
|
| 289 |
+
const $=(s,r=document)=>r.querySelector(s);
|
| 290 |
+
const $$=(s,r=document)=>[...r.querySelectorAll(s)];
|
| 291 |
+
const fmtH=n=>(Math.round(n*100)/100).toFixed(2);
|
| 292 |
+
const money=n=>"$"+n.toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2});
|
| 293 |
+
const esc=s=>String(s).replace(/[&<>"']/g,c=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[c]));
|
| 294 |
+
function addDays(iso,n){const d=new Date(iso+"T00:00:00");d.setDate(d.getDate()+n);return d.toISOString().slice(0,10);}
|
| 295 |
+
function logIdFor(e){const stamp=e.date.replaceAll("-","");const same=state.entries.filter(x=>x.date===e.date);return `ENG-${stamp}-${String(same.indexOf(e)+1).padStart(4,"0")}`;}
|
| 296 |
+
function allProjects(){const s=new Set(BASE_PROJECTS);state.entries.forEach(e=>s.add(e.project));state.parts.forEach(p=>s.add(p.proj));return[...s].sort();}
|
| 297 |
+
|
| 298 |
+
function metrics(){
|
| 299 |
+
const es=state.entries;
|
| 300 |
+
const total=es.reduce((a,e)=>a+e.hours,0);
|
| 301 |
+
const wkStart=addDays(TODAY,-6);
|
| 302 |
+
const wk=es.filter(e=>e.date>=wkStart&&e.date<=TODAY);
|
| 303 |
+
const blocked=es.filter(e=>e.status==="Blocked");
|
| 304 |
+
const byCat=CATEGORIES.map(c=>[c,es.filter(e=>e.category===c).reduce((a,e)=>a+e.hours,0)]).filter(x=>x[1]>0).sort((a,b)=>b[1]-a[1]);
|
| 305 |
+
const pm={};es.forEach(e=>pm[e.project]=(pm[e.project]||0)+e.hours);
|
| 306 |
+
const byProj=Object.entries(pm).sort((a,b)=>b[1]-a[1]);
|
| 307 |
+
const mm={};es.forEach(e=>{const m=e.date.slice(0,7);mm[m]=(mm[m]||0)+e.hours;});
|
| 308 |
+
const byMonth=Object.entries(mm).sort((a,b)=>a[0]<b[0]?-1:1);
|
| 309 |
+
const partCost=state.parts.reduce((a,p)=>a+p.cost*p.qty,0);
|
| 310 |
+
return{total,wkStart,wkHours:wk.reduce((a,e)=>a+e.hours,0),wkEntries:wk.length,blocked,byCat,byProj,byMonth,partCost,count:es.length};
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
function renderKPIs(m){
|
| 314 |
+
const t=[
|
| 315 |
+
{lab:"Total hours logged",val:fmtH(m.total),u:"h",meta:`${m.count} entries`,cls:""},
|
| 316 |
+
{lab:"This week",val:fmtH(m.wkHours),u:"h",meta:`${m.wkEntries} entries`,cls:""},
|
| 317 |
+
{lab:"Active blockers",val:String(m.blocked.length),u:"",meta:m.blocked.length?"needs attention":"all clear",cls:m.blocked.length?"k-crit":""},
|
| 318 |
+
{lab:"Tracked part cost",val:money(m.partCost),u:"",meta:`${state.parts.length} parts`,cls:"k-amber"},
|
| 319 |
+
];
|
| 320 |
+
$("#kpis").innerHTML=t.map(k=>`<div class="kpi ${k.cls}"><div class="lab">${k.lab}</div><div class="val">${k.val}${k.u?`<span class="u">${k.u}</span>`:""}</div><div class="meta">${k.meta}</div></div>`).join("");
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
function hbars(host,data,alt){
|
| 324 |
+
if(!data.length){host.innerHTML=`<div class="empty">No hours logged yet.</div>`;return;}
|
| 325 |
+
const W=560,rh=34,top=4,padR=52,labelW=132;
|
| 326 |
+
const H=top*2+data.length*rh, tx=labelW, tw=W-tx-padR, max=Math.max(...data.map(d=>d[1]))||1;
|
| 327 |
+
let s=`<svg class="chart" viewBox="0 0 ${W} ${H}" role="img" aria-label="bar chart">`;
|
| 328 |
+
data.forEach((d,i)=>{const y=top+i*rh,bw=Math.max(3,d[1]/max*tw);
|
| 329 |
+
s+=`<g class="bar" data-n="${esc(d[0])}" data-v="${fmtH(d[1])}"><text x="${tx-10}" y="${y+rh/2}" text-anchor="end" dominant-baseline="central" class="bar-lab">${esc(d[0])}</text><rect class="bar-track" x="${tx}" y="${y+8}" width="${tw}" height="${rh-16}" rx="4"/><rect class="bar-fill ${alt?"alt":""}" x="${tx}" y="${y+8}" width="${bw.toFixed(1)}" height="${rh-16}" rx="4"/><text x="${(tx+bw+8).toFixed(1)}" y="${y+rh/2}" dominant-baseline="central" class="bar-val">${fmtH(d[1])}</text></g>`;});
|
| 330 |
+
s+="</svg>";host.innerHTML=s;
|
| 331 |
+
$$(".bar",host).forEach(g=>{g.addEventListener("mousemove",e=>showTip(e,`<b>${esc(g.dataset.n)}</b>: ${esc(g.dataset.v)} h`));g.addEventListener("mouseleave",hideTip);});
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
function renderMonth(m){
|
| 335 |
+
const host=$("#monthChart"),data=m.byMonth;
|
| 336 |
+
if(!data.length){host.innerHTML=`<div class="empty">No hours logged yet.</div>`;return;}
|
| 337 |
+
const W=760,H=150,padB=26,padT=10,padL=8,padR=8,n=data.length;
|
| 338 |
+
const max=Math.max(...data.map(d=>d[1]))||1, slot=(W-padL-padR)/n, bw=Math.min(70,slot*0.5);
|
| 339 |
+
const names={"01":"Jan","02":"Feb","03":"Mar","04":"Apr","05":"May","06":"Jun","07":"Jul","08":"Aug","09":"Sep","10":"Oct","11":"Nov","12":"Dec"};
|
| 340 |
+
let s=`<svg class="chart mbar" viewBox="0 0 ${W} ${H}" role="img" aria-label="hours by month">`;
|
| 341 |
+
data.forEach((d,i)=>{const cx=padL+slot*i+slot/2,bh=(d[1]/max)*(H-padB-padT-14),x=cx-bw/2,y=H-padB-bh;
|
| 342 |
+
const lbl=names[d[0].slice(5,7)]+" "+d[0].slice(2,4);
|
| 343 |
+
s+=`<g><rect x="${x.toFixed(1)}" y="${y.toFixed(1)}" width="${bw.toFixed(1)}" height="${bh.toFixed(1)}" rx="4" class="bar-fill"><title>${lbl}: ${fmtH(d[1])} h</title></rect><text x="${cx.toFixed(1)}" y="${(y-5).toFixed(1)}" text-anchor="middle" class="bar-val">${fmtH(d[1])}</text><text x="${cx.toFixed(1)}" y="${H-9}" text-anchor="middle" class="month-lab">${lbl}</text></g>`;});
|
| 344 |
+
s+="</svg>";host.innerHTML=s;
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
function renderLog(){
|
| 348 |
+
const q=$("#search").value.trim().toLowerCase(),fc=$("#fCat").value,fp=$("#fProj").value,fs=$("#fStatus").value;
|
| 349 |
+
const rows=[...state.entries].map((e,idx)=>({e,idx})).filter(({e})=>(!fc||e.category===fc)&&(!fp||e.project===fp)&&(!fs||e.status===fs)&&(!q||(e.description+" "+e.engineer+" "+e.ticket+" "+e.project).toLowerCase().includes(q))).sort((a,b)=>a.e.date<b.e.date?1:a.e.date>b.e.date?-1:b.idx-a.idx);
|
| 350 |
+
const body=$("#logBody");
|
| 351 |
+
if(!rows.length){body.innerHTML=`<tr><td colspan="9" class="empty">No entries match these filters.</td></tr>`;return;}
|
| 352 |
+
body.innerHTML=rows.map(({e,idx})=>`<tr>
|
| 353 |
+
<td class="mono">${esc(logIdFor(e))}</td><td class="mono" style="color:var(--ink-2)">${esc(e.date)}</td><td>${esc(e.engineer)}</td><td>${esc(e.project)}</td>
|
| 354 |
+
<td><span class="chip">${esc(e.category)}</span></td>
|
| 355 |
+
<td>${esc(e.description)}${e.ticket?` <span class="mono" style="color:var(--muted)">[${esc(e.ticket)}]</span>`:""}${e.status==="Blocked"&&e.blocker?`<span class="blocker">Blocker: ${esc(e.blocker)}</span>`:""}</td>
|
| 356 |
+
<td class="num mono">${fmtH(e.hours)}</td>
|
| 357 |
+
<td><span class="pill ${STATUS_CLASS[e.status]}"><span class="dot"></span>${esc(e.status)}</span></td>
|
| 358 |
+
<td><button class="rowbtn" data-del="${idx}">Delete</button></td></tr>`).join("");
|
| 359 |
+
$$("[data-del]",body).forEach(b=>b.addEventListener("click",()=>{const i=+b.dataset.del;const id=logIdFor(state.entries[i]);state.entries.splice(i,1);save();renderAll();refreshOptions();toast(`Deleted ${id}`);}));
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
function renderParts(){
|
| 363 |
+
const body=$("#partsBody");
|
| 364 |
+
if(!state.parts.length){body.innerHTML=`<tr><td colspan="6" class="empty">No parts recorded.</td></tr>`;return;}
|
| 365 |
+
body.innerHTML=state.parts.map(p=>`<tr><td class="mono">${esc(p.num)}</td><td>${esc(p.desc)}</td><td style="color:var(--ink-2)">${esc(p.proj)}</td><td class="num mono">${money(p.cost)}</td><td class="num mono">${p.qty}</td><td class="num mono" style="font-weight:600">${money(p.cost*p.qty)}</td></tr>`).join("");
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
function renderAll(){const m=metrics();renderKPIs(m);hbars($("#projChart"),m.byProj,false);hbars($("#catChart"),m.byCat,true);renderMonth(m);renderLog();renderParts();$("#weekRange").textContent=`${m.wkStart} to ${TODAY}`;}
|
| 369 |
+
|
| 370 |
+
const tip=$("#tip");
|
| 371 |
+
function showTip(e,html){tip.innerHTML=html;tip.style.opacity="1";tip.style.left=(e.clientX+14)+"px";tip.style.top=(e.clientY-10)+"px";}
|
| 372 |
+
function hideTip(){tip.style.opacity="0";}
|
| 373 |
+
|
| 374 |
+
$$("[data-close]").forEach(b=>b.addEventListener("click",e=>e.target.closest(".overlay").hidden=true));
|
| 375 |
+
$$(".overlay").forEach(o=>o.addEventListener("click",e=>{if(e.target===o)o.hidden=true;}));
|
| 376 |
+
document.addEventListener("keydown",e=>{if(e.key==="Escape")$$(".overlay").forEach(o=>o.hidden=true);});
|
| 377 |
+
function openModal(id){const el=$(id);el.hidden=false;const f=el.querySelector("input,select");if(f)setTimeout(()=>f.focus(),30);}
|
| 378 |
+
|
| 379 |
+
["#search","#fCat","#fProj","#fStatus"].forEach(s=>$(s).addEventListener("input",renderLog));
|
| 380 |
+
$("#resetBtn").addEventListener("click",()=>{$("#search").value="";$("#fCat").value="";$("#fProj").value="";$("#fStatus").value="";renderLog();});
|
| 381 |
+
|
| 382 |
+
$("#addBtn").addEventListener("click",()=>{$("#entryForm").reset();$("#formErr").textContent="";$("#e_date").value=TODAY;$("#e_eng").value=state.entries[0]?.engineer||"A. Rivera";openModal("#entryModal");});
|
| 383 |
+
$("#entryForm").addEventListener("submit",e=>{
|
| 384 |
+
e.preventDefault();
|
| 385 |
+
const g=id=>$(id).value.trim();
|
| 386 |
+
const en={date:g("#e_date"),engineer:g("#e_eng"),project:g("#e_proj"),category:$("#e_cat").value,description:g("#e_desc"),hours:parseFloat($("#e_hours").value),status:$("#e_stat").value,ticket:g("#e_ticket"),blocker:g("#e_block")};
|
| 387 |
+
const err=validate(en);
|
| 388 |
+
if(err){$("#formErr").textContent=err;return;}
|
| 389 |
+
state.entries.push(en);save();renderAll();refreshOptions();$("#entryModal").hidden=true;toast(`Added ${logIdFor(en)}`);
|
| 390 |
+
});
|
| 391 |
+
function validate(e){
|
| 392 |
+
if(!e.engineer)return"Engineer is required.";
|
| 393 |
+
if(!e.date)return"Date is required.";
|
| 394 |
+
if(!e.project)return"Project is required.";
|
| 395 |
+
if(!e.description)return"Description is required.";
|
| 396 |
+
if(isNaN(e.hours))return"Hours must be a number.";
|
| 397 |
+
if(e.hours<0.25)return"Hours must be at least 0.25.";
|
| 398 |
+
if(e.hours>16)return"Hours must not exceed 16.00.";
|
| 399 |
+
if(e.status==="Blocked"&&!e.blocker)return"Add blocker details when the status is Blocked.";
|
| 400 |
+
return null;
|
| 401 |
+
}
|
| 402 |
+
$("#addPartBtn").addEventListener("click",()=>{$("#partForm").reset();$("#partErr").textContent="";openModal("#partModal");});
|
| 403 |
+
$("#partForm").addEventListener("submit",e=>{
|
| 404 |
+
e.preventDefault();
|
| 405 |
+
const num=$("#p_num").value.trim(),desc=$("#p_desc").value.trim(),proj=$("#p_proj").value.trim(),cost=parseFloat($("#p_cost").value),qty=parseInt($("#p_qty").value,10);
|
| 406 |
+
if(!num||!desc||!proj)return $("#partErr").textContent="Part number, description, and project are required.";
|
| 407 |
+
if(isNaN(cost)||cost<0)return $("#partErr").textContent="Unit cost must be zero or more.";
|
| 408 |
+
if(isNaN(qty)||qty<1)return $("#partErr").textContent="Quantity must be one or more.";
|
| 409 |
+
state.parts.push({num,desc,proj,cost,qty});save();renderAll();refreshOptions();$("#partModal").hidden=true;toast(`Added part ${num}`);
|
| 410 |
+
});
|
| 411 |
+
let toastT;
|
| 412 |
+
function toast(msg){const t=$("#toast");t.textContent=msg;t.classList.add("show");clearTimeout(toastT);toastT=setTimeout(()=>t.classList.remove("show"),2200);}
|
| 413 |
+
function fill(sel,items,all){const cur=sel.value;sel.innerHTML=(all?`<option value="">${all}</option>`:"")+items.map(i=>`<option>${esc(i)}</option>`).join("");sel.value=cur;}
|
| 414 |
+
function refreshOptions(){fill($("#e_cat"),CATEGORIES,null);fill($("#e_stat"),STATUSES,null);fill($("#fCat"),CATEGORIES,"All categories");fill($("#fStatus"),STATUSES,"All statuses");fill($("#fProj"),allProjects(),"All projects");$("#projList").innerHTML=allProjects().map(p=>`<option value="${esc(p)}">`).join("");}
|
| 415 |
+
|
| 416 |
+
refreshOptions();renderAll();
|
| 417 |
+
</script>
|