diff options
| author | Linnea Gräf <nea@nea.moe> | 2025-04-13 19:42:47 +0200 |
|---|---|---|
| committer | Linnea Gräf <nea@nea.moe> | 2025-04-13 19:42:47 +0200 |
| commit | 0d3b6a3f698853cbbf7d0ebf866eca8bccd196fb (patch) | |
| tree | e756da2ef87a13a269da71fac1cabd966423c2e9 | |
| download | ags-master.tar.gz ags-master.tar.bz2 ags-master.zip | |
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | app.ts | 12 | ||||
| -rw-r--r-- | env.d.ts | 21 | ||||
| -rw-r--r-- | package.json | 6 | ||||
| -rw-r--r-- | style.scss | 44 | ||||
| -rw-r--r-- | tsconfig.json | 14 | ||||
| -rw-r--r-- | widget/Bar.tsx | 93 |
7 files changed, 192 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..298eb4d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +@girs/ @@ -0,0 +1,12 @@ +import { App } from "astal/gtk3" +import style from "./style.scss" +import Bar from "./widget/Bar" + +App.start({ + css: style, + main() { + const monitors = App.get_monitors() + monitors.sort(it => it.geometry.x) + Bar(monitors[0]) + }, +}) diff --git a/env.d.ts b/env.d.ts new file mode 100644 index 0000000..467c0a4 --- /dev/null +++ b/env.d.ts @@ -0,0 +1,21 @@ +declare const SRC: string + +declare module "inline:*" { + const content: string + export default content +} + +declare module "*.scss" { + const content: string + export default content +} + +declare module "*.blp" { + const content: string + export default content +} + +declare module "*.css" { + const content: string + export default content +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..44226f2 --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "name": "astal-shell", + "dependencies": { + "astal": "/usr/share/astal/gjs" + } +} diff --git a/style.scss b/style.scss new file mode 100644 index 0000000..6c070fb --- /dev/null +++ b/style.scss @@ -0,0 +1,44 @@ +// 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 { + font-size: x-large; +} +.linky-button { + all: unset; + background: transparent; + border: 0; + color: inherit; +} + +.linky-button:hover { + /* This does not work. Why? */ + text-decoration-line: underline; + color: green; +} +.output-list { + background: #306c; + min-width: 20em; + padding: 1em; + padding-right: 1em; + color: #afa; + border-right: 1px solid #afa; + font-family: monospace; +} + +.monitor { + font-weight: bold; +} + +.workspace { + margin-left: 1em; +} +.active-ws { + color: greenyellow; +} + +.window { + margin-left: 2em; +} + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9471e35 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "experimentalDecorators": true, + "strict": true, + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "Bundler", + // "checkJs": true, + // "allowJs": true, + "jsx": "react-jsx", + "jsxImportSource": "astal/gtk3", + } +} diff --git a/widget/Bar.tsx b/widget/Bar.tsx new file mode 100644 index 0000000..ccbd496 --- /dev/null +++ b/widget/Bar.tsx @@ -0,0 +1,93 @@ +import { App, Astal, Gtk, Gdk } from "astal/gtk3" +import { exec, monitorFile, Variable } from "astal" +import { Button, Label } from "astal/gtk3/widget"; +import Pango from "gi://Pango?version=1.0"; + +const time = Variable("").poll(1000, "date") + +type Id = number +interface SwayNodeCommon { + id: Id, + orientation: 'horizontal' | 'vertical' | 'none', + name: string, + focus: Id[], + rect: Rect, + deco_rect: Rect, + window_rect: Rect, + geometry: Rect, +} +type SwayNode = SwayOutput | SwayRoot | SwayCon | SwayWorkspace; +type Rect = { x: number, y: number, width: number, height: number } +interface SwayWorkspace extends SwayNodeCommon { + type: 'workspace', + nodes: SwayCon[] +} +interface SwayCon extends SwayNodeCommon { + type: 'con', + window_properties?: { + class: string, + instance: string, + title: string, + window_role: string, + window_type: string, + }, +} +interface SwayOutput extends SwayNodeCommon { + type: 'output', + nodes: SwayWorkspace[], + focused: boolean, +} +interface SwayRoot extends SwayNodeCommon { + type: 'root', + nodes: SwayOutput[] +} +const swayTree = Variable({} as SwayRoot | { type: undefined }).poll(1000, "swaymsg -t get_tree", + text => JSON.parse(text) as SwayRoot +) +function omit<T extends object, K extends keyof T>(obj: T, ...ks: K[]): Omit<T, K> { + return Object.fromEntries(Object.entries(obj).filter(it => !ks.includes(it[0] as K))) as any +} +function Monitor(props: { monitor: SwayOutput }) { + return <> + <Label halign={Gtk.Align.START} className={"monitor"}> + {`${props.monitor.name} (${props.monitor.nodes.length})`} + </Label> + {props.monitor.nodes.map(ws => + <Workspace ws={ws} focused={props.monitor.focus.includes(ws.id)}></Workspace> + )} + </> +} +function Workspace(props: { ws: SwayWorkspace, focused: boolean }) { + return <> + <Button + halign={Gtk.Align.START} + onClickRelease={() => exec(['swaymsg', `workspace ${JSON.stringify(props.ws.name)}`])} + className={"workspace linky-button " + (props.focused ? 'active-ws ' : '')} relief={Gtk.ReliefStyle.NONE}> + {`Workspace ${props.ws.name}`} + </Button> + {props.ws.nodes.map(window => + <Label + ellipsize={Pango.EllipsizeMode.MIDDLE} + maxWidthChars={30} + halign={Gtk.Align.START} + className={"window"}>{window.window_properties?.title ?? window.name}</Label> + )} + </> +} +export default function Bar(gdkmonitor: Gdk.Monitor) { + const { TOP, LEFT, RIGHT, BOTTOM } = Astal.WindowAnchor + return <window + className="Bar" + gdkmonitor={gdkmonitor} + exclusivity={Astal.Exclusivity.EXCLUSIVE} + anchor={TOP | LEFT | BOTTOM} + application={App}> + <box vertical className={"output-list"}> + {swayTree(root => !root.type ? null + : root.nodes + .map(monitor => monitor.name.startsWith("_") ? null : <Monitor monitor={monitor}></Monitor>) + .filter(it => it) + )} + </box> + </window> +} |
