summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-04-02 18:43:01 +1100
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-04-02 18:43:01 +1100
commit33e1ab078501436b0d634b6f3f2f23687783894b (patch)
treefc0df9f8c3d58aed65df1b9a993be92b81f3d1f4
parentsidebar: truncate device selector (diff)
downloadcaelestia-shell-33e1ab078501436b0d634b6f3f2f23687783894b.tar.gz
caelestia-shell-33e1ab078501436b0d634b6f3f2f23687783894b.tar.bz2
caelestia-shell-33e1ab078501436b0d634b6f3f2f23687783894b.zip
bar: embedded style
-rw-r--r--app.tsx3
-rw-r--r--scss/bar.scss65
-rw-r--r--src/modules/bar.tsx113
-rw-r--r--src/modules/screencorners.tsx23
4 files changed, 163 insertions, 41 deletions
diff --git a/app.tsx b/app.tsx
index 351e617..b28369d 100644
--- a/app.tsx
+++ b/app.tsx
@@ -2,7 +2,7 @@ import Bar from "@/modules/bar";
import Launcher from "@/modules/launcher";
import NotifPopups from "@/modules/notifpopups";
import Osds from "@/modules/osds";
-import ScreenCorners from "@/modules/screencorners";
+import ScreenCorners, { BarScreenCorners } from "@/modules/screencorners";
import Session from "@/modules/session";
import SideBar from "@/modules/sidebar";
import Calendar from "@/services/calendar";
@@ -81,6 +81,7 @@ App.start({
Monitors.get_default().forEach(m => <SideBar monitor={m} />);
Monitors.get_default().forEach(m => <Bar monitor={m} />);
Monitors.get_default().forEach(m => <ScreenCorners monitor={m} />);
+ Monitors.get_default().forEach(m => <BarScreenCorners monitor={m} />);
// Init services
timeout(1000, () => {
diff --git a/scss/bar.scss b/scss/bar.scss
index b8d36e4..efd1935 100644
--- a/scss/bar.scss
+++ b/scss/bar.scss
@@ -15,7 +15,6 @@
@include font.mono;
font-size: lib.s(14);
- padding-right: lib.s(3);
label.icon {
font-size: lib.s(18);
@@ -183,12 +182,18 @@
}
&.gaps {
+ padding-right: lib.s(3);
+
.module {
@include lib.rounded(8);
background-color: scheme.$base;
}
+ .screen-corner {
+ background-color: transparent;
+ }
+
.os-icon {
@include lib.border(scheme.$yellow);
@@ -242,4 +247,62 @@
}
}
}
+
+ &.embedded {
+ $-rounding: 23;
+
+ margin: 0;
+
+ .module {
+ background-color: scheme.$mantle;
+ }
+
+ .screen-corner {
+ @include lib.rounded($-rounding);
+ }
+
+ &.horizontal {
+ .module {
+ padding: lib.s(10) lib.s(10);
+ padding-left: lib.s(15);
+ }
+
+ .before-spacer {
+ border-bottom-right-radius: lib.s($-rounding);
+ padding-right: lib.s(15);
+ }
+
+ .after-spacer {
+ border-bottom-left-radius: lib.s($-rounding);
+ }
+
+ .power {
+ padding-right: lib.s(12);
+ }
+ }
+
+ &.vertical {
+ .module {
+ padding: lib.s(8) lib.s(10);
+ }
+
+ .before-spacer {
+ border-bottom-right-radius: lib.s($-rounding);
+ padding-bottom: lib.s(15);
+ }
+
+ .after-spacer {
+ border-top-right-radius: lib.s($-rounding);
+ padding-top: lib.s(15);
+ }
+
+ .os-icon {
+ padding-top: lib.s(12);
+ }
+
+ .power {
+ padding-bottom: lib.s(12);
+ }
+ }
+ }
}
diff --git a/src/modules/bar.tsx b/src/modules/bar.tsx
index 2aa45b6..9d65191 100644
--- a/src/modules/bar.tsx
+++ b/src/modules/bar.tsx
@@ -10,7 +10,7 @@ import { setupCustomTooltip } from "@/utils/widgets";
import ScreenCorner from "@/widgets/screencorner";
import { execAsync, Variable } from "astal";
import Binding, { bind, kebabify } from "astal/binding";
-import { App, Astal, Gtk } from "astal/gtk3";
+import { App, Astal, Gtk, type Widget } from "astal/gtk3";
import { bar as config } from "config";
import AstalBattery from "gi://AstalBattery";
import AstalBluetooth from "gi://AstalBluetooth";
@@ -20,6 +20,11 @@ import AstalNotifd from "gi://AstalNotifd";
import AstalTray from "gi://AstalTray";
import AstalWp from "gi://AstalWp";
+interface SpacerClassNameProps {
+ beforeSpacer?: boolean;
+ afterSpacer?: boolean;
+}
+
const hyprland = AstalHyprland.get_default();
const getBatteryIcon = (perc: number) => {
@@ -74,19 +79,22 @@ const switchPane = (name: string) => {
}
};
-const OSIcon = () => (
+const spacerClassName = ({ beforeSpacer, afterSpacer }: SpacerClassNameProps) =>
+ `${beforeSpacer ? "before-spacer" : ""} ${afterSpacer ? "after-spacer" : ""}`;
+
+const OSIcon = (props: SpacerClassNameProps) => (
<button
- className="module os-icon"
+ className={`module os-icon ${spacerClassName(props)}`}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane("dashboard")}
>
{osIcon}
</button>
);
-const ActiveWindow = () => (
+const ActiveWindow = (props: SpacerClassNameProps) => (
<box
vertical={bind(config.vertical)}
- className="module active-window"
+ className={`module active-window ${spacerClassName(props)}`}
setup={self => {
const title = Variable("");
const updateTooltip = (c: AstalHyprland.Client | null) =>
@@ -124,7 +132,7 @@ const ActiveWindow = () => (
</box>
);
-const MediaPlaying = () => {
+const MediaPlaying = (props: SpacerClassNameProps) => {
const players = Players.get_default();
const getLabel = (fallback = "") =>
players.lastPlayer ? `${players.lastPlayer.title} - ${players.lastPlayer.artist}` : fallback;
@@ -141,7 +149,7 @@ const MediaPlaying = () => {
setupCustomTooltip(self, bind(label));
}}
>
- <box vertical={bind(config.vertical)} className="module media-playing">
+ <box vertical={bind(config.vertical)} className={`module media-playing ${spacerClassName(props)}`}>
<icon
setup={self =>
players.hookLastPlayer(self, "notify::identity", () => {
@@ -211,7 +219,7 @@ const Workspace = ({ idx }: { idx: number }) => {
);
};
-const Workspaces = () => (
+const Workspaces = (props: SpacerClassNameProps) => (
<eventbox
onScroll={(_, event) => {
const activeWs = hyprland.focusedClient?.workspace.name;
@@ -220,7 +228,7 @@ const Workspaces = () => (
hyprland.dispatch("workspace", (event.delta_y < 0 ? "-" : "+") + 1);
}}
>
- <box vertical={bind(config.vertical)} className="module workspaces">
+ <box vertical={bind(config.vertical)} className={`module workspaces ${spacerClassName(props)}`}>
{bind(config.modules.workspaces.shown).as(
n => Array.from({ length: n }).map((_, idx) => <Workspace idx={idx + 1} />) // Start from 1
)}
@@ -241,10 +249,10 @@ const TrayItem = (item: AstalTray.TrayItem) => (
</menubutton>
);
-const Tray = () => (
+const Tray = (props: SpacerClassNameProps) => (
<box
vertical={bind(config.vertical)}
- className="module tray"
+ className={`module tray ${spacerClassName(props)}`}
visible={bind(AstalTray.get_default(), "items").as(i => i.length > 0)}
>
{bind(AstalTray.get_default(), "items").as(i => i.map(TrayItem))}
@@ -420,14 +428,14 @@ const Bluetooth = () => (
</box>
);
-const StatusIcons = () => (
- <box vertical={bind(config.vertical)} className="module status-icons">
+const StatusIcons = (props: SpacerClassNameProps) => (
+ <box vertical={bind(config.vertical)} className={`module status-icons ${spacerClassName(props)}`}>
<Network />
<Bluetooth />
</box>
);
-const PkgUpdates = () => (
+const PkgUpdates = (props: SpacerClassNameProps) => (
<button
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane("packages")}
setup={self =>
@@ -437,14 +445,14 @@ const PkgUpdates = () => (
)
}
>
- <box vertical={bind(config.vertical)} className="module pkg-updates">
+ <box vertical={bind(config.vertical)} className={`module pkg-updates ${spacerClassName(props)}`}>
<label className="icon" label="download" />
<label label={bind(Updates.get_default(), "numUpdates").as(String)} />
</box>
</button>
);
-const NotifCount = () => (
+const NotifCount = (props: SpacerClassNameProps) => (
<button
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane("notifpane")}
setup={self =>
@@ -456,7 +464,7 @@ const NotifCount = () => (
)
}
>
- <box vertical={bind(config.vertical)} className="module notif-count">
+ <box vertical={bind(config.vertical)} className={`module notif-count ${spacerClassName(props)}`}>
<label
className="icon"
label={bind(AstalNotifd.get_default(), "dontDisturb").as(d => (d ? "notifications_off" : "info"))}
@@ -474,10 +482,10 @@ const NotifCount = () => (
</button>
);
-const Battery = () => {
+const Battery = (props: SpacerClassNameProps) => {
const className = Variable.derive(
[bind(AstalBattery.get_default(), "percentage"), bind(AstalBattery.get_default(), "charging")],
- (p, c) => `module battery ${c ? "charging" : p < 0.2 ? "low" : ""}`
+ (p, c) => `module battery ${c ? "charging" : p < 0.2 ? "low" : ""} ${spacerClassName(props)}`
);
const tooltip = Variable.derive(
[bind(AstalBattery.get_default(), "timeToEmpty"), bind(AstalBattery.get_default(), "timeToFull")],
@@ -500,14 +508,14 @@ const Battery = () => {
);
};
-const DateTime = () => (
+const DateTime = (props: SpacerClassNameProps) => (
<button
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane("time")}
setup={self =>
setupCustomTooltip(self, bindCurrentTime(bind(config.modules.dateTime.detailedFormat), undefined, self))
}
>
- <box className="module date-time">
+ <box className={`module date-time ${spacerClassName(props)}`}>
<label className="icon" label="calendar_month" />
<label
setup={self =>
@@ -521,14 +529,14 @@ const DateTime = () => (
</button>
);
-const DateTimeVertical = () => (
+const DateTimeVertical = (props: SpacerClassNameProps) => (
<button
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane("time")}
setup={self =>
setupCustomTooltip(self, bindCurrentTime(bind(config.modules.dateTime.detailedFormat), undefined, self))
}
>
- <box vertical className="module date-time">
+ <box vertical className={`module date-time ${spacerClassName(props)}`}>
<label className="icon" label="calendar_month" />
<label label={bindCurrentTime("%H")} />
<label label={bindCurrentTime("%M")} />
@@ -536,14 +544,24 @@ const DateTimeVertical = () => (
</button>
);
-const Power = () => (
+const Power = (props: SpacerClassNameProps) => (
<button
- className="module power"
+ className={`module power ${spacerClassName(props)}`}
label="power_settings_new"
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && App.toggle_window("session")}
/>
);
+const Spacer = ({ onScroll }: { onScroll: (self: Widget.EventBox, event: Astal.ScrollEvent) => void }) => (
+ <eventbox onScroll={onScroll}>
+ <box vertical={bind(config.vertical)}>
+ <ScreenCorner place="topleft" />
+ <box expand />
+ <ScreenCorner place={bind(config.vertical).as(v => (v ? "bottomleft" : "topright"))} />
+ </box>
+ </eventbox>
+);
+
const Dummy = () => <box visible={false} />; // Invisible box cause otherwise shows as text
const bindWidget = (module: keyof typeof config.modules, Widget: () => JSX.Element) =>
@@ -561,20 +579,26 @@ const Bar = ({ monitor }: { monitor: Monitor }) => {
return (
<centerbox vertical={bind(config.vertical)} className={bind(className)} onDestroy={() => className.drop()}>
<box vertical={bind(config.vertical)}>
- {bindWidget("osIcon", OSIcon)}
- {bindWidget("activeWindow", ActiveWindow)}
- {bindWidget("mediaPlaying", MediaPlaying)}
- <button
- expand
+ {bindWidget("osIcon", () => (
+ <OSIcon />
+ ))}
+ {bindWidget("activeWindow", () => (
+ <ActiveWindow />
+ ))}
+ {bindWidget("mediaPlaying", () => (
+ <MediaPlaying beforeSpacer />
+ ))}
+ <Spacer
onScroll={(_, event) =>
event.delta_y > 0 ? (monitor.brightness -= 0.1) : (monitor.brightness += 0.1)
}
/>
</box>
- {bindWidget("workspaces", Workspaces)}
+ {bindWidget("workspaces", () => (
+ <Workspaces beforeSpacer afterSpacer />
+ ))}
<box vertical={bind(config.vertical)}>
- <button
- expand
+ <Spacer
onScroll={(_, event) => {
const speaker = AstalWp.get_default()?.audio.defaultSpeaker;
if (!speaker) return console.error("Unable to connect to WirePlumber.");
@@ -583,10 +607,18 @@ const Bar = ({ monitor }: { monitor: Monitor }) => {
else speaker.volume += 0.1;
}}
/>
- {bindWidget("tray", Tray)}
- {bindWidget("statusIcons", StatusIcons)}
- {bindWidget("pkgUpdates", PkgUpdates)}
- {bindWidget("notifCount", NotifCount)}
+ {bindWidget("tray", () => (
+ <Tray afterSpacer />
+ ))}
+ {bindWidget("statusIcons", () => (
+ <StatusIcons />
+ ))}
+ {bindWidget("pkgUpdates", () => (
+ <PkgUpdates />
+ ))}
+ {bindWidget("notifCount", () => (
+ <NotifCount />
+ ))}
{bindCompositeWidget(
"battery",
bind(AstalBattery.get_default(), "isBattery").as(b => (b ? <Battery /> : <Dummy />))
@@ -595,7 +627,9 @@ const Bar = ({ monitor }: { monitor: Monitor }) => {
"dateTime",
bind(config.vertical).as(v => (v ? <DateTimeVertical /> : <DateTime />))
)}
- {bindWidget("power", Power)}
+ {bindWidget("power", () => (
+ <Power />
+ ))}
</box>
</centerbox>
);
@@ -616,8 +650,9 @@ export default ({ monitor }: { monitor: Monitor }) => (
<overlay
passThrough
overlays={[
- <ScreenCorner place="topleft" />,
+ <ScreenCorner visible={bind(config.style).as(s => s !== "embedded")} place="topleft" />,
<ScreenCorner
+ visible={bind(config.style).as(s => s !== "embedded")}
halign={bind(config.vertical).as(v => (v ? undefined : Gtk.Align.END))}
valign={bind(config.vertical).as(v => (v ? Gtk.Align.END : undefined))}
place={bind(config.vertical).as(v => (v ? "bottomleft" : "topright"))}
diff --git a/src/modules/screencorners.tsx b/src/modules/screencorners.tsx
index d160349..4368b87 100644
--- a/src/modules/screencorners.tsx
+++ b/src/modules/screencorners.tsx
@@ -26,3 +26,26 @@ export default ({ monitor }: { monitor: Monitor }) => (
</box>
</window>
);
+
+export const BarScreenCorners = ({ monitor }: { monitor: Monitor }) => (
+ <window
+ namespace="caelestia-screencorners"
+ monitor={monitor.id}
+ anchor={bind(bar.vertical).as(
+ v =>
+ Astal.WindowAnchor.TOP |
+ Astal.WindowAnchor.LEFT |
+ (v ? Astal.WindowAnchor.BOTTOM : Astal.WindowAnchor.RIGHT)
+ )}
+ visible={bind(bar.style).as(s => s === "embedded")}
+ setup={self =>
+ self.connect("size-allocate", () => self.get_window()?.input_shape_combine_region(new Cairo.Region(), 0, 0))
+ }
+ >
+ <box vertical={bind(bar.vertical)}>
+ <ScreenCorner place="topleft" />
+ <box expand />
+ <ScreenCorner place={bind(bar.vertical).as(v => (v ? "bottomleft" : "topright"))} />
+ </box>
+ </window>
+);