Layout: resizable window, fluid SVG ring, no scrollbars unless overflow, opaque bg

tauri.conf: resizable=true, min 220x240, default 300x320.
BlockRing: SVG scales via viewBox, claims remaining vertical space.
#app uses flex column with sections flex:0 0 auto — content reflows when window resized.
Bumped --bg opacity from 0.78 to 0.93 so files behind the widget don't bleed through.
Themed scrollbars subtle when they do appear.
This commit is contained in:
megaproxy 2026-05-09 01:56:59 +01:00
parent 75049903e7
commit f90bb3b0d5
4 changed files with 49 additions and 17 deletions

View file

@ -14,11 +14,11 @@
{
"label": "main",
"title": "Claude Usage",
"width": 280,
"height": 360,
"minWidth": 280,
"minHeight": 360,
"resizable": false,
"width": 300,
"height": 320,
"minWidth": 220,
"minHeight": 240,
"resizable": true,
"decorations": false,
"transparent": true,
"alwaysOnTop": true,

View file

@ -92,11 +92,10 @@
<style>
.loading {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
padding: 12px;
color: var(--fg-dim);
font-size: 12px;
text-align: center;
}
</style>

View file

@ -1,8 +1,8 @@
<script lang="ts">
import type { UsageBar } from "../types";
// Shows the *real* percentage from `claude /usage` — the
// "Current session" bar (5-hour rolling window).
// Shows the *real* "Current session" percentage from `claude /usage`.
// The SVG uses a viewBox so it scales to whatever container size we get.
let {
bar,
fallbackText = "—",
@ -11,7 +11,7 @@
fallbackText?: string;
} = $props();
// Geometry.
// Logical units; the SVG viewBox is fixed. CSS scales it.
const SIZE = 140;
const STROKE = 12;
const R = (SIZE - STROKE) / 2;
@ -26,7 +26,12 @@
</script>
<div class="wrap">
<svg width={SIZE} height={SIZE} viewBox={`0 0 ${SIZE} ${SIZE}`}>
<svg
viewBox={`0 0 ${SIZE} ${SIZE}`}
preserveAspectRatio="xMidYMid meet"
role="img"
aria-label={bar ? `${bar.percent} percent session used` : "no usage data"}
>
<circle
cx={SIZE / 2}
cy={SIZE / 2}
@ -60,7 +65,24 @@
</div>
<style>
.wrap { display: flex; justify-content: center; padding: 14px 0 6px; }
/*
Container reserves a roughly square area at ~50% of widget height.
The SVG fills the container and scales via viewBox.
*/
.wrap {
flex: 1 1 0;
min-height: 110px;
display: flex;
align-items: center;
justify-content: center;
padding: 6px 0;
}
svg {
width: 100%;
height: 100%;
max-width: 220px; /* don't get absurdly large in a wide window */
max-height: 220px;
}
text { fill: var(--fg); font-family: inherit; }
text.big { font-size: 26px; font-weight: 600; }
text.small { font-size: 11px; fill: var(--fg-dim); }

View file

@ -1,7 +1,7 @@
/* Glass / always-on-top widget look. */
:root {
--bg: rgba(18, 20, 26, 0.78);
--bg: rgba(18, 20, 26, 0.93);
--bg-card: rgba(255, 255, 255, 0.04);
--border: rgba(255, 255, 255, 0.08);
--fg: #e8eaf0;
@ -38,12 +38,22 @@ html, body {
background: var(--bg);
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
overflow: hidden; /* the window itself never scrolls */
display: flex;
flex-direction: column;
backdrop-filter: blur(14px);
}
/* Each child of #app gets a sensible flex behavior so resizing reflows
instead of overflowing. TitleBar and section panels are flex:0 (size
to content); the BlockRing wrap is flex:1 (claims remaining space). */
/* Hide scrollbars unless content really overflows; when they do appear,
make them subtle. */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); border-radius: 3px; }
::-webkit-scrollbar-track { background: transparent; }
button {
font: inherit;
color: inherit;
@ -78,7 +88,8 @@ input[type="number"], input[type="text"], select {
}
.section {
padding: 8px var(--pad);
flex: 0 0 auto;
padding: 6px var(--pad) 8px;
border-top: 1px solid var(--border);
}
.section:first-child { border-top: none; }