From 9e8634d892c559c5b44565a68bf35b13cbcb5572 Mon Sep 17 00:00:00 2001 From: Aylur Date: Thu, 16 Jan 2025 17:37:00 +0100 Subject: add: gtk3 ts popover example closes #224 closes #157 --- examples/js/.gitignore | 7 - examples/js/applauncher/README.md | 5 - examples/js/applauncher/app.ts | 9 -- examples/js/applauncher/style.scss | 1 - examples/js/applauncher/widget/Applauncher.scss | 59 -------- examples/js/applauncher/widget/Applauncher.tsx | 87 ----------- examples/js/media-player/README.md | 5 - examples/js/media-player/app.ts | 11 -- examples/js/media-player/style.scss | 1 - examples/js/media-player/widget/MediaPlayer.scss | 56 ------- examples/js/media-player/widget/MediaPlayer.tsx | 94 ------------ examples/js/notifications/README.md | 5 - examples/js/notifications/app.ts | 9 -- .../notifications/notifications/Notification.scss | 125 ---------------- .../notifications/notifications/Notification.tsx | 107 -------------- .../notifications/NotificationPopups.tsx | 105 -------------- examples/js/notifications/style.scss | 1 - examples/js/simple-bar/README.md | 12 -- examples/js/simple-bar/app.ts | 13 -- examples/js/simple-bar/style.scss | 106 -------------- examples/js/simple-bar/widget/Bar.tsx | 161 --------------------- 21 files changed, 979 deletions(-) delete mode 100644 examples/js/.gitignore delete mode 100644 examples/js/applauncher/README.md delete mode 100644 examples/js/applauncher/app.ts delete mode 100644 examples/js/applauncher/style.scss delete mode 100644 examples/js/applauncher/widget/Applauncher.scss delete mode 100644 examples/js/applauncher/widget/Applauncher.tsx delete mode 100644 examples/js/media-player/README.md delete mode 100644 examples/js/media-player/app.ts delete mode 100644 examples/js/media-player/style.scss delete mode 100644 examples/js/media-player/widget/MediaPlayer.scss delete mode 100644 examples/js/media-player/widget/MediaPlayer.tsx delete mode 100644 examples/js/notifications/README.md delete mode 100644 examples/js/notifications/app.ts delete mode 100644 examples/js/notifications/notifications/Notification.scss delete mode 100644 examples/js/notifications/notifications/Notification.tsx delete mode 100644 examples/js/notifications/notifications/NotificationPopups.tsx delete mode 100644 examples/js/notifications/style.scss delete mode 100644 examples/js/simple-bar/README.md delete mode 100644 examples/js/simple-bar/app.ts delete mode 100644 examples/js/simple-bar/style.scss delete mode 100644 examples/js/simple-bar/widget/Bar.tsx (limited to 'examples/js') diff --git a/examples/js/.gitignore b/examples/js/.gitignore deleted file mode 100644 index d53b85b..0000000 --- a/examples/js/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -@girs/ -tsconfig.json -env.d.ts -dist/ -node_modules/ -package.json -package-lock.json diff --git a/examples/js/applauncher/README.md b/examples/js/applauncher/README.md deleted file mode 100644 index 682adf1..0000000 --- a/examples/js/applauncher/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Applauncher - -![launcher](https://github.com/user-attachments/assets/2695e3bb-dff4-478a-b392-279fe638bfd3) - -Using [Apps](https://aylur.github.io/astal/guide/libraries/apps). diff --git a/examples/js/applauncher/app.ts b/examples/js/applauncher/app.ts deleted file mode 100644 index d6c9e1c..0000000 --- a/examples/js/applauncher/app.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { App } from "astal/gtk3" -import style from "./style.scss" -import Applauncher from "./widget/Applauncher" - -App.start({ - instanceName: "launcher", - css: style, - main: Applauncher, -}) diff --git a/examples/js/applauncher/style.scss b/examples/js/applauncher/style.scss deleted file mode 100644 index ba13eed..0000000 --- a/examples/js/applauncher/style.scss +++ /dev/null @@ -1 +0,0 @@ -@use "./widget/Applauncher.scss" diff --git a/examples/js/applauncher/widget/Applauncher.scss b/examples/js/applauncher/widget/Applauncher.scss deleted file mode 100644 index ae2453d..0000000 --- a/examples/js/applauncher/widget/Applauncher.scss +++ /dev/null @@ -1,59 +0,0 @@ -@use "sass:string"; - -@function gtkalpha($c, $a) { - @return string.unquote("alpha(#{$c},#{$a})"); -} - -// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss -$fg-color: #{"@theme_fg_color"}; -$bg-color: #{"@theme_bg_color"}; - -window#launcher { - all: unset; - - box.Applauncher { - background-color: $bg-color; - border-radius: 11px; - margin: 1rem; - padding: .8rem; - box-shadow: 2px 3px 8px 0 gtkalpha(black, .4); - - entry { - margin-bottom: .8rem; - } - - button { - min-width: 0; - min-height: 0; - padding: .5rem; - - icon { - font-size: 3em; - margin-right: .3rem; - } - - label.name { - font-weight: bold; - font-size: 1.1em - } - - label.description { - color: gtkalpha($fg-color, .8); - } - } - - box.not-found { - padding: 1rem; - - icon { - font-size: 6em; - color: gtkalpha($fg-color, .7); - } - - label { - color: gtkalpha($fg-color, .9); - font-size: 1.2em; - } - } - } -} diff --git a/examples/js/applauncher/widget/Applauncher.tsx b/examples/js/applauncher/widget/Applauncher.tsx deleted file mode 100644 index c7bac68..0000000 --- a/examples/js/applauncher/widget/Applauncher.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import Apps from "gi://AstalApps" -import { App, Astal, Gdk, Gtk } from "astal/gtk3" -import { Variable } from "astal" - -const MAX_ITEMS = 8 - -function hide() { - App.get_window("launcher")!.hide() -} - -function AppButton({ app }: { app: Apps.Application }) { - return -} - -export default function Applauncher() { - const { CENTER } = Gtk.Align - const apps = new Apps.Apps() - - const text = Variable("") - const list = text(text => apps.fuzzy_query(text).slice(0, MAX_ITEMS)) - const onEnter = () => { - apps.fuzzy_query(text.get())?.[0].launch() - hide() - } - - return text.set("")} - onKeyPressEvent={function (self, event: Gdk.Event) { - if (event.get_keyval()[1] === Gdk.KEY_Escape) - self.hide() - }}> - - - - - - text.set(self.text)} - onActivate={onEnter} - /> - - {list.as(list => list.map(app => ( - - )))} - - l.length === 0)}> - - - - - - - - -} diff --git a/examples/js/media-player/README.md b/examples/js/media-player/README.md deleted file mode 100644 index 4e3d237..0000000 --- a/examples/js/media-player/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Media Player - -![mpris](https://github.com/user-attachments/assets/891e9706-74db-4505-bd83-c3628d7b4fd0) - -Using [Mpris](https://aylur.github.io/astal/guide/libraries/mpris). diff --git a/examples/js/media-player/app.ts b/examples/js/media-player/app.ts deleted file mode 100644 index 5b7558a..0000000 --- a/examples/js/media-player/app.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { App, Widget } from "astal/gtk3" -import style from "./style.scss" -import MprisPlayers from "./widget/MediaPlayer" - -App.start({ - instanceName: "players", - css: style, - main: () => { - new Widget.Window({}, MprisPlayers()) - } -}) diff --git a/examples/js/media-player/style.scss b/examples/js/media-player/style.scss deleted file mode 100644 index 2e2f625..0000000 --- a/examples/js/media-player/style.scss +++ /dev/null @@ -1 +0,0 @@ -@use "./widget/MediaPlayer.scss"; diff --git a/examples/js/media-player/widget/MediaPlayer.scss b/examples/js/media-player/widget/MediaPlayer.scss deleted file mode 100644 index e1597c2..0000000 --- a/examples/js/media-player/widget/MediaPlayer.scss +++ /dev/null @@ -1,56 +0,0 @@ -// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss -$fg-color: #{"@theme_fg_color"}; -$bg-color: #{"@theme_bg_color"}; - -window { - all: unset; -} - -box.MediaPlayer { - padding: .6rem; - background-color: $bg-color; - - box.cover-art { - min-width: 120px; - min-height: 120px; - border-radius: 9px; - margin-right: .6rem; - background-size: contain; - background-position: center; - } - - box.title { - label { - font-weight: bold; - font-size: 1.1em; - } - } - - scale { - padding: 0; - margin: .4rem 0; - - trough { - min-height: 8px; - } - - highlight { - background-color: $fg-color; - } - - slider { - all: unset; - } - } - - centerbox.actions { - min-width: 220px; - - button { - min-width: 0; - min-height: 0; - padding: .4rem; - margin: 0 .2rem; - } - } -} diff --git a/examples/js/media-player/widget/MediaPlayer.tsx b/examples/js/media-player/widget/MediaPlayer.tsx deleted file mode 100644 index 06c7e77..0000000 --- a/examples/js/media-player/widget/MediaPlayer.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { Astal, Gtk } from "astal/gtk3" -import Mpris from "gi://AstalMpris" -import { bind } from "astal" - -function lengthStr(length: number) { - const min = Math.floor(length / 60) - const sec = Math.floor(length % 60) - const sec0 = sec < 10 ? "0" : "" - return `${min}:${sec0}${sec}` -} - - -function MediaPlayer({ player }: { player: Mpris.Player }) { - const { START, END } = Gtk.Align - - const title = bind(player, "title").as(t => - t || "Unknown Track") - - const artist = bind(player, "artist").as(a => - a || "Unknown Artist") - - const coverArt = bind(player, "coverArt").as(c => - `background-image: url('${c}')`) - - const playerIcon = bind(player, "entry").as(e => - Astal.Icon.lookup_icon(e) ? e : "audio-x-generic-symbolic") - - const position = bind(player, "position").as(p => player.length > 0 - ? p / player.length : 0) - - const playIcon = bind(player, "playbackStatus").as(s => - s === Mpris.PlaybackStatus.PLAYING - ? "media-playback-pause-symbolic" - : "media-playback-start-symbolic" - ) - - return - - - - - - -} - -export default function MprisPlayers() { - const mpris = Mpris.get_default() - return - {bind(mpris, "players").as(arr => arr.map(player => ( - - )))} - -} diff --git a/examples/js/notifications/README.md b/examples/js/notifications/README.md deleted file mode 100644 index 60dad60..0000000 --- a/examples/js/notifications/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Notifications Popups - -![notifs](https://github.com/user-attachments/assets/0df0eddc-5c74-4af0-a694-48dc8ec6bb44) - -A replacement for dunst and other daemons using [Notifd](https://aylur.github.io/astal/guide/libraries/notifd). diff --git a/examples/js/notifications/app.ts b/examples/js/notifications/app.ts deleted file mode 100644 index ed53292..0000000 --- a/examples/js/notifications/app.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { App } from "astal/gtk3" -import style from "./style.scss" -import NotificationPopups from "./notifications/NotificationPopups" - -App.start({ - instanceName: "notifications", - css: style, - main: () => App.get_monitors().map(NotificationPopups), -}) diff --git a/examples/js/notifications/notifications/Notification.scss b/examples/js/notifications/notifications/Notification.scss deleted file mode 100644 index a32f08b..0000000 --- a/examples/js/notifications/notifications/Notification.scss +++ /dev/null @@ -1,125 +0,0 @@ -@use "sass:string"; - -@function gtkalpha($c, $a) { - @return string.unquote("alpha(#{$c},#{$a})"); -} - -// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss -$fg-color: #{"@theme_fg_color"}; -$bg-color: #{"@theme_bg_color"}; -$error: red; - -window.NotificationPopups { - all: unset; -} - -eventbox.Notification { - - &:first-child>box { - margin-top: 1rem; - } - - &:last-child>box { - margin-bottom: 1rem; - } - - // eventboxes can not take margins so we style its inner box instead - >box { - min-width: 400px; - border-radius: 13px; - background-color: $bg-color; - margin: .5rem 1rem .5rem 1rem; - box-shadow: 2px 3px 8px 0 gtkalpha(black, .4); - border: 1pt solid gtkalpha($fg-color, .03); - } - - &.critical>box { - border: 1pt solid gtkalpha($error, .4); - - .header { - - .app-name { - color: gtkalpha($error, .8); - - } - - .app-icon { - color: gtkalpha($error, .6); - } - } - } - - .header { - padding: .5rem; - color: gtkalpha($fg-color, 0.5); - - .app-icon { - margin: 0 .4rem; - } - - .app-name { - margin-right: .3rem; - font-weight: bold; - - &:first-child { - margin-left: .4rem; - } - } - - .time { - margin: 0 .4rem; - } - - button { - padding: .2rem; - min-width: 0; - min-height: 0; - } - } - - separator { - margin: 0 .4rem; - background-color: gtkalpha($fg-color, .1); - } - - .content { - margin: 1rem; - margin-top: .5rem; - - .summary { - font-size: 1.2em; - color: $fg-color; - } - - .body { - color: gtkalpha($fg-color, 0.8); - } - - .image { - border: 1px solid gtkalpha($fg-color, .02); - margin-right: .5rem; - border-radius: 9px; - min-width: 100px; - min-height: 100px; - background-size: cover; - background-position: center; - } - } - - .actions { - margin: 1rem; - margin-top: 0; - - button { - margin: 0 .3rem; - - &:first-child { - margin-left: 0; - } - - &:last-child { - margin-right: 0; - } - } - } -} diff --git a/examples/js/notifications/notifications/Notification.tsx b/examples/js/notifications/notifications/Notification.tsx deleted file mode 100644 index 5149d5b..0000000 --- a/examples/js/notifications/notifications/Notification.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { GLib } from "astal" -import { Gtk, Astal } from "astal/gtk3" -import { type EventBox } from "astal/gtk3/widget" -import Notifd from "gi://AstalNotifd" - -const isIcon = (icon: string) => - !!Astal.Icon.lookup_icon(icon) - -const fileExists = (path: string) => - GLib.file_test(path, GLib.FileTest.EXISTS) - -const time = (time: number, format = "%H:%M") => GLib.DateTime - .new_from_unix_local(time) - .format(format)! - -const urgency = (n: Notifd.Notification) => { - const { LOW, NORMAL, CRITICAL } = Notifd.Urgency - // match operator when? - switch (n.urgency) { - case LOW: return "low" - case CRITICAL: return "critical" - case NORMAL: - default: return "normal" - } -} - -type Props = { - setup(self: EventBox): void - onHoverLost(self: EventBox): void - notification: Notifd.Notification -} - -export default function Notification(props: Props) { - const { notification: n, onHoverLost, setup } = props - const { START, CENTER, END } = Gtk.Align - - return - - - {(n.appIcon || n.desktopEntry) && } - - - - {n.image && fileExists(n.image) && } - {n.image && isIcon(n.image) && - - } - - - - {n.get_actions().length > 0 && - {n.get_actions().map(({ label, id }) => ( - - ))} - } - - -} diff --git a/examples/js/notifications/notifications/NotificationPopups.tsx b/examples/js/notifications/notifications/NotificationPopups.tsx deleted file mode 100644 index 13fdd88..0000000 --- a/examples/js/notifications/notifications/NotificationPopups.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { Astal, Gtk, Gdk } from "astal/gtk3" -import Notifd from "gi://AstalNotifd" -import Notification from "./Notification" -import { type Subscribable } from "astal/binding" -import { Variable, bind, timeout } from "astal" - -// see comment below in constructor -const TIMEOUT_DELAY = 5000 - -// The purpose if this class is to replace Variable> -// with a Map type in order to track notification widgets -// by their id, while making it conviniently bindable as an array -class NotifiationMap implements Subscribable { - // the underlying map to keep track of id widget pairs - private map: Map = new Map() - - // it makes sense to use a Variable under the hood and use its - // reactivity implementation instead of keeping track of subscribers ourselves - private var: Variable> = Variable([]) - - // notify subscribers to rerender when state changes - private notifiy() { - this.var.set([...this.map.values()].reverse()) - } - - constructor() { - const notifd = Notifd.get_default() - - /** - * uncomment this if you want to - * ignore timeout by senders and enforce our own timeout - * note that if the notification has any actions - * they might not work, since the sender already treats them as resolved - */ - // notifd.ignoreTimeout = true - - notifd.connect("notified", (_, id) => { - this.set(id, Notification({ - notification: notifd.get_notification(id)!, - - // once hovering over the notification is done - // destroy the widget without calling notification.dismiss() - // so that it acts as a "popup" and we can still display it - // in a notification center like widget - // but clicking on the close button will close it - onHoverLost: () => this.delete(id), - - // notifd by default does not close notifications - // until user input or the timeout specified by sender - // which we set to ignore above - setup: () => timeout(TIMEOUT_DELAY, () => { - /** - * uncomment this if you want to "hide" the notifications - * after TIMEOUT_DELAY - */ - // this.delete(id) - }) - })) - }) - - // notifications can be closed by the outside before - // any user input, which have to be handled too - notifd.connect("resolved", (_, id) => { - this.delete(id) - }) - } - - private set(key: number, value: Gtk.Widget) { - // in case of replacecment destroy previous widget - this.map.get(key)?.destroy() - this.map.set(key, value) - this.notifiy() - } - - private delete(key: number) { - this.map.get(key)?.destroy() - this.map.delete(key) - this.notifiy() - } - - // needed by the Subscribable interface - get() { - return this.var.get() - } - - // needed by the Subscribable interface - subscribe(callback: (list: Array) => void) { - return this.var.subscribe(callback) - } -} - -export default function NotificationPopups(gdkmonitor: Gdk.Monitor) { - const { TOP, RIGHT } = Astal.WindowAnchor - const notifs = new NotifiationMap() - - return - - {bind(notifs)} - - -} diff --git a/examples/js/notifications/style.scss b/examples/js/notifications/style.scss deleted file mode 100644 index 7ef0168..0000000 --- a/examples/js/notifications/style.scss +++ /dev/null @@ -1 +0,0 @@ -@use "./notifications/Notification.scss"; diff --git a/examples/js/simple-bar/README.md b/examples/js/simple-bar/README.md deleted file mode 100644 index f92b20e..0000000 --- a/examples/js/simple-bar/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Simple Bar Example - -![simple-bar](https://github.com/user-attachments/assets/a306c864-56b7-44c4-8820-81f424f32b9b) - -A simple bar for Hyprland using - -- [Battery library](https://aylur.github.io/astal/guide/libraries/battery). -- [Hyprland library](https://aylur.github.io/astal/guide/libraries/hyprland). -- [Mpris library](https://aylur.github.io/astal/guide/libraries/mpris). -- [Network library](https://aylur.github.io/astal/guide/libraries/network). -- [Tray library](https://aylur.github.io/astal/guide/libraries/tray). -- [WirePlumber library](https://aylur.github.io/astal/guide/libraries/wireplumber). diff --git a/examples/js/simple-bar/app.ts b/examples/js/simple-bar/app.ts deleted file mode 100644 index 4b7ea48..0000000 --- a/examples/js/simple-bar/app.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { App } from "astal/gtk3" -import style from "./style.scss" -import Bar from "./widget/Bar" - -App.start({ - css: style, - instanceName: "js", - requestHandler(request, res) { - print(request) - res("ok") - }, - main: () => App.get_monitors().map(Bar), -}) diff --git a/examples/js/simple-bar/style.scss b/examples/js/simple-bar/style.scss deleted file mode 100644 index f5f771a..0000000 --- a/examples/js/simple-bar/style.scss +++ /dev/null @@ -1,106 +0,0 @@ -@use "sass:color"; - -$bg: #212223; -$fg: #f1f1f1; -$accent: #378DF7; -$radius: 7px; - -window.Bar { - border: none; - box-shadow: none; - background-color: $bg; - color: $fg; - font-size: 1.1em; - font-weight: bold; - - label { - margin: 0 8px; - } - - .Workspaces { - button { - all: unset; - background-color: transparent; - - &:hover label { - background-color: color.adjust($fg, $alpha: -0.84); - border-color: color.adjust($accent, $alpha: -0.8); - } - - &:active label { - background-color: color.adjust($fg, $alpha: -0.8) - } - } - - label { - transition: 200ms; - padding: 0 8px; - margin: 2px; - border-radius: $radius; - border: 1pt solid transparent; - } - - .focused label { - color: $accent; - border-color: $accent; - } - } - - .SysTray { - margin-right: 8px; - - button { - padding: 0 4px; - } - } - - .FocusedClient { - color: $accent; - } - - .Media .Cover { - min-height: 1.2em; - min-width: 1.2em; - border-radius: $radius; - background-position: center; - background-size: contain; - } - - .Battery label { - padding-left: 0; - margin-left: 0; - } - - .AudioSlider { - * { - all: unset; - } - - icon { - margin-right: .6em; - } - - & { - margin: 0 1em; - } - - trough { - background-color: color.adjust($fg, $alpha: -0.8); - border-radius: $radius; - } - - highlight { - background-color: $accent; - min-height: .8em; - border-radius: $radius; - } - - slider { - background-color: $fg; - border-radius: $radius; - min-height: 1em; - min-width: 1em; - margin: -.2em; - } - } -} diff --git a/examples/js/simple-bar/widget/Bar.tsx b/examples/js/simple-bar/widget/Bar.tsx deleted file mode 100644 index 6592f6a..0000000 --- a/examples/js/simple-bar/widget/Bar.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import { App } from "astal/gtk3" -import { Variable, GLib, bind } from "astal" -import { Astal, Gtk, Gdk } from "astal/gtk3" -import Hyprland from "gi://AstalHyprland" -import Mpris from "gi://AstalMpris" -import Battery from "gi://AstalBattery" -import Wp from "gi://AstalWp" -import Network from "gi://AstalNetwork" -import Tray from "gi://AstalTray" - -function SysTray() { - const tray = Tray.get_default() - - return - {bind(tray, "items").as(items => items.map(item => ( - ["dbusmenu", ag])} - menuModel={bind(item, "menuModel")}> - - - )))} - -} - -function Wifi() { - const network = Network.get_default() - const wifi = bind(network, "wifi") - - return - {wifi.as(wifi => wifi && ( - - ))} - - -} - -function AudioSlider() { - const speaker = Wp.get_default()?.audio.defaultSpeaker! - - return - - speaker.volume = value} - value={bind(speaker, "volume")} - /> - -} - -function BatteryLevel() { - const bat = Battery.get_default() - - return - - -} - -function Media() { - const mpris = Mpris.get_default() - - return - {bind(mpris, "players").as(ps => ps[0] ? ( - - - `background-image: url('${cover}');` - )} - /> - - ) : ( - "Nothing Playing" - ))} - -} - -function Workspaces() { - const hypr = Hyprland.get_default() - - return - {bind(hypr, "workspaces").as(wss => wss - .filter(ws => !(ws.id >= -99 && ws.id <= -2)) // filter out special workspaces - .sort((a, b) => a.id - b.id) - .map(ws => ( - - )) - )} - -} - -function FocusedClient() { - const hypr = Hyprland.get_default() - const focused = bind(hypr, "focusedClient") - - return - {focused.as(client => ( - client && -} - -function Time({ format = "%H:%M - %A %e." }) { - const time = Variable("").poll(1000, () => - GLib.DateTime.new_now_local().format(format)!) - - return