From 603a1a2455f6a0387407e1017e42aa7415a147a5 Mon Sep 17 00:00:00 2001 From: AlexMnrs <10886760+AlexMnrs@users.noreply.github.com> Date: Mon, 24 Aug 2026 18:00:27 +0200 Subject: [PATCH 1/8] feat: add GitHub Activity plugin --- github-activity/README.md | 70 +++++ github-activity/lib/activity.luau | 378 +++++++++++++++++++++++++++ github-activity/panel.luau | 276 +++++++++++++++++++ github-activity/plugin.toml | 28 ++ github-activity/sync.luau | 212 +++++++++++++++ github-activity/thumbnail.webp | Bin 0 -> 28918 bytes github-activity/translations/en.json | 42 +++ github-activity/widget.luau | 60 +++++ 8 files changed, 1066 insertions(+) create mode 100644 github-activity/README.md create mode 100644 github-activity/lib/activity.luau create mode 100644 github-activity/panel.luau create mode 100644 github-activity/plugin.toml create mode 100644 github-activity/sync.luau create mode 100644 github-activity/thumbnail.webp create mode 100644 github-activity/translations/en.json create mode 100644 github-activity/widget.luau diff --git a/github-activity/README.md b/github-activity/README.md new file mode 100644 index 00000000..d6ec29d1 --- /dev/null +++ b/github-activity/README.md @@ -0,0 +1,70 @@ +# GitHub Activity + +A native GitHub contribution calendar for the Noctalia v5 bar. It displays +today's contributions in a compact widget and opens an adaptive, theme-aware +annual heatmap on click. + +## Plugin + +| Field | Value | +| --- | --- | +| Plugin ID | `alexmnrs/github-activity` | +| Entries | Bar widget: `activity`; panel: `calendar`; service: `sync` | +| Minimum Noctalia plugin API | `24` (Noctalia v5.0.0-beta.9) | + +## Requirements + +- [GitHub CLI](https://cli.github.com/) (`gh`), authenticated with the account + whose activity you want to display. +- `xdg-open` (`xdg-utils` on Arch) to open the profile button. + +Authenticate once before enabling the plugin: + +```bash +gh auth login -h github.com +``` + +## Usage + +1. Enable **GitHub Activity** in Noctalia's plugin manager. +2. Add the `activity` widget to a bar from the widget picker. +3. Left-click the widget to open the annual calendar. +4. Right-click the widget or use the panel's refresh button to refresh now. + +The panel can also be toggled through IPC: + +```bash +noctalia msg panel-toggle alexmnrs/github-activity:calendar +``` + +Request a refresh externally with: + +```bash +noctalia msg plugin alexmnrs/github-activity:sync all refresh +``` + +## Data and privacy + +The plugin runs `gh api graphql` to request the authenticated account's +`contributionCalendar`. It never reads, writes, or displays a GitHub token. +Authentication remains entirely inside GitHub CLI. + +The latest successful normalized calendar is cached in Noctalia's per-plugin +data directory. The cache contains the public contribution dates, counts, +levels, username, and fetch time; it contains no credentials. It lets the +widget continue to show the last known activity when offline. + +## Troubleshooting + +- **GitHub CLI is required:** install `github-cli` (or your distribution's + `gh` package). +- **GitHub CLI needs authentication:** run `gh auth login -h github.com`. +- **No data after a refresh:** run `gh auth status` in a terminal, then retry. +- **The profile button does nothing:** install `xdg-utils` so `xdg-open` is + available. + +## Compatibility + +Noctalia v5's plugin API is beta and can change before the stable release. This +plugin targets API 24 and uses Noctalia's declarative panel and shared-state +APIs only. diff --git a/github-activity/lib/activity.luau b/github-activity/lib/activity.luau new file mode 100644 index 00000000..8c3dd2d4 --- /dev/null +++ b/github-activity/lib/activity.luau @@ -0,0 +1,378 @@ +--!nonstrict + +local Activity = {} + +local levelByName = { + NONE = 0, + FIRST_QUARTILE = 1, + SECOND_QUARTILE = 2, + THIRD_QUARTILE = 3, + FOURTH_QUARTILE = 4, +} + +local colorByLevel = { + "surface_variant", + "primary/0.25", + "primary/0.45", + "primary/0.70", + "primary", +} + +function Activity.level(value) + if type(value) == "number" then + return math.clamp(math.floor(value), 0, 4) + end + + return levelByName[value] or 0 +end + +function Activity.color(level) + return colorByLevel[Activity.level(level) + 1] +end + +function Activity.symbol(level) + local symbols = { "·", "░", "▒", "▓", "█" } + return symbols[Activity.level(level) + 1] +end + +function Activity.levelForSymbol(symbol) + local levels = { + ["·"] = 0, + ["░"] = 1, + ["▒"] = 2, + ["▓"] = 3, + ["█"] = 4, + } + + return levels[symbol] or 0 +end + +function Activity.rowLevels(row) + local levels = {} + local byCodepoint = { + [0x00B7] = 0, + [0x2591] = 1, + [0x2592] = 2, + [0x2593] = 3, + [0x2588] = 4, + } + for _, codepoint in utf8.codes(row or "") do + table.insert(levels, byCodepoint[codepoint] or 0) + end + return levels +end + +function Activity.heatmapSvg(rows, dark) + local colors = dark + and { "#252a33", "#283f68", "#355b94", "#4b7dc5", "#72a7ec" } + or { "#e2e7ef", "#bdd4ed", "#82b4e2", "#468dcc", "#1769aa" } + local fragments = { + '', + } + + local levelRows = {} + local columnCount = 0 + for day = 1, 7 do + local levels = Activity.rowLevels((rows or {})[day]) + levelRows[day] = levels + columnCount = math.max(columnCount, #levels) + end + + local date = os.date("*t") + local monthNames = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } + local firstMonth = date.month - 11 + local textColor = dark and "#c6cbd4" or "#414750" + for offset = 0, 11 do + local month = ((firstMonth + offset - 1) % 12) + 1 + local week = math.floor(offset * math.max(1, columnCount - 1) / 11) + table.insert(fragments, + '' .. monthNames[month] .. "") + end + + for _, label in ipairs({ { "Mon", 1 }, { "Wed", 3 }, { "Fri", 5 } }) do + table.insert(fragments, + '' .. label[1] .. "") + end + + local paths = { {}, {}, {}, {}, {} } + for day = 1, 7 do + for week, level in ipairs(levelRows[day]) do + table.insert(paths[level + 1], "M" .. tostring(45 + (week - 1) * 10) + .. " " .. tostring(24 + (day - 1) * 13) .. "h8v8h-8z") + end + end + + for level = 1, 5 do + table.insert(fragments, '') + end + + table.insert(fragments, "") + return table.concat(fragments) +end + +function Activity.flatten(weeks) + local days = {} + + for _, week in ipairs(weeks or {}) do + for _, day in ipairs(week.days or {}) do + table.insert(days, day) + end + end + + return days +end + +function Activity.streaks(days, todayDate) + local best = 0 + local running = 0 + + for _, day in ipairs(days or {}) do + if (day.count or 0) > 0 then + running = running + 1 + best = math.max(best, running) + else + running = 0 + end + end + + local endIndex = nil + for index = #days, 1, -1 do + if days[index].date <= todayDate then + endIndex = index + break + end + end + + if endIndex == nil then + return 0, best + end + + -- A day that has not happened yet is irrelevant. If today is empty, retain + -- yesterday's active streak rather than resetting it early in the morning. + if days[endIndex].date == todayDate and (days[endIndex].count or 0) == 0 then + endIndex = endIndex - 1 + end + + local current = 0 + for index = endIndex, 1, -1 do + if (days[index].count or 0) == 0 then + break + end + current = current + 1 + end + + return current, best +end + +function Activity.countStreaks(counts, todayIndex) + local best = 0 + local running = 0 + for _, count in ipairs(counts or {}) do + if count > 0 then + running = running + 1 + best = math.max(best, running) + else + running = 0 + end + end + + if todayIndex == nil then + return 0, best + end + + local endIndex = todayIndex + if (counts[endIndex] or 0) == 0 then + endIndex = endIndex - 1 + end + + local current = 0 + for index = endIndex, 1, -1 do + if (counts[index] or 0) == 0 then + break + end + current = current + 1 + end + + return current, best +end + +function Activity.normalize(payload, todayDate) + local viewer = payload + and payload.data + and payload.data.viewer + local calendar = viewer + and viewer.contributionsCollection + and viewer.contributionsCollection.contributionCalendar + + if type(viewer) ~= "table" or type(calendar) ~= "table" then + return nil, "missing contribution calendar" + end + + if type(viewer.login) ~= "string" + or type(calendar.weeks) ~= "table" + or type(calendar.totalContributions) ~= "number" then + return nil, "invalid contribution calendar" + end + + local weeks = {} + for _, sourceWeek in ipairs(calendar.weeks) do + if type(sourceWeek.contributionDays) ~= "table" then + return nil, "invalid contribution week" + end + + local week = { days = {} } + for _, sourceDay in ipairs(sourceWeek.contributionDays) do + if type(sourceDay.date) ~= "string" or type(sourceDay.contributionCount) ~= "number" then + return nil, "invalid contribution day" + end + + table.insert(week.days, { + date = sourceDay.date, + count = math.max(0, math.floor(sourceDay.contributionCount)), + level = Activity.level(sourceDay.contributionLevel), + }) + end + table.insert(weeks, week) + end + + local days = Activity.flatten(weeks) + local today = 0 + for _, day in ipairs(days) do + if day.date == todayDate then + today = day.count + break + end + end + + local currentStreak, bestStreak = Activity.streaks(days, todayDate) + return { + login = viewer.login, + total = math.max(0, math.floor(calendar.totalContributions)), + weeks = weeks, + today = today, + currentStreak = currentStreak, + bestStreak = bestStreak, + fetchedAt = os.time(), + } +end + +function Activity.normalizeText(output, todayDate) + local header, body = string.match(output or "", "^([^\n]+)\n(.*)$") + if header == nil or body == nil then + return nil, "missing contribution header" + end + + local login, totalText = string.match(header, "^([^\t]+)\t(%d+)$") + if login == nil or totalText == nil then + return nil, "invalid contribution header" + end + + local rows = { "", "", "", "", "", "", "" } + local counts = {} + local todayIndex = nil + local today = 0 + local weekDay = 0 + local dayCount = 0 + + for line in string.gmatch(body, "[^\n]+") do + if line == "WEEK" then + weekDay = 0 + else + local date, countText, level = string.match(line, "^([^\t]+)\t(%d+)\t([^\t]+)$") + if date == nil then + return nil, "invalid contribution day" + end + + local count = tonumber(countText) + if count == nil then + return nil, "invalid contribution count" + end + + weekDay = weekDay + 1 + dayCount = dayCount + 1 + rows[weekDay] = rows[weekDay] .. Activity.symbol(level) + counts[dayCount] = count + if date == todayDate then + todayIndex = dayCount + today = count + end + end + end + + if dayCount == 0 then + return nil, "empty contribution calendar" + end + + local currentStreak, bestStreak = Activity.countStreaks(counts, todayIndex) + return { + login = login, + total = tonumber(totalText), + rows = rows, + details = data.details or {}, + today = today, + todayDate = todayDate, + currentStreak = currentStreak, + bestStreak = bestStreak, + fetchedAt = os.time(), + } +end + +-- Convert caches written by the first MVP build (which stored all 371 days) +-- into the compact representation used by the CPU-safe panel. +function Activity.compact(data, todayDate) + if type(data) ~= "table" then + return nil + end + + if type(data.rows) == "table" then + return data + end + + if type(data.weeks) ~= "table" + or type(data.login) ~= "string" + or type(data.total) ~= "number" then + return nil + end + + local rows = { "", "", "", "", "", "", "" } + for _, week in ipairs(data.weeks) do + if type(week) ~= "table" or type(week.days) ~= "table" then + return nil + end + + for index = 1, 7 do + local day = week.days[index] + if day ~= nil then + rows[index] = rows[index] .. Activity.symbol(day.level) + end + end + end + + return { + login = data.login, + total = data.total, + rows = rows, + today = data.today or 0, + todayDate = data.todayDate or todayDate or os.date("%Y-%m-%d"), + currentStreak = data.currentStreak or 0, + bestStreak = data.bestStreak or 0, + fetchedAt = data.fetchedAt or os.time(), + } +end + +function Activity.isValidCache(data) + return type(data) == "table" + and type(data.login) == "string" + and type(data.total) == "number" + and type(data.rows) == "table" + and (data.details == nil or type(data.details) == "table") + and type(data.today) == "number" + and type(data.todayDate) == "string" + and type(data.currentStreak) == "number" + and type(data.bestStreak) == "number" + and type(data.fetchedAt) == "number" +end + +return Activity diff --git a/github-activity/panel.luau b/github-activity/panel.luau new file mode 100644 index 00000000..f894f109 --- /dev/null +++ b/github-activity/panel.luau @@ -0,0 +1,276 @@ +--!nonstrict + +local Activity = require("./lib/activity.luau") + +local data = noctalia.state.get("data") +local status = noctalia.state.get("status") or "loading" +local stale = noctalia.state.get("stale") == true +local detail = noctalia.state.get("error") or "" +local selectedDate = nil +local selectedByKey = {} +local cachedHeatmap = nil +local gridColumns = {} +local gridLevels = {} +local gridDetails = {} +local gridWeek = 1 +local gridWeekCount = 0 +local gridPreparingDay = 1 +local gridReady = false +local open = false +local tr = noctalia.tr +local cellColors = { "surface_variant", "primary/0.25", "primary/0.45", "primary/0.70", "primary" } + +local function requestRefresh() + noctalia.state.set("refresh_request", noctalia.nowMs()) +end + +local function splitTabs(value) + local fields = {} + for field in string.gmatch((value or "") .. "\t", "(.-)\t") do + table.insert(fields, field) + end + return fields +end + +local function resetGrid(source) + cachedHeatmap = nil + gridColumns = {} + gridLevels = {} + gridDetails = {} + selectedByKey = {} + selectedDate = nil + gridWeek = 1 + gridPreparingDay = 1 + gridReady = source ~= nil and type(source.rows) == "table" + gridWeekCount = 0 +end + +local function prepareGridDay() + if not gridReady or data == nil or gridPreparingDay > 7 then + return + end + + local day = gridPreparingDay + gridLevels[day] = Activity.rowLevels(data.rows[day]) + gridDetails[day] = splitTabs((data.details or {})[day]) + gridWeekCount = math.max(gridWeekCount, #gridLevels[day]) + gridPreparingDay = gridPreparingDay + 1 +end + +local function prepareGridColumns() + if not gridReady or gridPreparingDay <= 7 then + return + end + + -- One native week per tick keeps every callback well below Noctalia's Luau + -- budget. The completed tree is otherwise identical to the original UI. + local lastWeek = math.min(gridWeek, gridWeekCount) + while gridWeek <= lastWeek do + local cells = {} + for day = 1, 7 do + local rawDetail = gridDetails[day][gridWeek] or "" + local date, countText = string.match(rawDetail, "^([^|]+)|(%d+)$") + if date ~= nil then + local key = "day-" .. date + selectedByKey[key] = { date = date, count = tonumber(countText) or 0 } + table.insert(cells, ui.box({ + key = key, + fill = cellColors[(gridLevels[day][gridWeek] or 0) + 1], + radius = 2, + width = 11, + height = 11, + onHover = "onDayHover", + })) + end + end + table.insert(gridColumns, ui.column({ key = "week-" .. tostring(gridWeek), gap = 2, align = "center" }, cells)) + gridWeek = gridWeek + 1 + end + + if gridWeek > gridWeekCount then + cachedHeatmap = ui.row({ gap = 1, align = "start" }, gridColumns) + end +end + +resetGrid(data) + +local function selectedDay() + if selectedDate == nil then + return nil + end + return selectedByKey["day-" .. selectedDate] +end + +local function metric(label, value) + return ui.column({ gap = 2, align = "center", flexGrow = 1 }, { + ui.label({ text = label, fontSize = 10, color = "on_surface_variant" }), + ui.label({ text = tostring(value), fontSize = 20, fontWeight = "bold" }), + }) +end + +local function statusText() + if status == "loading" then + return data ~= nil and tr("status.refreshing") or tr("status.loading") + elseif status == "stale" then + return tr("status.stale") + elseif status == "missing_gh" then + return tr("status.missing_gh") + elseif status == "auth_error" then + return tr("status.auth_error") + elseif status == "request_error" then + return tr("status.request_error") + elseif status == "invalid_response" then + return tr("status.invalid_response") + end + + return stale and tr("status.stale") or "" +end + +function render() + local body = { + ui.row({ align = "center", gap = 10 }, { + ui.glyph({ name = "brand-github", size = 19, color = "primary" }), + ui.label({ text = tr("panel.title"), fontSize = 17, fontWeight = "bold", flexGrow = 1 }), + ui.button({ glyph = "refresh", variant = "ghost", tooltip = tr("action.refresh"), onClick = "onRefreshClicked" }), + ui.button({ glyph = "x", variant = "ghost", tooltip = tr("action.close"), onClick = "onCloseClicked" }), + }), + } + + local message = statusText() + if message ~= "" then + table.insert(body, ui.label({ text = message, fontSize = 11, color = status == "ready" and "on_surface_variant" or "primary", maxLines = 2 })) + end + + if data == nil or cachedHeatmap == nil then + local emptyText = data ~= nil and "Preparing interactive calendar…" + or (detail ~= "" and statusText() or tr("status.no_data")) + table.insert(body, ui.spacer({ flexGrow = 1 })) + table.insert(body, ui.column({ gap = 12, align = "center" }, { + ui.glyph({ name = "brand-github", size = 36, color = "on_surface_variant" }), + ui.label({ text = emptyText, maxWidth = 520, textAlign = "center" }), + ui.button({ text = tr("action.try_again"), glyph = "refresh", variant = "primary", onClick = "onRefreshClicked" }), + })) + else + table.insert(body, ui.label({ text = tr("panel.year_total", { login = data.login, count = data.total }), fontSize = 12, color = "on_surface_variant" })) + table.insert(body, ui.row({ justify = "center", align = "start" }, { cachedHeatmap })) + + local day = selectedDay() + local selectedText = day ~= nil + and tr("panel.day_total", { date = day.date, count = day.count }) + or "Hover a day to inspect its activity." + table.insert(body, ui.label({ text = selectedText, fontSize = 11, color = "on_surface_variant", textAlign = "center" })) + table.insert(body, ui.separator({ spacing = 2 })) + table.insert(body, ui.row({ gap = 8, align = "center" }, { + metric(tr("metric.today"), data.today), + metric(tr("metric.current_streak"), tr("metric.days", { count = data.currentStreak })), + metric(tr("metric.best_streak"), tr("metric.days", { count = data.bestStreak })), + })) + table.insert(body, ui.row({ justify = "end" }, { + ui.button({ text = tr("action.open_profile"), glyph = "external-link", variant = "outline", onClick = "onOpenProfile" }), + })) + end + + panel.render(ui.column({ gap = 12, padding = 20, fill = "surface" }, body)) +end + +function onDayHover(hovered, key) + if hovered == "true" then + local day = selectedByKey[key] + if day ~= nil then + selectedDate = day.date + render() + end + elseif selectedDate ~= nil and key == "day-" .. selectedDate then + selectedDate = nil + render() + end +end + +function onOpen(_context) + open = true + if data ~= nil and cachedHeatmap == nil then + -- Panels only receive fast ticks after explicitly opting into frame ticks. + -- This lets us build the original native, hoverable cell tree safely. + panel.setWantsSecondTicks(true) + panel.setNeedsFrameTick(true) + end + render() +end + +function onClose() + open = false +end + +function onRefreshClicked() + requestRefresh() +end + +function onCloseClicked() + panel.close() +end + +function onOpenProfile() + if data == nil then + return + end + if not noctalia.commandExists("xdg-open") then + noctalia.notifyError(tr("panel.title"), tr("status.missing_xdg_open")) + return + end + noctalia.runAsync({ "xdg-open", "https://github.com/" .. data.login }) +end + +local function rerender(valueName, value) + if valueName == "data" then + data = value + resetGrid(data) + if open and data ~= nil then + panel.setWantsSecondTicks(true) + panel.setNeedsFrameTick(true) + end + elseif valueName == "status" then + status = value or "loading" + elseif valueName == "stale" then + stale = value == true + elseif valueName == "error" then + detail = value or "" + end + if open then + render() + end +end + +local function advanceGrid() + if not gridReady or cachedHeatmap ~= nil then + return + end + + if gridPreparingDay <= 7 then + prepareGridDay() + return + end + + prepareGridColumns() + if cachedHeatmap ~= nil then + panel.setWantsSecondTicks(false) + panel.setNeedsFrameTick(false) + if open then + render() + end + end +end + +function onFrameTick(_deltaMs) + advanceGrid() +end + +function update() + -- Fallback for a compositor that coalesces frame callbacks while a panel is + -- attached. Frame ticks normally complete this in about one second. + advanceGrid() +end + +noctalia.state.watch("data", function(value) rerender("data", value) end) +noctalia.state.watch("status", function(value) rerender("status", value) end) +noctalia.state.watch("stale", function(value) rerender("stale", value) end) +noctalia.state.watch("error", function(value) rerender("error", value) end) diff --git a/github-activity/plugin.toml b/github-activity/plugin.toml new file mode 100644 index 00000000..ad9751c0 --- /dev/null +++ b/github-activity/plugin.toml @@ -0,0 +1,28 @@ +id = "alexmnrs/github-activity" +name = "GitHub Activity" +version = "1.0.0" +plugin_api = 24 +author = "AlexMnrs" +license = "MIT" +icon = "brand-github" +description = "A native GitHub contribution calendar for your Noctalia bar." +tags = ["bar", "panel", "service", "development", "productivity", "utility", "network", "hyprland", "arch"] +dependencies = ["gh", "xdg-open"] + +[[widget]] +id = "activity" +entry = "widget.luau" + +[[panel]] +id = "calendar" +entry = "panel.luau" +width = 680 +height = 360 +placement = "attached" +position = "auto" +open_near_click = true +dismiss_on_outside_click = true + +[[service]] +id = "sync" +entry = "sync.luau" diff --git a/github-activity/sync.luau b/github-activity/sync.luau new file mode 100644 index 00000000..824fdbf7 --- /dev/null +++ b/github-activity/sync.luau @@ -0,0 +1,212 @@ +--!nonstrict + +local Activity = require("./lib/activity.luau") + +local QUERY = [[ +query { + viewer { + login + contributionsCollection { + contributionCalendar { + totalContributions + weeks { + contributionDays { + date + contributionCount + contributionLevel + } + } + } + } + } +} +]] + +local JQ_QUERY = [=[ +def sym: + if . == "NONE" then "·" + elif . == "FIRST_QUARTILE" then "░" + elif . == "SECOND_QUARTILE" then "▒" + elif . == "THIRD_QUARTILE" then "▓" + else "█" + end; +def maxrun: + reduce .[] as $value + ({ current: 0, maximum: 0 }; + if $value > 0 + then .current += 1 | .maximum = ([.maximum, .current] | max) + else .current = 0 + end + ) | .maximum; +def suffixrun: + reduce .[] as $value + ({ running: 0, stopped: false }; + if .stopped + then . + elif $value > 0 + then .running += 1 + else .stopped = true + end + ) | .running; + +(.data.viewer.contributionsCollection.contributionCalendar) as $calendar +| $calendar.weeks as $weeks +| [$weeks[] | .contributionDays[]] as $days +| (now | strftime("%Y-%m-%d")) as $today +| ([$days[] | .date] | index($today)) as $todayIndex +| (if $todayIndex == null + then null + elif $days[$todayIndex].contributionCount == 0 + then $todayIndex - 1 + else $todayIndex + end) as $streakEnd +| (if $streakEnd == null or $streakEnd < 0 + then 0 + else [range(0; $streakEnd + 1) as $offset + | $days[$streakEnd - $offset].contributionCount] | suffixrun + end) as $currentStreak +| ([$days[] | .contributionCount] | maxrun) as $bestStreak +| ([range(0; 7) as $day + | [$weeks[] + | ((.contributionDays | .[$day] | .contributionLevel // "NONE") | sym)] + | join("")]) as $rows +| ([range(0; 7) as $day + | [$weeks[] + | (.contributionDays | .[$day] // null) + | if . == null then "" else "\(.date)|\(.contributionCount)" end] + | join("\t")]) as $details +| { + login: .data.viewer.login, + total: $calendar.totalContributions, + rows: $rows, + details: $details, + today: (if $todayIndex == null then 0 else $days[$todayIndex].contributionCount end), + todayDate: $today, + currentStreak: $currentStreak, + bestStreak: $bestStreak, + fetchedAt: now + } +]=] + +local REFRESH_INTERVAL_MS = 30 * 60 * 1000 +local cachePath = nil +local inFlight = false + +local function todayDate() + return os.date("%Y-%m-%d") +end + +local function publish(status, detail) + noctalia.state.set("status", status) + noctalia.state.set("error", detail or "") +end + +local function initialiseCache() + local dataDir, error = noctalia.pluginDataDir() + if dataDir == nil then + noctalia.log("GitHub Activity could not create its data directory: " .. tostring(error)) + return + end + + cachePath = dataDir .. "/activity.json" + local contents, readError = noctalia.readFile(cachePath) + if contents == nil then + if readError ~= nil then + noctalia.log("GitHub Activity cache is unavailable: " .. tostring(readError)) + end + return + end + + local cached, decodeError = noctalia.json.decode(contents) + cached = Activity.compact(cached, todayDate()) + if cached == nil or not Activity.isValidCache(cached) then + noctalia.log("GitHub Activity ignored an invalid cache: " .. tostring(decodeError or "unexpected data")) + return + end + + noctalia.state.set("data", cached) + noctalia.state.set("stale", true) + publish("stale") +end + +local function persist(data) + if cachePath == nil then + return + end + + local encoded, encodeError = noctalia.json.encode(data) + if encoded == nil then + noctalia.log("GitHub Activity could not encode its cache: " .. tostring(encodeError)) + return + end + + local ok, writeError = noctalia.writeFile(cachePath, encoded) + if not ok then + noctalia.log("GitHub Activity could not write its cache: " .. tostring(writeError)) + end +end + +local function failure(status, detail) + inFlight = false + noctalia.state.set("stale", noctalia.state.get("data") ~= nil) + publish(status, detail) +end + +local function refresh() + if inFlight then + return + end + + if not noctalia.commandExists("gh") then + failure("missing_gh", "GitHub CLI (gh) is not installed.") + return + end + + inFlight = true + publish("loading") + noctalia.runAsync({ "gh", "api", "graphql", "--jq", JQ_QUERY, "-f", "query=" .. QUERY }, function(result) + if result.exitCode ~= 0 then + local message = string.lower(result.stderr or "") + if string.find(message, "auth", 1, true) or string.find(message, "token", 1, true) then + failure("auth_error", "Run gh auth login -h github.com to authenticate GitHub CLI.") + else + failure("request_error", "GitHub CLI could not fetch contribution data.") + end + return + end + + local data, decodeError = noctalia.json.decode(result.stdout or "") + if data == nil or not Activity.isValidCache(data) then + failure("invalid_response", "GitHub returned an unexpected contribution calendar: " .. tostring(decodeError or "invalid normalized data")) + return + end + + inFlight = false + persist(data) + noctalia.state.set("data", data) + noctalia.state.set("stale", false) + publish("ready") + end) +end + +noctalia.setUpdateInterval(REFRESH_INTERVAL_MS) +initialiseCache() +refresh() + +noctalia.state.watch("refresh_request", function(_value) + refresh() +end) + +function update() + refresh() +end + +function onEnable() + refresh() +end + +function onIpc(event, _payload) + if event == "refresh" then + refresh() + end +end diff --git a/github-activity/thumbnail.webp b/github-activity/thumbnail.webp new file mode 100644 index 0000000000000000000000000000000000000000..73837a0bad54e3a4cee1267aa3389c6c9299d888 GIT binary patch literal 28918 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 VSz505g1(JdH%N9J-4n^X002KLdoTb1 literal 0 HcmV?d00001 diff --git a/github-activity/translations/en.json b/github-activity/translations/en.json new file mode 100644 index 00000000..18ec9da8 --- /dev/null +++ b/github-activity/translations/en.json @@ -0,0 +1,42 @@ +{ + "plugin": { + "name": "GitHub Activity", + "description": "A native GitHub contribution calendar for your Noctalia bar." + }, + "widget": { + "tooltip": "{login}\\nToday: {today} contributions\\nCurrent streak: {streak} days\\n{freshness}", + "cached": "Cached data", + "up_to_date": "Up to date" + }, + "panel": { + "title": "GitHub Activity", + "year_total": "{login} · {count} contributions in the last year", + "day_total": "{date} · {count} contributions", + "hover_day": "Hover a day to inspect its activity.", + "no_today": "Today's contribution is not in the returned calendar." + }, + "metric": { + "today": "Today", + "current_streak": "Current streak", + "best_streak": "Best streak", + "days": "{count} days" + }, + "action": { + "refresh": "Refresh", + "close": "Close", + "try_again": "Try again", + "open_profile": "Open profile" + }, + "status": { + "loading": "Loading contribution data…", + "refreshing": "Refreshing contribution data…", + "stale": "Showing cached contribution data.", + "missing_gh": "GitHub CLI (gh) is required to load activity.", + "auth_error": "GitHub CLI needs authentication: gh auth login -h github.com", + "request_error": "GitHub Activity could not reach GitHub.", + "invalid_response": "GitHub returned an unexpected contribution calendar.", + "unavailable": "GitHub activity is unavailable.", + "no_data": "No contribution data is available yet.", + "missing_xdg_open": "xdg-open is required to open your profile." + } +} diff --git a/github-activity/widget.luau b/github-activity/widget.luau new file mode 100644 index 00000000..debd9b11 --- /dev/null +++ b/github-activity/widget.luau @@ -0,0 +1,60 @@ +--!nonstrict + +local data = noctalia.state.get("data") +local status = noctalia.state.get("status") or "loading" +local stale = noctalia.state.get("stale") == true +local tr = noctalia.tr + +local function tooltip() + if data ~= nil then + local freshness = stale and tr("widget.cached") or tr("widget.up_to_date") + return tr("widget.tooltip", { + login = data.login, + today = data.today, + streak = data.currentStreak, + freshness = freshness, + }) + end + + if status == "missing_gh" then + return tr("status.missing_gh") + elseif status == "auth_error" then + return tr("status.auth_error") + elseif status == "request_error" or status == "invalid_response" then + return tr("status.unavailable") + end + + return tr("status.loading") +end + +local function render() + barWidget.setGlyph("brand-github") + barWidget.setText(data ~= nil and tostring(data.today) or "—") + barWidget.setTooltip(tooltip()) + barWidget.setVisible(true) +end + +noctalia.state.watch("data", function(value) + data = value + render() +end) + +noctalia.state.watch("status", function(value) + status = value or "loading" + render() +end) + +noctalia.state.watch("stale", function(value) + stale = value == true + render() +end) + +function onClick() + noctalia.togglePanel("alexmnrs/github-activity:calendar") +end + +function onRightClick() + noctalia.state.set("refresh_request", noctalia.nowMs()) +end + +render() From 57c43707e94f1c2f9f06a6783c1a404e173b70b2 Mon Sep 17 00:00:00 2001 From: AlexMnrs <10886760+AlexMnrs@users.noreply.github.com> Date: Mon, 24 Aug 2026 18:16:56 +0200 Subject: [PATCH 2/8] refine GitHub Activity panel layout --- github-activity/panel.luau | 151 ++++++++++++++++++++++++++++++------ github-activity/plugin.toml | 2 +- 2 files changed, 127 insertions(+), 26 deletions(-) diff --git a/github-activity/panel.luau b/github-activity/panel.luau index f894f109..46ecc1ca 100644 --- a/github-activity/panel.luau +++ b/github-activity/panel.luau @@ -9,6 +9,7 @@ local detail = noctalia.state.get("error") or "" local selectedDate = nil local selectedByKey = {} local cachedHeatmap = nil +local cachedCalendar = nil local gridColumns = {} local gridLevels = {} local gridDetails = {} @@ -19,6 +20,7 @@ local gridReady = false local open = false local tr = noctalia.tr local cellColors = { "surface_variant", "primary/0.25", "primary/0.45", "primary/0.70", "primary" } +local monthNames = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } local function requestRefresh() noctalia.state.set("refresh_request", noctalia.nowMs()) @@ -34,6 +36,7 @@ end local function resetGrid(source) cachedHeatmap = nil + cachedCalendar = nil gridColumns = {} gridLevels = {} gridDetails = {} @@ -45,6 +48,72 @@ local function resetGrid(source) gridWeekCount = 0 end +local function monthForWeek(week) + local preferredDays = { 4, 1, 2, 3, 5, 6, 7 } + for _, day in ipairs(preferredDays) do + local rawDetail = (gridDetails[day] or {})[week] or "" + local date = string.match(rawDetail, "^([^|]+)|") + if date ~= nil then + return tonumber(string.sub(date, 6, 7)) + end + end + return nil +end + +local function buildMonthHeader() + local segments = {} + local segmentMonth = nil + local segmentWeeks = 0 + + local function appendSegment() + if segmentMonth == nil or segmentWeeks == 0 then + return + end + table.insert(segments, ui.column({ + width = segmentWeeks * 11 - 1, + height = 12, + align = "center", + justify = "center", + }, { + ui.label({ + text = segmentWeeks >= 2 and (monthNames[segmentMonth] or "") or "", + fontSize = 9, + color = "on_surface_variant", + textAlign = "center", + }), + })) + end + + for week = 1, gridWeekCount do + local month = monthForWeek(week) + if segmentMonth ~= nil and month ~= segmentMonth then + appendSegment() + segmentWeeks = 0 + end + segmentMonth = month or segmentMonth + segmentWeeks = segmentWeeks + 1 + end + appendSegment() + + return ui.row({ gap = 1, align = "center" }, segments) +end + +local function buildWeekdayLabels() + local names = { "", "Mon", "", "Wed", "", "Fri", "" } + local labels = {} + for day = 1, 7 do + table.insert(labels, ui.label({ + text = names[day], + width = 28, + height = 12, + fontSize = 9, + color = "on_surface_variant", + textAlign = "end", + })) + end + return ui.column({ gap = 3, align = "end" }, labels) +end + local function prepareGridDay() if not gridReady or data == nil or gridPreparingDay > 7 then return @@ -63,7 +132,7 @@ local function prepareGridColumns() end -- One native week per tick keeps every callback well below Noctalia's Luau - -- budget. The completed tree is otherwise identical to the original UI. + -- budget while preserving individual hover targets for every day. local lastWeek = math.min(gridWeek, gridWeekCount) while gridWeek <= lastWeek do local cells = {} @@ -77,18 +146,25 @@ local function prepareGridColumns() key = key, fill = cellColors[(gridLevels[day][gridWeek] or 0) + 1], radius = 2, - width = 11, - height = 11, + width = 10, + height = 12, onHover = "onDayHover", })) end end - table.insert(gridColumns, ui.column({ key = "week-" .. tostring(gridWeek), gap = 2, align = "center" }, cells)) + table.insert(gridColumns, ui.column({ key = "week-" .. tostring(gridWeek), gap = 3, align = "center" }, cells)) gridWeek = gridWeek + 1 end if gridWeek > gridWeekCount then cachedHeatmap = ui.row({ gap = 1, align = "start" }, gridColumns) + cachedCalendar = ui.row({ gap = 8, align = "end", justify = "center" }, { + buildWeekdayLabels(), + ui.column({ gap = 6, align = "start" }, { + buildMonthHeader(), + cachedHeatmap, + }), + }) end end @@ -101,10 +177,24 @@ local function selectedDay() return selectedByKey["day-" .. selectedDate] end -local function metric(label, value) - return ui.column({ gap = 2, align = "center", flexGrow = 1 }, { - ui.label({ text = label, fontSize = 10, color = "on_surface_variant" }), - ui.label({ text = tostring(value), fontSize = 20, fontWeight = "bold" }), +local function activityBlocks(filled, total) + local blocks = {} + for index = 1, total do + table.insert(blocks, ui.box({ + width = 9, + height = 9, + radius = 2, + fill = index <= filled and "primary" or "surface_variant", + })) + end + return ui.row({ gap = 3, align = "center", justify = "center" }, blocks) +end + +local function metric(label, value, visual) + return ui.column({ gap = 6, align = "center", flexGrow = 1 }, { + ui.label({ text = label, fontSize = 11, color = "on_surface_variant" }), + ui.label({ text = tostring(value), fontSize = 22, fontWeight = "bold" }), + visual, }) end @@ -127,21 +217,22 @@ local function statusText() end function render() - local body = { - ui.row({ align = "center", gap = 10 }, { - ui.glyph({ name = "brand-github", size = 19, color = "primary" }), - ui.label({ text = tr("panel.title"), fontSize = 17, fontWeight = "bold", flexGrow = 1 }), + local root = { + ui.row({ align = "center", gap = 12, paddingH = 18, paddingV = 10 }, { + ui.glyph({ name = "brand-github", size = 25, color = "on_surface" }), + ui.label({ text = tr("panel.title"), fontSize = 18, fontWeight = "bold", flexGrow = 1 }), ui.button({ glyph = "refresh", variant = "ghost", tooltip = tr("action.refresh"), onClick = "onRefreshClicked" }), - ui.button({ glyph = "x", variant = "ghost", tooltip = tr("action.close"), onClick = "onCloseClicked" }), }), + ui.separator({ thickness = 1, color = "outline/0.35" }), } + local body = {} local message = statusText() if message ~= "" then table.insert(body, ui.label({ text = message, fontSize = 11, color = status == "ready" and "on_surface_variant" or "primary", maxLines = 2 })) end - if data == nil or cachedHeatmap == nil then + if data == nil or cachedCalendar == nil then local emptyText = data ~= nil and "Preparing interactive calendar…" or (detail ~= "" and statusText() or tr("status.no_data")) table.insert(body, ui.spacer({ flexGrow = 1 })) @@ -151,26 +242,36 @@ function render() ui.button({ text = tr("action.try_again"), glyph = "refresh", variant = "primary", onClick = "onRefreshClicked" }), })) else - table.insert(body, ui.label({ text = tr("panel.year_total", { login = data.login, count = data.total }), fontSize = 12, color = "on_surface_variant" })) - table.insert(body, ui.row({ justify = "center", align = "start" }, { cachedHeatmap })) + table.insert(body, cachedCalendar) local day = selectedDay() local selectedText = day ~= nil and tr("panel.day_total", { date = day.date, count = day.count }) - or "Hover a day to inspect its activity." - table.insert(body, ui.label({ text = selectedText, fontSize = 11, color = "on_surface_variant", textAlign = "center" })) - table.insert(body, ui.separator({ spacing = 2 })) - table.insert(body, ui.row({ gap = 8, align = "center" }, { - metric(tr("metric.today"), data.today), - metric(tr("metric.current_streak"), tr("metric.days", { count = data.currentStreak })), - metric(tr("metric.best_streak"), tr("metric.days", { count = data.bestStreak })), + or tr("panel.year_total", { login = data.login, count = data.total }) + table.insert(body, ui.label({ text = selectedText, height = 14, fontSize = 10, color = "on_surface_variant", textAlign = "center" })) + table.insert(body, ui.separator({ thickness = 1, color = "outline/0.35" })) + table.insert(body, ui.row({ gap = 14, align = "stretch" }, { + metric(tr("metric.today"), data.today, activityBlocks(data.today > 0 and 1 or 0, 1)), + ui.separator({ orientation = "vertical", thickness = 1, color = "outline/0.35" }), + metric( + tr("metric.current_streak"), + data.currentStreak, + activityBlocks(math.min(data.currentStreak, 12), math.max(1, math.min(data.currentStreak, 12))) + ), + ui.separator({ orientation = "vertical", thickness = 1, color = "outline/0.35" }), + metric(tr("metric.best_streak"), data.bestStreak, activityBlocks(math.min(data.bestStreak, 12), 12)), })) - table.insert(body, ui.row({ justify = "end" }, { + end + + table.insert(root, ui.column({ gap = 12, paddingH = 18, paddingV = 14, fill = "surface", flexGrow = 1 }, body)) + if data ~= nil and cachedCalendar ~= nil then + table.insert(root, ui.separator({ thickness = 1, color = "outline/0.35" })) + table.insert(root, ui.row({ justify = "end", paddingH = 14, paddingV = 10 }, { ui.button({ text = tr("action.open_profile"), glyph = "external-link", variant = "outline", onClick = "onOpenProfile" }), })) end - panel.render(ui.column({ gap = 12, padding = 20, fill = "surface" }, body)) + panel.render(ui.column({ gap = 0, fill = "surface", flexGrow = 1, align = "stretch" }, root)) end function onDayHover(hovered, key) diff --git a/github-activity/plugin.toml b/github-activity/plugin.toml index ad9751c0..4bf7388e 100644 --- a/github-activity/plugin.toml +++ b/github-activity/plugin.toml @@ -17,7 +17,7 @@ entry = "widget.luau" id = "calendar" entry = "panel.luau" width = 680 -height = 360 +height = 430 placement = "attached" position = "auto" open_near_click = true From 67798afcf4019d31fc2cd614098e45e9ce82b840 Mon Sep 17 00:00:00 2001 From: AlexMnrs <10886760+AlexMnrs@users.noreply.github.com> Date: Mon, 24 Aug 2026 18:21:39 +0200 Subject: [PATCH 3/8] align calendar labels and typography --- github-activity/panel.luau | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/github-activity/panel.luau b/github-activity/panel.luau index 46ecc1ca..1117f6b4 100644 --- a/github-activity/panel.luau +++ b/github-activity/panel.luau @@ -77,7 +77,7 @@ local function buildMonthHeader() }, { ui.label({ text = segmentWeeks >= 2 and (monthNames[segmentMonth] or "") or "", - fontSize = 9, + fontSize = 10, color = "on_surface_variant", textAlign = "center", }), @@ -102,13 +102,18 @@ local function buildWeekdayLabels() local names = { "", "Mon", "", "Wed", "", "Fri", "" } local labels = {} for day = 1, 7 do - table.insert(labels, ui.label({ - text = names[day], - width = 28, + table.insert(labels, ui.column({ + width = 30, height = 12, - fontSize = 9, - color = "on_surface_variant", - textAlign = "end", + align = "end", + justify = "center", + }, { + ui.label({ + text = names[day], + fontSize = 11, + color = "on_surface_variant", + textAlign = "end", + }), })) end return ui.column({ gap = 3, align = "end" }, labels) @@ -158,7 +163,7 @@ local function prepareGridColumns() if gridWeek > gridWeekCount then cachedHeatmap = ui.row({ gap = 1, align = "start" }, gridColumns) - cachedCalendar = ui.row({ gap = 8, align = "end", justify = "center" }, { + cachedCalendar = ui.row({ gap = 10, align = "end", justify = "center" }, { buildWeekdayLabels(), ui.column({ gap = 6, align = "start" }, { buildMonthHeader(), @@ -192,8 +197,8 @@ end local function metric(label, value, visual) return ui.column({ gap = 6, align = "center", flexGrow = 1 }, { - ui.label({ text = label, fontSize = 11, color = "on_surface_variant" }), - ui.label({ text = tostring(value), fontSize = 22, fontWeight = "bold" }), + ui.label({ text = label, fontSize = 12, color = "on_surface_variant" }), + ui.label({ text = tostring(value), fontSize = 25, fontWeight = "bold" }), visual, }) end @@ -220,7 +225,7 @@ function render() local root = { ui.row({ align = "center", gap = 12, paddingH = 18, paddingV = 10 }, { ui.glyph({ name = "brand-github", size = 25, color = "on_surface" }), - ui.label({ text = tr("panel.title"), fontSize = 18, fontWeight = "bold", flexGrow = 1 }), + ui.label({ text = tr("panel.title"), fontSize = 19, fontWeight = "bold", flexGrow = 1 }), ui.button({ glyph = "refresh", variant = "ghost", tooltip = tr("action.refresh"), onClick = "onRefreshClicked" }), }), ui.separator({ thickness = 1, color = "outline/0.35" }), @@ -248,7 +253,7 @@ function render() local selectedText = day ~= nil and tr("panel.day_total", { date = day.date, count = day.count }) or tr("panel.year_total", { login = data.login, count = data.total }) - table.insert(body, ui.label({ text = selectedText, height = 14, fontSize = 10, color = "on_surface_variant", textAlign = "center" })) + table.insert(body, ui.label({ text = selectedText, height = 14, fontSize = 11, color = "on_surface_variant", textAlign = "center" })) table.insert(body, ui.separator({ thickness = 1, color = "outline/0.35" })) table.insert(body, ui.row({ gap = 14, align = "stretch" }, { metric(tr("metric.today"), data.today, activityBlocks(data.today > 0 and 1 or 0, 1)), From 7510952d24bb3b8bfe10718782b7c9c634f367e2 Mon Sep 17 00:00:00 2001 From: AlexMnrs <10886760+AlexMnrs@users.noreply.github.com> Date: Mon, 24 Aug 2026 19:03:31 +0200 Subject: [PATCH 4/8] show GitHub Activity preview in README --- github-activity/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/github-activity/README.md b/github-activity/README.md index d6ec29d1..f6db5685 100644 --- a/github-activity/README.md +++ b/github-activity/README.md @@ -4,6 +4,8 @@ A native GitHub contribution calendar for the Noctalia v5 bar. It displays today's contributions in a compact widget and opens an adaptive, theme-aware annual heatmap on click. +![GitHub Activity panel](thumbnail.webp) + ## Plugin | Field | Value | From 8a8ddbf508284b658dc5a37ac4040affc7d3ec59 Mon Sep 17 00:00:00 2001 From: AlexMnrs <10886760+AlexMnrs@users.noreply.github.com> Date: Tue, 25 Aug 2026 09:20:41 +0200 Subject: [PATCH 5/8] Use generator-exported plugin thumbnail --- github-activity/thumbnail.webp | Bin 28918 -> 59466 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/github-activity/thumbnail.webp b/github-activity/thumbnail.webp index 73837a0bad54e3a4cee1267aa3389c6c9299d888..6970b141c850cf042ef03cf783219f6c864b2151 100644 GIT binary patch literal 59466 zcmaHSW0WO9v+ZfywlUq)_Oxx=wmr?$wrx(^wx_LWP20AO^X9wv$Gtz^dzmYuc1G@1 z8Bw`vt<0<_6=?|xkrMzwQ(QzzLy21p9smH4{*yik00B5aT2xeN4D4SM05G|FGFVOl$eSu*v_zrcN&Z z;m7>r@Y&nB|7WcKl>bDBXzrk{`tJ(+PY40702P2FK;%F1|7-s%jzs_f_aguRk?=n@ zlS}}hEffI2UHcy!WdQ(y5&{6U&i;?>f1Zhxv5WD4-461f2Dh*P0Pe~F03>Yy0OJn; z0I&OBegD+|!#C1@U4;Mqa{N~<0d@d$04YEk-~ccMF#bcV0A>ISfb-uBld2s70I2=o zxnOkt5QN|YaNvPLfj|D4($Yq3tNJXqUwf9dfTL$NEp^(XseM9f+|G;CLnFnUg!(*^ zFO2V?tQ)zzx@(=!2Z($3skqoLtC-E*W>=8Um*s(A2x0W~_L09XDEj&OK;ZH7ao_L; z)VA#-xO!oD3_J(zJhUAtK7n?Cu6+|A&|3?L_lxV5>7L}}%NwW-Vgj*!v|TIy5jMSlIJ*Vv z|LOq+fK0!*uIr}bX||QW(z6UF1y(Zvtn5USIbhpHGrC z!6ne-hwpRM^Y)$LT^~uGPagmn1tR@Q{hWMUcsKmqeh`cRZh?9Z5}&T0x7&a<+d_uJ zz)Yaq*Y=m|`}1?(r=UyU5vU#{`sMS<^}_Vkchj5b-}B}A$@B_($Uo^D1$}~mZx|o0 z|2%QL%s=Rx0@{Oazs|4DSNblF-$5>lODOl-S^0gSkKZ?>n3=^0?0tTz4)5&w+~bx% zBsf6KZUoa>)tNj@UFgiYmm(Jte_76!ig){+B68b-Q{OZo#i+9V>7U<2_DJRA4G4#a zifEd>t(!joSmphB{Z%Ruf-9@6yY|IYJOQ)Igv+d7!H5X08hpjzSK5SE5|urVd9i!z zx?9{ms*EniXX0pvvFGU`TklLfz+^K(4>R3|9hLpJ8hbt&c0KQ63V)fdDyOE!tuwJ> z&jkS8V1+c&5tXjTZpy$hM*oUoIP~3u%J-B8`Gu4@k;RH(2TP*;gNZ2om9fj8 zF1ij(NQOwo##JrJoMRU31(P?tVy}h!#_7bKCF;plPts^%r621zsHG^9<`m&cA^Sr6 zkkB$i-_3f?Ls*7+8{vl6T5r-`Uls8-NV+dhD3MBFIxVA6CtMCC46nt*a3>STLNHAF znK^yfOE7it){TPFR1mq03jgVqZ=S1U#24O&(f}#YM5AqKGL7?a4rB2FCt|!sK(I3m z^z<{~8FPgTYx9^Lc#W_Zm8kY{tRNB9d&Zu)Xic=(^|c@}P$&wH?vXcA!tB1SVy z;B+2XyU9P#h5o__Z3ABi$QKRiH9|PiQz0&xRmPmgC}?|vZBDgipGF)wovM=7{>5TG zIdLK>Qkgm{vXaK4oAq)zsd#h!Qm9^)M9Isg@K>@)Fdv3%=~RYR6hAG3uD%DLIQME? ztts_MWI-25ZM!Ynt#xKuiJXmmAe@Q7pV*%2>Rq+-#$q<9Z#Kiho^4llq$5sqHZ@w- zh^&?@QxeH~N0FC}43EL-pUZ2HN3^GbX!o%9rZ^fdJAYU8*9_uLH}qaKcZUp9Kz_>4 zNMU|#EV7y}^nARI#)A!*)N-4QQI$D8EO$_KHI4I8moC6I*Id_Xh&vQ_@X7GXyV<0& zV~GK=i)VDaT}X-oo9(i&FjstXMu1*mWxAOQQ0 zD1UBlz#SB1d+UB3$4e6=G@5cR&isC+F5INqD`&I`1-)VXVqh8n(HGU!Y%#|FZjJX>@u)lWTuHGK#)6y$OU|Q=@w(aKQ_l8bR7< zIFL1r;ma5Ue|1eD*wEo-7<_PI@;h`bYE2z;0)Xchf}?yAhl5G`g?A8l^87GtWNOq^ zZg#tguGuui7n)8hOL;w9?d*QX*N22i@v@dyMV-3tPP>mT`5Zp5?~$vhO`xBjAcD9m z8WUTZe2Rgqe@Uq`9||U-!%>D#R3eQ13;roeDi!u;y(IpyGpn1Yn{wQpG%>({PNc@Z z5)8$unyq5};sg_$tMBd4#c zI6F-7+|YF#ao%;A@0iBO-vHe+xGS^N=anb$Wvcok-Qv(*^)tE@s9uh3%4 zn%6(H+T+Rz!`O{~XvFj%azdUxvE5+^o-?bA`oC@}!9Ol>ZoD|Mge_byTM!yXOVYQ+@bZA)2PGrf?lNdvbtEEa{rR7tE ze)xy0bmMH#$2a+M7`l-Mb9{7=I>WU(%>H2f4oTUpW$r>11M8RmH=hy95z!%mP{@}N zGq)cJ{~me`9ibFUj?Y3#vW_-*5L?tb+8A=7mE6Q95LVdz+}NARoYHr8rN(*>LAy{P zCBTBS%Y$Dl5Gvv-82{({p!JBta_Hbf9#1uKwNFXWfp4MC{)HU8D9rdbo1@TZ){rXKzP0cg+z#h&n~=+OLI>la&$0fgZnQ}AMQ6ir%WXN zA&b0P7>D-=gc&@w4)H4cdW;!J>-^~c{ zHGS6o88QNfSJ+vKkL$vgdlr9)@*N;4$ECC^@J$}4TxE|^V+ZfgkRL974!G4aM(A90i0%?2nW((>6VhRdMQ%BZUio zr%@|t6s0n1b-0Q&f~HI~nnnG613@D$J~+a5o?7vov27Kt@7)$+l^F5$;{aA1O+7e2 zdzpPV9g+@XyY1wNm7L-y;jdr)2oX`|F^V2%KN?U!jKItP;08<3(eBXtOxpE$=N`Sx zPUQ}oPA?IpJxp>a9*9n1F}pdj?VI^*JPo?|lFtx)Bvl>c^gU#0!*Cp^hxgtFt;}if z&veEfJZef&C9EmxM5(jsU>W+@OQozz^Trkw*wxKU*Di1zs=Q=5z6ax<*cDwu<8>7k zLR=m;AaYjzCE5nlDz_^%ZKK)5qiPk62>q2M^leLzCx{CRL$j$JZ`*C;$UAazdnxQ3 z4D*OM$V|I6N5!`gdeKTvzkFBk_}af@7{0D0>#o?VisgcAl^@U7=bFr%&#`Hc-Pk=f z8rP<={Ght3)rf!|{LwMjp&`xr3@$JL(qLw zB9(n+2$obDQ?CHud!5IQY8W>}(*!!a#ndT3t63M5^ZoEqzceDb3E|ffM}T|sRa=Bl zf5zAWO3gLW-z+hv3SK`=2na?NYkSL0NCma2hY_SHF9j^vlTyUuDp_^?hXl-=aZPRK zcFaZQXX*ofZOpe?zJ2J}pkIkr@68K^iVL1W!Ap$hOmFZjyV>)D(+VDrAvjY^`Vi)p z&-hls&6<;e6EU+%(MLUXZs_(wO<(ohF?!n99M|UXPcyoj7By=fn^?i7+sIUhTlf-D z9XUlIX5V)u?{U-=>@-B1`gkuw?&trwN~C?e#3e=$UlBIuIj5kU$y?j_GZ!Sdwcj_y zhpM&a!isXHDS;%gjV<2a7twq_3xB!8S!%1Zz)aq}akNT6g0d;C=tajvfLF}aV}>mK zb)C8#Vr_kI*zT!HKabSy#7>+#l0)!77QxEAWOfs-$-67Y$PZ1s^jo-Mn#=in4}SKJ zD}15(dDC-WHPffET;1%S4JUseZQ8D@s8@FQO8qE!P9Ke-2!!?#C_tTFE!=5GhliSt zRs>ODN~A!bRAYtxE^8q_?@1S86)~|HQN&A`$42x&zFea}?OvGRv$kQCeObwTYR9p9pCUJO75^m;1 z#ot>p5}5h9Tvha)qUk}xEUDUoEFTlJd(`0%Ke%VKnKUVVYvNv5>LM0;?6K?;-3y+E z%24g-KB)be78GO)1j;JC5?*J&eWljPCD`ux%4(t?3QzYojAW$ce#;i>ei^E+rtb$Q z{6%;=BxV4kAv`mphd`k%Do`CfcsO_f{*d$FhR;sokeEA&xk4s2MPOWD-|b+qkH%PN}682fCPXgtqmAdmQQO zF*v#jp=^)Fk{+u*dqQ|M&!zJVFVT^K+b<7CMl;B8?DnQ}_uwyYF!k}%ye3<|_gSpV zMrCCN!kwaG#jScF_(4S2pX8`RrMKh(eBozz3SOW%T-S$+3{07fNC{P0%Gz!&1Jek( z3JbTNW0_@t;m3L@(+$em`5jG`-gOYg7aB}XDxUPJ+myoGL$7#F02*OZ#dp&-e@I68 zUezd?Iou3F-pIT@sb{=wxr3mtG|@+>Wpj6vDVunO&dt%f3+wr|7bP@V!3+c5>G^JKZoseUd&lUgabcs! zelM6&=D%fu=LtJifPDl0n|(o3ua$-)PI?(AaY(c?W)pC4uOCtm)4W=tw=`1T;P>&T zO9~)*vClHMdZl>dHK_3oNGL_LmQ)0&wN#o*6|X=2vcrv!72F$@)YPa0s7{Io(CLD= zi00>IDlX6dBAZQ7u|SC6R=M}Fg4+Qj&PBjxy1}B8H_&rRQ!O4S#Z{ABO;8E{BgIZb zM_Xc@)0^!<5vlm~Jf)rzeq@dd_C8Hm5Id(pJ))OFNkRNs+*xV}ho#;{4t)G};fa<6 zmAT&1z)518MM0hziI^boh7aSy*7Wi#+}FV~+<4m8lExBz%(w+!= zpNvL<89OPxH(y#M(m)RUgK^*3c7%pTI{f1tI)iOcJAcoO5=NX-!#NC{H@}_(eOL$O z-Sf5EYo*$jtrBWn((RXKDCUuS;TL?O&hpwIsel^yfzilCeV6$euxKUW^-EKlo7vv!%>fqpvylJ^keiN0o>-0m0 zPM-x&3LTNXC$JcUoqK!`No5>|p|4V>Sj-rh^V0ex|Cxw2H}kOx{@iP{UwHG84nAP@ zeTiPK@2;qSv1;sHiUP{m0iyUX+GFr#n>1b6SOGjN+bbOshT3b*%EwSGV= zPGshJ6$z&^R=;^tYtJ-=G`8lYTm$v0khQ*TDsImw>Wj)c2UM(=jGBbJ87kNMlIRMz zuq<`)uv^lNb~T0XJ9Q>=Q!F$@)I(JzRt_YoAN;;*K-0TXb%!@MSc3NsHn=*OM)DU2k7QepB`!m-ER+)wH%RmH3GD=mA!&Yljt54>AhuOcEt$B|4P1Qire$j zL*dkjToYsCi+6utlCed75i+7ls_*1sY*sphU5j7<=VeeqN0=C|1a@#w(Svy|sf}gs z`tXS(ka$)F4T$k~_zRpvC9`6$Ddh@nyw*AuxTdBfwIRfp5ieoB#CAIAcMG}4(FluP z@%-L=SR6G}K^qJZ{<>XHStE^8K~{xMG_Y?)UA9s8naIMickKOuFGu%_d!OJOjixU{ z?$;i)SmCk%T>T*y3r+72pU=pjF-11`jINMyNdnGrS{*1Um8+hh6J$FlwJ5QN!q5rO zPw4n{tR3@0hF5>bdc)&-#c_ejJ?9yK z=u~qE?ybn4EqXm8sY!(_C{bXQSLfL1MY$q*;uhf(wvvF9ELc=1XC%24?B_vm>Cp6# zAT92EqRhX@KK|>PxB@E?dteZKaHPo~VKJ8Z>)6r5evVggdDaN~6z3_OGOW+m5Cg-} zE*kl*VS&41UzADi$!r2~+l8&HDDKWF4+cYpwfucUkQ~rs;wSID`kv0ONIb`FiMPgE zz3cfF5Ic+U7w~P$Budt-jrx^PLdLT9&wCk|Q^;P8E+gHSmI>iX4M+k%hn3&0i2&{ojmE(C5ZP>|G?dvtcOcv>& zu!HekDF$>1FTSAzYsOju0PyvB;>NY~%OeCBDEopL^S~lgnF?<3=}NjsmV62uTy0YN zZ^zRvMlwmw3QXR`^)VKu7rT;QVh3G1=iyy{1;&BTDd&Y{o<})+>$;tka=H^&?QV-9 zT!mkboDsTxut-FE+J7WL*qJ&uPGH&V16u>WWKZV$K-fn}FP0xhxleQcJ}8f@Qj??z zkG^oSsZcJg_Hr$mzD&Kzk}s40q!IRpI3VOXf5=b%u~ZCwEy~|BIrw?iA7>WG8@fF z^r70o4xPVd5NL||bMBjUc!8-jhGhp6muO?-sshv$Z{~s(QzYBkXp`RcTsrSU{w4NI zRF~7DRTu48W>K{KCd>sgF75f^4#vnmlROy-UH$|2Y=bvN^2sCwjToi^r~gm5I}sr6 z7;bguElp)?$Df3~{vgK3twatvEA(1p>QNi?f;t5ZVL3H&k>t7>zyohmhJKFy=~m1u=J(iA zIriFf7|^R(2JZyXmX zc&`->9mbbqZTFIeK2wu0^VoSRS{A-%kfPD)Ta4G_L~zqY7BiAwKP6)D_|xD_0ojmw zyxw9SFf*f5+aGV5W4dV!&u1*)L#rl|-H(SA2U+MIQ&go5#z+}86~zeFuE0UICUV81 zAax`I`T0+a;ql|-qq3T2|IuWNd^&@D0jXTTIeDD=Zj!NGxRV==e~F^n;!bqKhk`E)PzadV`h`8|MZ z(WFefzsUi={|tZA?Q=gOw-(c|%CaA-0HQOa|MG_;LM52Zt|FqH(Q|)y!m)=VR5$P_ z>!PA96tEpBJVxg4=OG$r+3*`B75D+wNaMncC0&?MUZK)DZMj{1_d_{=`xWhj2nk=v zFg3d}b95nZ?*3ga2eLyDRS40O;tqRg*z%MyJle?H0WIIbVS}>O7BhvoOTrGW@R93G zr%E#`D;0LBj8xnX$~kj6$k4-4lie+g3z7epmq9t7WGYo!P5Kw|hWM+0Q2n=zWCPZ} zpK)!~2v4oqtQAqC5|Ra$D++2z$4Ux|6Rpm{)^%0X@|i6bOwJ!pwBKVfKXLNnQN@Ak zz5)mL#j3~6jXxq4b>P?fFQtA9e5iR4 z=sa_?JXGd)H%y6%PyDD}rk)>Rg^tESF=KVm|~*nV6g zI`0#ST_n7e-syU&$yb4_<4ubqfp`^A*)!VHPS1+>&swH@=i0DMfVk-jObP;kGCUYZ zk9fn&U3y9nk-#&%3iGMX1{O1pNz^~nNUEo1cF_Kzu7CGh z&Y|1?_7c=YMb9qs{S0BNTgLd>ReP7PIL1Hxgl$k7Kp+PLL5geId-C1~n!MrhS#Os| z0gQX6ddU&zvnte~2EZ*b)(E(^03Fe-3JfUC>)tIo35xs;Q_ai+IzMDtpH8ykpMG=B zuUiPkK7RS6w$>mc*h5iMfh!TOn*@(6p{#1k`5lLMeM_w;+Is}+f%;QJ`V7NFkn_4V zxIeJl_Yq@^mi?zEqSSjf{#R|pe496TKxg}DwE3^Qhf!8$3SH}ux=LUPB34-27)oLY z`WEPeI@4iCz-l>0Rq0cyQU_RNn3aiGQ-zo~{+ysWA@OEakQgT#=X%zLdJ4=a=W)hUvrJ{&)YYK&&>MfD2$&bf$5nOc7QmMOB-wCBLiCuU3{ zS>f0e_JVB;^KN^m<>CSvJpbDaKjva@nqpyiGMav_0K>b8MAS{jW`6EZuff7Id$!?R zk~mp5=`5aycri#ma;9@Em+!G3XhW2p|1jLuYPK+f-K1w|)rP~xCw zNWjXu8pd{<8U94&tnlPE(dSpTWC19@V5eK}6?ZhLX-PizH1A$@ISkWxRyD=sN?xik z(}L!uV`Q%%;q<7b1waS=4oOHZ?7^_gU1oLUCOrgjQNjspOdUuGvx$tU`GWR4p83Ch zC6_da0#>T#cA&}SfkSc?TSV>eD>C2xv!PoB*}j8ee>}wxwd@2M-x*l_Ei%mTZisb` z?Uqva)CWQHXcVa`XvD?vut&mb59-XE`?2Pdfh7wrL%wrI8uG)mK^cVjUgy>xSwEMb zby&2BPUifz!?Mg|CKyux3#E<_uX%wCxp_-@oNx8ik{8b5TX5s|J`Vv?8u5ev{rAS~ zwB}ap55{_U9}LdvBeC7)%t}Sz{Uf>kZt~H^>#W)Q@T0|$>(qh15qgZJZBnfGxrGQb z@+F-Wx>T!z`ZV*sMiH1zMBN+41?1ehdfp^WGnduQ%}r)BQQz8&4lU!>Tf3UkFf99r z?Wk$H2F+q!_*>3oa2i*}vu{*v)=?c{7Wcr`Jq2kk5rWR&xt5i)af%aDhp4ueTxrkz z54hahVl-eJ`GT~QOQ?^(Glw5}#&ELn+Bzy0@c0aNE~T>oSy zT&tZ610BR79M*++YO~!^>ZZ!N zPEb6;TGF@MHv8zhO9~A!nX;A9RLMxNxI`tJuar#F>@f$SuIS_){rzO;eSL4O6^Vq6 zumwlt>BrsSV;aGH&}s7@RPO@dqg(q1>+n*O}75jXKFR_t&E--rH!=`K(sTqycg zrBk=yzW9qWNdS)jfJ7Fa=h;0n%l1;I>yzBmmRYUnT=R}){IVd`TL&J2&v}->+HUVN zAB10Xva|=y+$UkFCu;mn3R~QtY1rk$LAZ+M*TP+d>_wC7;KK)x-8Hquih8#f@>B#= zAs^U16R5F(fMYjL#G82?#U}Pa;ZIRF|AM@~?T;pOfrQ?tac(6y3`>#xqa^Y-Puc{H zlJg}!JO7CdXZ&{AZ%R1;awyMqsvZ9zQ}22HNw{bW?^jxmvq}}o!ZmB(YrS@xueU!rM_|# z(E~D7=M}6=+aKAQXAWMRTVPXWYy%?~*!5cl4%(i>y(pB2$b1Uu)hvNOwibERli9XA zc;bIc;Jf+%ar5eosK)#}EdGm)klq?vd3Sg1gBV_-TILB~qH2XzHLr8KVC}Cl??v^++Z#5lz*G6yTILcP_qK!_ zs~U_Pt=wXrT8NbF6LQ|))Zcoa;AMvJ7~Ml$1tQ-VtKa?V*73VT!+q?a*GoaIT00Di zxjg5zZ9uYhJR)hZ2qJ;9Oe+VyyVjTepk0nB8O&mT9hkl$pJ6i+o$g5jv?I@5yD_g< z+}hwZkdPiGq9rO6qS~SlJLMB|4S=V3-Dzzk;$7vweJ=3}C|`|xfA4CO-jkS&aZ7Xj zC^^4mo8}$qJMIPd_8OYWowT<6+D_fjtHm&T9{ojiE@h!XC!CEt`q#q-Vk+N*H;bkK zPC$fXgc2?PHW9}|Nuj2D*F9dY?e+rcRX1itKBCH2Tl{X>;yQ8Zn(4t8L^(W!$Rh?D zc+NWhOFwo4%1R|0CrwJqC$vLYF_Si)RZ>0n0)3w}?7m=>{0V(JdMg!D{di3rQDL0@ zllS_ibQTVZZ=yRZ!%_WP&*CV?#vUE{^J{J|af-9;a6&!nEhaMDE$MY^=1L5X%G2@c z0sa&CMhhdo9%kr3$cVZ?!9?xSc7|g{x$+w{2z8h01m5l9f{4x6UlcKeFU094yMlN_uqf zc+*3Iu+DT2f704fI27lQ1c>~o5EvGXe7L%-JpP1kf=!LBClb^M2J!vm)NkOrIcEaC zBlW$mN>5swvWf?0`Snvhc*4xe84@$vLR1&#b-*K9p4(2fMOxufq?-6;XU?y5RzYc@ z@Y`PG!a{|U5dQqB&WE}$#miy>$>%+P8WOdq<_D9Ur|w~hg<*w|uW|8eTMFwn`@H&C zrjSl0n8~vkb$~l*;RtmeA>Z4FFv9DPKkqpDI^Ki1SkRK-KqQPr;vJFJu@*M_lun}^ z5@j}JuIKR6*(yNMs@yTiCj}nSdqE!<<#3wJseJN+(nS|fbw(le2)wM! z-#VqwOIrGiR}>YVGq2iM0^z(_E;oir=@UAiY*)p`H!fwcC(YatI4eL8&IPmOEoG4xkh3 z#zzBi%2~H~snCp?s>E|e3bXAu67y6lf<2ioHz5Wp9RyV6(CZNF!LO46=$K$##YKkT54;=dfX5|9Mi1sbxAiFMt0|hTZ=5JR{7w&{ zI;2kPG4d4KmKXVpbUU)7vC=-1fd{9QUXMDdYx~0n?;ApPho_RtEw(~kNX=C8a`oOtrH)Fd+A zz*ppHk^z8-7k3^xny=%$j#|oSvRv8vVbYQMA5^lT6;l+S+ zaks+8Hf&jl_z3`7l#ZkI@<8hGA|L7rNIjVJ8YFij+gyKYv2i8?q zN$^jBngtG`!E&+A+`qfDs9&`&XPXvxFEqQVDR885sT^5d) zH{81BY=NU6nx-z_n?pXUlE$qy1XE<_Qu)`Uitbn*OyS)BWP9X~QDpcJog6}Qikk%Y z*+{=J-w4=L3&hdDd0(#{&zApKt2iJQ_RsT&@8a6`dNgR!3>$`;x6e#1mLr>%F<@J!Lp*T(&JPO$A~8t5`ov(wAjW|S@XmICd!r~$UL($q-|G$Q=KXf`7kWDl}Il1 zY+t<4-%%V1-L5-yS`VB3ICBb{REQppxS6!1vlFp}IH}g8v71W=AIm7r*=VM);~?}s zIYFLw6EtGUc5)^*S_5M6=lEqLjD7P#Pumr0s_MXzHknGyK}uv_2J3kWH-z0Io-P=1 zUw+sd086yjtGgfbBXIcVS;-4HX?Iqbyp~uqJ2-~y=I?9%$PKM?BmfJw$(xc<(H~kv zrA=^z;F5Ea$YR76-o8%kscTr9rF_5IY_DU<*&|`QtYR!{T@Ng@6CyI43aB1cW z%bZ-C&qCbnQbz4u8Ewg-=nI2-IkbqtI+u1^b&`eU3AtW6@M{ctj9{DfVrDL5?v<`NwD(=97a zt-dPM*kt6F{>5Cs4*IIUCPfokN=AU?zHRe?VpciYv`w==bHst;cIskGDZyOa9L@vq z{O2*kfn(O<;Eh(qLxZrRfqJcE*Y5?HP`c=fZQH6e@~T9Jm)%&v)3XllsYLgnq=lCG zMNqFCB922|EHq22Qzhs3Y6iLQ9qd~e28!*xSSHkyfZ`x#x00cLnS5RZbj5^&Mvl4j zC~w`^JX9LKW2tyDIEitbINI>1VW8%;$iL$YzvzQq*h%LVRLNNq3?8AjS6fL(rLBUa zZ+vK!j|L^$Pu8-38tTigHw9bR7ZN%GE<=8T=Q?9TI?rw_*M&wCTKGg9+qrf0_-T@6 z)wbD^xk7B9MRFooIuNhI;j$(&28z0mddEEy-N)Pzo^^qlv#9_3tOFUzU9mhFwV0#d zl`e;$zcg^#V>wU2_!w44Qd$|pybaBvR<1;o6=x`hr}ZMR0LK1_t#UJ0>1nSBuq)j< z-8PW~?j1-END04;O){mklW$>xrU( zU>e`8FV6waJr|N5yWKsniSsCHZ92-jzckVWnuBhl3&h>0wKZMsj2P)rUNwjilNTH6 z%B^n|438IXNqAsx4bZ&LxR3;h8M+6iD^+6ahB%n{JPX zw?Sz|Jj9s0aqfqh@LA3ZRjE9_{s%Q4+IvhKjOC#_e+wuC_0>6nan3u1iWbKZ+3(6|E0%L_m%0%&eR(V}O9v9AJ79pFV*BUnMDwcW}2DEi*13a_xR?#ecYx={FZokWM!$ z^?xWoy$R>J&fTmSV~4cOo-UgAZ7_l?G2|bgI8KbgP`)uuDJgn%x$A2ta>}D zP3`jdKw(0W9qDO5DPR_;zrA6y8DtZ%h5VtTjxg0wJ+UsGwpOBD!y)CPSIm7mJ=l(F zlCl87drK?+qMUT#OHp^iT%GY!|IL)xXOX*t$~>hBON;o?H&IN7MU(4+Uf&=_^hOhM zjKO3qsx5mWDJGl?6YVpu`{Lx{}Qq8E$ z9=cw4W}h_52dRNOx!7DM!Y!7Y8A9TsSHJfQIAw|oaT^R#27Bn!qnEwGy%!h~?$yFS5P1<<_ zjrG!jaPw=$5&C(aPg5RCaCtia}&h{;VnR#$YXM=Gkd&D0`pehNnyEHz>a8y4ys( z+bj8jN5lRt#GK~jibB*|xdPR|Lk%>3cv&UXVc^O{ekQP<#GxZ&X~x3pCKrSlNGCwz z;DsBz8RX-2GVv-AmN%K~g99VC-jZ2GlMLSLd?SAb>zS5ywh7I>3pRbL11n0u9~&r- zqU|IBgtI@RaO0rfx)c6r zt|KyeIf$Bfkcvx7HzV8iWurTK$2l+Gl^Iq#pb0^udQw84Nc`3tr+}{-ds#bTmoek9 z*kT^OHcjvA;hdbuQgi|32s4mG<^EDC`))sAPOFJ*-`_~m71!)LzteT@v8ML7YF$au z^j-ZY(0J=QzOOv!Dvdve{T$iu9ycJe)HW`5a@#(-y+l;Cjqe4e zWE+wm8TM|1qH{IwKK}z^f`MjeYxo6GADp{JO%CxG!c1$@vW+m>y&O%3tlpb&HuFLz z(cW?NTXu%=u+~*ylpBAa$Xv052g^9Ts)aZq+c)!su@)8?I5IgnEGYKz@PrW^i0k|} zNnY0Y(Y^D@?7!;LZtcdk6{(@Cw4buCI_Jf`U~y$elMf;K3h6GfyDK9)U9yGld8iLQghZF0=~ zv=`3gWSElQ*5Oazz2RCj^C~MB3HlVR;J+Urw%^-dfz~zTAvRzJaWmX*TMte2ZZNjK zcTDtKB!Ss~IOs_8#HH1R!@Nqj4a?Hn5wo$Vfx`!&weWSlM0ke-kM`iun!wuyH``AXF0HJyDVtHF;0#7lVk0nz9yU?vIEBI~V5&=w~(9`q`>#N#wNHT=*jzGx3Vm2@J_ zZ$#^PJ;!~+1LAQ4I(eJ+xnhNo@jIthutNgpKMIyVBOxtz-z@ta-;+Ou1?VX{f~?fT znDg5>-1~Tx2uvh??}S6BauKZ*h&-cnzOk=!WTaVuF9Al>&}gwo&}hDb6&!|C4=JVT zj>PnlxSqZU5+&o)2r>s~WkzI~Cnv2P2=DrLof*4n0IvfEf zZx3Xzk?M$CB`0lc$7Uo!r6JT1D<8NrFRLj1PKrZv!~B4vU5wrTltmj3O!eHs7G3@Yz%C-U zzq!A{h1H(NM9C|M$j%gMRDd7{i@N=5iaZLy2?VP*z=lGXz{fI7oL|3*40dID_y27o z{yv}O<~itflK(MB^+;$KgbjaEQP9+TFrLqE{Xsz#V_`V%u@Aqs=--S<^L8P<^ta^# zPXMv2_lv}LOp%bRM;0T8k^>gL@`f)w*(0|3$8Gd!mi1#sv{B;|%etxHGYY-WRNW1# z;Ca!<89sfGhKhO0J^o=U?BE+hv7Z?Xv9^*!+qiS`JWG*EEzAaHEuqAfXU$e8doU-m z!J`{V+K8BU@f`H9T=^J5QoyT0X6x>z)8tEdA9C&A?FUlqcvQ!QnrV8%%V|6@q(3h| zXFbM ztNE}&HCgyR)*m0Fato%5HFY-^*^_uiqvR#lB6+$=a6*51x&VJQwn}cCX&t$pGu|m) z;}RLMwO$OqRXFSst;RWK4(^}7B^!QN8i{98P;^H zz&eV>vRJH_cQTUg(DN^0u`R)P$zg3LdQnHSKv|&xt4+rulbq;fQ8EL6ZiIJ%vRA@x zg&gzo2Kr84Z8*Y<@r!8fMDt%5L7vU_!^;F8#nEIGvc@?sfhP?-ZzWVEt-lLLku4a| zrk;t|MI@l_`M=AIz3#d1iWOl#X3`+Nfvq;IWq(2GbBOJz18Jv^0*n=H+%K`bEiR0L zVdO9K>ZNqb0^$ySV8UD|^iHC!?O3t2_Y5pn~9l zUpu0m}soTy5a ze%gxWKnelsuf7wb@(CB>upL3xjAbY!N#Qvf|+jP*= zQgEiY;SEHQI$vL{q#I5LB7?_o>u2V)z=eihnJ#Bk_N4s4H{ z;t{+QhRY7rgr)@nJn9SO#p4w&eW~A=Bos}?B5K*3dt9b=y@iul^`XSGUtrdtHL}$rQJ?eX$lbK%>BbZZtgAS!7zd-x1Mk5kRI)=8iCm;GTFm=V zTww*k)?=?q z=1pS2kVJD&ZCz{fezQCA0t=Gq!%yF@pPh42c*yOXIY`UPYPb3yP*6R>has!;#6aIQJ)`E*#BgKO!VA6M`A~ z5w8!=kl^+tU%}}{oA7yIfF8+EQC$;VQ{|56)UlI^8;^`8*yPlBtcX;gr?jsq4<<~AI>h+xAW5sF zR?BE>_~dtF52|s`&fjbjzYC- z6u_vk>c3`)cz2jBw!4tPC1K1h91OY{F^~r(WA~uNu%#O>zsRq86%KWi_TFQg7HIs@ z?XMZ4rMu?Z89@0rI0pL)oEd<9S&##_TfD)?#b}*K`E$i_4OC)XzYQjlsdEY`1Ee|v zU+4 zqi@EcnC*p})YK|!L^IL?B<;5NC@0N&+Q&w)_uPilYJ~ZtHl3M5fg!AX=wZHI&ApTw7+c>sXmQe+@ zpEh#V^Q9R-wW`|s|DSB-&VRMyfS$M9h!m3WizH7uE-Eh#y2U7+Id$zBWf0p{s?v-!C-TO0I*~5hFk^nB{MbTqu zQwA9Uc7XlO<_0sveKFF~_Yj3e+y%x@Z$&=RX*(T9@SwP& zr;aO1c710D5LhpA=`pTC@44YuJ(*PMXKs~GLvT&Z!)V$W3-oNRrTxHYJFnJxm?X#{&1DiOD@Gg7Iqms-ystAXK!A&Cs+TJe5nlWrC)Ni`Gg#5wgfeOD%F}#{>v-&{gIhi5Ky}ex^$t0!O+78BAPSfw$ zMwuQ%RHUm%|KCMG;G{^@D7aEQqmtNMK+p+aeCBCj&`^jW`CG#Ehfb!|(Pg}6l;B@D zDVWOx>=P!4yCR6|Q}R)dCfv4GB#&4)AKppPPI?9sANSQ8;&fNbUfbUu0;e6JXaCIAW%)<%L44xfZDP9;->Yu z6TECo{}AR9qC5gVqpRXF!~!JQd%$;pQQbt4$@lh@Nz964G$s;k*Um?_91=r0VmqRL z{EOFKS^t#eKz?`uj`Wo>n$H64mQz%>-d0FzT8~Nso`EucJ`iZ_#@6c7o7Y}nD}sSB z&?gb1%kVqKlZ|H!$I`F^+#%p|vF)MR&|i&K)tb)(i#PS((^3|B z^Z|WD*{DT_nn9kFu6->JPH89l(({b@i555^ye>DLzmhxu(t@F7{AF*PFv!dm9t=s2GpWn$eH zp`AlArgV)G?K{E;gbIR{MqMp!W-EG})0RKN0W9-UlASy_jqF`n=E$p<+B-OSojw>**1s_e>U~!`zW~Lbu zC}!>$iPt!=cQaM7<8-}5F=-)bpRb)H>I2?`DogS}qI^9*sqsfm~3(Otug2dLdX{j`A9nA>PI{%15Q z#>)DMsEI`L>dnO8=;VD(qH}Df+8Wn1>h!dVRa#3d8>xCkC7uBBZ&`Xgfn)g_(64mD zZ1Zzei2hg2`!^Ezl!1r=Lb7}L$m~g;bdmBmPsrsmyr&%MndR|AK-958u zQ)sc8vIr1$oDe#4rM)S2`AG{1*>jJFgM`?pLQU3Wjg$;)vJ46k?c}azqpqF5`w;QV z_(dyJTi4vQ8z~66}dVnIFgGcTJ1WhGo@{0l*C~wj$PZA z0sQKk_!!`d_7{kr023FIOhS4%_UR17j6;NAWr?!`p*Rn{#|W@5pI#spoBB*9|M z`Y@Se@^l3kXw)+4m-&(eGjFWh(GuchhR{

