Widen side cards, add icon badges and graphics, add wallpaper button

This commit is contained in:
2026-07-27 12:00:04 -04:00
parent 9b839ffaf1
commit cffe15e1f6
6 changed files with 132 additions and 38 deletions
+15 -15
View File
@@ -1,22 +1,24 @@
import { Gtk } from "ags/gtk3"
import { createPoll } from "ags/time"
import { shell } from "../lib/utils"
import { CardHeader, StatRow } from "./WidgetCard"
type ClaudeUsage = {
available: boolean
tokens: number
messages: number
cacheHitPercent: number
}
const usage = createPoll<ClaudeUsage>(
{ available: false, tokens: 0, messages: 0 },
{ available: false, tokens: 0, messages: 0, cacheHitPercent: 0 },
60000,
shell("bash $HOME/.config/ags/lib/claude-usage.sh"),
(stdout) => {
try {
return JSON.parse(stdout.trim())
} catch {
return { available: false, tokens: 0, messages: 0 }
return { available: false, tokens: 0, messages: 0, cacheHitPercent: 0 }
}
},
)
@@ -29,11 +31,8 @@ function formatTokens(tokens: number) {
export function ClaudeUsageCard() {
return (
<box class="panel widget-card" vertical spacing={6}>
<box spacing={8}>
<label class="widget-card-icon" label={""} />
<label class="widget-card-title" label="Claude Code" xalign={0} halign={Gtk.Align.START} hexpand />
</box>
<box class="panel widget-card" vertical spacing={10}>
<CardHeader icon={""} title="Claude Code" />
<label
class="widget-card-empty"
label="No usage logs found"
@@ -41,14 +40,15 @@ export function ClaudeUsageCard() {
halign={Gtk.Align.START}
visible={usage.as((u) => !u.available)}
/>
<box vertical spacing={4} visible={usage.as((u) => u.available)}>
<box spacing={8}>
<label class="widget-card-label" label="Tokens today" xalign={0} halign={Gtk.Align.START} hexpand />
<label class="widget-card-value" label={usage.as((u) => formatTokens(u.tokens))} />
</box>
<box spacing={8}>
<label class="widget-card-label" label="Messages today" xalign={0} halign={Gtk.Align.START} hexpand />
<label class="widget-card-value" label={usage.as((u) => `${u.messages}`)} />
<box vertical spacing={8} visible={usage.as((u) => u.available)}>
<StatRow icon={""} label="Tokens today" value={usage.as((u) => formatTokens(u.tokens))} />
<StatRow icon={""} label="Messages today" value={usage.as((u) => `${u.messages}`)} />
<box vertical spacing={4}>
<box spacing={8}>
<label class="widget-card-label" label="Cache hit rate" xalign={0} halign={Gtk.Align.START} hexpand />
<label class="widget-card-value" label={usage.as((u) => `${Math.round(u.cacheHitPercent)}%`)} />
</box>
<levelbar class="widget-level-bar" value={usage.as((u) => u.cacheHitPercent / 100)} />
</box>
</box>
</box>
+39 -13
View File
@@ -4,6 +4,7 @@ import { createState } from "ags"
import { createPoll, interval } from "ags/time"
import { sh, shell } from "../lib/utils"
import { ClaudeUsageCard } from "./ClaudeUsage"
import { CardHeader, StatRow } from "./WidgetCard"
export const QUICKSETTINGS_WINDOW = "quick-settings"
@@ -91,6 +92,9 @@ function Header() {
<label class="cc-clock" label={clock} xalign={0} halign={Gtk.Align.START} />
<label class="cc-date" label={today} xalign={0} halign={Gtk.Align.START} />
</box>
<button class="panel-icon-btn" tooltipText="Change wallpaper" onClicked={() => { closePanel(); sh("blob_wallpaper") }}>
<label label={""} />
</button>
<button class="panel-icon-btn" tooltipText="Lock" onClicked={() => { closePanel(); sh("omarchy-system-lock") }}>
<label label={""} />
</button>
@@ -313,28 +317,50 @@ const uptime = createPoll("", 60000, shell("uptime -p"), (stdout) =>
function UptimeCard() {
return (
<box class="panel widget-card" vertical spacing={6}>
<box spacing={8}>
<label class="widget-card-icon" label={""} />
<label class="widget-card-title" label="Uptime" xalign={0} halign={Gtk.Align.START} hexpand />
</box>
<label class="widget-card-value" label={uptime} xalign={0} halign={Gtk.Align.START} wrap />
<box class="panel widget-card" vertical spacing={10}>
<CardHeader icon={""} title="Uptime" />
<label class="widget-hero-value" label={uptime} xalign={0} halign={Gtk.Align.START} wrap />
</box>
)
}
const weather = createPoll("Loading...", 600000, shell("omarchy-weather-status"), (stdout) =>
stdout.trim(),
type Weather = { ok: boolean; icon: string; place: string; temp: string; wind: string }
function parseWeather(raw: string): Weather {
const parts = raw.split(" · ")
if (parts.length < 3) return { ok: false, icon: "", place: raw, temp: "", wind: "" }
const match = parts[0].match(/^(\S+)\s*(.*)$/)
return {
ok: true,
icon: match ? match[1] : "",
place: match ? match[2].trim() : parts[0].trim(),
temp: parts[1].replace(/^Temp\s*/, ""),
wind: parts[2].replace(/^Wind\s*/, ""),
}
}
const weather = createPoll<Weather>(
{ ok: false, icon: "", place: "Loading...", temp: "", wind: "" },
600000,
shell("omarchy-weather-status"),
(stdout) => parseWeather(stdout.trim()),
)
function WeatherCard() {
return (
<box class="panel widget-card" vertical spacing={6}>
<box spacing={8}>
<label class="widget-card-icon" label={""} />
<label class="widget-card-title" label="Weather" xalign={0} halign={Gtk.Align.START} hexpand />
<box class="panel widget-card" vertical spacing={10}>
<CardHeader icon={weather.as((w) => w.icon)} title={weather.as((w) => w.place)} />
<label
class="widget-card-empty"
label="Weather unavailable"
xalign={0}
halign={Gtk.Align.START}
visible={weather.as((w) => !w.ok)}
/>
<box vertical spacing={8} visible={weather.as((w) => w.ok)}>
<StatRow icon={""} label="Temperature" value={weather.as((w) => w.temp)} />
<StatRow icon={""} label="Wind" value={weather.as((w) => w.wind)} />
</box>
<label class="widget-card-value" label={weather} xalign={0} halign={Gtk.Align.START} wrap />
</box>
)
}
+22
View File
@@ -0,0 +1,22 @@
import { Gtk } from "ags/gtk3"
export function CardHeader({ icon, title }: { icon: any; title: any }) {
return (
<box class="widget-card-header" spacing={10}>
<box class="widget-icon-badge">
<label label={icon} />
</box>
<label class="widget-card-title" label={title} xalign={0} halign={Gtk.Align.START} hexpand />
</box>
)
}
export function StatRow({ icon, label, value }: { icon: string; label: string; value: any }) {
return (
<box class="widget-stat-row" spacing={8}>
<label class="widget-stat-icon" label={icon} />
<label class="widget-card-label" label={label} xalign={0} halign={Gtk.Align.START} hexpand />
<label class="widget-card-value" label={value} />
</box>
)
}