diff options
Diffstat (limited to 'docs/src/content')
-rw-r--r-- | docs/src/content/config.ts | 6 | ||||
-rw-r--r-- | docs/src/content/docs/ags/cli-app.md | 129 | ||||
-rw-r--r-- | docs/src/content/docs/ags/faq.md | 159 | ||||
-rw-r--r-- | docs/src/content/docs/ags/first-widgets.mdx | 429 | ||||
-rw-r--r-- | docs/src/content/docs/ags/theming.md | 113 | ||||
-rw-r--r-- | docs/src/content/docs/ags/utilities.md | 179 | ||||
-rw-r--r-- | docs/src/content/docs/ags/variable.md | 142 | ||||
-rw-r--r-- | docs/src/content/docs/ags/widget.md | 150 | ||||
-rw-r--r-- | docs/src/content/docs/getting-started/installation.mdx | 103 | ||||
-rw-r--r-- | docs/src/content/docs/getting-started/introduction.md | 28 | ||||
-rw-r--r-- | docs/src/content/docs/getting-started/languages.md | 64 | ||||
-rw-r--r-- | docs/src/content/docs/getting-started/nix.md | 8 | ||||
-rw-r--r-- | docs/src/content/docs/index.mdx | 67 | ||||
-rw-r--r-- | docs/src/content/docs/libraries/references.md | 49 | ||||
-rw-r--r-- | docs/src/content/showcases.ts | 13 |
15 files changed, 0 insertions, 1639 deletions
diff --git a/docs/src/content/config.ts b/docs/src/content/config.ts deleted file mode 100644 index 45f60b0..0000000 --- a/docs/src/content/config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineCollection } from 'astro:content'; -import { docsSchema } from '@astrojs/starlight/schema'; - -export const collections = { - docs: defineCollection({ schema: docsSchema() }), -}; diff --git a/docs/src/content/docs/ags/cli-app.md b/docs/src/content/docs/ags/cli-app.md deleted file mode 100644 index 3365505..0000000 --- a/docs/src/content/docs/ags/cli-app.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -title: CLI and App -description: Reference of the singleton App instance -sidebar: - order: 3 ---- - -`App` is a singleton **instance** of [Astal.Application](/astal/reference/class.Application.html). - -```tsx -import { App } from "astal" -``` - -## Entry point - -```tsx -// app.ts -App.start({ - main() { - // setup anything - // instantiate widgets - }, -}) -``` - -:::caution -You can not instantiate widgets outside of the main function. -::: - -## Instance identifier - -You can run multiple instance by defining a unique instance name. - -```tsx -// app.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.ts -App.start({ - main() {}, - requestHandler(request: string, res: (response: any) => void) { - if (request == "say hi") { - res("hi cli") - } - res("unknown command") - }, -}) -``` - -```bash -# ags cli -$ ags -m "say hi" -hi cli - -# astal cli -$ 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.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. - -```bash -$ ags -m "'hello'" -hello -``` - -If the string contains a semicolon, you have to return explicitly - -```bash -$ ags -m "'hello';" -undefined - -$ ags -m "return 'hello';" -hello -``` - -## 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. - -```ts -// main.ts -App.start({ - // main instance - main(...args: Array<string>) { - print(...args) - }, - - // every subsequent calls - client(message: (msg: string) => string, ...args: Array<string>) { - 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/src/content/docs/ags/faq.md b/docs/src/content/docs/ags/faq.md deleted file mode 100644 index 5599fe3..0000000 --- a/docs/src/content/docs/ags/faq.md +++ /dev/null @@ -1,159 +0,0 @@ ---- -title: FAQ -description: Frequently asked question, common issues, tips and tricks ---- - -## Monitor id does not match compositor - -The monitor 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 which you can get from compositor libraries. - -Example with Hyprland - -```js -import Hyprland from "gi://AstalHyprland" - -function Bar(gdkmonitor) { - return <window gdkmonitor={gdkmonitor} /> -} - -function main() { - for (const m of Hyprland.get_default().get_monitors()) { - Bar(m.gdk_monitor) - } -} - -App.start({ main }) -``` - -## Environment variables - -JavaScript is **not** an bash. - -```tsx -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. - -:::caution[Please don't do this] -You could pass it to bash, but that is a horrible approach. - -```tsx -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). - -```tsx -import GLib from "gi://GLib" - -const HOME = GLib.getenv("HOME") -``` - -## Custom svg symbolic icons - -Put the svgs in a directory, named `<icon-name>-symbolic.svg` -and use `App.add_icons` or `icons` parameter in `App.start` - -```js -// 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 - }) - }, -}) -``` - -:::note -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. - -```js -print("print this line to stdout") -printerr("print this line to stderr") -``` - -## Binding custom structures - -The `bind` function can take two types of objects. - -```typescript -interface Subscribable<T = unknown> { - subscribe(callback: (value: T) => void): () => void - get(): T -} - -interface Connectable { - connect(signal: string, callback: (...args: any[]) => unknown): number - disconnect(id: number): void -} -``` - -`Connectable` is for mostly gobjects, while `Subscribable` is for `Variables` -and custom objects. - -For example you can compose `Variables` in using a class. - -```typescript -type MyVariableValue = { - number: number - string: string -} - -class MyVariable { - number = Variable(0) - string = Variable("") - - get(): MyVariableValue { - return { - number: this.number.get(), - string: this.string.get(), - } - } - - subscribe(callback: (v: MyVariableValue) => void) { - const unsub1 = this.number.subscribe((value) => { - callback({ string: value, number: this.number.get() }) - }) - - const unsub2 = this.string.subscribe((value) => { - callback({ number: value, string: this.string.get() }) - }) - - return () => { - unsub1() - unsub2() - } - } -} -``` - -Then it can be used with `bind`. - -```tsx -function MyWidget() { - const myvar = new MyVariableValue() - const label = bind(myvar).as(({ string, number }) => { - return `${string} ${number}` - }) - - return <label label={label} /> -} -``` diff --git a/docs/src/content/docs/ags/first-widgets.mdx b/docs/src/content/docs/ags/first-widgets.mdx deleted file mode 100644 index 3feb498..0000000 --- a/docs/src/content/docs/ags/first-widgets.mdx +++ /dev/null @@ -1,429 +0,0 @@ ---- -title: First Widgets -description: Getting started with creating widgets -sidebar: - order: 0 ---- - -import { FileTree } from "@astrojs/starlight/components" -import { Tabs, TabItem } from "@astrojs/starlight/components" - -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. - -## JavaScript - -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 - -```bash -ags --init -``` - -then run `ags` in the terminal - -```bash -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/). -::: - -The generated project structure is the following: - -<FileTree> - -- @girs/ generated types with [ts-for-gir](https://github.com/gjsify/ts-for-gir) -- widget - - Bar.tsx -- app.ts entry point of our app -- style.css -- env.d.ts informs the LSP about the environment -- tsconfig.json configuration of the LSP - -</FileTree> - -## 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]() which will hold all widgets. - -```tsx -// widget/Bar.tsx -function Bar(monitor = 0) { - return ( - <window className="Bar" monitor={monitor}> - <box>Content of the widget</box> - </window> - ) -} -``` - -```tsx -// 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. - -<Tabs> - <TabItem label="markup"> - -```tsx -function MyButton(): JSX.Element { - return <button onClicked="echo hello">Clicke Me!</button> -} -``` - - </TabItem> - <TabItem label="constructor functions"> - -```tsx -import { Widget } from "astal" - -function MyButton(): Widget.Button { - return Widget.Button({ - onClicked: "echo hello", - label: "Click Me!", - }) -} -``` - - </TabItem> -</Tabs> - -:::note -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 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 ( - <window> - <box> - Click The button - <MyButton /> - </box> - </window> - ) -} -``` - -Notice that widgets you defined start with a capital letter `<MyButton />`. -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 to the user. - -```tsx -function MyWidget() { - const label = "hello" - - return <button>{label}</button> -} -``` - -You can also pass JavaScript to markup attributes - -```tsx -function MyWidget() { - const label = "hello" - - return <button label={label} /> -} -``` - -## Conditional Rendering - -You can use the same techniques as you use when writing regular JavaScript code. -For example, you can use an if statement to conditionally include JSX: - -```tsx -function MyWidget() { - let content - - if (condition) { - content = <True /> - } else { - content = <False /> - } - - return <box>{content}</box> -} -``` - -You can also inline a [conditional `?`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_operator) (ternary) expression. - -```tsx -function MyWidget() { - return <box>{condition ? <True /> : <False />}</box> -} -``` - -When you don’t need the `else` branch, you can also use a shorter [logical && syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND#short-circuit_evaluation): - -```tsx -function MyWidget() { - return <box>{condition && <True />}</box> -} -``` - -:::note -As you can guess from the above snippet, [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) values are not rendered. -::: - -## Rendering lists - -You can use [`for` loops](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) or [array `map()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). - -```tsx -function MyWidget() { - const labels = [ - "label1" - "label2" - "label3" - ] - - return <box> - {labels.map(label => ( - <label label={label} /> - ))} - </box> -} -``` - -## Widget signal handlers - -You can respond to events by declaring event handler functions inside your widget: - -```tsx -function MyButton() { - function onClicked(self: Widget.Button, ...args) { - console.log(self, "was clicked") - } - - return <button onClicked={onClicked} /> -} -``` - -The handler can also be a string, which will get executed in a subprocess asynchronously. - -```tsx -function MyButton() { - return <button onClicked="echo hello" /> -} -``` - -:::note -Attributes prefixed with `on` will connect to a `signal` of the widget. -Their types are not generated, but written by hand, which means not all of them are typed. -Refer to the Gtk and Astal docs to have a full list of them. -::: - -## How properties are passed - -Using JSX, a custom widget will always have a single object as its parameter. - -```ts -type Props = { - myprop: string - child?: JSX.Element // when only one child is passed - children?: Array<JSX.Element> // when multiple children are passed -} - -function MyWidget({ myprop, child, children }: Props) { - // -} -``` - -```tsx -// child prop of MyWidget is the box -return ( - <MyWidget myprop="hello"> - <box /> - </MyWidget> -) -``` - -```tsx -// children prop of MyWidget is [box, box, box] -return ( - <MyWidget myprop="hello"> - <box /> - <box /> - <box /> - </MyWidget> -) -``` - -## State management - -The state of widgets are handled with [Bindings](). A `Binding` lets you -connect the state of one [GObject]() to another, in our case it is used to -rerender part of a widget based on the state of a `GObject`. -A `GObject` can be a [Variable]() or it can be from a [Library](). - -We use the `bind` function to create a `Binding` object from a `Variable` or -a regular GObject and one of its properties. - -Here is an example of a Counter widget that uses a `Variable` as its state: - -```tsx -import { Variable, bind } from "astal" - -function Counter() { - const count = Variable(0) - - function increment() { - count.set(count.get() + 1) - } - - return <box> - <label label={bind(count).as(num => num.toString())} /> - <button onClicked={increment}> - Click to increment - <button> - </box> -} -``` - -:::note -Bindings have an `.as()` method which lets you transform the assigned value. -In the case of a Label, its label property expects a string, so it needs to be -turned to a string first. -::: - -:::tip -`Variables` have a shorthand for `bind(variable).as(transform)` - -```tsx -const v = Variable(0) -const transform = (v) => v.toString() - -// these two are equivalent -return ( - <box> - <label label={bind(v).as(transform)} /> - <label label={v(transform)} /> - </box> -) -``` - -::: - -Here is an example of a battery percent label that binds the `percentage` -property of the Battery object from the [Battery Library](): - -```tsx -import Battery from "gi://AstalBattery" -import { bind } from "astal" - -function BatteryPercentage() { - const bat = Battery.get_default() - - return <label label={bind(bat, "percentage").as((p) => p * 100 + " %")} /> -} -``` - -## Dynamic children - -You can also use a `Binding` for `child` and `children` properties. - -```tsx -const child = Variable(<box />) - -return <box>{child}</box> -``` - -```tsx -const num = Variable(3) -const range = (n) => [...Array(n).keys()] - -return <box> - {num(n => range(n).map(i => ( - <button> - {i.toString()} - <button/> - )))} -<box> -``` - -:::caution -Only bind children of the `box` widget. Gtk does not cleanup widgets by default, -they have to be explicitly destroyed. The box widget is a special container that -will implicitly call `.destroy()` on its removed child widgets. -You can disable this behavior by setting the `noImplicityDestroy` property. -::: - -:::note -The above example destroys and recreates every widget in the list everytime -the value of the `Variable` changes. There might be cases where you would -want to handle child creation yourself, because you don't want to lose the -inner state of widgets that does not need to be recreated. -::: - -When there is at least one `Binding` passed as a child, the `children` -parameter will always be a flattened `Binding<Array<JSX.Element>>` - -```tsx -function MyContainer({ children }) { - // children is a Binding over an Array of widgets -} - -return <MyContainer> - <box /> - {num(n => range(n).map(i => ( - <button> - {i.toString()} - <button/> - )))} - [ - [ - <button /> - ] - <button /> - ] -</MyContainer> -``` - -:::note -You can pass the followings as children: - -- widgets -- deeply nested arrays of widgets -- bindings of widgets, -- bindings of deeply nested arrays of widgets - -falsy values are not rendered and anything not from this list -will be coerced into a string and rendered as a label -::: diff --git a/docs/src/content/docs/ags/theming.md b/docs/src/content/docs/ags/theming.md deleted file mode 100644 index ef2fe92..0000000 --- a/docs/src/content/docs/ags/theming.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: Theming -description: GTK3 CSS theming -sidebar: - order: 1 ---- - -Since the widget toolkit is **GTK3** theming is done with **CSS**. - -- [CSS tutorial](https://www.w3schools.com/css/) -- [GTK CSS Overview wiki](https://docs.gtk.org/gtk3/css-overview.html) -- [GTK CSS Properties Overview wiki](https://docs.gtk.org/gtk3/css-properties.html) - -:::caution[GTK is not the web] -While most features are implemented in GTK, -you can't assume anything that works on the web will work with GTK. -Refer to the [GTK docs](https://docs.gtk.org/gtk3/css-overview.html) -to see what is available. -::: - -So far every widget you made used your default GTK3 theme. -To make them more custom, you can apply stylesheets to them. - -## From file at startup - -You can pass a path to a file or css as a string in `App.start` - -```tsx -const inlineCss = ` -window { - background-color: transparent; -} -` - -// app.ts -App.start({ - css: "/home/username/.config/ags/style.css", - css: `${SRC}/style.css'`, - css: inlineCss, -}) -``` - -:::note -The global `SRC` will point to the directory `app.ts` is in. -You can pass a relative path, but its resolution will be relative to the current working directory. -::: - -## Css Property on Widgets - -```tsx -Widget.Label({ - css: "color: blue; padding: 1em;", - label: "hello", -}) -``` - -:::note -The `css` property of a widget will not cascade to its children. -::: - -## Apply Stylesheets at Runtime - -You can apply additional styles at runtime. - -```tsx -App.apply_css("/path/to/file.css") -``` - -```tsx -App.apply_css(` -window { - background-color: transparent; -} -`) -``` - -```tsx -App.reset_css() // reset if need -``` - -:::caution -`App.apply_css` will apply on top of other stylesheets applied before. -You can reset stylesheets with `App.resetCss` -::: - -## Inspector - -If you are not sure about the widget hierarchy or any CSS selector, -you can use the [GTK inspector](https://wiki.gnome.org/Projects/GTK/Inspector) - -```bash -# to bring up the inspector run -ags --inspector -``` - -## Using pre-processors like SCSS - -```tsx -// app.ts -// main scss file -const scss = `${SRC}/style.scss` - -// target css file -const css = `/tmp/my-style.css` - -// make sure sassc is installed on your system -exec(`sassc ${scss} ${css}`) - -App.config({ - css, - main() {}, -}) -``` diff --git a/docs/src/content/docs/ags/utilities.md b/docs/src/content/docs/ags/utilities.md deleted file mode 100644 index a26bb52..0000000 --- a/docs/src/content/docs/ags/utilities.md +++ /dev/null @@ -1,179 +0,0 @@ ---- -title: Utilities -description: Reference of bultin utility functions -sidebar: - order: 5 ---- - -## File functions - -Import them from `astal` or `astal/file` - -```js -import { - readFile, - readFileAsync, - writeFile, - writeFileAsync, - monitorFile, -} from "astal" -``` - -### Reading files - -```typescript -function readFile(path: string): string -function readFileAsync(path: string): Promise<string> -``` - -### Writing files - -```typescript -function writeFile(path: string, content: string): void -function writeFileAsync(path: string, content: string): Promise<void> -``` - -### Monitoring files - -```typescript -function monitorFile( - path: string, - callback: (file: string, event: Gio.FileMonitorEvent) => void, -): Gio.FileMonitor -``` - -## Timeouts and Intervals - -Import them from `astal` or `astal/time` - -```js -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]() instance. - -`Astal.Time` has a `now` signal and a `cancelled` signal. - -### Interval - -Will immediately execute the function and every `interval` millisecond. - -```typescript -function interval(interval: number, callback?: () => void): Astal.Time -``` - -### Timeout - -Will execute the `callback` after `timeout` millisecond. - -```typescript -function timeout(timeout: number, callback?: () => void): Astal.Time -``` - -### Idle - -Executes `callback` whenever there are no higher priority events pending. - -```typescript -function idle(callback?: () => void): Astal.Time -``` - -Example: - -```typescript -const timer = interval(1000, () => { - console.log("optional callback") -}) - -timer.connect("now", () => { - console.log("tick") -}) - -timer.connect("cancelled", () => { - console.log("cancelled") -}) - -timer.cancel() -``` - -## Process functions - -Import them from `astal` or `astal/proc` - -```js -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]() has a `stdout` and `stderr` signal. - -```typescript -function subprocess(args: { - cmd: string | string[] - out?: (stdout: string) => void - err?: (stderr: string) => void -}): Astal.Process - -function subprocess( - cmd: string | string[], - onOut?: (stdout: string) => void, - onErr?: (stderr: string) => void, -): Astal.Process -``` - -Example: - -```typescript -const proc = subprocess( - "some-command", - (out) => console.log(out), // optional - (err) => console.error(out), // optional -) - -// or with signals -const proc = subprocess("some-command") -proc.connect("stdout", (out) => console.log(out)) -proc.connect("stderr", (err) => console.error(err)) -``` - -### Executing external commands and scripts - -```typescript -function exec(cmd: string | string[]): string -function execAsync(cmd: string | string[]): Promise<string> -``` - -Example: - -```typescript -try { - const out = exec("/path/to/script") - console.log(out) -} catch (err) { - console.error(err) -} - -execAsync(["bash", "-c", "/path/to/script.sh"]) - .then((out) => console.log(out)) - .catch((err) => console.error(err)) -``` - -:::caution -`subprocess`, `exec`, and `execAsync` executes the passed executable as is. -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 `||`. - -If you want bash, run them with bash. - -```js -exec(["bash", "-c", "command $VAR && command"]) -exec("bash -c 'command $VAR' && command") -``` - -::: diff --git a/docs/src/content/docs/ags/variable.md b/docs/src/content/docs/ags/variable.md deleted file mode 100644 index d6023fe..0000000 --- a/docs/src/content/docs/ags/variable.md +++ /dev/null @@ -1,142 +0,0 @@ ---- -title: Variable -description: Reference of the builtin Variable type -sidebar: - order: 6 ---- - -```js -import { Variable } from "astal" -``` - -Variable is just a simple `GObject` that holds a value. -And has shortcuts for hooking up subprocesses. - -## Variable as state - -```typescript -const myvar = Variable<string>("initial-value") - -// whenever its value changes, callback will be executed -myvar.subscribe((value: string) => { - console.log(value) -}) - -// settings its value -myvar.set("new value") - -// getting its value -const value = myvar.get() - -// binding them to widgets -Widget.Label({ - label: bind(myvar).as((value) => `transformed ${value}`), - label: myvar((value) => `transformed ${value}`), // shorthand for the above -}) -``` - -:::caution -Make sure to make the transform functions pure. The `.get()` function can be called -anytime by `astal` especially when `deriving`, so make sure there are no sideeffects. -::: - -## Composing variables - -Using `Variable.derive` we can compose both Variables and Bindings. - -```typescript -const v1: Variable<number> = Variable(2) -const v2: Variable<number> = Variable(3) - -// first argument is a list of dependencies -// second argument is a transform function, -// where the parameters are the values of the dependencies in the order they were passed -const v3: Variable<number> = Variable.derive([v1, v2], (v1, v2) => { - return v1 * v2 -}) - -const b1: Binding<string> = bind(obj, "prop") -const b2: Binding<string> = bind(obj, "prop") - -const b3: Variable<string> = Variable.derive([b1, b2], (b1, b2) => { - return `${b1}-${b2}` -}) -``` - -## Subprocess shorthands - -Using `.poll` and `.watch` we can start subprocess and capture their -output in `Variables`. They can poll and watch at the same time, but they -can only poll/watch one subprocess. - -:::caution -The command parameter is passed to [execAsync](/astal/ags/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 `||`. - -If you want bash, run them with bash. - -```js -Variable("").poll(1000, ["bash", "-c", "command $VAR && command"]) -``` - -::: - -```typescript -const myVar = Variable<number>(0) - .poll(1000, "command", (out: string, prev: number) => parseInt(out)) - .poll(1000, ["bash", "-c", "command"], (out, prev) => parseInt(out)) - .poll(1000, (prev) => prev + 1) -``` - -```typescript -const myVar = Variable<number>(0) - .watch("command", (out: string, prev: number) => parseInt(out)) - .watch(["bash", "-c", "command"], (out, prev) => parseInt(out)) -``` - -You can temporarily stop them and restart them whenever. - -```js -myvar.stopWatch() // this kills the subprocess -myvar.stopPoll() - -myvar.startListen() // launches the subprocess again -myvar.startPoll() - -console.log(myvar.isListening()) -console.log(myvar.isPolling()) -``` - -## Gobject connection shorthands - -Using `.observe` you can connect gobject signals and capture their value. - -```typescript -const myvar = Variable("") - .observe(obj1, "signal", () => "") - .observe(obj2, "signal", () => "") -``` - -## Dispose if no longer needed - -This will stop the interval and force exit the subprocess and disconnect gobjects. - -```js -myVar.drop() -``` - -:::caution -Don't forget to drop them when they are defined inside widgets -with either `.poll`, `.watch` or `.observe` - -```tsx -function MyWidget() { - const myvar = Variable().poll() - - return <box onDestroy={() => myvar.drop()} /> -} -``` - -::: diff --git a/docs/src/content/docs/ags/widget.md b/docs/src/content/docs/ags/widget.md deleted file mode 100644 index 8e47490..0000000 --- a/docs/src/content/docs/ags/widget.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -title: Widget -description: Reference of the builtin and gtk widgets -sidebar: - order: 4 ---- - -## AGS widget properties - -These are properties that Astal.js additionally adds to Gtk.Widgets - -- className: `string` - List of class CSS selectors separated by white space. -- css: `string` - Inline CSS. e.g `label { color: white; }`. If no selector is specified `*` will be assumed. e.g `color: white;` will be inferred as `* { color: white; }`. -- cursor: `string` - Cursor style when hovering over widgets that have hover states, e.g it won't work on labels. [list of valid values](https://docs.gtk.org/gdk3/ctor.Cursor.new_from_name.html). -- clickThrough: `boolean` - Lets click events through. - -To have a full list of available properties, reference the documentation of the widget. - -- [Astal widgets](/astal/reference#classes) -- [Gtk widgets](https://docs.gtk.org/gtk3/#classes) - -You can check the [source code](https://github.com/aylur/astal/blob/main/gjs/src/widgets.ts) to have a full list of builtin widgets. - -## AGS widget methods - -Additional methods that Astal.js add to Gtk.Widget instances - -### setup - -`setup` is a convenience prop to not have predefine widgets before returning them - -without `setup` - -```tsx -function MyWidget() { - const button = Widget.Button() - // setup button - return button -} -``` - -using `setup` - -```tsx -function MyWidget() { - function setup(button: Widget.Button) { - // setup button - } - - return <buttons setup={setup} /> -} -``` - -### hook - -Shorthand for connection and disconnecting to gobjects. - -without `hook` - -```tsx -function MyWidget() { - const id = gobject.connect("signal", callback) - - return <box - onDestroy={() => { - gobject.disconnect(id) - }} - /> -} -``` - -with `hook` - -```tsx -function MyWidget() { - return <box - setup={(self) => { - self.hook(gobject, "signal", callback) - }} - /> -} -``` - -### toggleClassName - -Toggle classNames based on a condition - -```tsx -function MyWidget() { - return <box - setup={(self) => { - self.toggleClassName("classname", someCondition) - }} - /> -} -``` - -## How to use non builtin Gtk widgets - -Using `Widget.astalify` you can setup widget constructors to behave like builtin widgets. -The `astalify` function will apply the following: - -- set `visible` to true by default (Gtk3 widgets are invisible by default) -- make gobject properties accept and consume `Binding` objects -- add properties and methods listed above -- proxify the constructor so the `new` keyword is not needed -- sets up signal handlers that are passed as props prefixed with `on` - -```tsx -import { Widget, Gtk } from "astal" - -// define its props, constructor and type -export type ColorButtonProps = Widget.ConstructProps< - Gtk.ColorButton, - Gtk.ColorButton.ConstructorProps, - { onColorSet: [] } -> -export const ColorButton = Widget.astalify< - typeof Gtk.ColorButton, - ColorButtonProps, - "ColorButton" ->(Gtk.ColorButton) -export type ColorButton = ReturnType<typeof ColorButton> - -function MyWidget() { - function setup(button: ColorButton) {} - - return <ColorButton - setup={setup} - useAlpha - rgba={ - new Gdk.RGBA({ - red: 1, - green: 0, - blue: 0, - alpha: 0.5, - }) - } - onColorSet={(self) => { - console.log(self.rgba) - }} - /> -} -``` - -:::note -Signal properties have to be annotated manually for TypeScript. -You can reference [Gtk3](https://gjs-docs.gnome.org/gtk30~3.0/) -and [Astal](/astal/reference#classes) for available signals. -::: diff --git a/docs/src/content/docs/getting-started/installation.mdx b/docs/src/content/docs/getting-started/installation.mdx deleted file mode 100644 index 086ff5b..0000000 --- a/docs/src/content/docs/getting-started/installation.mdx +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: Installation -description: How to install Astal -sidebar: - order: 1 ---- - -import { Tabs, TabItem } from "@astrojs/starlight/components" - -## Nix - -maintainer: [@Aylur](https://github.com/Aylur) - -Read more about it on the [nix page](../nix) - -## Arch - -maintainer: [@kotontrion](https://github.com/kotontrion) - -<Tabs> - <TabItem label="Core Library"> - -```bash -yay -S libastal-git -``` - - </TabItem> - <TabItem label="Every Library"> - -```bash -yay -S libastal-meta -``` - - </TabItem> -</Tabs> - -## Bulding core from source - -1. Clone the repo - -```bash -git clone https://github.com/aylur/astal.git -cd astal/core -``` - -2. Install the following dependencies - -<Tabs> - <TabItem label="Fedora"> - -```bash -sudo dnf install meson gcc valac gtk3-devel gtk-layer-shell-devel -``` - - </TabItem> - <TabItem label="Arch"> - -```bash -sudo pacman -Syu meson vala gtk3 gtk-layer-shell gobject-introspection -``` - - </TabItem> - <TabItem label="Alpine"> - -```bash -sudo apk add meson g++ vala gtk+3.0-dev gtk-layer-shell-dev gobject-introspection-dev -``` - - </TabItem> - <TabItem label="Ubuntu"> - -```bash -sudo apt install meson valac libgtk3-dev libgtk-layer-shell-dev gobject-introspection -``` - - </TabItem> - <TabItem label="openSUSE"> - -```bash -sudo zypper install gcc meson vala gtk3-devel gtk-layer-shell-devel gobject-introspection-devel -``` - - </TabItem> -</Tabs> - -3. Build and install with `meson` - -```bash -meson setup build -meson install -C build -``` - -:::note -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, you set the `prefix` option: - -```bash -meson setup --prefix /usr build -meson install -C build -``` - -::: diff --git a/docs/src/content/docs/getting-started/introduction.md b/docs/src/content/docs/getting-started/introduction.md deleted file mode 100644 index f215707..0000000 --- a/docs/src/content/docs/getting-started/introduction.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: Introduction -description: What is Astal? -sidebar: - order: 0 ---- - -## 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](/astal/reference) has some Gtk widgets that come packaged, -the most important one is the [Window](/astal/reference/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. - -## Why Astal? - -What makes Astal convenient to use is not the core library, as it could 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_) - -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](/astal/libraries/overview), 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/src/content/docs/getting-started/languages.md b/docs/src/content/docs/getting-started/languages.md deleted file mode 100644 index 08dda01..0000000 --- a/docs/src/content/docs/getting-started/languages.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: Supported Languages -description: Choosing a language to get started -banner: - content: 🚧 Examples are in the works. 🚧 ---- - -## JavaScript - -The main intended usage of Astal is in TypeScript with [AGS](/astal/ags/first-widgets). -It supports JSX and has a state management solution similar to web frameworks. -Only a minimal knowledge of JavaScript's syntax is needed to get started. - -:::tip -The runtime is [GJS](https://gitlab.gnome.org/GNOME/gjs) and **not** nodejs -::: - -Examples: - -- TODO - -## Lua - -Similar to how there is a [TypeScript]() lib for GJS, there is also an accompanying library for [Lua](). -Unfortunately, I have encountered very heavy [performance issues]() 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. - -Examples: - -- TODO - -## Python - -There is a WIP [library for 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]() intended it. - -Examples: - -- TODO - -## Vala - -Vala is a language that simply put uses C# syntax and compiles to C. -It is the language most of Astal is written in. - -Examples: - -- TODO - -## C - -I don't recommend using C as it requires quite a lot of boilerplate. - -Examples: - -- TODO - -## Other languages - -There a few more that supports gobject-introspection, most notably Haskell, Rust and C++. -If you are interested and feel like contributing, PRs are welcome for bindings, and examples. diff --git a/docs/src/content/docs/getting-started/nix.md b/docs/src/content/docs/getting-started/nix.md deleted file mode 100644 index 8a1df7a..0000000 --- a/docs/src/content/docs/getting-started/nix.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Nix -description: Usage with the Nix package manager -sidebar: - hidden: true ---- - -## Nix diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx deleted file mode 100644 index 5c292de..0000000 --- a/docs/src/content/docs/index.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Build Your Own Desktop Shell -description: The best way to make beautiful and functional widgets on wayland -template: splash -banner: - content: 🚧 The library and this documentation is still under development. 🚧 -hero: - tagline: The best way to make <i>beautiful</i> <b>and</b> <i>functional</i> wayland widgets! - image: - file: ../../assets/front-image.png - actions: - - text: Get Started - link: /astal/getting-started/introduction/ - icon: right-arrow - variant: primary - - text: Reference - link: /astal/libraries/references - icon: open-book - variant: secondary - - text: View on GitHub - link: https://github.com/Aylur/Astal - icon: github - variant: minimal ---- - -import { Card, CardGrid } from "@astrojs/starlight/components" -import { showcases } from "../showcases.ts" -import Showcase from "../../components/Showcase.astro" - -<CardGrid> - <Card title="Use your preferred language" icon="seti:json"> - The main focus of Astal is TypeScript using JSX. But you can use the - libraries in any language that supports [Gobject - Introspection](https://en.wikipedia.org/wiki/List_of_language_bindings_for_GTK). - </Card> - <Card title="No bash scripts needed" icon="pencil"> - Includes modules to work with Network, Bluetooth, Battery, Audio and - more. See the list of included [Libraries](/astal/libraries/overview). - </Card> - <Card title="Use any Gtk widget" icon="puzzle"> - With Astal you work with Gtk directly. You are not limited to only a set - of them. See the list of [Widgets](/astal/libraries/widgets) that come - bundled. - </Card> - <Card title="Examples" icon="open-book"> - Have a look at some simple and not simple [examples](./config/examples). - In [TypeScript](https://github.com/Aylur/Astal/tree/main/examples/ts), - [Lua](https://github.com/Aylur/Astal/tree/main/examples/lua), - [Python](https://github.com/Aylur/Astal/tree/main/examples/python). - </Card> -</CardGrid> - -## Showcases - -<div class="showcases"> - {showcases.map((showcase) => - Array.isArray(showcase) ? ( - <CardGrid> - {showcase.map((elem) => ( - <Showcase {...elem} /> - ))} - </CardGrid> - ) : ( - <Showcase {...showcase} /> - ), - )} -</div> diff --git a/docs/src/content/docs/libraries/references.md b/docs/src/content/docs/libraries/references.md deleted file mode 100644 index f7b597d..0000000 --- a/docs/src/content/docs/libraries/references.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: References -description: References of libraries -sidebar: - order: 0 ---- - -The references of the libraries are annotated for the C language. -Reading their documentation will vary depending on the language they are used in. - -TODO: list some examples on how to read docs, -for example the difference between C enums and gjs enums - -## Additional references - -### GJS - -- [gjs-docs.gnome.org](https://gjs-docs.gnome.org/): Library references annotated for GJS -- [gjs.guide](https://gjs.guide/): GJS and GObject guide - -### Python - -- [pgi-docs](https://lazka.github.io/pgi-docs/): Library references annotated for Python -- [pygobject.gnome.org](https://pygobject.gnome.org/): PyGObject reference and guide - -### Lua - -- [lua-lgi docs](https://github.com/lgi-devs/lgi/tree/master/docs): GObject bindings guide for Lua - -### Vala - -- [vala.dev](https://vala.dev/): Guide for the Vala language -- [valadoc.org](https://valadoc.org/): Library references annotated for Vala - -## Astal Libraries - -- [Astal](/reference): libastal the core library, which has the widgets and utilites -- [Apps](/reference/apps): Library and cli tool for querying applications -- [Auth](/reference/auth): Authentication library using PAM -- [Battery](/reference/battery): DBus proxy library for upower daemon -- [Bluetooth](/reference/bluetooth): Library to control bluez over dbus -- [Hyprland](/reference/hyprland): Library and cli tool for Hyprland IPC socket -- [Mpris](/reference/mpris): Library and cli tool for controlling media players -- [Network](/reference/network): NetworkManager wrapper library -- [Notifd](/reference/notifd): A notification daemon library and cli tool -- [PowerProfiles](/reference/powerprofiles): Library and cli to control upowerd powerprofiles -- [River](/reference/river): Library and cli tool for getting status information of the river wayland compositor -- [Tray](/reference/tray): A systemtray library and cli tool -- [WirePlumber](/reference/wireplumber): A library for audio control using wireplumber diff --git a/docs/src/content/showcases.ts b/docs/src/content/showcases.ts deleted file mode 100644 index 0082c93..0000000 --- a/docs/src/content/showcases.ts +++ /dev/null @@ -1,13 +0,0 @@ -type Showcase = { - author: string - src: string - url: string -} - -type Grid<T> = - | [T, T] - | [T, T, T, T] - -export const showcases: Array<Showcase | Grid<Showcase>> = [ - { author: "Aylur", src: "/astal/showcase/aylur1.png", url: "https://github.com/Aylur/dotfiles" }, -] |