diff options
| -rw-r--r-- | scss/sidebar.scss | 164 | ||||
| -rw-r--r-- | src/modules/sidebar/modules/media.tsx | 39 |
2 files changed, 134 insertions, 69 deletions
diff --git a/scss/sidebar.scss b/scss/sidebar.scss index 83d1953..9f72ca8 100644 --- a/scss/sidebar.scss +++ b/scss/sidebar.scss @@ -171,7 +171,7 @@ } } - .dashboard .media { + .media { @include lib.spacing(15); .cover-art { @@ -316,91 +316,129 @@ } } - .audio .media { - @include lib.spacing(40, true); + .players { + .player { + @include lib.spacing(40, true); - .cover-art { - @include lib.rounded(10); - @include lib.element-decel; - @include lib.shadow(scheme.$mantle, $blur: 5, $spread: 2); + .cover-art { + @include lib.rounded(10); + @include lib.element-decel; + @include lib.shadow(scheme.$mantle, $blur: 5, $spread: 2); - background-position: center; - background-repeat: no-repeat; - background-size: cover; - min-width: lib.s(256); - min-height: lib.s(256); - font-size: lib.s(96); - font-weight: bold; - background-color: scheme.$base; - color: scheme.$subtext0; - margin-top: lib.s(20); - } + background-position: center; + background-repeat: no-repeat; + background-size: cover; + min-width: lib.s(256); + min-height: lib.s(256); + font-size: lib.s(96); + font-weight: bold; + background-color: scheme.$base; + color: scheme.$subtext0; + margin-top: lib.s(20); + } - .progress { - margin: 0 lib.s(40); + .progress { + margin: 0 lib.s(40); - .slider { - @include lib.rounded(8); - @include lib.fluent-decel(1000ms); + .slider { + @include lib.rounded(8); + @include lib.fluent-decel(1000ms); - min-height: lib.s(15); - background-color: scheme.$overlay0; - color: scheme.$subtext1; - } + min-height: lib.s(15); + background-color: scheme.$overlay0; + color: scheme.$subtext1; + } - .time { - margin-top: lib.s(5); - font-size: lib.s(13); - color: scheme.$subtext1; + .time { + margin-top: lib.s(5); + font-size: lib.s(13); + color: scheme.$subtext1; + } } - } - .details { - font-size: lib.s(14); - margin-top: lib.s(20); + .details { + font-size: lib.s(14); + margin-top: lib.s(20); - @include lib.spacing(3, true); + @include lib.spacing(3, true); - .title { - font-size: lib.s(18); - color: scheme.$text; - font-weight: bold; - } + .title { + font-size: lib.s(18); + color: scheme.$text; + font-weight: bold; + } - .artist { - color: scheme.$green; + .artist { + color: scheme.$green; + } + + .album { + color: scheme.$subtext0; + } } - .album { - color: scheme.$subtext0; + .controls { + margin-top: lib.s(-20); + margin-bottom: lib.s(5); + + button { + @include media-button; + + // Cause some nerd font icons don't have the correct width + &.needs-adjustment { + padding-right: lib.s(5); + } + } + + .playback { + font-size: lib.s(32); + + @include lib.spacing(40); + } + + .options { + margin: 0 lib.s(40); + margin-top: lib.s(-10); + font-size: lib.s(20); + + @include lib.spacing(20); + } } } - .controls { - margin-top: lib.s(-20); - margin-bottom: lib.s(5); + .indicators { + @include lib.spacing(10); - button { - @include media-button; + & > button { + @include lib.rounded(1000); + @include lib.element-decel; - // Cause some nerd font icons don't have the correct width - &.needs-adjustment { - padding-right: lib.s(5); + min-width: lib.s(10); + min-height: lib.s(10); + + background-color: color.change(scheme.$overlay0, $alpha: 0.5); + + &:hover, + &:focus { + background-color: color.change(scheme.$overlay1, $alpha: 0.5); } - } - .playback { - font-size: lib.s(32); + &:active { + background-color: color.change(scheme.$overlay2, $alpha: 0.5); + } - @include lib.spacing(40); - } + &.active { + background-color: color.change(scheme.$primary, $alpha: 0.9); - .options { - margin: 0 lib.s(40); - margin-top: lib.s(-10); - font-size: lib.s(20); + &:hover, + &:focus { + background-color: color.change(scheme.$primary, $alpha: 0.7); + } - @include lib.spacing(20); + &:active { + background-color: color.change(scheme.$primary, $alpha: 0.6); + } + } } } } diff --git a/src/modules/sidebar/modules/media.tsx b/src/modules/sidebar/modules/media.tsx index 4392aa7..e14590e 100644 --- a/src/modules/sidebar/modules/media.tsx +++ b/src/modules/sidebar/modules/media.tsx @@ -1,6 +1,6 @@ import Players from "@/services/players"; import Slider from "@/widgets/slider"; -import { bind, Variable } from "astal"; +import { bind, timeout, Variable } from "astal"; import { Gtk } from "astal/gtk3"; import AstalMpris from "gi://AstalMpris"; @@ -12,7 +12,7 @@ const lengthStr = (length: number) => const noNull = (s: string | null) => s ?? "-"; const NoMedia = () => ( - <box vertical className="media" name="none"> + <box vertical className="player" name="none"> <box homogeneous halign={Gtk.Align.CENTER} className="cover-art"> <label xalign={0.4} label="" /> </box> @@ -50,7 +50,7 @@ const Player = ({ player }: { player: AstalMpris.Player }) => { const position = Variable.derive([bind(player, "position"), bind(player, "length")], (p, l) => p / l); return ( - <box vertical className="media" name={player.busName} onDestroy={() => position.drop()}> + <box vertical className="player" name={player.busName} onDestroy={() => position.drop()}> <box homogeneous halign={Gtk.Align.CENTER} @@ -131,19 +131,46 @@ const Player = ({ player }: { player: AstalMpris.Player }) => { ); }; +const Indicator = ({ active, player }: { active: Variable<string>; player: AstalMpris.Player }) => ( + <button + className={bind(active).as(a => (a === player.busName ? "active" : ""))} + cursor="pointer" + onClicked={() => active.set(player.busName)} + /> +); + export default () => { - const active = Variable(Players.get_default().list[0]?.busName ?? "none"); + const players = Players.get_default(); + const active = Variable(players.lastPlayer?.busName ?? "none"); + + active.observe(players, "notify::list", () => { + const prev = active.get(); + timeout(10, () => { + if (players.list.some(p => p.busName === prev)) active.set(prev); + else active.set(players.lastPlayer?.busName ?? "none"); + }); + return "none"; + }); return ( - <box vertical> + <box vertical className="players" onDestroy={() => active.drop()}> <stack transitionType={Gtk.StackTransitionType.SLIDE_LEFT_RIGHT} transitionDuration={150} shown={bind(active)} > <NoMedia /> - {bind(Players.get_default(), "list").as(ps => ps.map(p => <Player player={p} />))} + {bind(players, "list").as(ps => ps.map(p => <Player player={p} />))} </stack> + <revealer + transitionType={Gtk.RevealerTransitionType.SLIDE_DOWN} + transitionDuration={120} + revealChild={bind(players, "list").as(l => l.length > 1)} + > + <box halign={Gtk.Align.CENTER} className="indicators"> + {bind(players, "list").as(ps => ps.map(p => <Indicator active={active} player={p} />))} + </box> + </revealer> </box> ); }; |