diff options
| author | srdusr <trevorgray@srdusr.com> | 2025-08-30 19:22:59 +0200 |
|---|---|---|
| committer | srdusr <trevorgray@srdusr.com> | 2025-08-30 19:22:59 +0200 |
| commit | 19120d4f9761c67d99ed1ce3da6084b83f5a49c9 (patch) | |
| tree | f234cad1bdad88114a63c9702144da487024967a /linux/home/.config/ags/widget/datemenu | |
| parent | 5928998af5404ae2be84c6cecc10ebf84bd3f3ed (diff) | |
| download | dotfiles-19120d4f9761c67d99ed1ce3da6084b83f5a49c9.tar.gz dotfiles-19120d4f9761c67d99ed1ce3da6084b83f5a49c9.zip | |
Linux-specific dotfiles
Diffstat (limited to 'linux/home/.config/ags/widget/datemenu')
4 files changed, 317 insertions, 0 deletions
diff --git a/linux/home/.config/ags/widget/datemenu/DateColumn.ts b/linux/home/.config/ags/widget/datemenu/DateColumn.ts new file mode 100644 index 0000000..a462302 --- /dev/null +++ b/linux/home/.config/ags/widget/datemenu/DateColumn.ts @@ -0,0 +1,58 @@ +import { clock, uptime } from 'lib/variables'; +import GLib from 'gi://GLib'; +import Gtk from 'gi://Gtk'; + +function up(up: number) { + const h = Math.floor(up / 60); + const m = Math.floor(up % 60); + return `uptime: ${h}:${m < 10 ? '0' + m : m}`; +} + +export default () => + Widget.Box({ + vertical: true, + class_name: 'date-column vertical', + children: [ + Widget.Box({ + class_name: 'clock-box', + vertical: true, + children: [ + Widget.Label({ + class_name: 'clock', + label: clock.bind().as(t => t.format('%H:%M')!), + }), + Widget.Label({ + class_name: 'uptime', + label: uptime.bind().as(up), + }), + ], + }), + Widget.Box({ + class_name: 'calendar', + children: [ + (() => { + const calendar = Widget.Calendar({ + hexpand: true, + hpack: 'center', + }); + + // Get today's date and mark it + const today = new Date(); + calendar.select_day(today.getDate()); + calendar.select_month(today.getMonth(), today.getFullYear()); + calendar.mark_day(today.getDate()); // This should trigger styling + + // Prevent scrolling from triggering GNOME Calendar + const eventBox = Widget.EventBox({ + child: calendar, + onPrimaryClick: () => { + GLib.spawn_command_line_async('gnome-calendar'); + }, + }); + + return eventBox; + })(), + ], + }), + ], + }); diff --git a/linux/home/.config/ags/widget/datemenu/DateMenu.ts b/linux/home/.config/ags/widget/datemenu/DateMenu.ts new file mode 100644 index 0000000..f7fdf6d --- /dev/null +++ b/linux/home/.config/ags/widget/datemenu/DateMenu.ts @@ -0,0 +1,36 @@ +import PopupWindow from "widget/PopupWindow" +import NotificationColumn from "./NotificationColumn" +import DateColumn from "./DateColumn" +import options from "options" + +const { bar, datemenu } = options +const pos = bar.position.bind() +const layout = Utils.derive([bar.position, datemenu.position], (bar, qs) => + `${bar}-${qs}` as const, +) + +const Settings = () => Widget.Box({ + class_name: "datemenu horizontal", + vexpand: false, + children: [ + NotificationColumn(), + Widget.Separator({ orientation: 1 }), + DateColumn(), + ], +}) + +const DateMenu = () => PopupWindow({ + name: "datemenu", + exclusivity: "exclusive", + transition: pos.as(pos => pos === "top" ? "slide_down" : "slide_up"), + layout: layout.value, + child: Settings(), +}) + +export function setupDateMenu() { + App.addWindow(DateMenu()) + layout.connect("changed", () => { + App.removeWindow("datemenu") + App.addWindow(DateMenu()) + }) +} diff --git a/linux/home/.config/ags/widget/datemenu/NotificationColumn.ts b/linux/home/.config/ags/widget/datemenu/NotificationColumn.ts new file mode 100644 index 0000000..07d6829 --- /dev/null +++ b/linux/home/.config/ags/widget/datemenu/NotificationColumn.ts @@ -0,0 +1,113 @@ +import { type Notification as Notif } from "types/service/notifications" +import Notification from "widget/notifications/Notification" +import options from "options" +import icons from "lib/icons" + +const notifications = await Service.import("notifications") +const notifs = notifications.bind("notifications") + +const Animated = (n: Notif) => Widget.Revealer({ + transition_duration: options.transition.value, + transition: "slide_down", + child: Notification(n), + setup: self => Utils.timeout(options.transition.value, () => { + if (!self.is_destroyed) + self.reveal_child = true + }), +}) + +const ClearButton = () => Widget.Button({ + on_clicked: notifications.clear, + sensitive: notifs.as(n => n.length > 0), + child: Widget.Box({ + children: [ + Widget.Label("Clear "), + Widget.Icon({ + icon: notifs.as(n => icons.trash[n.length > 0 ? "full" : "empty"]), + }), + ], + }), +}) + +const Header = () => Widget.Box({ + class_name: "header", + children: [ + Widget.Label({ label: "Notifications", hexpand: true, xalign: 0 }), + ClearButton(), + ], +}) + +const NotificationList = () => { + const map: Map<number, ReturnType<typeof Animated>> = new Map + const box = Widget.Box({ + vertical: true, + children: notifications.notifications.map(n => { + const w = Animated(n) + map.set(n.id, w) + return w + }), + visible: notifs.as(n => n.length > 0), + }) + + function remove(_: unknown, id: number) { + const n = map.get(id) + if (n) { + n.reveal_child = false + Utils.timeout(options.transition.value, () => { + n.destroy() + map.delete(id) + }) + } + } + + return box + .hook(notifications, remove, "closed") + .hook(notifications, (_, id: number) => { + if (id !== undefined) { + if (map.has(id)) + remove(null, id) + + const n = notifications.getNotification(id)! + + const w = Animated(n) + map.set(id, w) + box.children = [w, ...box.children] + } + }, "notified") +} + +const Placeholder = () => Widget.Box({ + class_name: "placeholder", + vertical: true, + vpack: "center", + hpack: "center", + vexpand: true, + hexpand: true, + visible: notifs.as(n => n.length === 0), + children: [ + Widget.Icon(icons.notifications.silent), + Widget.Label("Your inbox is empty"), + ], +}) + +export default () => Widget.Box({ + class_name: "notifications", + css: options.notifications.width.bind().as(w => `min-width: ${w}px`), + vertical: true, + children: [ + Header(), + Widget.Scrollable({ + vexpand: true, + hscroll: "never", + class_name: "notification-scrollable", + child: Widget.Box({ + class_name: "notification-list vertical", + vertical: true, + children: [ + NotificationList(), + Placeholder(), + ], + }), + }), + ], +}) diff --git a/linux/home/.config/ags/widget/datemenu/datemenu.scss b/linux/home/.config/ags/widget/datemenu/datemenu.scss new file mode 100644 index 0000000..6fd9257 --- /dev/null +++ b/linux/home/.config/ags/widget/datemenu/datemenu.scss @@ -0,0 +1,110 @@ +@import "../notifications/notifications.scss"; + +@mixin calendar { + @include widget; + padding: $padding*2 $padding*2 0; + + calendar { + all: unset; + + &.button { + @include button($flat: true); + } + + &:selected { + box-shadow: inset 0 -8px 0 0 transparentize($primary-bg, 0.5), + inset 0 0 0 1px $primary-bg; + border-radius: $radius*0.6; + } + + &.header { + background-color: transparent; + border: none; + color: transparentize($fg, 0.5); + } + + &.highlight { + background-color: transparent; + color: transparentize($primary-bg, 0.5); + } + + &:indeterminate { + color: transparentize($fg, 0.9); + } + + font-size: 1.1em; + padding: .2em; + } +} + +window#datemenu .datemenu { + @include floating-widget; + + .notifications { + .header { + margin-bottom: $spacing; + margin-right: $spacing; + + >label { + margin-left: $radius * .5; + } + + button { + @include button; + padding: $padding*.7 $padding; + } + } + + .notification-scrollable { + @include scrollable($top: true, $bottom: true); + } + + .notification-list { + margin-right: $spacing; + } + + .notification { + @include notification; + @include widget; + padding: $padding; + margin-bottom: $spacing; + } + + .placeholder { + image { + font-size: 7em; + } + + label { + font-size: 1.2em; + } + } + } + + + separator { + background-color: $popover-border-color; + border-radius: $radius; + margin-right: $spacing; + } + + .datemenu { + @include spacing; + } + + .clock-box { + padding: $padding; + + .clock { + font-size: 5em; + } + + .uptime { + color: transparentize($fg, 0.2); + } + } + + .calendar { + @include calendar; + } +} |
