TOTEM Studio commited on
Commit
c7d94b0
·
1 Parent(s): d369b66

fix gauge gradient: multi-segment arcs (no defs), hero height + signal wrap sizing

Browse files
Files changed (1) hide show
  1. app.py +38 -34
app.py CHANGED
@@ -368,11 +368,11 @@ TOTEM_CSS = """
368
 
369
  .totem-hero {
370
  position: relative;
371
- padding: 40px 52px;
372
  overflow: hidden;
373
  border: 1px solid rgba(242, 193, 78, 0.35);
374
  background: #06091e;
375
- min-height: 200px;
376
  }
377
 
378
  .totem-hero::after {
@@ -413,8 +413,9 @@ TOTEM_CSS = """
413
  }
414
 
415
  .totem-hero-right {
416
- flex: 0 0 180px;
417
  display: flex;
 
418
  align-items: center;
419
  justify-content: center;
420
  }
@@ -424,8 +425,8 @@ TOTEM_CSS = """
424
  right: auto;
425
  top: auto;
426
  transform: none;
427
- width: 160px;
428
- height: 160px;
429
  }
430
 
431
  .totem-signal {
@@ -1323,41 +1324,44 @@ def render_topbar(state: dict) -> str:
1323
 
1324
  def render_signal_gauge(value: int) -> str:
1325
  clamped = max(0, min(100, int(value or 0)))
1326
- circumference = 427.26
1327
- progress = clamped / 100.0
1328
- dash_offset = circumference * (1 - progress)
1329
- # Color state based on signal strength per manual spec
1330
- if clamped < 25:
1331
- state_class = "gauge-state-low"
1332
- elif clamped < 50:
1333
- state_class = "gauge-state-weak"
1334
- elif clamped < 70:
1335
- state_class = "gauge-state-developing"
1336
- elif clamped < 85:
1337
- state_class = "gauge-state-strong"
1338
- else:
1339
- state_class = "gauge-state-excellent"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1340
  return f"""
1341
- <div class="totem-signal-wrap {state_class}">
1342
  <svg class="totem-signal" viewBox="0 0 160 160" role="img" aria-label="TOTEM Signal {clamped} percent">
1343
- <defs>
1344
- <linearGradient id="gaugeGradient" x1="0%" y1="0%" x2="100%" y2="100%">
1345
- <stop offset="0%" stop-color="#8A4DFF"/>
1346
- <stop offset="40%" stop-color="#39C9FF"/>
1347
- <stop offset="75%" stop-color="#22B573"/>
1348
- <stop offset="100%" stop-color="#F2C14E"/>
1349
- </linearGradient>
1350
- </defs>
1351
  <!-- Outer decorative ring -->
1352
  <circle class="signal-outer-ring" cx="80" cy="80" r="76"></circle>
1353
  <!-- Track -->
1354
  <circle class="signal-track" cx="80" cy="80" r="68"></circle>
1355
- <!-- Progress arc -->
1356
- <circle
1357
- class="signal-progress"
1358
- cx="80" cy="80" r="68"
1359
- style="stroke-dasharray:{circumference:.2f};stroke-dashoffset:{dash_offset:.2f};"
1360
- ></circle>
1361
  <!-- Inner radar rings -->
1362
  <circle class="signal-inner-ring" cx="80" cy="80" r="52"></circle>
1363
  <circle class="signal-inner-ring" cx="80" cy="80" r="40"></circle>
 
368
 
369
  .totem-hero {
370
  position: relative;
371
+ padding: 44px 52px 52px 52px;
372
  overflow: hidden;
373
  border: 1px solid rgba(242, 193, 78, 0.35);
374
  background: #06091e;
375
+ min-height: 240px;
376
  }
377
 
378
  .totem-hero::after {
 
413
  }
414
 
415
  .totem-hero-right {
416
+ flex: 0 0 200px;
417
  display: flex;
418
+ flex-direction: column;
419
  align-items: center;
420
  justify-content: center;
421
  }
 
425
  right: auto;
426
  top: auto;
427
  transform: none;
428
+ width: 170px;
429
+ height: 170px;
430
  }
431
 
432
  .totem-signal {
 
1324
 
1325
  def render_signal_gauge(value: int) -> str:
1326
  clamped = max(0, min(100, int(value or 0)))
1327
+ circ = 427.26
1328
+ filled = circ * (clamped / 100.0)
1329
+ # Segment colours: violet, cyan, emerald, gold - each covers 25% of circumference
1330
+ # We layer 4 coloured arcs masked by dasharray to fake a gradient
1331
+ seg = circ / 4 # 106.815 per segment
1332
+ segs = [
1333
+ ("#8A4DFF", 0),
1334
+ ("#39C9FF", 1),
1335
+ ("#22B573", 2),
1336
+ ("#F2C14E", 3),
1337
+ ]
1338
+ arc_elements = []
1339
+ for color, idx in segs:
1340
+ seg_start = idx * seg
1341
+ seg_end = (idx + 1) * seg
1342
+ if filled <= seg_start:
1343
+ break # nothing to draw for this segment
1344
+ seg_filled = min(filled - seg_start, seg)
1345
+ # offset = circ - seg_filled, rotated so this segment starts at the right angle
1346
+ rotate_deg = -90 + (seg_start / circ) * 360
1347
+ arc_elements.append(
1348
+ f'<circle cx="80" cy="80" r="68" fill="none" stroke="{color}" '
1349
+ f'stroke-width="7" stroke-linecap="round" '
1350
+ f'stroke-dasharray="{seg_filled:.2f} {circ:.2f}" '
1351
+ f'stroke-dashoffset="0" '
1352
+ f'style="transform:rotate({rotate_deg:.1f}deg);transform-origin:80px 80px;'
1353
+ f'filter:drop-shadow(0 0 4px {color}88);" />'
1354
+ )
1355
+ arcs_html = "\n ".join(arc_elements)
1356
  return f"""
1357
+ <div class="totem-signal-wrap">
1358
  <svg class="totem-signal" viewBox="0 0 160 160" role="img" aria-label="TOTEM Signal {clamped} percent">
 
 
 
 
 
 
 
 
1359
  <!-- Outer decorative ring -->
1360
  <circle class="signal-outer-ring" cx="80" cy="80" r="76"></circle>
1361
  <!-- Track -->
1362
  <circle class="signal-track" cx="80" cy="80" r="68"></circle>
1363
+ <!-- Gradient arc segments -->
1364
+ {arcs_html}
 
 
 
 
1365
  <!-- Inner radar rings -->
1366
  <circle class="signal-inner-ring" cx="80" cy="80" r="52"></circle>
1367
  <circle class="signal-inner-ring" cx="80" cy="80" r="40"></circle>