feat: add navbar
For controlling sidebar panes + other stuff later
This commit is contained in:
parent
ecd12e3094
commit
b0f857f0d1
19 changed files with 259 additions and 46 deletions
2
app.tsx
2
app.tsx
|
|
@ -1,5 +1,6 @@
|
||||||
import Bar from "@/modules/bar";
|
import Bar from "@/modules/bar";
|
||||||
import Launcher from "@/modules/launcher";
|
import Launcher from "@/modules/launcher";
|
||||||
|
import NavBar from "@/modules/navbar";
|
||||||
import NotifPopups from "@/modules/notifpopups";
|
import NotifPopups from "@/modules/notifpopups";
|
||||||
import Osds from "@/modules/osds";
|
import Osds from "@/modules/osds";
|
||||||
import ScreenCorners, { BarScreenCorners } from "@/modules/screencorners";
|
import ScreenCorners, { BarScreenCorners } from "@/modules/screencorners";
|
||||||
|
|
@ -80,6 +81,7 @@ App.start({
|
||||||
<Session />;
|
<Session />;
|
||||||
Monitors.get_default().forEach(m => <NotifPopups monitor={m} />);
|
Monitors.get_default().forEach(m => <NotifPopups monitor={m} />);
|
||||||
Monitors.get_default().forEach(m => <SideBar monitor={m} />);
|
Monitors.get_default().forEach(m => <SideBar monitor={m} />);
|
||||||
|
Monitors.get_default().forEach(m => <NavBar monitor={m} />);
|
||||||
Monitors.get_default().forEach(m => <Bar monitor={m} />);
|
Monitors.get_default().forEach(m => <Bar monitor={m} />);
|
||||||
Monitors.get_default().forEach(m => <ScreenCorners monitor={m} />);
|
Monitors.get_default().forEach(m => <ScreenCorners monitor={m} />);
|
||||||
Monitors.get_default().forEach(m => <BarScreenCorners monitor={m} />);
|
Monitors.get_default().forEach(m => <BarScreenCorners monitor={m} />);
|
||||||
|
|
|
||||||
9
package-lock.json
generated
9
package-lock.json
generated
|
|
@ -4,7 +4,6 @@
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "shell",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fuzzysort": "^3.1.0",
|
"fuzzysort": "^3.1.0",
|
||||||
"ical.js": "^2.1.0",
|
"ical.js": "^2.1.0",
|
||||||
|
|
@ -12,7 +11,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"esbuild": "^0.25.2",
|
"esbuild": "^0.25.2",
|
||||||
"typescript": "^5.7.3"
|
"typescript": "5.7.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
|
|
@ -600,9 +599,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.8.3",
|
"version": "5.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
|
||||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"esbuild": "^0.25.2",
|
"esbuild": "^0.25.2",
|
||||||
"typescript": "^5.7.3"
|
"typescript": "5.7.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
64
scss/navbar.scss
Normal file
64
scss/navbar.scss
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
@use "sass:color";
|
||||||
|
@use "scheme";
|
||||||
|
@use "lib";
|
||||||
|
@use "font";
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
@include font.mono;
|
||||||
|
|
||||||
|
background-color: scheme.$mantle;
|
||||||
|
|
||||||
|
button {
|
||||||
|
color: scheme.$subtext1;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
color: scheme.$subtext0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: color.change(scheme.$overlay2, $alpha: 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.current {
|
||||||
|
.pane-button {
|
||||||
|
background-color: scheme.$primary;
|
||||||
|
color: color.change(scheme.$base, $alpha: 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .pane-button,
|
||||||
|
&:focus .pane-button {
|
||||||
|
background-color: color.mix(scheme.$primary, scheme.$base, 80%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active .pane-button {
|
||||||
|
background-color: color.mix(scheme.$primary, scheme.$base, 70%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child .pane-button {
|
||||||
|
margin-top: lib.s(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child .pane-button {
|
||||||
|
margin-bottom: lib.s(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane-button {
|
||||||
|
@include lib.rounded(20);
|
||||||
|
@include lib.element-decel;
|
||||||
|
|
||||||
|
padding: lib.s(10) lib.s(8);
|
||||||
|
margin: lib.s(5) lib.s(8);
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: lib.s(28);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: lib.s(12);
|
||||||
|
margin-bottom: lib.s(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -112,6 +112,10 @@ export default {
|
||||||
sidebar: {
|
sidebar: {
|
||||||
showOnStartup: false,
|
showOnStartup: false,
|
||||||
},
|
},
|
||||||
|
navbar: {
|
||||||
|
persistent: false, // Whether to show all the time or only on hover
|
||||||
|
appearWidth: 10, // The width in pixels of the hover area for the navbar to show up
|
||||||
|
},
|
||||||
// Services
|
// Services
|
||||||
math: {
|
math: {
|
||||||
maxHistory: 100,
|
maxHistory: 100,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ export const {
|
||||||
notifpopups,
|
notifpopups,
|
||||||
osds,
|
osds,
|
||||||
sidebar,
|
sidebar,
|
||||||
|
navbar,
|
||||||
math,
|
math,
|
||||||
updates,
|
updates,
|
||||||
weather,
|
weather,
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,9 @@ export default {
|
||||||
"osds.lock.num.hideDelay": NUM,
|
"osds.lock.num.hideDelay": NUM,
|
||||||
// Sidebar
|
// Sidebar
|
||||||
"sidebar.showOnStartup": BOOL,
|
"sidebar.showOnStartup": BOOL,
|
||||||
|
// Navbar
|
||||||
|
"navbar.persistent": BOOL,
|
||||||
|
"navbar.appearWidth": NUM,
|
||||||
// Services
|
// Services
|
||||||
"math.maxHistory": NUM,
|
"math.maxHistory": NUM,
|
||||||
"updates.interval": NUM,
|
"updates.interval": NUM,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import type SideBar from "@/modules/sidebar";
|
|
||||||
import type { Monitor } from "@/services/monitors";
|
import type { Monitor } from "@/services/monitors";
|
||||||
import Players from "@/services/players";
|
import Players from "@/services/players";
|
||||||
import Updates from "@/services/updates";
|
import Updates from "@/services/updates";
|
||||||
|
|
@ -18,6 +17,7 @@ import AstalNetwork from "gi://AstalNetwork";
|
||||||
import AstalNotifd from "gi://AstalNotifd";
|
import AstalNotifd from "gi://AstalNotifd";
|
||||||
import AstalTray from "gi://AstalTray";
|
import AstalTray from "gi://AstalTray";
|
||||||
import AstalWp from "gi://AstalWp";
|
import AstalWp from "gi://AstalWp";
|
||||||
|
import { switchPane } from "./sidebar";
|
||||||
|
|
||||||
interface ClassNameProps {
|
interface ClassNameProps {
|
||||||
beforeSpacer: boolean;
|
beforeSpacer: boolean;
|
||||||
|
|
@ -75,15 +75,6 @@ const hookFocusedClientProp = (
|
||||||
callback(lastClient);
|
callback(lastClient);
|
||||||
};
|
};
|
||||||
|
|
||||||
const switchPane = (monitor: Monitor, name: string) => {
|
|
||||||
const sidebar = App.get_window(`sidebar${monitor.id}`) as SideBar | null;
|
|
||||||
if (sidebar) {
|
|
||||||
if (sidebar.visible && sidebar.shown.get() === name) sidebar.hide();
|
|
||||||
else sidebar.show();
|
|
||||||
sidebar.shown.set(name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getClassName = ({ beforeSpacer, afterSpacer, first, last }: ClassNameProps) =>
|
const getClassName = ({ beforeSpacer, afterSpacer, first, last }: ClassNameProps) =>
|
||||||
`${beforeSpacer ? "before-spacer" : ""} ${afterSpacer ? "after-spacer" : ""}` +
|
`${beforeSpacer ? "before-spacer" : ""} ${afterSpacer ? "after-spacer" : ""}` +
|
||||||
` ${first ? "first" : ""} ${last ? "last" : ""}`;
|
` ${first ? "first" : ""} ${last ? "last" : ""}`;
|
||||||
|
|
|
||||||
120
src/modules/navbar.tsx
Normal file
120
src/modules/navbar.tsx
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
import type { Monitor } from "@/services/monitors";
|
||||||
|
import type { AstalWidget } from "@/utils/types";
|
||||||
|
import { Variable } from "astal";
|
||||||
|
import { Astal, Gtk } from "astal/gtk3";
|
||||||
|
import { navbar as config } from "config";
|
||||||
|
import AstalHyprland from "gi://AstalHyprland";
|
||||||
|
import SideBar, { awaitSidebar, paneNames, switchPane, type PaneName } from "./sidebar";
|
||||||
|
|
||||||
|
const getPaneIcon = (name: PaneName) => {
|
||||||
|
if (name === "dashboard") return "dashboard";
|
||||||
|
if (name === "audio") return "tune";
|
||||||
|
if (name === "connectivity") return "settings_ethernet";
|
||||||
|
if (name === "packages") return "package_2";
|
||||||
|
if (name === "notifpane") return "notifications";
|
||||||
|
return "date_range";
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPaneName = (name: PaneName) => {
|
||||||
|
if (name === "dashboard") return "Dash";
|
||||||
|
if (name === "audio") return "Audio";
|
||||||
|
if (name === "connectivity") return "Conn";
|
||||||
|
if (name === "packages") return "Pkgs";
|
||||||
|
if (name === "notifpane") return "Alrts";
|
||||||
|
return "Time";
|
||||||
|
};
|
||||||
|
|
||||||
|
const hookIsCurrent = (
|
||||||
|
self: AstalWidget,
|
||||||
|
sidebar: Variable<SideBar | null>,
|
||||||
|
name: PaneName,
|
||||||
|
callback: (isCurrent: boolean) => void
|
||||||
|
) => {
|
||||||
|
const unsub = sidebar.subscribe(s => {
|
||||||
|
if (!s) return;
|
||||||
|
self.hook(s.shown, (_, v) => callback(s.visible && v === name));
|
||||||
|
self.hook(s, "notify::visible", () => callback(s.visible && s.shown.get() === name));
|
||||||
|
callback(s.visible && s.shown.get() === name);
|
||||||
|
unsub();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const PaneButton = ({
|
||||||
|
monitor,
|
||||||
|
name,
|
||||||
|
sidebar,
|
||||||
|
}: {
|
||||||
|
monitor: Monitor;
|
||||||
|
name: PaneName;
|
||||||
|
sidebar: Variable<SideBar | null>;
|
||||||
|
}) => (
|
||||||
|
<button
|
||||||
|
cursor="pointer"
|
||||||
|
onClick={() => switchPane(monitor, name)}
|
||||||
|
setup={self => hookIsCurrent(self, sidebar, name, c => self.toggleClassName("current", c))}
|
||||||
|
>
|
||||||
|
<box vertical className="pane-button">
|
||||||
|
<label className="icon" label={getPaneIcon(name)} />
|
||||||
|
<revealer
|
||||||
|
transitionType={Gtk.RevealerTransitionType.SLIDE_DOWN}
|
||||||
|
transitionDuration={150}
|
||||||
|
setup={self => hookIsCurrent(self, sidebar, name, c => self.set_reveal_child(c))}
|
||||||
|
>
|
||||||
|
<label className="label" label={getPaneName(name)} />
|
||||||
|
</revealer>
|
||||||
|
</box>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default ({ monitor }: { monitor: Monitor }) => {
|
||||||
|
const sidebar = Variable<SideBar | null>(null);
|
||||||
|
awaitSidebar(monitor).then(s => sidebar.set(s));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<window
|
||||||
|
namespace="caelestia-navbar"
|
||||||
|
monitor={monitor.id}
|
||||||
|
anchor={Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.BOTTOM}
|
||||||
|
exclusivity={Astal.Exclusivity.EXCLUSIVE}
|
||||||
|
visible={config.persistent.get()}
|
||||||
|
setup={self => {
|
||||||
|
const hyprland = AstalHyprland.get_default();
|
||||||
|
const visible = Variable(config.persistent.get());
|
||||||
|
|
||||||
|
visible.poll(100, () => {
|
||||||
|
const width = self.visible
|
||||||
|
? Math.max(config.appearWidth.get(), self.get_allocated_width())
|
||||||
|
: config.appearWidth.get();
|
||||||
|
return hyprland.get_cursor_position().x < width;
|
||||||
|
});
|
||||||
|
if (config.persistent.get()) visible.stopPoll();
|
||||||
|
|
||||||
|
self.hook(config.persistent, (_, v) => {
|
||||||
|
if (v) {
|
||||||
|
visible.stopPoll();
|
||||||
|
visible.set(true);
|
||||||
|
} else visible.startPoll();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.hook(visible, (_, v) => self.set_visible(v));
|
||||||
|
self.connect("destroy", () => visible.drop());
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<eventbox
|
||||||
|
onScroll={(_, event) => {
|
||||||
|
const shown = sidebar.get()?.shown;
|
||||||
|
if (!shown) return;
|
||||||
|
const idx = paneNames.indexOf(shown.get());
|
||||||
|
if (event.delta_y > 0) shown.set(paneNames[Math.min(paneNames.length - 1, idx + 1)]);
|
||||||
|
else shown.set(paneNames[Math.max(0, idx - 1)]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<box vertical className="navbar">
|
||||||
|
{paneNames.map(n => (
|
||||||
|
<PaneButton monitor={monitor} name={n} sidebar={sidebar} />
|
||||||
|
))}
|
||||||
|
</box>
|
||||||
|
</eventbox>
|
||||||
|
</window>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import type { Monitor } from "@/services/monitors";
|
import type { Monitor } from "@/services/monitors";
|
||||||
import { idle, timeout } from "astal";
|
import { setupChildClickthrough } from "@/utils/widgets";
|
||||||
import { App, Astal, Gtk } from "astal/gtk3";
|
import Notification from "@/widgets/notification";
|
||||||
|
import { Astal, Gtk } from "astal/gtk3";
|
||||||
import { notifpopups as config } from "config";
|
import { notifpopups as config } from "config";
|
||||||
import AstalNotifd from "gi://AstalNotifd";
|
import AstalNotifd from "gi://AstalNotifd";
|
||||||
import { setupChildClickthrough } from "../utils/widgets";
|
|
||||||
import Notification from "../widgets/notification";
|
|
||||||
import type SideBar from "./sidebar";
|
import type SideBar from "./sidebar";
|
||||||
|
import { awaitSidebar } from "./sidebar";
|
||||||
|
|
||||||
export default ({ monitor }: { monitor: Monitor }) => (
|
export default ({ monitor }: { monitor: Monitor }) => (
|
||||||
<window
|
<window
|
||||||
|
|
@ -61,13 +61,8 @@ export default ({ monitor }: { monitor: Monitor }) => (
|
||||||
});
|
});
|
||||||
self.hook(notifd, "resolved", (_, id) => map.get(id)?.destroyWithAnims());
|
self.hook(notifd, "resolved", (_, id) => map.get(id)?.destroyWithAnims());
|
||||||
|
|
||||||
let sidebar: SideBar | null;
|
let sidebar: SideBar | null = null;
|
||||||
|
awaitSidebar(monitor).then(s => (sidebar = s));
|
||||||
const awaitSidebar = () => {
|
|
||||||
sidebar = App.get_window(`sidebar${monitor.id}`) as SideBar | null;
|
|
||||||
if (!sidebar) timeout(100, awaitSidebar);
|
|
||||||
};
|
|
||||||
idle(awaitSidebar);
|
|
||||||
|
|
||||||
// Change input region to child region so can click through empty space
|
// Change input region to child region so can click through empty space
|
||||||
setupChildClickthrough(self);
|
setupChildClickthrough(self);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import Monitors, { type Monitor } from "@/services/monitors";
|
import Monitors, { type Monitor } from "@/services/monitors";
|
||||||
|
import { capitalize } from "@/utils/strings";
|
||||||
import PopupWindow from "@/widgets/popupwindow";
|
import PopupWindow from "@/widgets/popupwindow";
|
||||||
import { bind, execAsync, register, timeout, Variable, type Time } from "astal";
|
import { bind, execAsync, register, timeout, Variable, type Time } from "astal";
|
||||||
import { App, Astal, Gtk, Widget } from "astal/gtk3";
|
import { App, Astal, Gtk, Widget } from "astal/gtk3";
|
||||||
|
|
@ -282,7 +283,7 @@ class LockOsd extends Widget.Window {
|
||||||
this.add(
|
this.add(
|
||||||
<box vertical halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER} className={`lock ${type}`}>
|
<box vertical halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER} className={`lock ${type}`}>
|
||||||
<label vexpand className="icon" label={icon} />
|
<label vexpand className="icon" label={icon} />
|
||||||
<label vexpand className="text" label={type.slice(0, 1).toUpperCase() + type.slice(1) + "lock"} />
|
<label vexpand className="text" label={capitalize(type) + "lock"} />
|
||||||
</box>
|
</box>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
import PopupWindow from "@/widgets/popupwindow";
|
||||||
import { execAsync } from "astal";
|
import { execAsync } from "astal";
|
||||||
import { App, Astal, Gtk } from "astal/gtk3";
|
import { App, Astal, Gtk } from "astal/gtk3";
|
||||||
import PopupWindow from "../widgets/popupwindow";
|
|
||||||
|
|
||||||
const Item = ({ icon, label, cmd, isDefault }: { icon: string; label: string; cmd: string; isDefault?: boolean }) => (
|
const Item = ({ icon, label, cmd, isDefault }: { icon: string; label: string; cmd: string; isDefault?: boolean }) => (
|
||||||
<box vertical className="item">
|
<box vertical className="item">
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,42 @@ import NotifPane from "./notifpane";
|
||||||
import Packages from "./packages";
|
import Packages from "./packages";
|
||||||
import Time from "./time";
|
import Time from "./time";
|
||||||
|
|
||||||
|
export const paneNames = ["dashboard", "audio", "connectivity", "packages", "notifpane", "time"] as const;
|
||||||
|
export type PaneName = (typeof paneNames)[number];
|
||||||
|
|
||||||
|
export const switchPane = (monitor: Monitor, name: PaneName) => {
|
||||||
|
const sidebar = App.get_window(`sidebar${monitor.id}`) as SideBar | null;
|
||||||
|
if (sidebar) {
|
||||||
|
if (sidebar.visible && sidebar.shown.get() === name) sidebar.hide();
|
||||||
|
else sidebar.show();
|
||||||
|
sidebar.shown.set(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const awaitSidebar = (monitor: Monitor) =>
|
||||||
|
new Promise<SideBar>(resolve => {
|
||||||
|
let sidebar: SideBar | null = null;
|
||||||
|
|
||||||
|
const awaitSidebar = () => {
|
||||||
|
sidebar = App.get_window(`sidebar${monitor.id}`) as SideBar | null;
|
||||||
|
if (sidebar) resolve(sidebar);
|
||||||
|
else idle(awaitSidebar);
|
||||||
|
};
|
||||||
|
idle(awaitSidebar);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getPane = (name: PaneName) => {
|
||||||
|
if (name === "dashboard") return <Dashboard />;
|
||||||
|
if (name === "audio") return <Audio />;
|
||||||
|
if (name === "connectivity") return <Connectivity />;
|
||||||
|
if (name === "packages") return <Packages />;
|
||||||
|
if (name === "notifpane") return <NotifPane />;
|
||||||
|
return <Time />;
|
||||||
|
};
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
export default class SideBar extends Widget.Window {
|
export default class SideBar extends Widget.Window {
|
||||||
readonly shown: Variable<string>;
|
readonly shown: Variable<PaneName>;
|
||||||
|
|
||||||
constructor({ monitor }: { monitor: Monitor }) {
|
constructor({ monitor }: { monitor: Monitor }) {
|
||||||
super({
|
super({
|
||||||
|
|
@ -24,16 +57,15 @@ export default class SideBar extends Widget.Window {
|
||||||
visible: false,
|
visible: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const panes = [<Dashboard />, <Audio />, <Connectivity />, <Packages />, <NotifPane />, <Time />];
|
this.shown = Variable(paneNames[0]);
|
||||||
this.shown = Variable(panes[0].name);
|
|
||||||
|
|
||||||
this.add(
|
this.add(
|
||||||
<eventbox
|
<eventbox
|
||||||
onScroll={(_, event) => {
|
onScroll={(_, event) => {
|
||||||
if (event.modifier & Gdk.ModifierType.BUTTON1_MASK) {
|
if (event.modifier & Gdk.ModifierType.BUTTON1_MASK) {
|
||||||
const index = panes.findIndex(p => p.name === this.shown.get()) + (event.delta_y < 0 ? -1 : 1);
|
const index = paneNames.indexOf(this.shown.get()) + (event.delta_y < 0 ? -1 : 1);
|
||||||
if (index < 0 || index >= panes.length) return;
|
if (index < 0 || index >= paneNames.length) return;
|
||||||
this.shown.set(panes[index].name);
|
this.shown.set(paneNames[index]);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -44,7 +76,7 @@ export default class SideBar extends Widget.Window {
|
||||||
transitionDuration={200}
|
transitionDuration={200}
|
||||||
shown={bind(this.shown)}
|
shown={bind(this.shown)}
|
||||||
>
|
>
|
||||||
{panes}
|
{paneNames.map(getPane)}
|
||||||
</stack>
|
</stack>
|
||||||
</box>
|
</box>
|
||||||
</eventbox>
|
</eventbox>
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,11 @@ export default ({ compact }: { compact?: boolean }) => (
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
cursor="pointer"
|
cursor="pointer"
|
||||||
onClicked={() => AstalNotifd.get_default().notifications.forEach(n => n.dismiss())}
|
onClicked={() =>
|
||||||
|
AstalNotifd.get_default()
|
||||||
|
.get_notifications()
|
||||||
|
.forEach(n => n.dismiss())
|
||||||
|
}
|
||||||
label=" Clear"
|
label=" Clear"
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { isRealPlayer } from "@/utils/mpris";
|
||||||
import { GLib, GObject, property, readFile, register, writeFileAsync } from "astal";
|
import { GLib, GObject, property, readFile, register, writeFileAsync } from "astal";
|
||||||
import AstalMpris from "gi://AstalMpris";
|
import AstalMpris from "gi://AstalMpris";
|
||||||
import { isRealPlayer } from "../utils/mpris";
|
|
||||||
|
|
||||||
@register({ GTypeName: "Players" })
|
@register({ GTypeName: "Players" })
|
||||||
export default class Players extends GObject.Object {
|
export default class Players extends GObject.Object {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { capitalize } from "@/utils/strings";
|
||||||
import { execAsync, GLib, GObject, property, readFileAsync, register, writeFileAsync } from "astal";
|
import { execAsync, GLib, GObject, property, readFileAsync, register, writeFileAsync } from "astal";
|
||||||
import { updates as config } from "config";
|
import { updates as config } from "config";
|
||||||
|
|
||||||
|
|
@ -124,7 +125,7 @@ export default class Updates extends GObject.Object {
|
||||||
repo: await this.getRepo(r),
|
repo: await this.getRepo(r),
|
||||||
updates: [],
|
updates: [],
|
||||||
icon: this.getRepoIcon(r),
|
icon: this.getRepoIcon(r),
|
||||||
name: r[0].toUpperCase() + r.slice(1) + " repository",
|
name: capitalize(r) + " repository",
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,5 @@ export const pathToFileName = (path: string, ext?: string) => {
|
||||||
const dir = path.slice(start, path.lastIndexOf("/")).replaceAll("/", "-");
|
const dir = path.slice(start, path.lastIndexOf("/")).replaceAll("/", "-");
|
||||||
return `${dir}-${basename(path, ext !== undefined)}${ext ? `.${ext}` : ""}`;
|
return `${dir}-${basename(path, ext !== undefined)}${ext ? `.${ext}` : ""}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
|
|
|
||||||
|
|
@ -71,13 +71,6 @@ export class MenuItem extends astalify(Gtk.MenuItem) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@register()
|
|
||||||
export class Calendar extends astalify(Gtk.Calendar) {
|
|
||||||
constructor(props: ConstructProps<Calendar, Gtk.Calendar.ConstructorProps>) {
|
|
||||||
super(props as any);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
export class FlowBox extends astalify(Gtk.FlowBox) {
|
export class FlowBox extends astalify(Gtk.FlowBox) {
|
||||||
constructor(props: ConstructProps<FlowBox, Gtk.FlowBox.ConstructorProps>) {
|
constructor(props: ConstructProps<FlowBox, Gtk.FlowBox.ConstructorProps>) {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
@use "scss/osds";
|
@use "scss/osds";
|
||||||
@use "scss/session";
|
@use "scss/session";
|
||||||
@use "scss/sidebar";
|
@use "scss/sidebar";
|
||||||
|
@use "scss/navbar";
|
||||||
|
|
||||||
* {
|
* {
|
||||||
all: unset; // Remove GTK theme styles
|
all: unset; // Remove GTK theme styles
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue