From 6c4753b5e14a50c617e326d97d270ff51156a183 Mon Sep 17 00:00:00 2001 From: Aylur Date: Sun, 1 Sep 2024 15:23:08 +0200 Subject: initial docs --- docs/src/content/config.ts | 6 + docs/src/content/docs/ags/cli-app.md | 129 +++++++ docs/src/content/docs/ags/faq.md | 80 ++++ docs/src/content/docs/ags/first-widgets.mdx | 429 +++++++++++++++++++++ docs/src/content/docs/ags/libraries.md | 8 + docs/src/content/docs/ags/theming.md | 113 ++++++ docs/src/content/docs/ags/utilities.md | 8 + docs/src/content/docs/ags/variable.md | 8 + docs/src/content/docs/ags/widget.md | 124 ++++++ .../content/docs/getting-started/installation.mdx | 92 +++++ .../content/docs/getting-started/introduction.md | 28 ++ docs/src/content/docs/getting-started/languages.md | 64 +++ docs/src/content/docs/getting-started/nix.md | 8 + docs/src/content/docs/index.mdx | 67 ++++ docs/src/content/docs/libraries/overview.md | 8 + docs/src/content/showcases.ts | 13 + 16 files changed, 1185 insertions(+) create mode 100644 docs/src/content/config.ts create mode 100644 docs/src/content/docs/ags/cli-app.md create mode 100644 docs/src/content/docs/ags/faq.md create mode 100644 docs/src/content/docs/ags/first-widgets.mdx create mode 100644 docs/src/content/docs/ags/libraries.md create mode 100644 docs/src/content/docs/ags/theming.md create mode 100644 docs/src/content/docs/ags/utilities.md create mode 100644 docs/src/content/docs/ags/variable.md create mode 100644 docs/src/content/docs/ags/widget.md create mode 100644 docs/src/content/docs/getting-started/installation.mdx create mode 100644 docs/src/content/docs/getting-started/introduction.md create mode 100644 docs/src/content/docs/getting-started/languages.md create mode 100644 docs/src/content/docs/getting-started/nix.md create mode 100644 docs/src/content/docs/index.mdx create mode 100644 docs/src/content/docs/libraries/overview.md create mode 100644 docs/src/content/showcases.ts (limited to 'docs/src/content') diff --git a/docs/src/content/config.ts b/docs/src/content/config.ts new file mode 100644 index 0000000..45f60b0 --- /dev/null +++ b/docs/src/content/config.ts @@ -0,0 +1,6 @@ +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 new file mode 100644 index 0000000..6b9d4c3 --- /dev/null +++ b/docs/src/content/docs/ags/cli-app.md @@ -0,0 +1,129 @@ +--- +title: CLI and App +description: Reference of the singleton App instance +sidebar: + order: 3 +--- + +`App` is a singleton **instance** of [Astal.Application](/libastal/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) { + 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/src/content/docs/ags/faq.md b/docs/src/content/docs/ags/faq.md new file mode 100644 index 0000000..eca31c7 --- /dev/null +++ b/docs/src/content/docs/ags/faq.md @@ -0,0 +1,80 @@ +--- +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 +} + +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 `-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 +::: diff --git a/docs/src/content/docs/ags/first-widgets.mdx b/docs/src/content/docs/ags/first-widgets.mdx new file mode 100644 index 0000000..3feb498 --- /dev/null +++ b/docs/src/content/docs/ags/first-widgets.mdx @@ -0,0 +1,429 @@ +--- +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: + + + +- @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 + + + +## 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 ( + + Content of the widget + + ) +} +``` + +```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. + + + + +```tsx +function MyButton(): JSX.Element { + return +} +``` + + + + +```tsx +import { Widget } from "astal" + +function MyButton(): Widget.Button { + return Widget.Button({ + onClicked: "echo hello", + label: "Click Me!", + }) +} +``` + + + + +:::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 ( + + + 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 to the user. + +```tsx +function MyWidget() { + const label = "hello" + + return +} +``` + +You can also pass JavaScript to markup attributes + +```tsx +function MyWidget() { + const label = "hello" + + return