a(n#@4YvFN}*w>2!|b3C}+v$Feu`2 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%0DQ;l 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

Q150>dLyJ_+z=zZwP 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

o~g) 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 VSz505g1(JdH%N9J-4n^X002KLdoTb1 From cffdb1abc819b03178a38a179eb645b770cbfbbe Mon Sep 17 00:00:00 2001 From: AlexMnrs <10886760+AlexMnrs@users.noreply.github.com> Date: Tue, 25 Aug 2026 13:10:24 +0200 Subject: [PATCH 6/8] fix: localize calendar labels --- github-activity/panel.luau | 19 ++++++++++++++++--- github-activity/plugin.toml | 2 +- github-activity/translations/en.json | 22 +++++++++++++++++++++- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/github-activity/panel.luau b/github-activity/panel.luau index 1117f6b4..b7f49c89 100644 --- a/github-activity/panel.luau +++ b/github-activity/panel.luau @@ -20,7 +20,20 @@ local gridReady = false local open = false local tr = noctalia.tr local cellColors = { "surface_variant", "primary/0.25", "primary/0.45", "primary/0.70", "primary" } -local monthNames = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } +local monthNames = { + tr("panel.months.jan"), + tr("panel.months.feb"), + tr("panel.months.mar"), + tr("panel.months.apr"), + tr("panel.months.may"), + tr("panel.months.jun"), + tr("panel.months.jul"), + tr("panel.months.aug"), + tr("panel.months.sep"), + tr("panel.months.oct"), + tr("panel.months.nov"), + tr("panel.months.dec"), +} local function requestRefresh() noctalia.state.set("refresh_request", noctalia.nowMs()) @@ -99,7 +112,7 @@ local function buildMonthHeader() end local function buildWeekdayLabels() - local names = { "", "Mon", "", "Wed", "", "Fri", "" } + local names = { "", tr("panel.weekdays.mon"), "", tr("panel.weekdays.wed"), "", tr("panel.weekdays.fri"), "" } local labels = {} for day = 1, 7 do table.insert(labels, ui.column({ @@ -238,7 +251,7 @@ function render() end if data == nil or cachedCalendar == nil then - local emptyText = data ~= nil and "Preparing interactive calendar…" + local emptyText = data ~= nil and tr("panel.preparing") or (detail ~= "" and statusText() or tr("status.no_data")) table.insert(body, ui.spacer({ flexGrow = 1 })) table.insert(body, ui.column({ gap = 12, align = "center" }, { diff --git a/github-activity/plugin.toml b/github-activity/plugin.toml index 4bf7388e..12e9c3b0 100644 --- a/github-activity/plugin.toml +++ b/github-activity/plugin.toml @@ -1,6 +1,6 @@ id = "alexmnrs/github-activity" name = "GitHub Activity" -version = "1.0.0" +version = "1.0.1" plugin_api = 24 author = "AlexMnrs" license = "MIT" diff --git a/github-activity/translations/en.json b/github-activity/translations/en.json index 18ec9da8..316609ef 100644 --- a/github-activity/translations/en.json +++ b/github-activity/translations/en.json @@ -13,7 +13,27 @@ "year_total": "{login} · {count} contributions in the last year", "day_total": "{date} · {count} contributions", "hover_day": "Hover a day to inspect its activity.", - "no_today": "Today's contribution is not in the returned calendar." + "no_today": "Today's contribution is not in the returned calendar.", + "preparing": "Preparing interactive calendar…", + "months": { + "jan": "Jan", + "feb": "Feb", + "mar": "Mar", + "apr": "Apr", + "may": "May", + "jun": "Jun", + "jul": "Jul", + "aug": "Aug", + "sep": "Sep", + "oct": "Oct", + "nov": "Nov", + "dec": "Dec" + }, + "weekdays": { + "mon": "Mon", + "wed": "Wed", + "fri": "Fri" + } }, "metric": { "today": "Today", From 364981e0cabaec06391e91ba2f74f4f872cf1fa5 Mon Sep 17 00:00:00 2001 From: AlexMnrs <10886760+AlexMnrs@users.noreply.github.com> Date: Tue, 25 Aug 2026 14:13:14 +0200 Subject: [PATCH 7/8] chore: remove unused activity code --- github-activity/lib/activity.luau | 155 --------------------------- github-activity/panel.luau | 7 +- github-activity/translations/en.json | 6 +- 3 files changed, 2 insertions(+), 166 deletions(-) diff --git a/github-activity/lib/activity.luau b/github-activity/lib/activity.luau index 8c3dd2d4..c95a7910 100644 --- a/github-activity/lib/activity.luau +++ b/github-activity/lib/activity.luau @@ -35,18 +35,6 @@ function Activity.symbol(level) return symbols[Activity.level(level) + 1] end -function Activity.levelForSymbol(symbol) - local levels = { - ["·"] = 0, - ["░"] = 1, - ["▒"] = 2, - ["▓"] = 3, - ["█"] = 4, - } - - return levels[symbol] or 0 -end - function Activity.rowLevels(row) local levels = {} local byCodepoint = { @@ -62,56 +50,6 @@ function Activity.rowLevels(row) return levels end -function Activity.heatmapSvg(rows, dark) - local colors = dark - and { "#252a33", "#283f68", "#355b94", "#4b7dc5", "#72a7ec" } - or { "#e2e7ef", "#bdd4ed", "#82b4e2", "#468dcc", "#1769aa" } - local fragments = { - '', - } - - local levelRows = {} - local columnCount = 0 - for day = 1, 7 do - local levels = Activity.rowLevels((rows or {})[day]) - levelRows[day] = levels - columnCount = math.max(columnCount, #levels) - end - - local date = os.date("*t") - local monthNames = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } - local firstMonth = date.month - 11 - local textColor = dark and "#c6cbd4" or "#414750" - for offset = 0, 11 do - local month = ((firstMonth + offset - 1) % 12) + 1 - local week = math.floor(offset * math.max(1, columnCount - 1) / 11) - table.insert(fragments, - '' .. monthNames[month] .. "") - end - - for _, label in ipairs({ { "Mon", 1 }, { "Wed", 3 }, { "Fri", 5 } }) do - table.insert(fragments, - '' .. label[1] .. "") - end - - local paths = { {}, {}, {}, {}, {} } - for day = 1, 7 do - for week, level in ipairs(levelRows[day]) do - table.insert(paths[level + 1], "M" .. tostring(45 + (week - 1) * 10) - .. " " .. tostring(24 + (day - 1) * 13) .. "h8v8h-8z") - end - end - - for level = 1, 5 do - table.insert(fragments, '') - end - - table.insert(fragments, "") - return table.concat(fragments) -end - function Activity.flatten(weeks) local days = {} @@ -166,38 +104,6 @@ function Activity.streaks(days, todayDate) return current, best end -function Activity.countStreaks(counts, todayIndex) - local best = 0 - local running = 0 - for _, count in ipairs(counts or {}) do - if count > 0 then - running = running + 1 - best = math.max(best, running) - else - running = 0 - end - end - - if todayIndex == nil then - return 0, best - end - - local endIndex = todayIndex - if (counts[endIndex] or 0) == 0 then - endIndex = endIndex - 1 - end - - local current = 0 - for index = endIndex, 1, -1 do - if (counts[index] or 0) == 0 then - break - end - current = current + 1 - end - - return current, best -end - function Activity.normalize(payload, todayDate) local viewer = payload and payload.data @@ -258,67 +164,6 @@ function Activity.normalize(payload, todayDate) } end -function Activity.normalizeText(output, todayDate) - local header, body = string.match(output or "", "^([^\n]+)\n(.*)$") - if header == nil or body == nil then - return nil, "missing contribution header" - end - - local login, totalText = string.match(header, "^([^\t]+)\t(%d+)$") - if login == nil or totalText == nil then - return nil, "invalid contribution header" - end - - local rows = { "", "", "", "", "", "", "" } - local counts = {} - local todayIndex = nil - local today = 0 - local weekDay = 0 - local dayCount = 0 - - for line in string.gmatch(body, "[^\n]+") do - if line == "WEEK" then - weekDay = 0 - else - local date, countText, level = string.match(line, "^([^\t]+)\t(%d+)\t([^\t]+)$") - if date == nil then - return nil, "invalid contribution day" - end - - local count = tonumber(countText) - if count == nil then - return nil, "invalid contribution count" - end - - weekDay = weekDay + 1 - dayCount = dayCount + 1 - rows[weekDay] = rows[weekDay] .. Activity.symbol(level) - counts[dayCount] = count - if date == todayDate then - todayIndex = dayCount - today = count - end - end - end - - if dayCount == 0 then - return nil, "empty contribution calendar" - end - - local currentStreak, bestStreak = Activity.countStreaks(counts, todayIndex) - return { - login = login, - total = tonumber(totalText), - rows = rows, - details = data.details or {}, - today = today, - todayDate = todayDate, - currentStreak = currentStreak, - bestStreak = bestStreak, - fetchedAt = os.time(), - } -end - -- Convert caches written by the first MVP build (which stored all 371 days) -- into the compact representation used by the CPU-safe panel. function Activity.compact(data, todayDate) diff --git a/github-activity/panel.luau b/github-activity/panel.luau index b7f49c89..72982dd0 100644 --- a/github-activity/panel.luau +++ b/github-activity/panel.luau @@ -19,7 +19,6 @@ local gridPreparingDay = 1 local gridReady = false local open = false local tr = noctalia.tr -local cellColors = { "surface_variant", "primary/0.25", "primary/0.45", "primary/0.70", "primary" } local monthNames = { tr("panel.months.jan"), tr("panel.months.feb"), @@ -162,7 +161,7 @@ local function prepareGridColumns() selectedByKey[key] = { date = date, count = tonumber(countText) or 0 } table.insert(cells, ui.box({ key = key, - fill = cellColors[(gridLevels[day][gridWeek] or 0) + 1], + fill = Activity.color(gridLevels[day][gridWeek]), radius = 2, width = 10, height = 12, @@ -324,10 +323,6 @@ function onRefreshClicked() requestRefresh() end -function onCloseClicked() - panel.close() -end - function onOpenProfile() if data == nil then return diff --git a/github-activity/translations/en.json b/github-activity/translations/en.json index 316609ef..a0245b9f 100644 --- a/github-activity/translations/en.json +++ b/github-activity/translations/en.json @@ -12,8 +12,6 @@ "title": "GitHub Activity", "year_total": "{login} · {count} contributions in the last year", "day_total": "{date} · {count} contributions", - "hover_day": "Hover a day to inspect its activity.", - "no_today": "Today's contribution is not in the returned calendar.", "preparing": "Preparing interactive calendar…", "months": { "jan": "Jan", @@ -38,12 +36,10 @@ "metric": { "today": "Today", "current_streak": "Current streak", - "best_streak": "Best streak", - "days": "{count} days" + "best_streak": "Best streak" }, "action": { "refresh": "Refresh", - "close": "Close", "try_again": "Try again", "open_profile": "Open profile" }, From 24602f345264aa3c91cbb02892c177d04b0ac886 Mon Sep 17 00:00:00 2001 From: AlexMnrs <10886760+AlexMnrs@users.noreply.github.com> Date: Tue, 25 Aug 2026 14:32:53 +0200 Subject: [PATCH 8/8] feat: sync GitHub Activity 1.2.1 --- github-activity/README.md | 10 ++++++++++ github-activity/lib/settings.luau | 21 +++++++++++++++++++++ github-activity/panel.luau | 9 +++++++++ github-activity/plugin.toml | 14 +++++++++++++- github-activity/sync.luau | 13 +++++++++++-- github-activity/translations/en.json | 16 ++++++++++++++-- github-activity/widget.luau | 7 +++++++ 7 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 github-activity/lib/settings.luau diff --git a/github-activity/README.md b/github-activity/README.md index f6db5685..274393b3 100644 --- a/github-activity/README.md +++ b/github-activity/README.md @@ -33,6 +33,16 @@ gh auth login -h github.com 3. Left-click the widget to open the annual calendar. 4. Right-click the widget or use the panel's refresh button to refresh now. +## Settings + +| Setting | Options | Default | +| --- | --- | --- | +| Automatic refresh interval | 15, 30, or 60 minutes | 30 minutes | + +Changing the interval applies it immediately and requests a refresh unless a +request is already in progress. The widget tooltip and calendar panel show the +last update time and selected automatic refresh interval. + The panel can also be toggled through IPC: ```bash diff --git a/github-activity/lib/settings.luau b/github-activity/lib/settings.luau new file mode 100644 index 00000000..27bf811c --- /dev/null +++ b/github-activity/lib/settings.luau @@ -0,0 +1,21 @@ +--!nonstrict + +local Settings = {} + +local DEFAULT_REFRESH_INTERVAL_MINUTES = 30 +local refreshIntervalMinutes = { + ["15"] = 15, + ["30"] = 30, + ["60"] = 60, +} + +function Settings.refreshIntervalMinutes(value) + return type(value) == "string" and refreshIntervalMinutes[value] + or DEFAULT_REFRESH_INTERVAL_MINUTES +end + +function Settings.refreshIntervalMs(value) + return Settings.refreshIntervalMinutes(value) * 60 * 1000 +end + +return Settings diff --git a/github-activity/panel.luau b/github-activity/panel.luau index 72982dd0..b31f7864 100644 --- a/github-activity/panel.luau +++ b/github-activity/panel.luau @@ -1,6 +1,7 @@ --!nonstrict local Activity = require("./lib/activity.luau") +local Settings = require("./lib/settings.luau") local data = noctalia.state.get("data") local status = noctalia.state.get("status") or "loading" @@ -233,6 +234,13 @@ local function statusText() return stale and tr("status.stale") or "" end +local function refreshSchedule() + return tr("status.refresh_schedule", { + time = os.date("%H:%M", math.floor(data.fetchedAt)), + interval = Settings.refreshIntervalMinutes(noctalia.getConfig("refresh_interval_minutes")), + }) +end + function render() local root = { ui.row({ align = "center", gap = 12, paddingH = 18, paddingV = 10 }, { @@ -266,6 +274,7 @@ function render() and tr("panel.day_total", { date = day.date, count = day.count }) or tr("panel.year_total", { login = data.login, count = data.total }) table.insert(body, ui.label({ text = selectedText, height = 14, fontSize = 11, color = "on_surface_variant", textAlign = "center" })) + table.insert(body, ui.label({ text = refreshSchedule(), height = 12, fontSize = 10, color = "on_surface_variant", textAlign = "center" })) table.insert(body, ui.separator({ thickness = 1, color = "outline/0.35" })) table.insert(body, ui.row({ gap = 14, align = "stretch" }, { metric(tr("metric.today"), data.today, activityBlocks(data.today > 0 and 1 or 0, 1)), diff --git a/github-activity/plugin.toml b/github-activity/plugin.toml index 12e9c3b0..47b8b534 100644 --- a/github-activity/plugin.toml +++ b/github-activity/plugin.toml @@ -1,6 +1,6 @@ id = "alexmnrs/github-activity" name = "GitHub Activity" -version = "1.0.1" +version = "1.2.1" plugin_api = 24 author = "AlexMnrs" license = "MIT" @@ -9,6 +9,18 @@ description = "A native GitHub contribution calendar for your Noctalia bar." tags = ["bar", "panel", "service", "development", "productivity", "utility", "network", "hyprland", "arch"] dependencies = ["gh", "xdg-open"] +[[setting]] +key = "refresh_interval_minutes" +type = "select" +label_key = "settings.refresh_interval.label" +description_key = "settings.refresh_interval.description" +default = "30" +options = [ + { value = "15", label_key = "settings.refresh_interval.options.fifteen" }, + { value = "30", label_key = "settings.refresh_interval.options.thirty" }, + { value = "60", label_key = "settings.refresh_interval.options.sixty" }, +] + [[widget]] id = "activity" entry = "widget.luau" diff --git a/github-activity/sync.luau b/github-activity/sync.luau index 824fdbf7..0a89ca35 100644 --- a/github-activity/sync.luau +++ b/github-activity/sync.luau @@ -1,6 +1,7 @@ --!nonstrict local Activity = require("./lib/activity.luau") +local Settings = require("./lib/settings.luau") local QUERY = [[ query { @@ -88,7 +89,6 @@ def suffixrun: } ]=] -local REFRESH_INTERVAL_MS = 30 * 60 * 1000 local cachePath = nil local inFlight = false @@ -189,7 +189,11 @@ local function refresh() end) end -noctalia.setUpdateInterval(REFRESH_INTERVAL_MS) +local function configureRefreshInterval() + noctalia.setUpdateInterval(Settings.refreshIntervalMs(noctalia.getConfig("refresh_interval_minutes"))) +end + +configureRefreshInterval() initialiseCache() refresh() @@ -205,6 +209,11 @@ function onEnable() refresh() end +function onConfigChanged() + configureRefreshInterval() + refresh() +end + function onIpc(event, _payload) if event == "refresh" then refresh() diff --git a/github-activity/translations/en.json b/github-activity/translations/en.json index a0245b9f..0932edbc 100644 --- a/github-activity/translations/en.json +++ b/github-activity/translations/en.json @@ -3,8 +3,19 @@ "name": "GitHub Activity", "description": "A native GitHub contribution calendar for your Noctalia bar." }, + "settings": { + "refresh_interval": { + "label": "Refresh interval", + "description": "How often GitHub contribution data refreshes automatically.", + "options": { + "fifteen": "Every 15 minutes", + "thirty": "Every 30 minutes", + "sixty": "Every 60 minutes" + } + } + }, "widget": { - "tooltip": "{login}\\nToday: {today} contributions\\nCurrent streak: {streak} days\\n{freshness}", + "tooltip": "{login}\nToday: {today} contributions\nCurrent streak: {streak} days\n{freshness}\n{refresh}", "cached": "Cached data", "up_to_date": "Up to date" }, @@ -53,6 +64,7 @@ "invalid_response": "GitHub returned an unexpected contribution calendar.", "unavailable": "GitHub activity is unavailable.", "no_data": "No contribution data is available yet.", - "missing_xdg_open": "xdg-open is required to open your profile." + "missing_xdg_open": "xdg-open is required to open your profile.", + "refresh_schedule": "Last updated at {time} · Auto-refresh every {interval} min" } } diff --git a/github-activity/widget.luau b/github-activity/widget.luau index debd9b11..96ba2720 100644 --- a/github-activity/widget.luau +++ b/github-activity/widget.luau @@ -1,5 +1,7 @@ --!nonstrict +local Settings = require("./lib/settings.luau") + local data = noctalia.state.get("data") local status = noctalia.state.get("status") or "loading" local stale = noctalia.state.get("stale") == true @@ -8,11 +10,16 @@ local tr = noctalia.tr local function tooltip() if data ~= nil then local freshness = stale and tr("widget.cached") or tr("widget.up_to_date") + local refreshSchedule = tr("status.refresh_schedule", { + time = os.date("%H:%M", math.floor(data.fetchedAt)), + interval = Settings.refreshIntervalMinutes(noctalia.getConfig("refresh_interval_minutes")), + }) return tr("widget.tooltip", { login = data.login, today = data.today, streak = data.currentStreak, freshness = freshness, + refresh = refreshSchedule, }) end