aboutsummaryrefslogtreecommitdiffstats
AgeCommit message (Collapse)AuthorFilesLines
10 daysfeat(immich): mark the big value with a Y ago unitDanilo M.2-5/+22
The years-ago count read as a bare number unless you read the subtitle. It now carries a small Y at its top-right, where a degree sign sits on a temperature, and ago under it on the baseline. The subtitle drops its now redundant "years ago" and keeps only the i/n counter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
10 daysfeat(dashboard): move the Immich card to the top of the boardDanilo M.1-1/+1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
10 daysfeat: add an Immich memories card with click and scrollDanilo M.10-1/+377
A centred card showing today's "N years ago" photos from Immich, one at a time on a 30-second rotation, with when each was taken and where. bin/immich-fetch.sh runs from conky's execi every 30 minutes: it asks /api/memories for today, converts each preview to PNG (Cairo loads nothing else) and writes an index with the year, local capture time and place. The place needs the key's asset.read permission and reads '--' without it. The key lives in ~/.config/udt/immich.env, like the weather key, because a GPG-backed store would raise a pinentry unattended. The dashboard now registers lua_mouse_hook and hands pointer events to the widget under the pointer. On this card, scrolling steps through the photos and a left click opens the photo in Immich's web UI and hides the dashboard so the browser is not stuck beneath it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
10 daysfix(calendar): drop the cache when khal is missingDanilo M.1-0/+8
With khal uninstalled the sampler still wrote a cache with a generated key and no events, because khal's stderr is discarded. The card then read "nothing this week" while an event was scheduled. Removing the cache instead shows the card's "no calendar data" face. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
14 daysfeat(dashboard): describe the dashboard bindDanilo M.1-1/+1
The quickshell keybind reminder lists hyprctl binds -j, which reports Lua actions as an opaque handle, so a bind shows what it does only through its description. This was the one bind left undescribed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-19feat: label the Slackware age and use Italian weekday initialsDanilo M.2-2/+9
The Slackware card's big value gave no hint it was the slackpkg ChangeLog age. Add a small line under the title naming it. The calendar's weekday initials were English. Use the Italian single-letter form, matching the card's already-Italian breaktimer labels.
2026-09-18feat: add a title icon to every labelled cardDanilo M.11-25/+62
Add card.ICON and a card.title helper that draws the glyph in the highlight colour before the label, at the label's own size. The eight labelled cards use it, in both the fit_unit width measurement and the draw, so the icon cannot overrun a narrow cell. Clock (no label) and weather (condition glyph already) are unchanged, and the no-data notice titles stay text-only. Codepoints were chosen against a rendered contact sheet, not fontconfig alone, since a wrong codepoint draws a plausible neighbour.
2026-09-18refactor: unify card no-data face and fluid sizingDanilo M.11-105/+77
Extract card.notice so every cached card's no-data state is one fluid, theme-consistent face instead of a copy per widget, and delete the fixed-size card.label it replaces. Derive weather's arc geometry from its band (pad, curve room, sun dot, time labels) instead of fixed pixels, and cap the arc at a proportion of the card's width rather than 240px. Derive disks' bar-fallback height and its address type from the card's own label scale. Standardise the big-value factor to 1.0 across the fit_unit cards and document the big-value colour rule and the disks headline exception.
2026-09-18feat: add a breaktimer cardDanilo M.7-2/+307
Replaces the Waybar module that used to show breaktimer.sh with a card on the dashboard. The card's big value is the phase countdown, coloured by phase with the same language the Waybar module used, and two rows name the phase and what the countdown leads to. Data comes from bin/breaktimer-sample.sh, run by conky at execi 5, which reads the daemon's runtime files into a cache. The sampler owns the kill -0 liveness check, because conky's Lua cannot run a process and a dead daemon must read as 'fermo' rather than a stale 'running'. Drops outside the work-hours window freeze the countdown while the phase stays 'working'. The sampler detects this from the remain file's age and the card reads it as 'outside working hours', which also covers a hung daemon. The phase words and colour roles live in data.breaktimer_parse so they are unit-tested; the card only draws the result.
2026-09-18Added todo to ignored listDanilo M.1-0/+1
2026-09-18docs: mark the dashboard's monitor pin as non-functionalDanilo M.1-4/+16
The workspace rule pinning special:dash to DP-1 does not work: special workspaces ignore a workspace_rule's `monitor` and open on whichever monitor has focus. Verified on 0.56.2; upstream hyprwm/Hyprland#7990 and #5570, both closed in the issues-to-discussions migration rather than fixed. The comment claimed the opposite, which was convincing because the rule does register and `hyprctl workspacerules` reports it enabled. The rule stays, so the intent is recorded and the line is ready if upstream fixes it, and the bind now names the manual step: focus DP-1 first. Also notes that the window stays on DP-3 once opened there, so a later toggle is cropped until it is moved back, the conky surface being a fixed 2560x1080. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18chore: place the calendar card on the boardDanilo M.1-4/+4
Calendar to the middle column, with the clock and weather shifted down and right to make room for it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18feat: date the calendar rows and pin a colour legendDanilo M.2-14/+92
Three changes to the calendar card: The month grid drops further below the header. The weekday initials sat close enough to read as part of the header rather than as the top of the grid. Event rows carry the date before the time, day/month with no year: the window is a week and the grid above already names the month, so a year would spend three characters on the one field that cannot vary. A legend of the calendar colours is pinned along the card's bottom, and the event rows now end above it rather than at the card's inner edge. It lists every calendar khal declared a colour for, in name order so it does not reshuffle between frames, since pairs() walks a hash. The row budget also counted one row more than the drawing loop would draw, which suppressed the '+N more' line exactly when it was needed: the loop cut the row the count had already spent. Both now test the same condition. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18feat: add a calendar card reading khalDanilo M.8-3/+556
The month grid with the week's appointments below it, colour-coded by calendar. Events come from a cache file rather than a live call: khal costs about 200ms of Python startup, which is two orders of magnitude over the 2-second draw budget, so bin/calendar-sample.sh writes the cache on a 5-minute execi and the widget only parses. Calendar colours are read out of khal's own config by the sampler and mapped onto the board's palette roles, so the card follows a scheme change instead of pinning three literal hues. khal will not emit an ISO date: {start-date} uses the user's dateformat, which carries no year here, and a strftime spec inside the field raises. The sampler asks for {start-date-long} and data.calendar_date recovers the numbers by position, resolving day/month by magnitude and reading a genuinely ambiguous pair day-first. A 2-digit year is refused rather than guessed at. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: give the CPU and board rows their own accentsDanilo M.1-1/+8
The two rows name two different pieces of hardware and read as one block in a single colour. heading and highlight are the palette roles that carry no state meaning, so they can stand for an identity; ok/warning/critical could not, since those say how something is doing and these strings never change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17docs: document the network and slackware cardsDanilo M.1-15/+69
Notes the two things a reader would otherwise get wrong: br0 is a bridge, so local VM traffic shows up in the chart, and the disks card reads df's available column rather than computing size minus used, which would overstate free space by the root-reserved blocks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: put the network and slackware cards on the boardDanilo M.2-1/+5
Placement is provisional: there is no settled arrangement yet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: show free and total under each disk ringDanilo M.2-9/+25
Replaces the percentage, which the ring already draws as an angle. A number repeating it costs a row in a column about 75px wide. Free carries the threshold colour because it is the measured quantity; the total is fixed and stays in the plain value colour, so each column has one coloured number. The cache card adopts card.truncate in the same pass: it was slicing names by byte, which halves a multi-byte character. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: name the CPU and motherboard on the system cardDanilo M.1-3/+53
Both read once: neither changes without a reboot, and /proc/cpuinfo repeats its model-name line once per thread. The two rows come out of the equaliser's height budget, since it is the card's designated slack absorber. Its floor drops from 18px to zero: with rows above it the band can genuinely run out of room, and a fixed floor meant it kept height it did not have and the temperatures drew over it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: add the slackware cardDanilo M.1-0/+121
The big value is the time since slackpkg's ChangeLog changed, coloured green under a day, amber to a week, red past it. A cache with no changelog key is a different failure from no cache at all: the sampler ran and the ChangeLog is what was missing, so the rows still draw and only the age reads '--'. Collapsing the two would send the reader to the wrong problem. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17docs: correct the claim about counting a symlinked directoryDanilo M.3-13/+25
GNU ls follows a symlink to a directory with or without a trailing slash, so both forms count the packages correctly. Only -d lists the link itself. The original claim came from a count taken where the path did not resolve at all, and it reached the spec, the plan and two commit messages. The count was always right; the reason given for it was not, and a comment that teaches the next reader something false is worse than no comment. Records the real trap in its place: ls aliased to a long format counts its "total" header as a package. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: sample the Slackware facts into a cache fileDanilo M.1-0/+47
Conky's Lua has no lfs, so it cannot stat a file, and counting 2800 package files per draw would be a directory walk every two seconds. Writes epochs rather than formatted dates. The shell function this replaces rebuilds a date from ls -l output with the year hardcoded, which breaks every January and on any file older than six months. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: add the network cardDanilo M.4-0/+214
Two lines on one chart against a shared ceiling, one sample per pixel column so nothing is interpolated. The history is module state sized from the card's width, so moving the card reframes the window rather than clearing it. The public address is refused once stale: an address that may no longer be yours, displayed with confidence, is worse than a dash. The fixture uses TEST-NET-1. This repository is public. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: sample the public IP into a cache fileDanilo M.1-0/+48
The draw hook must never make a network call: a hung request blocks the Cairo draw and freezes the dashboard. Thirty minutes, not the old config's five, because a residential address is stable for days. Validates the response before writing. A captive portal and a rate-limit message both arrive with a 200 and would otherwise be drawn as an address. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: read the available column from dfDanilo M.2-1/+27
Free space is read rather than derived: size - used overstates it by the root-reserved blocks, tens of gigabytes on a large filesystem, none of it available to anyone but root. Also asserts fs[3], the row whose device name ends in a digit. It sits next to a numeric column and is the row most likely to break a parser counting fields, and nothing covered it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17fix: strip the clock from every Intel form, not just the fixture'sDanilo M.2-1/+26
The pattern required a literal CPU token immediately before the @, which the one Intel fixture happens to carry. A Xeon reads 'E5-2680 v4 @ 2.40GHz' and a Tiger Lake 'i7-1165G7 @ 2.80GHz', so both kept their clock on the card. A generation prefix hid the vendor word from its anchor for the same reason: '11th Gen Intel Core i7-1165G7' kept 'Intel'. Three more forms added as tests. The Intel fixture was meant to keep the stripping a rule, and one fixture was not enough to do it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: parse the CPU and motherboard model stringsDanilo M.4-0/+118
Stripping by rule rather than by a table of known parts: a leading vendor word, trademark noise, a trailing core count or clock. The Intel fixture exists to keep it a rule. DMI placeholders read as no board at all. 'To Be Filled By O.E.M.' on the dashboard is worse than a blank row. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: parse the sampler's key/value cache formatDanilo M.3-0/+44
Only the first space separates, so a value keeps its own spaces. Values stay strings: the sampler writes epochs and the widget decides whether an age reads as hours or days. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17test: cover the rate counter's explicit fallback intervalDanilo M.1-0/+9
The widget passes conky's update_interval rather than letting it default, so the argument path is the one that ships and nothing exercised it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: add a byte-rate counter for interface statisticsDanilo M.2-0/+68
Mirrors new_cpu_counter: cumulative counters need two samples to yield a rate, and each direction carries its own previous reading. Clamps a negative delta to zero rather than letting a 32-bit wrap or an interface reset produce a spike. One bogus sample sets the shared autoscale and flattens the entire window. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17feat: add card.plot, a shared-scale line chartDanilo M.1-0/+54
Several series on one baseline and one ceiling. The shared ceiling is the point: scaled independently, a 200kB/s upload draws the same height as a 40MB/s download, which is a lie about a link's shape. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17fix: restore the line width card.ring sets, add card.truncateDanilo M.2-2/+54
A ring left its line width behind, so the next stroke on the card inherited a hairline several pixels thick. It already restored the cap for the same reason. card.truncate replaces byte slicing, which cuts a multi-byte character in half and emits an invalid sequence Cairo draws as a box. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17docs: plan the network and slackware widgetsDanilo M.1-0/+2046
Fifteen tasks, TDD throughout: parsers and primitives first, then the samplers, then the cards, then the edits to existing widgets. Verified two assumptions the plan rests on rather than assuming them: Lua 5.4 provides utf8, so card.truncate can cut on a character boundary, and conky's Cairo bindings export cairo_get_line_width, without which the ring line-state fix has nothing to restore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17feat: move the cards to the right of the screenDanilo M.1-4/+4
Groups the machine cards into the right-hand columns and leaves the clock and weather alone on the left, rather than spreading all six across the middle. Provisional: there is no settled arrangement for the board yet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17docs: design the network and slackware widgetsDanilo M.1-0/+313
Two new cards and three fixes to existing ones. The network card reads the interface byte counters directly and keeps its own history, one sample per pixel column, so the chart never interpolates. Both series share one autoscale: drawn independently, a 200kB/s upload would look like a 40MB/s download. The public address moves from the old config's 5 minute poll to 30 minutes, since a residential address is stable for days. The slackware card takes its numbers from a sampler rather than the draw hook, and stores epochs instead of reconstructed dates. The shell function it replaces parses ls -l output and hardcodes the year, which breaks every January and on any file older than six months. Records two things found while checking real values against the design: /var/log/packages is a symlink, so counting it without a trailing slash reports 1 package rather than 2817, and the ChangeLog mtime on this machine currently reads in the future, so the age arithmetic has to survive a negative difference. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17docs: record the visual identity in DESIGN.mdDanilo M.3-0/+108
DESIGN.md states the two rules that carry the board's identity (big value at the card's top-right, rows label-left/value-right), plus the type, colour and glyph conventions, with AGENTS.md pointing at it for anyone adding a widget.
2026-09-17feat: put every card's big number in the same placeDanilo M.3-18/+21
Mirror the weather header so the glyph sits large on the left and the temperature, city and condition run against the right edge, and move the system card's CPU percentage onto its header line, right-aligned. All big values now render at the card's right edge.
2026-09-17feat: make the system card type fluidDanilo M.1-18/+40
The label, headline, RAM and temperature rows now derive from one base size, chosen from the cell height and a measured width fit, and the per-core equaliser absorbs the height left over. Bigger cell, bigger type instead of empty space; the size shrinks only on a width clash.
2026-09-17fix: shorten the cpu equaliser bars to 75%Danilo M.1-1/+1
2026-09-17fix: sit the gpu and cache titles level with the big valueDanilo M.2-3/+3
The 'GPU' and 'CACHE' labels shared the big number's baseline, so they read as sitting under it. Move them to the card's top-left, the same title position the other cards use, level with the top of the value.
2026-09-17feat: fluid type for the gpu and cache cardsDanilo M.4-41/+132
The big value moves to the right of the heading, on the same baseline, so the card's width carries it instead of leaving the right half empty. Type now scales to fill the cell: card.fit_unit measures the rows and returns the largest size that fits the width, and the widget takes the smaller of that and its height budget, shrinking only where a row would collide.
2026-09-17docs: correct the system-widget comments and defer the age markerDanilo M.5-7/+21
Fix the conky.conf.in comment to name all three samplers and the README to say the cache sampler runs every 15 minutes. Rewrite the disks layout comment to match per_row = n (no wrapping), drop the stale "seventeenth bar" note, and record in the spec that the cache age marker is deliberately deferred with the epoch-line upgrade path.
2026-09-17fix: stop the widgets from stalling or raising the drawDanilo M.6-14/+33
Memoize hwmon_dir by chip name so sensor reads no longer popen grep on every frame, cache misses included. Floor fractional byte counts in card.human so it cannot raise. Drop the GPU package-temperature row, which duplicated the headline. Set umask before mkdir in both samplers so a fresh cache directory is not world-readable. Make render.lua exit non-zero on a draw error and tolerate an unset HOME.
2026-09-17docs: document the system widgetsDanilo M.1-0/+94
2026-09-17fix: adjust the system cards against the screenshotsDanilo M.2-4/+4
2026-09-17feat: add the disks and cache cardsDanilo M.4-0/+204
disks draws a ring per filesystem from the df sample, with the NFS server address read from the device field and a labelled-bar fallback when the rings would be too small to read. cache shows the ~/.cache total and its four largest children from the du sample. card.ring now resets the cairo path first: a preceding card.text() leaves a current point, and cairo_arc() joins to it with a straight line, so the disks rings were drawn with stray chords. The ring primitive had no caller until now, which is why it went unnoticed.
2026-09-17feat: add the GPU cardDanilo M.2-0/+74
2026-09-17feat: add the system card with a per-core equaliserDanilo M.2-0/+112
2026-09-17feat: add bar, vbar, ring and threshold primitivesDanilo M.1-0/+91
2026-09-17feat: add the disks and cache samplersDanilo M.3-1/+74