Fix theme swatches and calendar nav, add collapsible card sections
Claude-Session: https://claude.ai/code/session_014ADhvRXuiTvrXSbConxUey
This commit is contained in:
+24
-3
@@ -497,13 +497,34 @@ tooltip.background label {
|
||||
background-color: @accent;
|
||||
}
|
||||
|
||||
.widget-section-toggle {
|
||||
border-top: 1px solid alpha(@foreground, 0.12);
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
border-radius: 0;
|
||||
background-color: transparent;
|
||||
padding: 10px 0 2px 0;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.widget-section-toggle:hover .widget-section-title,
|
||||
.widget-section-toggle:hover .widget-section-caret {
|
||||
opacity: 1;
|
||||
color: @accent;
|
||||
}
|
||||
|
||||
.widget-section-title {
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
opacity: 0.45;
|
||||
border-top: 1px solid alpha(@foreground, 0.12);
|
||||
padding-top: 10px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.widget-section-caret {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
opacity: 0.45;
|
||||
min-width: 14px;
|
||||
}
|
||||
|
||||
.agent-mark {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Gtk } from "ags/gtk3"
|
||||
import { createPoll } from "ags/time"
|
||||
import { For } from "ags"
|
||||
import { For, createState } from "ags"
|
||||
import { shell } from "../lib/utils"
|
||||
|
||||
type Limit = {
|
||||
@@ -198,8 +198,33 @@ const usage = createPoll<AgentUsage>(
|
||||
(stdout) => parseUsage(stdout),
|
||||
)
|
||||
|
||||
function SectionTitle({ title }: { title: string }) {
|
||||
return <label class="widget-section-title" label={title} xalign={0} halign={Gtk.Align.START} />
|
||||
const [limitsExpanded, setLimitsExpanded] = createState(true)
|
||||
const [daysExpanded, setDaysExpanded] = createState(true)
|
||||
const [modelsExpanded, setModelsExpanded] = createState(true)
|
||||
|
||||
function Section({ title, expanded, onToggle, content }: {
|
||||
title: string
|
||||
expanded: any
|
||||
onToggle: () => void
|
||||
content: any
|
||||
}) {
|
||||
return (
|
||||
<box vertical spacing={6}>
|
||||
<button
|
||||
class="widget-section-toggle"
|
||||
tooltipText={expanded.as((open: boolean) => (open ? `Collapse ${title}` : `Expand ${title}`))}
|
||||
onClicked={onToggle}
|
||||
>
|
||||
<box spacing={6}>
|
||||
<label class="widget-section-title" label={title} xalign={0} halign={Gtk.Align.START} hexpand />
|
||||
<label class="widget-section-caret" label={expanded.as((open: boolean) => (open ? "-" : "+"))} />
|
||||
</box>
|
||||
</button>
|
||||
<revealer revealChild={expanded} transitionDuration={150}>
|
||||
{content}
|
||||
</revealer>
|
||||
</box>
|
||||
)
|
||||
}
|
||||
|
||||
function LimitRow({ limit }: { limit: Limit }) {
|
||||
@@ -289,26 +314,50 @@ export function ClaudeUsageCard() {
|
||||
/>
|
||||
</box>
|
||||
|
||||
<box vertical spacing={10} visible={usage.as((u) => u.limits.length > 0)}>
|
||||
<SectionTitle title="LIMITS" />
|
||||
<box vertical visible={usage.as((u) => u.limits.length > 0)}>
|
||||
<Section
|
||||
title="LIMITS"
|
||||
expanded={limitsExpanded}
|
||||
onToggle={() => setLimitsExpanded(!limitsExpanded.get())}
|
||||
content={
|
||||
<box vertical spacing={10}>
|
||||
<For each={usage.as((u) => u.limits)} id={(limit: Limit) => limit.label}>
|
||||
{(limit: Limit) => <LimitRow limit={limit} />}
|
||||
</For>
|
||||
</box>
|
||||
}
|
||||
/>
|
||||
</box>
|
||||
|
||||
<box vertical spacing={6} visible={usage.as((u) => u.days.length > 0)}>
|
||||
<SectionTitle title="TOKENS BY DAY" />
|
||||
<box vertical visible={usage.as((u) => u.days.length > 0)}>
|
||||
<Section
|
||||
title="TOKENS BY DAY"
|
||||
expanded={daysExpanded}
|
||||
onToggle={() => setDaysExpanded(!daysExpanded.get())}
|
||||
content={
|
||||
<box vertical spacing={6}>
|
||||
<For each={usage.as((u) => u.days)} id={(day: DayUsage) => day.key}>
|
||||
{(day: DayUsage) => <DayRow day={day} />}
|
||||
</For>
|
||||
</box>
|
||||
}
|
||||
/>
|
||||
</box>
|
||||
|
||||
<box vertical spacing={4} visible={usage.as((u) => u.models.length > 0)}>
|
||||
<SectionTitle title="TOKENS BY MODEL" />
|
||||
<box vertical visible={usage.as((u) => u.models.length > 0)}>
|
||||
<Section
|
||||
title="TOKENS BY MODEL"
|
||||
expanded={modelsExpanded}
|
||||
onToggle={() => setModelsExpanded(!modelsExpanded.get())}
|
||||
content={
|
||||
<box vertical spacing={4}>
|
||||
<For each={usage.as((u) => u.models)} id={(model: ModelUsage) => model.key}>
|
||||
{(model: ModelUsage) => <ModelRow model={model} />}
|
||||
</For>
|
||||
</box>
|
||||
}
|
||||
/>
|
||||
</box>
|
||||
</box>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ function CalendarSection() {
|
||||
tooltipText="Scroll to change month"
|
||||
/>
|
||||
<button class="cc-calendar-nav" tooltipText="Previous month" onClicked={() => shiftMonth(-1)}>
|
||||
<label label={""} />
|
||||
<label label={"<"} />
|
||||
</button>
|
||||
<button
|
||||
class="cc-calendar-nav"
|
||||
@@ -403,10 +403,10 @@ function CalendarSection() {
|
||||
visible={monthOffset.as((offset) => offset !== 0)}
|
||||
onClicked={resetMonth}
|
||||
>
|
||||
<label label={""} />
|
||||
<label label={"Today"} />
|
||||
</button>
|
||||
<button class="cc-calendar-nav" tooltipText="Next month" onClicked={() => shiftMonth(1)}>
|
||||
<label label={""} />
|
||||
<label label={">"} />
|
||||
</button>
|
||||
</box>
|
||||
<label class="cc-calendar-grid" label={monthGrid} halign={Gtk.Align.CENTER} />
|
||||
|
||||
@@ -11,8 +11,10 @@ const COLUMNS = 3
|
||||
type Theme = { slug: string; name: string; swatches: string[] }
|
||||
|
||||
const swatchProgram =
|
||||
"{ key=$1; value=$2; gsub(/[ \\t]/, \"\", key); gsub(/[ \"\\t]/, \"\", value); " +
|
||||
"if (value ~ /^#/) palette[key] = value } " +
|
||||
"{ key=$1; value=$2; gsub(/[ \\t]/, \"\", key); " +
|
||||
"if (match(value, /\"[^\"]*\"/)) value = substr(value, RSTART + 1, RLENGTH - 2); " +
|
||||
"else { sub(/#.*$/, \"\", value); gsub(/[ \\t]/, \"\", value) } " +
|
||||
"if (value ~ /^#[0-9A-Fa-f]+$/) palette[key] = value } " +
|
||||
"END { split(\"color1 color2 color3 color4 color5 color6\", legacy, \" \"); " +
|
||||
"split(\"red green yellow blue magenta cyan\", named, \" \"); " +
|
||||
"for (i = 1; i <= 6; i++) { " +
|
||||
@@ -41,7 +43,10 @@ const themes = createPoll<Theme[]>(
|
||||
.filter((line) => line.length > 0)
|
||||
.map((line) => {
|
||||
const [slug, name, swatchStr] = line.split("|")
|
||||
return { slug, name: name ?? slug, swatches: (swatchStr ?? "").split(",").filter(Boolean) }
|
||||
const swatches = (swatchStr ?? "")
|
||||
.split(",")
|
||||
.filter((color) => /^#[0-9A-Fa-f]{3,8}$/.test(color))
|
||||
return { slug, name: name ?? slug, swatches }
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user