summaryrefslogtreecommitdiff
path: root/examples/js
diff options
context:
space:
mode:
authorAylur <[email protected]>2025-01-16 17:37:00 +0100
committerAylur <[email protected]>2025-01-16 17:37:04 +0100
commit9e8634d892c559c5b44565a68bf35b13cbcb5572 (patch)
tree36a8b911e919959cdf64d3c64646f5066c6a2523 /examples/js
parentbc796ac226800c43e724e27f53f410c157acaffe (diff)
add: gtk3 ts popover example
closes #224 closes #157
Diffstat (limited to 'examples/js')
-rw-r--r--examples/js/.gitignore7
-rw-r--r--examples/js/applauncher/README.md5
-rw-r--r--examples/js/applauncher/app.ts9
-rw-r--r--examples/js/applauncher/style.scss1
-rw-r--r--examples/js/applauncher/widget/Applauncher.scss59
-rw-r--r--examples/js/applauncher/widget/Applauncher.tsx87
-rw-r--r--examples/js/media-player/README.md5
-rw-r--r--examples/js/media-player/app.ts11
-rw-r--r--examples/js/media-player/style.scss1
-rw-r--r--examples/js/media-player/widget/MediaPlayer.scss56
-rw-r--r--examples/js/media-player/widget/MediaPlayer.tsx94
-rw-r--r--examples/js/notifications/README.md5
-rw-r--r--examples/js/notifications/app.ts9
-rw-r--r--examples/js/notifications/notifications/Notification.scss125
-rw-r--r--examples/js/notifications/notifications/Notification.tsx107
-rw-r--r--examples/js/notifications/notifications/NotificationPopups.tsx105
-rw-r--r--examples/js/notifications/style.scss1
-rw-r--r--examples/js/simple-bar/README.md12
-rw-r--r--examples/js/simple-bar/app.ts13
-rw-r--r--examples/js/simple-bar/style.scss106
-rw-r--r--examples/js/simple-bar/widget/Bar.tsx161
21 files changed, 0 insertions, 979 deletions
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 <button
- className="AppButton"
- onClicked={() => { hide(); app.launch() }}>
- <box>
- <icon icon={app.iconName} />
- <box valign={Gtk.Align.CENTER} vertical>
- <label
- className="name"
- truncate
- xalign={0}
- label={app.name}
- />
- {app.description && <label
- className="description"
- wrap
- xalign={0}
- label={app.description}
- />}
- </box>
- </box>
- </button>
-}
-
-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 <window
- name="launcher"
- anchor={Astal.WindowAnchor.TOP | Astal.WindowAnchor.BOTTOM}
- exclusivity={Astal.Exclusivity.IGNORE}
- keymode={Astal.Keymode.ON_DEMAND}
- application={App}
- onShow={() => text.set("")}
- onKeyPressEvent={function (self, event: Gdk.Event) {
- if (event.get_keyval()[1] === Gdk.KEY_Escape)
- self.hide()
- }}>
- <box>
- <eventbox widthRequest={4000} expand onClick={hide} />
- <box hexpand={false} vertical>
- <eventbox heightRequest={100} onClick={hide} />
- <box widthRequest={500} className="Applauncher" vertical>
- <entry
- placeholderText="Search"
- text={text()}
- onChanged={self => text.set(self.text)}
- onActivate={onEnter}
- />
- <box spacing={6} vertical>
- {list.as(list => list.map(app => (
- <AppButton app={app} />
- )))}
- </box>
- <box
- halign={CENTER}
- className="not-found"
- vertical
- visible={list.as(l => l.length === 0)}>
- <icon icon="system-search-symbolic" />
- <label label="No match found" />
- </box>
- </box>
- <eventbox expand onClick={hide} />
- </box>
- <eventbox widthRequest={4000} expand onClick={hide} />
- </box>
- </window>
-}
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 <box className="MediaPlayer">
- <box className="cover-art" css={coverArt} />
- <box vertical>
- <box className="title">
- <label truncate hexpand halign={START} label={title} />
- <icon icon={playerIcon} />
- </box>
- <label halign={START} valign={START} vexpand wrap label={artist} />
- <slider
- visible={bind(player, "length").as(l => l > 0)}
- onDragged={({ value }) => player.position = value * player.length}
- value={position}
- />
- <centerbox className="actions">
- <label
- hexpand
- className="position"
- halign={START}
- visible={bind(player, "length").as(l => l > 0)}
- label={bind(player, "position").as(lengthStr)}
- />
- <box>
- <button
- onClicked={() => player.previous()}
- visible={bind(player, "canGoPrevious")}>
- <icon icon="media-skip-backward-symbolic" />
- </button>
- <button
- onClicked={() => player.play_pause()}
- visible={bind(player, "canControl")}>
- <icon icon={playIcon} />
- </button>
- <button
- onClicked={() => player.next()}
- visible={bind(player, "canGoNext")}>
- <icon icon="media-skip-forward-symbolic" />
- </button>
- </box>
- <label
- className="length"
- hexpand
- halign={END}
- visible={bind(player, "length").as(l => l > 0)}
- label={bind(player, "length").as(l => l > 0 ? lengthStr(l) : "0:00")}
- />
- </centerbox>
- </box>
- </box>
-}
-
-export default function MprisPlayers() {
- const mpris = Mpris.get_default()
- return <box vertical>
- {bind(mpris, "players").as(arr => arr.map(player => (
- <MediaPlayer player={player} />
- )))}
- </box>
-}
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 <eventbox
- className={`Notification ${urgency(n)}`}
- setup={setup}
- onHoverLost={onHoverLost}>
- <box vertical>
- <box className="header">
- {(n.appIcon || n.desktopEntry) && <icon
- className="app-icon"
- visible={Boolean(n.appIcon || n.desktopEntry)}
- icon={n.appIcon || n.desktopEntry}
- />}
- <label
- className="app-name"
- halign={START}
- truncate
- label={n.appName || "Unknown"}
- />
- <label
- className="time"
- hexpand
- halign={END}
- label={time(n.time)}
- />
- <button onClicked={() => n.dismiss()}>
- <icon icon="window-close-symbolic" />
- </button>
- </box>
- <Gtk.Separator visible />
- <box className="content">
- {n.image && fileExists(n.image) && <box
- valign={START}
- className="image"
- css={`background-image: url('${n.image}')`}
- />}
- {n.image && isIcon(n.image) && <box
- expand={false}
- valign={START}
- className="icon-image">
- <icon icon={n.image} expand halign={CENTER} valign={CENTER} />
- </box>}
- <box vertical>
- <label
- className="summary"
- halign={START}
- xalign={0}
- label={n.summary}
- truncate
- />
- {n.body && <label
- className="body"
- wrap
- useMarkup
- halign={START}
- xalign={0}
- justifyFill
- label={n.body}
- />}
- </box>
- </box>
- {n.get_actions().length > 0 && <box className="actions">
- {n.get_actions().map(({ label, id }) => (
- <button
- hexpand
- onClicked={() => n.invoke(id)}>
- <label label={label} halign={CENTER} hexpand />
- </button>
- ))}
- </box>}
- </box>
- </eventbox>
-}
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<Array<Widget>>
-// with a Map<number, Widget> 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<number, Gtk.Widget> = 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<Array<Gtk.Widget>> = 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<Gtk.Widget>) => void) {
- return this.var.subscribe(callback)
- }
-}
-
-export default function NotificationPopups(gdkmonitor: Gdk.Monitor) {
- const { TOP, RIGHT } = Astal.WindowAnchor
- const notifs = new NotifiationMap()
-
- return <window
- className="NotificationPopups"
- gdkmonitor={gdkmonitor}
- exclusivity={Astal.Exclusivity.EXCLUSIVE}
- anchor={TOP | RIGHT}>
- <box vertical noImplicitDestroy>
- {bind(notifs)}
- </box>
- </window>
-}
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 <box className="SysTray">
- {bind(tray, "items").as(items => items.map(item => (
- <menubutton
- tooltipMarkup={bind(item, "tooltipMarkup")}
- usePopover={false}
- actionGroup={bind(item, "actionGroup").as(ag => ["dbusmenu", ag])}
- menuModel={bind(item, "menuModel")}>
- <icon gicon={bind(item, "gicon")} />
- </menubutton>
- )))}
- </box>
-}
-
-function Wifi() {
- const network = Network.get_default()
- const wifi = bind(network, "wifi")
-
- return <box visible={wifi.as(Boolean)}>
- {wifi.as(wifi => wifi && (
- <icon
- tooltipText={bind(wifi, "ssid").as(String)}
- className="Wifi"
- icon={bind(wifi, "iconName")}
- />
- ))}
- </box>
-
-}
-
-function AudioSlider() {
- const speaker = Wp.get_default()?.audio.defaultSpeaker!
-
- return <box className="AudioSlider" css="min-width: 140px">
- <icon icon={bind(speaker, "volumeIcon")} />
- <slider
- hexpand
- onDragged={({ value }) => speaker.volume = value}
- value={bind(speaker, "volume")}
- />
- </box>
-}
-
-function BatteryLevel() {
- const bat = Battery.get_default()
-
- return <box className="Battery"
- visible={bind(bat, "isPresent")}>
- <icon icon={bind(bat, "batteryIconName")} />
- <label label={bind(bat, "percentage").as(p =>
- `${Math.floor(p * 100)} %`
- )} />
- </box>
-}
-
-function Media() {
- const mpris = Mpris.get_default()
-
- return <box className="Media">
- {bind(mpris, "players").as(ps => ps[0] ? (
- <box>
- <box
- className="Cover"
- valign={Gtk.Align.CENTER}
- css={bind(ps[0], "coverArt").as(cover =>
- `background-image: url('${cover}');`
- )}
- />
- <label
- label={bind(ps[0], "title").as(() =>
- `${ps[0].title} - ${ps[0].artist}`
- )}
- />
- </box>
- ) : (
- "Nothing Playing"
- ))}
- </box>
-}
-
-function Workspaces() {
- const hypr = Hyprland.get_default()
-
- return <box className="Workspaces">
- {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 => (
- <button
- className={bind(hypr, "focusedWorkspace").as(fw =>
- ws === fw ? "focused" : "")}
- onClicked={() => ws.focus()}>
- {ws.id}
- </button>
- ))
- )}
- </box>
-}
-
-function FocusedClient() {
- const hypr = Hyprland.get_default()
- const focused = bind(hypr, "focusedClient")
-
- return <box
- className="Focused"
- visible={focused.as(Boolean)}>
- {focused.as(client => (
- client && <label label={bind(client, "title").as(String)} />
- ))}
- </box>
-}
-
-function Time({ format = "%H:%M - %A %e." }) {
- const time = Variable<string>("").poll(1000, () =>
- GLib.DateTime.new_now_local().format(format)!)
-
- return <label
- className="Time"
- onDestroy={() => time.drop()}
- label={time()}
- />
-}
-
-export default function Bar(monitor: Gdk.Monitor) {
- const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
-
- return <window
- className="Bar"
- gdkmonitor={monitor}
- exclusivity={Astal.Exclusivity.EXCLUSIVE}
- anchor={TOP | LEFT | RIGHT}>
- <centerbox>
- <box hexpand halign={Gtk.Align.START}>
- <Workspaces />
- <FocusedClient />
- </box>
- <box>
- <Media />
- </box>
- <box hexpand halign={Gtk.Align.END} >
- <SysTray />
- <Wifi />
- <AudioSlider />
- <BatteryLevel />
- <Time />
- </box>
- </centerbox>
- </window>
-}