From ede8890a08b3fbbb1f6df3b8c277ab6424d1befd Mon Sep 17 00:00:00 2001 From: Aylur Date: Tue, 15 Oct 2024 01:22:24 +0000 Subject: docs: better explain ags --- docs/guide/ags/binding.md | 234 ------------ docs/guide/ags/cli-app.md | 167 --------- docs/guide/ags/faq.md | 266 -------------- docs/guide/ags/first-widgets.md | 402 --------------------- docs/guide/ags/gobject.md | 166 --------- docs/guide/ags/installation.md | 65 ---- docs/guide/ags/theming.md | 161 --------- docs/guide/ags/utilities.md | 174 --------- docs/guide/ags/variable.md | 153 -------- docs/guide/ags/widget.md | 208 ----------- docs/guide/getting-started/installation.md | 14 +- docs/guide/getting-started/introduction.md | 19 +- docs/guide/getting-started/nix.md | 20 +- docs/guide/getting-started/supported-languages.md | 25 +- docs/guide/lua/first-widgets.md | 3 + docs/guide/lua/installation.md | 3 + docs/guide/typescript/binding.md | 235 ++++++++++++ docs/guide/typescript/cli-app.md | 174 +++++++++ docs/guide/typescript/faq.md | 266 ++++++++++++++ docs/guide/typescript/first-widgets.md | 412 ++++++++++++++++++++++ docs/guide/typescript/gobject.md | 165 +++++++++ docs/guide/typescript/installation.md | 89 +++++ docs/guide/typescript/theming.md | 179 ++++++++++ docs/guide/typescript/utilities.md | 168 +++++++++ docs/guide/typescript/variable.md | 153 ++++++++ docs/guide/typescript/widget.md | 214 +++++++++++ 26 files changed, 2115 insertions(+), 2020 deletions(-) delete mode 100644 docs/guide/ags/binding.md delete mode 100644 docs/guide/ags/cli-app.md delete mode 100644 docs/guide/ags/faq.md delete mode 100644 docs/guide/ags/first-widgets.md delete mode 100644 docs/guide/ags/gobject.md delete mode 100644 docs/guide/ags/installation.md delete mode 100644 docs/guide/ags/theming.md delete mode 100644 docs/guide/ags/utilities.md delete mode 100644 docs/guide/ags/variable.md delete mode 100644 docs/guide/ags/widget.md create mode 100644 docs/guide/lua/first-widgets.md create mode 100644 docs/guide/lua/installation.md create mode 100644 docs/guide/typescript/binding.md create mode 100644 docs/guide/typescript/cli-app.md create mode 100644 docs/guide/typescript/faq.md create mode 100644 docs/guide/typescript/first-widgets.md create mode 100644 docs/guide/typescript/gobject.md create mode 100644 docs/guide/typescript/installation.md create mode 100644 docs/guide/typescript/theming.md create mode 100644 docs/guide/typescript/utilities.md create mode 100644 docs/guide/typescript/variable.md create mode 100644 docs/guide/typescript/widget.md (limited to 'docs/guide') diff --git a/docs/guide/ags/binding.md b/docs/guide/ags/binding.md deleted file mode 100644 index f1592a0..0000000 --- a/docs/guide/ags/binding.md +++ /dev/null @@ -1,234 +0,0 @@ -# Binding - -As mentioned before binding an object's state to another - -so in most cases a `Variable` or a `GObject.Object` property to a widget's property - -is done through the `bind` function which returns a `Binding` object. - -`Binding` objects simply hold information about the source and how it should be transformed -which Widget constructors can use to setup a connection between themselves and the source. - -```ts -class Binding { - private transformFn: (v: any) => unknown - private emitter: Subscribable | Connectable - private prop?: string - - as(fn: (v: Value) => T): Binding - get(): Value - subscribe(callback: (value: Value) => void): () => void -} -``` - -A `Binding` can be constructed from an object implementing -the `Subscribable` interface (usually a `Variable`) -or an object implementing the `Connectable` interface and one of its properties -(usually a `GObject.Object` instance). - -```ts -function bind(obj: Subscribable): Binding - -function bind< - Obj extends Connectable, - Prop extends keyof Obj, ->(obj: Obj, prop: Prop): Binding -``` - -## Subscribable and Connectable interface - -Any object implementing one of these interfaces can be used with `bind`. - -```ts -interface Subscribable { - subscribe(callback: (value: T) => void): () => void - get(): T -} - -interface Connectable { - connect(signal: string, callback: (...args: any[]) => unknown): number - disconnect(id: number): void -} -``` - -## Example Custom Subscribable - -When binding the children of a box from an array, usually not all elements -of the array changes each time, so it would make sense to not destroy -the widget which represents the element. - -::: code-group - -```ts :line-numbers [varmap.ts] -import { type Subscribable } from "astal/binding" -import { Gtk } from "astal" - -export class VarMap implements Subscribable { - #subs = new Set<(v: Array<[K, T]>) => void>() - #map: Map - - #notifiy() { - const value = this.get() - for (const sub of this.#subs) { - sub(value) - } - } - - #delete(key: K) { - const v = this.#map.get(key) - - if (v instanceof Gtk.Widget) { - v.destroy() - } - - this.#map.delete(key) - } - - constructor(initial?: Iterable<[K, T]>) { - this.#map = new Map(initial) - } - - set(key: K, value: T) { - this.#delete(key) - this.#map.set(key, value) - this.#notifiy() - } - - delete(key: K) { - this.#delete(key) - this.#notifiy() - } - - get() { - return [...this.#map.entries()] - } - - subscribe(callback: (v: Array<[K, T]>) => void) { - this.#subs.add(callback) - return () => this.#subs.delete(callback) - } -} -``` - -::: - -And this `VarMap` can be used as an alternative to `Variable>`. - -```tsx -function MappedBox() { - const map = new VarMap([ - [1, ] - [2, ] - ]) - - const conns = [ - gobject.connect("added", (_, id) => map.set(id, MyWidget({ id }))), - gobject.connect("removed", (_, id) => map.delete(id, MyWidget({ id }))), - ] - - return conns.map(id => gobject.disconnect(id))}> - {bind(map).as(arr => arr.sort(([a], [b]) => a - b).map(([,w]) => w))} - -} -``` - -## Example Custom Connectable - -This was formerly known as a "Service" in AGS. -Astal provides [decorator functions](./gobject#example-usage) that make it easy to subclass gobjects, however -you can read more about GObjects and subclassing on [gjs.guide](https://gjs.guide/guides/gobject/subclassing.html#gobject-subclassing). - -Objects coming from [libraries](../libraries/references#astal-libraries) -usually have a singleton gobject you can access with `.get_default()`. - -Here is an example of a Brightness library by wrapping the `brightnessctl` cli utility -and by monitoring `/sys/class/backlight` - -::: code-group - -```ts :line-numbers [brightness.ts] -import GObject, { register, property } from "astal/gobject" -import { monitorFile, readFileAsync } from "astal/file" -import { exec, execAsync } from "astal/process" - -const get = (args: string) => Number(exec(`brightnessctl ${args}`)) -const screen = exec(`bash -c "ls -w1 /sys/class/backlight | head -1"`) -const kbd = exec(`bash -c "ls -w1 /sys/class/leds | head -1"`) - -@register({ GTypeName: "Brightness" }) -export default class Brightness extends GObject.Object { - static instance: Brightness - static get_default() { - if (!this.instance) - this.instance = new Brightness() - - return this.instance - } - - #kbdMax = get(`--device ${kbd} max`) - #kbd = get(`--device ${kbd} get`) - #screenMax = get("max") - #screen = get("get") / (get("max") || 1) - - @property(Number) - get kbd() { return this.#kbd } - - set kbd(value) { - if (value < 0 || value > this.#kbdMax) - return - - execAsync(`brightnessctl -d ${kbd} s ${value} -q`).then(() => { - this.#kbd = value - this.notify("kbd") - }) - } - - @property(Number) - get screen() { return this.#screen } - - set screen(percent) { - if (percent < 0) - percent = 0 - - if (percent > 1) - percent = 1 - - execAsync(`brightnessctl set ${Math.floor(percent * 100)}% -q`).then(() => { - this.#screen = percent - this.notify("screen") - }) - } - - constructor() { - super() - - const screenPath = `/sys/class/backlight/${screen}/brightness` - const kbdPath = `/sys/class/leds/${kbd}/brightness` - - monitorFile(screenPath, async f => { - const v = await readFileAsync(f) - this.#screen = Number(v) / this.#screenMax - this.notify("screen") - }) - - monitorFile(kbdPath, async f => { - const v = await readFileAsync(f) - this.#kbd = Number(v) / this.#kbdMax - this.notify("kbd") - }) - } -} -``` - -::: - -And it can be used like any other library object. - -```tsx -function BrightnessSlider() { - const brightness = Brightness.get_default() - - return brightness.screen = value} - /> -} -``` diff --git a/docs/guide/ags/cli-app.md b/docs/guide/ags/cli-app.md deleted file mode 100644 index ec6d174..0000000 --- a/docs/guide/ags/cli-app.md +++ /dev/null @@ -1,167 +0,0 @@ -# CLI and App - -`App` is a singleton **instance** of [Astal.Application](https://aylur.github.io/libastal/class.Application.html). - -```ts -import { App } from "astal" -``` - -## Entry point - -:::code-group - -```ts [app.ts] -App.start({ - main() { - // setup anything - // instantiate widgets - }, -}) -``` - -::: - -:::warning -You can not instantiate widgets outside of the main function. -::: - -## Instance identifier - -You can run multiple instance by defining a unique instance name. - -```ts -App.start({ - instanceName: "my-instance", // defaults to "astal" - main() {}, -}) -``` - -## Messaging from CLI - -If you want to interact with an instance from the cli, you can do so by sending a message. - -```ts -App.start({ - main() {}, - requestHandler(request: string, res: (response: any) => void) { - if (request == "say hi") { - res("hi cli") - } - res("unknown command") - }, -}) -``` - -:::code-group - -```sh [ags] -ags -m "say hi" -# hi cli -``` - -```sh [astal] -astal say hi -# hi cli -``` - -::: - -If you want to run arbitrary JavaScript from cli, you can use `App.eval`. -It will evaluate the passed string as the body of an `async` function. - -```ts -App.start({ - main() {}, - requestHandler(js: string, res) { - App.eval(js).then(res).catch(res) - }, -}) -``` - -If the string does not contain a semicolon, a single expression is assumed and returned implicity. - -```sh -ags -m "'hello'" -# hello -``` - -If the string contains a semicolon, you have to return explicitly - -```sh -ags -m "'hello';" -# undefined - -ags -m "return 'hello';" -# hello -``` - -## Toggling Windows by their name - -In order for AGS to know about your windows, you have to register them. -You can do this by specifying a **unique** `name` and calling `App.add_window` - -```tsx {4} -import { App } from "astal" - -function Bar() { - return App.add_window(self)}> - - -} -``` - -You can also invoke `App.add_window` by simply passing the `App` to the `application` prop. - -```tsx {4} -import { App } from "astal" - -function Bar() { - return - - -} -``` - -:::warning -When assigning the `application` prop make sure `name` comes before. -Props are set sequentially and if name is applied after application it won't work. -::: - -```sh -ags -t Bar -``` - -## App without AGS - -As mentioned before AGS is only a scaffolding tool. You can setup -a dev environment and a bundler yourself. In which case you won't be using -the ags cli to run the bundled scripts. The produced script can run as the main instance -and a "client" instance. - -The first time you run your bundled script the `main` function gets executed. -While that instance is running any subsequent execution of the script will call -the `client` function. - -:::code-group - -```ts [main.ts] -App.start({ - // main instance - main(...args: Array) { - print(...args) - }, - - // every subsequent calls - client(message: (msg: string) => string, ...args: Array) { - const res = message("you can message the main instance") - console.log(res) - }, - - // this runs in the main instance - requestHandler(request: string, res: (response: any) => void) { - res("response from main") - }, -}) -``` - -::: diff --git a/docs/guide/ags/faq.md b/docs/guide/ags/faq.md deleted file mode 100644 index 76d8e72..0000000 --- a/docs/guide/ags/faq.md +++ /dev/null @@ -1,266 +0,0 @@ -# Frequently asked question, common issues, tips and tricks - -## Monitor id does not match compositor - -The monitor id property that windows expect is mapped by Gdk, which is not always -the same as the compositor. Instead use the `gdkmonitor` property which expects -a `Gdk.Monitor` object. - -```tsx -import { App } from "astal" - -function Bar(gdkmonitor) { - return -} - -function main() { - for (const monitor of App.get_monitors()) { - if (monitor.model == "your-desired-model") { - Bar(monitor) - } - } -} - -App.start({ main }) -``` - -## Environment variables - -JavaScript is **not** an bash. - -```ts -const HOME = exec("echo $HOME") // does not work -``` - -`exec` and `execAsync` runs the passed program as is, its **not** run in a -shell environment, so the above example just passes `$HOME` as a string literal -to the `echo` program. - -:::danger Please don't do this -You could pass it to bash, but that is a horrible approach. - -```ts -const HOME = exec("bash -c 'echo $HOME'") -``` - -::: - -You can read environment variables with [GLib.getenv](https://gjs-docs.gnome.org/glib20~2.0/glib.getenv). - -```ts -import GLib from "gi://GLib" - -const HOME = GLib.getenv("HOME") -``` - -## Custom SVG symbolic icons - -Put the svgs in a directory, named `-symbolic.svg` -and use `App.add_icons` or `icons` parameter in `App.start` - -:::code-group - -```ts [app.ts] -App.start({ - icons: `${SRC}/icons`, - main() { - Widget.Icon({ - icon: "custom-symbolic", // custom-symbolic.svg - css: "color: green;", // can be colored, like other named icons - }) - }, -}) -``` - -::: - -:::info -If there is a name clash with an icon from your current icon pack -the icon pack will take precedence -::: - -## Logging - -The `console` API in gjs uses glib logging functions. -If you just want to print some text as is to stdout -use the globally available `print` function or `printerr` for stderr. - -```ts -print("print this line to stdout") -printerr("print this line to stderr") -``` - -## Populate the global scope with frequently accessed variables - -It might be annoying to always import Gtk only for `Gtk.Align` enums. - -:::code-group - -```ts [globals.ts] -import Gtk from "gi://Gtk" - -declare global { - const START: number - const CENTER: number - const END: number - const FILL: number -} - -Object.assign(globalThis, { - START: Gtk.Align.START, - CENTER: Gtk.Align.CENTER, - END: Gtk.Align.END, - FILL: Gtk.Align.FILL, -}) -``` - -::: - -:::code-group - -```tsx [Bar.tsx] -export default function Bar() { - return - - -} -``` - -::: - -:::code-group - -```ts [app.ts] -import "./globals" -import Bar from "./Bar" - -App.start({ - main: Bar -}) -``` - -::: - -:::info -It is considered bad practice to populate the global scope, but its your code, not a public library. -::: - -## Auto create Window for each Monitor - -To have Window widgets appear on a monitor when its plugged in, listen to `App.monitor_added`. - -:::code-group - -```tsx [Bar.tsx] -export default function Bar(gdkmonitor: Gdk.Monitor) { - return -} -``` - -::: - -:::code-group - -```ts [app.ts] -import { Gdk, Gtk } from "astal" -import Bar from "./Bar" - -function main() { - const bars = new Map() - - // initialize - for (const gdkmonitor of App.get_monitors()) { - bars.set(gdkmonitor, Bar(gdkmonitor)) - } - - App.connect("monitor-added", (_, gdkmonitor) => { - bars.set(gdkmonitor, Bar(gdkmonitor)) - }) - - App.connect("monitor-removed", (_, gdkmonitor) => { - bars.get(gdkmonitor)?.destroy() - bars.delete(gdkmonitor) - }) -} - -App.start({ main }) -``` - -::: - -## Error: Can't convert non-null pointer to JS value - -These happen when accessing list type properties. Gjs fails to correctly bind -`List` and other array like types of Vala as a property. - -```ts -import Notifd from "gi://AstalNotifd" -const notifd = Notifd.get_default() - -notifd.notifications // ❌ // [!code error] - -notifd.get_notifications() // ✅ -``` - -## How to create regular floating windows - -Use `Gtk.Window` with [Widget.astalify](/guide/ags/widget#how-to-use-non-builtin-gtk-widgets). - -By default `Gtk.Window` is destroyed on close. To prevent this add a handler for `delete-event`. - -```tsx {4-7} -const RegularWindow = Widget.astalify(Gtk.Window) - -return { - self.hide() - return true - }} -> - {child} - -``` - -## Is there a way to limit the width/height of a widget? - -Unfortunately not. You can set a minimum size with `min-width` and `min-heigth` css attributes, -but you can not set max size. - -## Custom widgets with bindable properties - -In function components you can wrap any primitive to handle both -binding and value cases as one. - -```tsx -function MyWidget(props: { prop: string | Binding }) { - const prop = props.prop instanceof Binding - ? props.prop - : bind({ get: () => props.prop, subscribe: () => () => {} }) - - function setup(self: Widget.Box) { - self.hook(prop, () => { - const value = prop.get() - // handler - }) - } - - return - -} -``` - -You can pass the prop the super constructor in subclasses - -```tsx -@register() -class MyWidget extends Widget.Box { - @property(String) - set prop(v: string) { - // handler - } - - constructor(props: { prop: string | Binding }) { - super(props) - } -} -``` diff --git a/docs/guide/ags/first-widgets.md b/docs/guide/ags/first-widgets.md deleted file mode 100644 index 6dba7b3..0000000 --- a/docs/guide/ags/first-widgets.md +++ /dev/null @@ -1,402 +0,0 @@ -# First Widgets - -AGS is the predecessor of Astal, which was written purely in TypeScript and so only supported -JavaScript/TypeScript. Now it serves as a scaffolding tool for Astal projects in TypeScript. -While what made AGS what it is, is now part of the Astal project, for simplicity we will -refer to the Astal TypeScript lib as AGS. - -:::tip -If you are not familiar with the JavaScript syntax [MDN](https://developer.mozilla.org/en-US/) -and [javascript.info](https://javascript.info/) have great references. -::: - -## Getting Started - -Start by initializing a project - -```sh -ags --init -``` - -then run `ags` in the terminal - -```sh -ags -``` - -Done! You have now a custom written bar using Gtk. - -:::tip -AGS will transpile every `.ts`, `.jsx` and `.tsx` files into regular javascript then -it will bundle everything into a single javascript file which then GJS can execute. -The bundler used is [esbuild](https://esbuild.github.io/). -::: - -## Root of every shell component: Window - -Astal apps are composed of widgets. A widget is a piece of UI that has its own logic and style. -A widget can be as small as a button or an entire bar. -The top level widget is always a [Window](https://aylur.github.io/libastal/class.Window.html) which will hold all widgets. - -::: code-group - -```tsx [widget/Bar.tsx] -function Bar(monitor = 0) { - return - Content of the widget - -} -``` - -::: - -::: code-group - -```ts [app.ts] -import Bar from "./widget/Bar" - -App.start({ - main() { - Bar(0) - Bar(1) // instantiate for each monitor - }, -}) -``` - -::: - -## Creating and nesting widgets - -Widgets are JavaScript functions which return Gtk widgets, -either by using JSX or using a widget constructor. - -:::code-group - -```tsx [MyButton.tsx] -function MyButton(): JSX.Element { - return -} -``` - -```ts [MyButton.ts] -import { Widget } from "astal" - -function MyButton(): Widget.Button { - return new Widget.Button( - { onClicked: "echo hello" }, - new Widget.Label({ label: "Click me!" }), - ) -} -``` - -::: - -:::info -The only difference between the two is the return type. -Using markup the return type is always `Gtk.Widget` (globally available as `JSX.Element`), -while using constructors the return type is the actual type of the widget. -It is rare to need the actual return type, so most if not all of the time, you can use markup. -::: - -Now that you have declared `MyButton`, you can nest it into another component. - -```tsx -function MyBar() { - return - - Click The button - - - -} -``` - -Notice that widgets you defined start with a capital letter ``. -Lowercase tags are builtin widgets, while capital letter is for custom widgets. - -## Displaying Data - -JSX lets you put markup into JavaScript. -Curly braces let you “escape back” into JavaScript so that you can embed some variable -from your code and display it. - -```tsx -function MyWidget() { - const label = "hello" - - return -} -``` - -You can also pass JavaScript to markup attributes - -```tsx -function MyWidget() { - const label = "hello" - - return -} -``` - -## Builtin Widgets - -You can check the [source code](https://github.com/aylur/astal/blob/main/core/gjs/src/widgets.ts) to have a full list of builtin widgets. - -These widgets are available by default in JSX. - -- box: [Astal.Box](https://aylur.github.io/libastal/class.Box.html) -- button: [Astal.Button](https://aylur.github.io/libastal/class.Button.html) -- centerbox: [Astal.CenterBox](https://aylur.github.io/libastal/class.CenterBox.html) -- circularprogress: [Astal.CircularProgress](https://aylur.github.io/libastal/class.CircularProgress.html) -- drawingarea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/class.DrawingArea.html) -- entry: [Gtk.Entry](https://docs.gtk.org/gtk3/class.Entry.html) -- eventbox: [Astal.EventBox](https://aylur.github.io/libastal/class.EventBox.html) -- icon: [Astal.Icon](https://aylur.github.io/libastal/class.Icon.html) -- label: [Astal.Label](https://aylur.github.io/libastal/class.Label.html) -- levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/class.LevelBar.html) -- overlay: [Astal.Overlay](https://aylur.github.io/libastal/class.Overlay.html) -- revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/class.Revealer.html) -- scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/class.Scrollable.html) -- slider: [Astal.Slider](https://aylur.github.io/libastal/class.Slider.html) -- stack: [Astal.Stack](https://aylur.github.io/libastal/class.Stack.html) -- switch: [Gtk.Switch](https://docs.gtk.org/gtk3/class.Switch.html) -- window: [Astal.Window](https://aylur.github.io/libastal/class.Window.html) diff --git a/docs/guide/getting-started/installation.md b/docs/guide/getting-started/installation.md index af82cf5..6ad951a 100644 --- a/docs/guide/getting-started/installation.md +++ b/docs/guide/getting-started/installation.md @@ -10,6 +10,8 @@ Read more about it on the [nix page](./nix#astal) maintainer: [@kotontrion](https://github.com/kotontrion) + + :::code-group ```sh [Core Library] @@ -28,7 +30,6 @@ yay -S libastal-meta ```sh git clone https://github.com/aylur/astal.git -cd astal/core ``` 2. Install the following dependencies @@ -51,7 +52,18 @@ sudo apt install meson valac libgtk-3-dev libgtk-layer-shell-dev gobject-introsp 3. Build and install with `meson` +- astal-io + +```sh +cd lib/astal/io +meson setup build +meson install -C build +``` + +- astal3 + ```sh +cd lib/astal/gtk3 meson setup build meson install -C build ``` diff --git a/docs/guide/getting-started/introduction.md b/docs/guide/getting-started/introduction.md index 92d2ff1..af176c3 100644 --- a/docs/guide/getting-started/introduction.md +++ b/docs/guide/getting-started/introduction.md @@ -2,22 +2,25 @@ ## What is Astal? -Astal (_meaning "desk"_) is a bundle of libraries built using [GLib](https://docs.gtk.org/glib/) in Vala and C. -The core library [libastal](https://aylur.github.io/libastal) has some Gtk widgets that come packaged, -the most important one is the [Window](https://aylur.github.io/libastal/class.Window.html) which is the main toplevel component using [gtk-layer-shell](https://github.com/wmww/gtk-layer-shell). +Astal (_meaning "desk"_) is a suite of libraries in Vala and C. +The core library [astal3](https://aylur.github.io/libastal/astal3) and +[astal4](https://aylur.github.io/libastal/astal4) (not yet available) +has some Gtk widgets that come packaged, +the most important one being the [Window](https://aylur.github.io/libastal/class.Window.html) which is the main toplevel component using [gtk-layer-shell](https://github.com/wmww/gtk-layer-shell). This is what allows us to use Gtk as shell components on Wayland. -libastal also comes with some utility functions such as running external processes, -reading, writing and monitoring files. +The other part of the core library [astal-io](https://aylur.github.io/libastal/astal-io) +which contains some utility GLib shortcut for running external processes, +reading, writing and monitoring files, timeout and interval functions. ## Why Astal? -What makes Astal convenient to use is not the core library, as it could easily be replaced +What makes Astal convenient to use is not the core libraries, as they can easily be replaced by the standard library of any of your favorite language that has bindings to Gtk, it is the -accompanying libraries (_formerly known as "services" in AGS_) +accompanying libraries (_formerly known as "services" in AGS_). Have you ever wanted to write a custom bar, custom notification popups or an applauncher, but gave up because writing a workspace widget, implementing the notification daemon or handling a search filter was too much of a hassle? -Astal libraries have you [covered](/guide/libraries/references), you don't have to worry about these, +Astal libraries have you [covered](../libraries/references#astal-libraries), you don't have to worry about these, you just define the layout, style it with CSS and that's it. diff --git a/docs/guide/getting-started/nix.md b/docs/guide/getting-started/nix.md index 81f4e4d..5c0db28 100644 --- a/docs/guide/getting-started/nix.md +++ b/docs/guide/getting-started/nix.md @@ -1,3 +1,8 @@ +--- +next: + link: '/guide/getting-started/supported-languages' + text: 'Supported Languages' +--- # Nix ## Astal @@ -74,11 +79,16 @@ Using Astal on Nix will require you to package your project. } ``` +```nix [ TypeScript] +# The usage of AGS (read below) is recommended +# Usage without AGS is not yet documented +``` + ::: ## AGS -The recommended way to use AGS on NixOS is through the home-manager module. +The recommended way to use [AGS](../ags/first-widgets#first-widgets) on NixOS is through the home-manager module. Example content of a `flake.nix` file that contains your `homeConfigurations`. @@ -144,7 +154,7 @@ Example content of `home.nix` file ::: -AGS by default only includes the core `libastal` library. +AGS by default only includes the core `astal3/astal4` and `astal-io` libraries. If you want to include any other [library](../libraries/references) you have to add them to `extraPackages`. You can also add binaries which will be added to the gjs runtime. @@ -158,7 +168,11 @@ The AGS flake does not expose the `astal` cli to the home environment, you have :::code-group ```nix [ home.nix] -home.packages = [ inputs.ags.packages.${pkgs.system}.astal ]; +home.packages = [ inputs.ags.packages.${pkgs.system}.default ]; +``` + +```sh [ sh] +astal --help ``` ::: diff --git a/docs/guide/getting-started/supported-languages.md b/docs/guide/getting-started/supported-languages.md index 4cb7f3a..47d5dbd 100644 --- a/docs/guide/getting-started/supported-languages.md +++ b/docs/guide/getting-started/supported-languages.md @@ -1,9 +1,15 @@ # Supported Languages +There are currently two languages that have an additional +Astal package: Lua and Gjs. Their purpose is to abstract away +Gtk by implementing a state management and UI declaring solution. + ## JavaScript -The main intended usage of Astal is in TypeScript with [AGS](/guide/ags/first-widgets). -It supports JSX and has a state management solution similar to web frameworks. +The main intended usage of Astal is in TypeScript+JSX. +It is recommended to use [AGS](/guide/ags/first-widgets) to scaffold and run projects in TypeScript. +However, if you are familiar with JavaScript's tooling +ecosystem you can also setup an environment yourself. Only a minimal knowledge of JavaScript's syntax is needed to get started. :::info @@ -17,11 +23,7 @@ Examples: ## Lua -Similar to how there is a [TypeScript](https://github.com/Aylur/astal/tree/main/core/gjs) lib for GJS, there is also an accompanying library for [Lua](https://github.com/Aylur/astal/tree/main/core/lua). - -Unfortunately, I have encountered very heavy [performance issues](https://github.com/aylur/astal) with [lgi](https://github.com/lgi-devs/lgi), -and so currently I don't recommend using Lua for full desktop shells, but only for static -components that don't render child nodes dynamically, bars and panels for example. +Lua is well-supported, but I would still recommend TypeScript, as Lua lacks a type system, which in turn limits editor support. Examples: @@ -30,10 +32,9 @@ Examples: ## Python -There was a WIP [library for python](https://github.com/aylur/astal/tree/feat/python), to make it behave similar to the above two -but I don't plan on finishing it, because I'm not a fan of python. -If you are interested in picking it up, feel free to open a PR. -Nonetheless you can still use python the OOP way [pygobject](https://pygobject.gnome.org/tutorials/gobject/subclassing.html) intended it. +There is a WIP [package for python](https://github.com/aylur/astal/tree/feat/python), +to bring declaritivity to Python similar to the above two languages. +However, you can still use python the OOP way [pygobject](https://pygobject.gnome.org/tutorials/gobject/subclassing.html) intended it in the meantime. Examples: @@ -44,7 +45,7 @@ Examples: Vala is a language that simply put uses C# syntax and compiles to C. It is the language most of Astal is written in. I would still recommend -using TypeScript or Lua over Vala as they don't need a build step. +using TypeScript or Lua over Vala as they are simpler to work with. Examples: diff --git a/docs/guide/lua/first-widgets.md b/docs/guide/lua/first-widgets.md new file mode 100644 index 0000000..2abe7c5 --- /dev/null +++ b/docs/guide/lua/first-widgets.md @@ -0,0 +1,3 @@ +# First Widgets + +🚧 Lua documentation is in Progress 🚧 diff --git a/docs/guide/lua/installation.md b/docs/guide/lua/installation.md new file mode 100644 index 0000000..48241f9 --- /dev/null +++ b/docs/guide/lua/installation.md @@ -0,0 +1,3 @@ +# Installation + +🚧 Lua documentation is in Progress 🚧 diff --git a/docs/guide/typescript/binding.md b/docs/guide/typescript/binding.md new file mode 100644 index 0000000..05645ab --- /dev/null +++ b/docs/guide/typescript/binding.md @@ -0,0 +1,235 @@ +# Binding + +As mentioned before binding an object's state to another - +so in most cases a `Variable` or a `GObject.Object` property to a widget's property - +is done through the `bind` function which returns a `Binding` object. + +`Binding` objects simply hold information about the source and how it should be transformed +which Widget constructors can use to setup a connection between themselves and the source. + +```ts +class Binding { + private transformFn: (v: any) => unknown + private emitter: Subscribable | Connectable + private prop?: string + + as(fn: (v: Value) => T): Binding + get(): Value + subscribe(callback: (value: Value) => void): () => void +} +``` + +A `Binding` can be constructed from an object implementing +the `Subscribable` interface (usually a `Variable`) +or an object implementing the `Connectable` interface and one of its properties +(usually a `GObject.Object` instance). + +```ts +function bind(obj: Subscribable): Binding + +function bind< + Obj extends Connectable, + Prop extends keyof Obj, +>(obj: Obj, prop: Prop): Binding +``` + +## Subscribable and Connectable interface + +Any object implementing one of these interfaces can be used with `bind`. + +```ts +interface Subscribable { + subscribe(callback: (value: T) => void): () => void + get(): T +} + +interface Connectable { + connect(signal: string, callback: (...args: any[]) => unknown): number + disconnect(id: number): void +} +``` + +## Example Custom Subscribable + +When binding the children of a box from an array, usually not all elements +of the array changes each time, so it would make sense to not destroy +the widget which represents the element. + +::: code-group + +```ts :line-numbers [varmap.ts] +import { type Subscribable } from "astal/binding" +import { Gtk } from "astal" + +export class VarMap implements Subscribable { + #subs = new Set<(v: Array<[K, T]>) => void>() + #map: Map + + #notifiy() { + const value = this.get() + for (const sub of this.#subs) { + sub(value) + } + } + + #delete(key: K) { + const v = this.#map.get(key) + + if (v instanceof Gtk.Widget) { + v.destroy() + } + + this.#map.delete(key) + } + + constructor(initial?: Iterable<[K, T]>) { + this.#map = new Map(initial) + } + + set(key: K, value: T) { + this.#delete(key) + this.#map.set(key, value) + this.#notifiy() + } + + delete(key: K) { + this.#delete(key) + this.#notifiy() + } + + get() { + return [...this.#map.entries()] + } + + subscribe(callback: (v: Array<[K, T]>) => void) { + this.#subs.add(callback) + return () => this.#subs.delete(callback) + } +} +``` + +::: + +And this `VarMap` can be used as an alternative to `Variable>`. + +```tsx +function MappedBox() { + const map = new VarMap([ + [1, ] + [2, ] + ]) + + const conns = [ + gobject.connect("added", (_, id) => map.set(id, MyWidget({ id }))), + gobject.connect("removed", (_, id) => map.delete(id, MyWidget({ id }))), + ] + + return conns.map(id => gobject.disconnect(id))}> + {bind(map).as(arr => arr.sort(([a], [b]) => a - b).map(([,w]) => w))} + +} +``` + +## Example Custom Connectable + +Astal provides [decorator functions](./gobject#example-usage) +that make it easy to subclass gobjects, however +you can read more about GObjects and subclassing +on [gjs.guide](https://gjs.guide/guides/gobject/subclassing.html#gobject-subclassing). + +Objects coming from [libraries](../libraries/references#astal-libraries) +usually have a singleton gobject you can access with `.get_default()`. + +Here is an example of a Brightness library by wrapping the `brightnessctl` cli utility +and by monitoring `/sys/class/backlight` + +::: code-group + +```ts :line-numbers [brightness.ts] +import GObject, { register, property } from "astal/gobject" +import { monitorFile, readFileAsync } from "astal/file" +import { exec, execAsync } from "astal/process" + +const get = (args: string) => Number(exec(`brightnessctl ${args}`)) +const screen = exec(`bash -c "ls -w1 /sys/class/backlight | head -1"`) +const kbd = exec(`bash -c "ls -w1 /sys/class/leds | head -1"`) + +@register({ GTypeName: "Brightness" }) +export default class Brightness extends GObject.Object { + static instance: Brightness + static get_default() { + if (!this.instance) + this.instance = new Brightness() + + return this.instance + } + + #kbdMax = get(`--device ${kbd} max`) + #kbd = get(`--device ${kbd} get`) + #screenMax = get("max") + #screen = get("get") / (get("max") || 1) + + @property(Number) + get kbd() { return this.#kbd } + + set kbd(value) { + if (value < 0 || value > this.#kbdMax) + return + + execAsync(`brightnessctl -d ${kbd} s ${value} -q`).then(() => { + this.#kbd = value + this.notify("kbd") + }) + } + + @property(Number) + get screen() { return this.#screen } + + set screen(percent) { + if (percent < 0) + percent = 0 + + if (percent > 1) + percent = 1 + + execAsync(`brightnessctl set ${Math.floor(percent * 100)}% -q`).then(() => { + this.#screen = percent + this.notify("screen") + }) + } + + constructor() { + super() + + const screenPath = `/sys/class/backlight/${screen}/brightness` + const kbdPath = `/sys/class/leds/${kbd}/brightness` + + monitorFile(screenPath, async f => { + const v = await readFileAsync(f) + this.#screen = Number(v) / this.#screenMax + this.notify("screen") + }) + + monitorFile(kbdPath, async f => { + const v = await readFileAsync(f) + this.#kbd = Number(v) / this.#kbdMax + this.notify("kbd") + }) + } +} +``` + +::: + +And it can be used like any other library object. + +```tsx +function BrightnessSlider() { + const brightness = Brightness.get_default() + + return brightness.screen = value} + /> +} +``` diff --git a/docs/guide/typescript/cli-app.md b/docs/guide/typescript/cli-app.md new file mode 100644 index 0000000..3407e06 --- /dev/null +++ b/docs/guide/typescript/cli-app.md @@ -0,0 +1,174 @@ +# CLI and App + +`App` is a singleton **instance** of an [Astal.Application](https://aylur.github.io/libastal/class.Application.html). + +Depending on gtk version import paths will differ + +```ts +import { App } from "astal/gtk3" + +import { App } from "astal/gtk4" +``` + +## Entry point + +:::code-group + +```ts [app.ts] +App.start({ + main() { + // setup anything + // instantiate widgets + }, +}) +``` + +::: + +## Instance identifier + +You can run multiple instance by defining a unique instance name. + +```ts +App.start({ + instanceName: "my-instance", // defaults to "astal" + main() { }, +}) +``` + +## Messaging from CLI + +If you want to interact with an instance from the CLI, +you can do so by sending a message. + +```ts +App.start({ + requestHandler(request: string, res: (response: any) => void) { + if (request == "say hi") { + res("hi cli") + } + res("unknown command") + }, + main() { }, +}) +``` + +:::code-group + +```sh [astal] +astal say hi +# hi cli +``` + +```sh [ags] +ags -m "say hi" +# hi cli +``` + +::: + +If you want to run arbitrary JavaScript from CLI, you can use `App.eval` +which will evaluate the passed string as the body of an `async` function. + +```ts +App.start({ + main() {}, + requestHandler(js, res) { + App.eval(js).then(res).catch(res) + }, +}) +``` + +If the string does not contain a semicolon, a single expression is assumed and returned implicity. + +```sh +astal "'hello'" +# hello +``` + +If the string contains a semicolon, you have to return explicitly + +```sh +astal "'hello';" +# undefined + +astal "return 'hello';" +# hello +``` + +## Toggling Windows by their name + +In order for Astal to know about your windows, you have to register them. +You can do this by specifying a **unique** `name` and calling `App.add_window` + +```tsx {4} +import { App } from "astal" + +function Bar() { + return App.add_window(self)}> + + +} +``` + +You can also invoke `App.add_window` by simply passing the `App` to the `application` prop. + +```tsx {4} +import { App } from "astal" + +function Bar() { + return + + +} +``` + +:::warning +When assigning the `application` prop make sure `name` comes before. +Props are set sequentially and if name is applied after application it won't work. +::: + +:::code-group + +```sh [astal] +astal -t Bar +``` + +```sh [ags] +ags -t Bar +``` + +::: + +## Bundled scripts + +The produced scripts when bundling can run as the main instance +and a "client" instance. + +The first time you execute your bundled script the `main` function gets called. +While that instance is running any subsequent execution of the script will call +the `client` function. + +:::code-group + +```ts [main.ts] +App.start({ + // main instance + main(...args: Array) { + print(...args) + }, + + // every subsequent calls + client(message: (msg: string) => string, ...args: Array) { + const res = message("you can message the main instance") + console.log(res) + }, + + // this runs in the main instance + requestHandler(request: string, res: (response: any) => void) { + res("response from main") + }, +}) +``` + +::: diff --git a/docs/guide/typescript/faq.md b/docs/guide/typescript/faq.md new file mode 100644 index 0000000..76d8e72 --- /dev/null +++ b/docs/guide/typescript/faq.md @@ -0,0 +1,266 @@ +# Frequently asked question, common issues, tips and tricks + +## Monitor id does not match compositor + +The monitor id property that windows expect is mapped by Gdk, which is not always +the same as the compositor. Instead use the `gdkmonitor` property which expects +a `Gdk.Monitor` object. + +```tsx +import { App } from "astal" + +function Bar(gdkmonitor) { + return +} + +function main() { + for (const monitor of App.get_monitors()) { + if (monitor.model == "your-desired-model") { + Bar(monitor) + } + } +} + +App.start({ main }) +``` + +## Environment variables + +JavaScript is **not** an bash. + +```ts +const HOME = exec("echo $HOME") // does not work +``` + +`exec` and `execAsync` runs the passed program as is, its **not** run in a +shell environment, so the above example just passes `$HOME` as a string literal +to the `echo` program. + +:::danger Please don't do this +You could pass it to bash, but that is a horrible approach. + +```ts +const HOME = exec("bash -c 'echo $HOME'") +``` + +::: + +You can read environment variables with [GLib.getenv](https://gjs-docs.gnome.org/glib20~2.0/glib.getenv). + +```ts +import GLib from "gi://GLib" + +const HOME = GLib.getenv("HOME") +``` + +## Custom SVG symbolic icons + +Put the svgs in a directory, named `-symbolic.svg` +and use `App.add_icons` or `icons` parameter in `App.start` + +:::code-group + +```ts [app.ts] +App.start({ + icons: `${SRC}/icons`, + main() { + Widget.Icon({ + icon: "custom-symbolic", // custom-symbolic.svg + css: "color: green;", // can be colored, like other named icons + }) + }, +}) +``` + +::: + +:::info +If there is a name clash with an icon from your current icon pack +the icon pack will take precedence +::: + +## Logging + +The `console` API in gjs uses glib logging functions. +If you just want to print some text as is to stdout +use the globally available `print` function or `printerr` for stderr. + +```ts +print("print this line to stdout") +printerr("print this line to stderr") +``` + +## Populate the global scope with frequently accessed variables + +It might be annoying to always import Gtk only for `Gtk.Align` enums. + +:::code-group + +```ts [globals.ts] +import Gtk from "gi://Gtk" + +declare global { + const START: number + const CENTER: number + const END: number + const FILL: number +} + +Object.assign(globalThis, { + START: Gtk.Align.START, + CENTER: Gtk.Align.CENTER, + END: Gtk.Align.END, + FILL: Gtk.Align.FILL, +}) +``` + +::: + +:::code-group + +```tsx [Bar.tsx] +export default function Bar() { + return + + +} +``` + +::: + +:::code-group + +```ts [app.ts] +import "./globals" +import Bar from "./Bar" + +App.start({ + main: Bar +}) +``` + +::: + +:::info +It is considered bad practice to populate the global scope, but its your code, not a public library. +::: + +## Auto create Window for each Monitor + +To have Window widgets appear on a monitor when its plugged in, listen to `App.monitor_added`. + +:::code-group + +```tsx [Bar.tsx] +export default function Bar(gdkmonitor: Gdk.Monitor) { + return +} +``` + +::: + +:::code-group + +```ts [app.ts] +import { Gdk, Gtk } from "astal" +import Bar from "./Bar" + +function main() { + const bars = new Map() + + // initialize + for (const gdkmonitor of App.get_monitors()) { + bars.set(gdkmonitor, Bar(gdkmonitor)) + } + + App.connect("monitor-added", (_, gdkmonitor) => { + bars.set(gdkmonitor, Bar(gdkmonitor)) + }) + + App.connect("monitor-removed", (_, gdkmonitor) => { + bars.get(gdkmonitor)?.destroy() + bars.delete(gdkmonitor) + }) +} + +App.start({ main }) +``` + +::: + +## Error: Can't convert non-null pointer to JS value + +These happen when accessing list type properties. Gjs fails to correctly bind +`List` and other array like types of Vala as a property. + +```ts +import Notifd from "gi://AstalNotifd" +const notifd = Notifd.get_default() + +notifd.notifications // ❌ // [!code error] + +notifd.get_notifications() // ✅ +``` + +## How to create regular floating windows + +Use `Gtk.Window` with [Widget.astalify](/guide/ags/widget#how-to-use-non-builtin-gtk-widgets). + +By default `Gtk.Window` is destroyed on close. To prevent this add a handler for `delete-event`. + +```tsx {4-7} +const RegularWindow = Widget.astalify(Gtk.Window) + +return { + self.hide() + return true + }} +> + {child} + +``` + +## Is there a way to limit the width/height of a widget? + +Unfortunately not. You can set a minimum size with `min-width` and `min-heigth` css attributes, +but you can not set max size. + +## Custom widgets with bindable properties + +In function components you can wrap any primitive to handle both +binding and value cases as one. + +```tsx +function MyWidget(props: { prop: string | Binding }) { + const prop = props.prop instanceof Binding + ? props.prop + : bind({ get: () => props.prop, subscribe: () => () => {} }) + + function setup(self: Widget.Box) { + self.hook(prop, () => { + const value = prop.get() + // handler + }) + } + + return + +} +``` + +You can pass the prop the super constructor in subclasses + +```tsx +@register() +class MyWidget extends Widget.Box { + @property(String) + set prop(v: string) { + // handler + } + + constructor(props: { prop: string | Binding }) { + super(props) + } +} +``` diff --git a/docs/guide/typescript/first-widgets.md b/docs/guide/typescript/first-widgets.md new file mode 100644 index 0000000..3664bfa --- /dev/null +++ b/docs/guide/typescript/first-widgets.md @@ -0,0 +1,412 @@ +# First Widgets + +## Getting Started + +Start by initializing a project + +```sh +ags --init +``` + +then run `ags` in the terminal + +```sh +ags +``` + +:::details Usage without AGS +🚧 Not yet documented. 🚧 +::: + +That's it! You have now a custom written bar using Gtk. + +:::tip +AGS will transpile every `.ts`, `.jsx` and `.tsx` files into regular JavaScript, then +it will bundle everything into a single JavaScript file which then GJS can execute. +::: + +The AGS init command will generate the following files + +```txt +. +├── @girs/ # generated types +├── widget/ +│ └── Bar.tsx +├── app.ts # entry proint +├── env.d.ts # additional types +├── style.css +└── tsconfig.json # needed by LSPs +``` + +## Root of every shell component: Window + +Astal apps are composed of widgets. A widget is a piece of UI that has its own logic and style. +A widget can be as small as a button or an entire bar. +The top level widget is always a [Window](https://aylur.github.io/libastal/class.Window.html) which will hold all widgets. + +::: code-group + +```tsx [widget/Bar.tsx] +function Bar(monitor = 0) { + return + Content of the widget + +} +``` + +::: + +::: code-group + +```ts [app.ts] +import Bar from "./widget/Bar" + +App.start({ + main() { + Bar(0) + Bar(1) // instantiate for each monitor + }, +}) +``` + +::: + +## Creating and nesting widgets + +Widgets are JavaScript functions which return Gtk widgets, +either by using JSX or using a widget constructor. + +:::code-group + +```tsx [MyButton.tsx] +function MyButton(): JSX.Element { + return +} +``` + +```ts [MyButton.ts] +import { Widget } from "astal/gtk3" + +function MyButton(): Widget.Button { + return new Widget.Button( + { onClicked: "echo hello" }, + new Widget.Label({ label: "Click me!" }), + ) +} +``` + +::: + +:::info +The only difference between the two is the return type. +Using markup the return type is always `Gtk.Widget` (globally available as `JSX.Element`), +while using constructors the return type is the actual type of the widget. +It is rare to need the actual return type, so most if not all of the time, you can use markup. +::: + +Now that you have declared `MyButton`, you can nest it into another component. + +```tsx +function MyBar() { + return + + Click The button + + + +} +``` + +Notice that widgets you defined start with a capital letter ``. +Lowercase tags are builtin widgets, while capital letter is for custom widgets. + +## Displaying Data + +JSX lets you put markup into JavaScript. +Curly braces let you “escape back” into JavaScript so that you can embed some variable +from your code and display it. + +```tsx +function MyWidget() { + const label = "hello" + + return +} +``` + +You can also pass JavaScript to markup attributes + +```tsx +function MyWidget() { + const label = "hello" + + return +} +``` + +### Builtin Widgets + +You can check the [source code](https://github.com/aylur/astal/blob/main/lang/gjs/src/gtk3/index.ts) to have a full list of builtin widgets. + +These widgets are available by default in JSX. + +- box: [Astal.Box](https://aylur.github.io/libastal/class.Box.html) +- button: [Astal.Button](https://aylur.github.io/libastal/class.Button.html) +- centerbox: [Astal.CenterBox](https://aylur.github.io/libastal/class.CenterBox.html) +- circularprogress: [Astal.CircularProgress](https://aylur.github.io/libastal/class.CircularProgress.html) +- drawingarea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/class.DrawingArea.html) +- entry: [Gtk.Entry](https://docs.gtk.org/gtk3/class.Entry.html) +- eventbox: [Astal.EventBox](https://aylur.github.io/libastal/class.EventBox.html) +- icon: [Astal.Icon](https://aylur.github.io/libastal/class.Icon.html) +- label: [Astal.Label](https://aylur.github.io/libastal/class.Label.html) +- levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/class.LevelBar.html) +- overlay: [Astal.Overlay](https://aylur.github.io/libastal/class.Overlay.html) +- revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/class.Revealer.html) +- scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/class.Scrollable.html) +- slider: [Astal.Slider](https://aylur.github.io/libastal/class.Slider.html) +- stack: [Astal.Stack](https://aylur.github.io/libastal/class.Stack.html) +- switch: [Gtk.Switch](https://docs.gtk.org/gtk3/class.Switch.html) +- window: [Astal.Window](https://aylur.github.io/libastal/class.Window.html) + +## Gtk4 + +🚧 Work in Progress 🚧 -- cgit v1.2.3 From fe11c037bad45697451b7264ff93fa37f1fac78f Mon Sep 17 00:00:00 2001 From: Aylur Date: Tue, 15 Oct 2024 11:55:53 +0000 Subject: docs: recommend /usr prefix by default --- docs/guide/getting-started/installation.md | 14 +------------- docs/guide/libraries/apps.md | 18 +----------------- docs/guide/libraries/auth.md | 13 +------------ docs/guide/libraries/battery.md | 13 +------------ docs/guide/libraries/bluetooth.md | 13 +------------ docs/guide/libraries/hyprland.md | 13 +------------ docs/guide/libraries/mpris.md | 13 +------------ docs/guide/libraries/network.md | 13 +------------ docs/guide/libraries/notifd.md | 13 +------------ docs/guide/libraries/powerprofiles.md | 13 +------------ docs/guide/libraries/references.md | 1 - docs/guide/libraries/river.md | 13 +------------ docs/guide/libraries/tray.md | 13 +------------ docs/guide/libraries/wireplumber.md | 13 +------------ docs/guide/typescript/installation.md | 4 ++-- 15 files changed, 15 insertions(+), 165 deletions(-) (limited to 'docs/guide') diff --git a/docs/guide/getting-started/installation.md b/docs/guide/getting-started/installation.md index 6ad951a..96cbdfa 100644 --- a/docs/guide/getting-started/installation.md +++ b/docs/guide/getting-started/installation.md @@ -56,7 +56,7 @@ sudo apt install meson valac libgtk-3-dev libgtk-layer-shell-dev gobject-introsp ```sh cd lib/astal/io -meson setup build +meson setup --prefix /usr build meson install -C build ``` @@ -64,18 +64,6 @@ meson install -C build ```sh cd lib/astal/gtk3 -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build meson install -C build ``` - -::: diff --git a/docs/guide/libraries/apps.md b/docs/guide/libraries/apps.md index c53daf0..7f9ee6e 100644 --- a/docs/guide/libraries/apps.md +++ b/docs/guide/libraries/apps.md @@ -32,22 +32,11 @@ cd astal/lib/apps 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Apps reference](https://aylur.github.io/libastal/apps). @@ -106,8 +95,3 @@ end ``` ::: - -:::info -The fuzzy query uses [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance). I am not a mathematician, but if you know how to reimplement -the logic of [fzf](https://github.com/junegunn/fzf) to make it better feel free to open PRs. -::: diff --git a/docs/guide/libraries/auth.md b/docs/guide/libraries/auth.md index 1f07a17..d5f0a49 100644 --- a/docs/guide/libraries/auth.md +++ b/docs/guide/libraries/auth.md @@ -42,22 +42,11 @@ cd astal/lib/auth 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Auth reference](https://aylur.github.io/libastal/auth). diff --git a/docs/guide/libraries/battery.md b/docs/guide/libraries/battery.md index b42d747..7f94297 100644 --- a/docs/guide/libraries/battery.md +++ b/docs/guide/libraries/battery.md @@ -36,22 +36,11 @@ cd astal/lib/battery 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Battery reference](https://aylur.github.io/libastal/battery). diff --git a/docs/guide/libraries/bluetooth.md b/docs/guide/libraries/bluetooth.md index 04d9db2..672f66d 100644 --- a/docs/guide/libraries/bluetooth.md +++ b/docs/guide/libraries/bluetooth.md @@ -36,22 +36,11 @@ cd astal/lib/bluetooth 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Bluetooth reference](https://aylur.github.io/libastal/bluetooth). diff --git a/docs/guide/libraries/hyprland.md b/docs/guide/libraries/hyprland.md index faf9e50..672faad 100644 --- a/docs/guide/libraries/hyprland.md +++ b/docs/guide/libraries/hyprland.md @@ -31,22 +31,11 @@ cd astal/lib/hyprland 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Hyprland reference](https://aylur.github.io/libastal/hyprland). diff --git a/docs/guide/libraries/mpris.md b/docs/guide/libraries/mpris.md index dfe7956..4f8c017 100644 --- a/docs/guide/libraries/mpris.md +++ b/docs/guide/libraries/mpris.md @@ -35,22 +35,11 @@ cd astal/lib/mpris 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Mpris reference](https://aylur.github.io/libastal/mpris). diff --git a/docs/guide/libraries/network.md b/docs/guide/libraries/network.md index afeb5d2..e076950 100644 --- a/docs/guide/libraries/network.md +++ b/docs/guide/libraries/network.md @@ -31,22 +31,11 @@ cd astal/lib/network 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Network reference](https://aylur.github.io/libastal/network). diff --git a/docs/guide/libraries/notifd.md b/docs/guide/libraries/notifd.md index 7e02149..094b770 100644 --- a/docs/guide/libraries/notifd.md +++ b/docs/guide/libraries/notifd.md @@ -35,22 +35,11 @@ cd astal/lib/notifd 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Notifd reference](https://aylur.github.io/libastal/notifd). diff --git a/docs/guide/libraries/powerprofiles.md b/docs/guide/libraries/powerprofiles.md index 8571c29..159f3ff 100644 --- a/docs/guide/libraries/powerprofiles.md +++ b/docs/guide/libraries/powerprofiles.md @@ -36,22 +36,11 @@ cd astal/lib/powerprofiles 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [PowerProfiles reference](https://aylur.github.io/libastal/powerprofiles). diff --git a/docs/guide/libraries/references.md b/docs/guide/libraries/references.md index 8f2bd02..3a85d73 100644 --- a/docs/guide/libraries/references.md +++ b/docs/guide/libraries/references.md @@ -29,7 +29,6 @@ Reading their documentation will vary depending on the language they are used in ## Astal Libraries -- [Astal](https://aylur.github.io/libastal): libastal the core library, which has the widgets and utilites - [Apps](https://aylur.github.io/libastal/apps): Library and cli tool for querying applications - [Auth](https://aylur.github.io/libastal/auth): Authentication library using PAM - [Battery](https://aylur.github.io/libastal/battery): DBus proxy library for upower daemon diff --git a/docs/guide/libraries/river.md b/docs/guide/libraries/river.md index 4818d0b..299aa8c 100644 --- a/docs/guide/libraries/river.md +++ b/docs/guide/libraries/river.md @@ -31,22 +31,11 @@ cd astal/lib/river 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [River reference](https://aylur.github.io/libastal/river). diff --git a/docs/guide/libraries/tray.md b/docs/guide/libraries/tray.md index c8d093b..b5cccc7 100644 --- a/docs/guide/libraries/tray.md +++ b/docs/guide/libraries/tray.md @@ -31,22 +31,11 @@ cd astal/lib/tray 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Tray reference](https://aylur.github.io/libastal/tray). diff --git a/docs/guide/libraries/wireplumber.md b/docs/guide/libraries/wireplumber.md index 5f1daab..0592628 100644 --- a/docs/guide/libraries/wireplumber.md +++ b/docs/guide/libraries/wireplumber.md @@ -31,22 +31,11 @@ cd astal/lib/wireplumber 3. install -```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - ```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Wireplumber reference](https://aylur.github.io/libastal/wireplumber). diff --git a/docs/guide/typescript/installation.md b/docs/guide/typescript/installation.md index 4c31b6e..f085194 100644 --- a/docs/guide/typescript/installation.md +++ b/docs/guide/typescript/installation.md @@ -9,7 +9,7 @@ It lets you - generate a tsconfig which is used by LSPs - bundle your TypeScript and JavaScript code using [esbuild](https://esbuild.github.io/). -::: details Trivia +:::details Trivia AGS is the predecessor of Astal, which was written purely in TypeScript and so only supported JavaScript/TypeScript. Now it serves as a scaffolding tool for Astal+TypeScript+JSX projects. ::: @@ -43,7 +43,7 @@ meson install -C build :::tip You might be wondering why it is recommended to install a JavaScript package on the system instead of installing it as a node module. -It is solely to keep it in **sync** with the core `astal-sh` and `astal3`/`astal4` package. +It is solely to keep it in **sync** with the core `astal-io` and `astal3`/`astal4` package. ::: 3. Install the following dependencies -- cgit v1.2.3 From bafd48d3df9b43a1d49ec015eff30619d595468b Mon Sep 17 00:00:00 2001 From: Aylur Date: Tue, 15 Oct 2024 13:25:45 +0000 Subject: update lua and gjs layout installing the gjs package through meson or npm now results in the same exposed structure lua: fix rockspec docs: aur package --- docs/guide/getting-started/installation.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'docs/guide') diff --git a/docs/guide/getting-started/installation.md b/docs/guide/getting-started/installation.md index 96cbdfa..aaa6d0d 100644 --- a/docs/guide/getting-started/installation.md +++ b/docs/guide/getting-started/installation.md @@ -10,12 +10,10 @@ Read more about it on the [nix page](./nix#astal) maintainer: [@kotontrion](https://github.com/kotontrion) - - :::code-group ```sh [Core Library] -yay -S libastal-git +yay -S libastal-io-git libastal-git ``` ```sh [Every Library] -- cgit v1.2.3 From b33c3bf91dbbea13b1a2c8603e00809b22cd42c8 Mon Sep 17 00:00:00 2001 From: Aylur Date: Tue, 15 Oct 2024 13:36:16 +0000 Subject: docs: fix links --- docs/guide/getting-started/introduction.md | 2 +- docs/guide/getting-started/nix.md | 2 +- docs/guide/getting-started/supported-languages.md | 2 +- docs/guide/typescript/cli-app.md | 2 +- docs/guide/typescript/faq.md | 2 +- docs/guide/typescript/first-widgets.md | 4 +-- docs/guide/typescript/utilities.md | 4 +-- docs/guide/typescript/variable.md | 4 +-- docs/guide/typescript/widget.md | 34 +++++++++++------------ 9 files changed, 28 insertions(+), 28 deletions(-) (limited to 'docs/guide') diff --git a/docs/guide/getting-started/introduction.md b/docs/guide/getting-started/introduction.md index af176c3..782c069 100644 --- a/docs/guide/getting-started/introduction.md +++ b/docs/guide/getting-started/introduction.md @@ -6,7 +6,7 @@ Astal (_meaning "desk"_) is a suite of libraries in Vala and C. The core library [astal3](https://aylur.github.io/libastal/astal3) and [astal4](https://aylur.github.io/libastal/astal4) (not yet available) has some Gtk widgets that come packaged, -the most important one being the [Window](https://aylur.github.io/libastal/class.Window.html) which is the main toplevel component using [gtk-layer-shell](https://github.com/wmww/gtk-layer-shell). +the most important one being the [Window](https://aylur.github.io/libastal/astal3/class.Window.html) which is the main toplevel component using [gtk-layer-shell](https://github.com/wmww/gtk-layer-shell). This is what allows us to use Gtk as shell components on Wayland. The other part of the core library [astal-io](https://aylur.github.io/libastal/astal-io) which contains some utility GLib shortcut for running external processes, diff --git a/docs/guide/getting-started/nix.md b/docs/guide/getting-started/nix.md index 5c0db28..1d50d35 100644 --- a/docs/guide/getting-started/nix.md +++ b/docs/guide/getting-started/nix.md @@ -88,7 +88,7 @@ Using Astal on Nix will require you to package your project. ## AGS -The recommended way to use [AGS](../ags/first-widgets#first-widgets) on NixOS is through the home-manager module. +The recommended way to use [AGS](../typescript/first-widgets#first-widgets) on NixOS is through the home-manager module. Example content of a `flake.nix` file that contains your `homeConfigurations`. diff --git a/docs/guide/getting-started/supported-languages.md b/docs/guide/getting-started/supported-languages.md index 47d5dbd..d6d669d 100644 --- a/docs/guide/getting-started/supported-languages.md +++ b/docs/guide/getting-started/supported-languages.md @@ -7,7 +7,7 @@ Gtk by implementing a state management and UI declaring solution. ## JavaScript The main intended usage of Astal is in TypeScript+JSX. -It is recommended to use [AGS](/guide/ags/first-widgets) to scaffold and run projects in TypeScript. +It is recommended to use [AGS](/guide/typescript/first-widgets) to scaffold and run projects in TypeScript. However, if you are familiar with JavaScript's tooling ecosystem you can also setup an environment yourself. Only a minimal knowledge of JavaScript's syntax is needed to get started. diff --git a/docs/guide/typescript/cli-app.md b/docs/guide/typescript/cli-app.md index 3407e06..f409176 100644 --- a/docs/guide/typescript/cli-app.md +++ b/docs/guide/typescript/cli-app.md @@ -1,6 +1,6 @@ # CLI and App -`App` is a singleton **instance** of an [Astal.Application](https://aylur.github.io/libastal/class.Application.html). +`App` is a singleton **instance** of an [Astal.Application](https://aylur.github.io/libastal/astal3/class.Application.html). Depending on gtk version import paths will differ diff --git a/docs/guide/typescript/faq.md b/docs/guide/typescript/faq.md index 76d8e72..48c802c 100644 --- a/docs/guide/typescript/faq.md +++ b/docs/guide/typescript/faq.md @@ -204,7 +204,7 @@ notifd.get_notifications() // ✅ ## How to create regular floating windows -Use `Gtk.Window` with [Widget.astalify](/guide/ags/widget#how-to-use-non-builtin-gtk-widgets). +Use `Gtk.Window` with [Widget.astalify](/guide/typescript/widget#how-to-use-non-builtin-gtk-widgets). By default `Gtk.Window` is destroyed on close. To prevent this add a handler for `delete-event`. diff --git a/docs/guide/typescript/first-widgets.md b/docs/guide/typescript/first-widgets.md index 3664bfa..a7372a8 100644 --- a/docs/guide/typescript/first-widgets.md +++ b/docs/guide/typescript/first-widgets.md @@ -42,7 +42,7 @@ The AGS init command will generate the following files Astal apps are composed of widgets. A widget is a piece of UI that has its own logic and style. A widget can be as small as a button or an entire bar. -The top level widget is always a [Window](https://aylur.github.io/libastal/class.Window.html) which will hold all widgets. +The top level widget is always a [Window](https://aylur.github.io/libastal/astal3/class.Window.html) which will hold all widgets. ::: code-group @@ -363,7 +363,7 @@ by setting `noImplicityDestroy` property on the container widget. :::info The above example destroys and recreates every widget in the list **every time** the value of the `Variable` changes. There might be cases where you would -want to [handle child creation and deletion](/guide/ags/faq#avoiding-unnecessary-re-rendering) +want to [handle child creation and deletion](/guide/typescript/faq#avoiding-unnecessary-re-rendering) yourself, because you don't want to lose the inner state of widgets that does not need to be recreated. In this case you can create a [custom reactive structure](./binding#example-custom-subscribable) diff --git a/docs/guide/typescript/utilities.md b/docs/guide/typescript/utilities.md index 9bc56b2..f808044 100644 --- a/docs/guide/typescript/utilities.md +++ b/docs/guide/typescript/utilities.md @@ -44,7 +44,7 @@ import { interval, timeout, idle } from "astal" You can use javascript native `setTimeout` or `setInterval` they return a [GLib.Source](https://docs.gtk.org/glib/struct.Source.html) instance. Alternatively you can use these functions provided by Astal, -which return an [Astal.Time](https://aylur.github.io/libastal/class.Time.html) instance. +which return an [Astal.Time](https://aylur.github.io/libastal/io/class.Time.html) instance. `Astal.Time` has a `now` signal and a `cancelled` signal. @@ -99,7 +99,7 @@ import { subprocess, exec, execAsync } from "astal" ### Subprocess You can start a subprocess and run callback functions whenever it outputs to -stdout or stderr. [Astal.Process](https://aylur.github.io/libastal/class.Process.html) has a `stdout` and `stderr` signal. +stdout or stderr. [Astal.Process](https://aylur.github.io/libastal/io/class.Process.html) has a `stdout` and `stderr` signal. ```ts function subprocess(args: { diff --git a/docs/guide/typescript/variable.md b/docs/guide/typescript/variable.md index 4207f61..2abacbd 100644 --- a/docs/guide/typescript/variable.md +++ b/docs/guide/typescript/variable.md @@ -8,7 +8,7 @@ Variable is just a simple object which holds a single value. It also has some shortcuts for hooking up subprocesses, intervals and other gobjects. :::info -The `Variable` object imported from the `"astal"` package is **not** [Astal.Variable](https://aylur.github.io/libastal/class.Variable.html). +The `Variable` object imported from the `"astal"` package is **not** [Astal.Variable](https://aylur.github.io/libastal/io/class.Variable.html). ::: ## Example Usage @@ -75,7 +75,7 @@ output. They can poll and watch at the same time, but they can only poll/watch once. :::warning -The command parameter is passed to [execAsync](/guide/ags/utilities#executing-external-commands-and-scripts) +The command parameter is passed to [execAsync](/guide/typescript/utilities#executing-external-commands-and-scripts) which means they are **not** executed in a shell environment, they do **not** expand ENV variables like `$HOME`, and they do **not** handle logical operators like `&&` and `||`. diff --git a/docs/guide/typescript/widget.md b/docs/guide/typescript/widget.md index 03ba9ea..d16d194 100644 --- a/docs/guide/typescript/widget.md +++ b/docs/guide/typescript/widget.md @@ -191,23 +191,23 @@ You can check the [source code](https://github.com/aylur/astal/blob/main/lang/gj These widgets are available by default in JSX. -- box: [Astal.Box](https://aylur.github.io/libastal/class.Box.html) -- button: [Astal.Button](https://aylur.github.io/libastal/class.Button.html) -- centerbox: [Astal.CenterBox](https://aylur.github.io/libastal/class.CenterBox.html) -- circularprogress: [Astal.CircularProgress](https://aylur.github.io/libastal/class.CircularProgress.html) -- drawingarea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/class.DrawingArea.html) -- entry: [Gtk.Entry](https://docs.gtk.org/gtk3/class.Entry.html) -- eventbox: [Astal.EventBox](https://aylur.github.io/libastal/class.EventBox.html) -- icon: [Astal.Icon](https://aylur.github.io/libastal/class.Icon.html) -- label: [Astal.Label](https://aylur.github.io/libastal/class.Label.html) -- levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/class.LevelBar.html) -- overlay: [Astal.Overlay](https://aylur.github.io/libastal/class.Overlay.html) -- revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/class.Revealer.html) -- scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/class.Scrollable.html) -- slider: [Astal.Slider](https://aylur.github.io/libastal/class.Slider.html) -- stack: [Astal.Stack](https://aylur.github.io/libastal/class.Stack.html) -- switch: [Gtk.Switch](https://docs.gtk.org/gtk3/class.Switch.html) -- window: [Astal.Window](https://aylur.github.io/libastal/class.Window.html) +- box: [Astal.Box](https://aylur.github.io/libastal/astal3/class.Box.html) +- button: [Astal.Button](https://aylur.github.io/libastal/astal3/class.Button.html) +- centerbox: [Astal.CenterBox](https://aylur.github.io/libastal/astal3/class.CenterBox.html) +- circularprogress: [Astal.CircularProgress](https://aylur.github.io/libastal/astal3/class.CircularProgress.html) +- drawingarea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/astal3/class.DrawingArea.html) +- entry: [Gtk.Entry](https://docs.gtk.org/gtk3/astal3/class.Entry.html) +- eventbox: [Astal.EventBox](https://aylur.github.io/libastal/astal3/class.EventBox.html) +- icon: [Astal.Icon](https://aylur.github.io/libastal/astal3/class.Icon.html) +- label: [Astal.Label](https://aylur.github.io/libastal/astal3/class.Label.html) +- levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/astal3/class.LevelBar.html) +- overlay: [Astal.Overlay](https://aylur.github.io/libastal/astal3/class.Overlay.html) +- revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/astal3/class.Revealer.html) +- scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/astal3/class.Scrollable.html) +- slider: [Astal.Slider](https://aylur.github.io/libastal/astal3/class.Slider.html) +- stack: [Astal.Stack](https://aylur.github.io/libastal/astal3/class.Stack.html) +- switch: [Gtk.Switch](https://docs.gtk.org/gtk3/astal3/class.Switch.html) +- window: [Astal.Window](https://aylur.github.io/libastal/astal3/class.Window.html) ## Gtk4 -- cgit v1.2.3