diff --git a/docs/guide/getting-started/supported-languages.md b/docs/guide/getting-started/supported-languages.md index a9d28247..55ea6b2f 100644 --- a/docs/guide/getting-started/supported-languages.md +++ b/docs/guide/getting-started/supported-languages.md @@ -24,6 +24,8 @@ Examples: - [Notification Popups](https://github.com/Aylur/astal/tree/main/examples/js/notifications) ![notification-popups](https://github.com/user-attachments/assets/0df0eddc-5c74-4af0-a694-48dc8ec6bb44) +- [Media Player](https://github.com/Aylur/astal/tree/main/examples/js/media-player) +![media-player](https://github.com/user-attachments/assets/891e9706-74db-4505-bd83-c3628d7b4fd0) ## Lua diff --git a/examples/js/media-player/.gitignore b/examples/js/media-player/.gitignore new file mode 100644 index 00000000..6850183b --- /dev/null +++ b/examples/js/media-player/.gitignore @@ -0,0 +1,2 @@ +@girs/ +node_modules/ \ No newline at end of file diff --git a/examples/js/media-player/README.md b/examples/js/media-player/README.md new file mode 100644 index 00000000..4e3d237b --- /dev/null +++ b/examples/js/media-player/README.md @@ -0,0 +1,5 @@ +# 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 new file mode 100644 index 00000000..5b7558a0 --- /dev/null +++ b/examples/js/media-player/app.ts @@ -0,0 +1,11 @@ +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 new file mode 100644 index 00000000..2e2f625c --- /dev/null +++ b/examples/js/media-player/style.scss @@ -0,0 +1 @@ +@use "./widget/MediaPlayer.scss"; diff --git a/examples/js/media-player/widget/MediaPlayer.scss b/examples/js/media-player/widget/MediaPlayer.scss new file mode 100644 index 00000000..e1597c28 --- /dev/null +++ b/examples/js/media-player/widget/MediaPlayer.scss @@ -0,0 +1,56 @@ +// 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 new file mode 100644 index 00000000..06c7e77f --- /dev/null +++ b/examples/js/media-player/widget/MediaPlayer.tsx @@ -0,0 +1,94 @@ +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 => ( + + )))} + +}