diff options
author | Aylur <[email protected]> | 2024-09-01 15:23:08 +0200 |
---|---|---|
committer | Aylur <[email protected]> | 2024-09-01 15:23:08 +0200 |
commit | 6c4753b5e14a50c617e326d97d270ff51156a183 (patch) | |
tree | 560ffd167d6b4f1da04e545990666c447c15e35b /docs/src | |
parent | 27c25b0e6070f291b33107a0bbfe5086b6d3f119 (diff) |
initial docs
Diffstat (limited to 'docs/src')
-rw-r--r-- | docs/src/assets/front-image.png | bin | 0 -> 138489 bytes | |||
-rw-r--r-- | docs/src/components/Showcase.astro | 37 | ||||
-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 | 80 | ||||
-rw-r--r-- | docs/src/content/docs/ags/first-widgets.mdx | 429 | ||||
-rw-r--r-- | docs/src/content/docs/ags/libraries.md | 8 | ||||
-rw-r--r-- | docs/src/content/docs/ags/theming.md | 113 | ||||
-rw-r--r-- | docs/src/content/docs/ags/utilities.md | 8 | ||||
-rw-r--r-- | docs/src/content/docs/ags/variable.md | 8 | ||||
-rw-r--r-- | docs/src/content/docs/ags/widget.md | 124 | ||||
-rw-r--r-- | docs/src/content/docs/getting-started/installation.mdx | 92 | ||||
-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/overview.md | 8 | ||||
-rw-r--r-- | docs/src/content/showcases.ts | 13 | ||||
-rw-r--r-- | docs/src/env.d.ts | 2 | ||||
-rw-r--r-- | docs/src/style.css | 72 |
20 files changed, 1296 insertions, 0 deletions
diff --git a/docs/src/assets/front-image.png b/docs/src/assets/front-image.png Binary files differnew file mode 100644 index 0000000..0fbfcca --- /dev/null +++ b/docs/src/assets/front-image.png diff --git a/docs/src/components/Showcase.astro b/docs/src/components/Showcase.astro new file mode 100644 index 0000000..7eea178 --- /dev/null +++ b/docs/src/components/Showcase.astro @@ -0,0 +1,37 @@ +--- +interface Props { + src: string + author: string + url: string +} + +const { src, author, url } = Astro.props +--- + +<figure> + <a href={url}> + <img src={src} alt={author}> + </a> + <figcaption> + <span>Author: {author}</span> + </figcaption> +</figure> + +<style> +img { + border-radius: calc(var(--card-radius) - 8px); +} + +figure { + padding: .8rem; + padding-bottom: 0; + border-radius: var(--card-radius); + background-color: color-mix(in srgb, var(--sl-color-black), var(--sl-color-white) 2%); + border: 1px solid var(--sl-color-gray-6); +} + +figcaption { + text-align: center; + margin: 0; +} +</style> 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<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 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 <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 +::: 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: + +<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/libraries.md b/docs/src/content/docs/ags/libraries.md new file mode 100644 index 0000000..e594de8 --- /dev/null +++ b/docs/src/content/docs/ags/libraries.md @@ -0,0 +1,8 @@ +--- +title: Libraries +description: How to use Astal libraries +sidebar: + order: 7 +--- + +## TODO: diff --git a/docs/src/content/docs/ags/theming.md b/docs/src/content/docs/ags/theming.md new file mode 100644 index 0000000..5c930ea --- /dev/null +++ b/docs/src/content/docs/ags/theming.md @@ -0,0 +1,113 @@ +--- +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 over 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 new file mode 100644 index 0000000..7c03f50 --- /dev/null +++ b/docs/src/content/docs/ags/utilities.md @@ -0,0 +1,8 @@ +--- +title: Utilities +description: Reference of bultin utility functions +sidebar: + order: 5 +--- + +## TODO: diff --git a/docs/src/content/docs/ags/variable.md b/docs/src/content/docs/ags/variable.md new file mode 100644 index 0000000..e172b7d --- /dev/null +++ b/docs/src/content/docs/ags/variable.md @@ -0,0 +1,8 @@ +--- +title: Variable +description: Reference of the builtin Variable type +sidebar: + order: 6 +--- + +## TODO: diff --git a/docs/src/content/docs/ags/widget.md b/docs/src/content/docs/ags/widget.md new file mode 100644 index 0000000..905c2a0 --- /dev/null +++ b/docs/src/content/docs/ags/widget.md @@ -0,0 +1,124 @@ +--- +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](/libastal/#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 + +```tsx +import { astalify, Gtk } from "astal" + +// define its props, constructor and type +export type ColorButtonProps = Widget.ConstructProps<Gtk.ColorButton, Gtk.ColorButton.ConstructorProps> +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, + })} + /> +} +``` diff --git a/docs/src/content/docs/getting-started/installation.mdx b/docs/src/content/docs/getting-started/installation.mdx new file mode 100644 index 0000000..c1f4060 --- /dev/null +++ b/docs/src/content/docs/getting-started/installation.mdx @@ -0,0 +1,92 @@ +--- +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> + <TabItem label="AGS"> + +```bash +yay -S aylurs-gtk-shell-git +``` + + </TabItem> +</Tabs> + +## From Source + +```bash +git clone https://github.com/Aylur/Astal.git +cd Astal +``` + +<Tabs> + <TabItem label="Fedora"> + +```bash +sudo dnf install meson + +meson setup --prefix /usr build +meson install -C build +``` + + </TabItem> + <TabItem label="Arch"> + +```bash +sudo pacman -Syu meson + +arch-meson build +meson install -C build +``` + + </TabItem> + <TabItem label="Alpine"> + +```bash +sudo apk add meson + +meson setup --prefix /usr build +meson install -C build +``` + + </TabItem> + <TabItem label="Ubuntu"> + +```bash +sudo apt install meson + +meson setup --prefix /usr build +meson install -C build +``` + + </TabItem> +</Tabs> diff --git a/docs/src/content/docs/getting-started/introduction.md b/docs/src/content/docs/getting-started/introduction.md new file mode 100644 index 0000000..cb46b29 --- /dev/null +++ b/docs/src/content/docs/getting-started/introduction.md @@ -0,0 +1,28 @@ +--- +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](/libastal) has some Gtk widgets that come packaged, +the most important one is the [Window](/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. + +## 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 new file mode 100644 index 0000000..08dda01 --- /dev/null +++ b/docs/src/content/docs/getting-started/languages.md @@ -0,0 +1,64 @@ +--- +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 new file mode 100644 index 0000000..8a1df7a --- /dev/null +++ b/docs/src/content/docs/getting-started/nix.md @@ -0,0 +1,8 @@ +--- +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 new file mode 100644 index 0000000..17cb867 --- /dev/null +++ b/docs/src/content/docs/index.mdx @@ -0,0 +1,67 @@ +--- +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/reference/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](./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](./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/overview.md b/docs/src/content/docs/libraries/overview.md new file mode 100644 index 0000000..e39d746 --- /dev/null +++ b/docs/src/content/docs/libraries/overview.md @@ -0,0 +1,8 @@ +--- +title: Libraries +description: Overview of incuded Astal Libraries +sidebar: + order: 0 +--- + +## Libs diff --git a/docs/src/content/showcases.ts b/docs/src/content/showcases.ts new file mode 100644 index 0000000..0082c93 --- /dev/null +++ b/docs/src/content/showcases.ts @@ -0,0 +1,13 @@ +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" }, +] diff --git a/docs/src/env.d.ts b/docs/src/env.d.ts new file mode 100644 index 0000000..acef35f --- /dev/null +++ b/docs/src/env.d.ts @@ -0,0 +1,2 @@ +/// <reference path="../.astro/types.d.ts" /> +/// <reference types="astro/client" /> diff --git a/docs/src/style.css b/docs/src/style.css new file mode 100644 index 0000000..b6a0047 --- /dev/null +++ b/docs/src/style.css @@ -0,0 +1,72 @@ +/* Dark mode colors. */ +:root { + --sl-color-accent-low: #10243e; + --sl-color-accent: #3584e4; + --sl-color-accent-high: #99c1f1; + --sl-color-white: #ffffff; + --sl-color-gray-1: #eeeeee; + --sl-color-gray-2: #c2c2c2; + --sl-color-gray-3: #8b8b8b; + --sl-color-gray-4: #585858; + --sl-color-gray-5: #383838; + --sl-color-gray-6: #272727; + --sl-color-black: #171718; +} + +/* Light mode colors. */ +:root[data-theme='light'] { + --sl-color-accent-low: #c5d9f2; + --sl-color-accent: #156ac7; + --sl-color-accent-high: #11325b; + --sl-color-white: #181818; + --sl-color-gray-1: #272727; + --sl-color-gray-2: #383838; + --sl-color-gray-3: #585858; + --sl-color-gray-4: #8b8b8b; + --sl-color-gray-5: #c2c2c2; + --sl-color-gray-6: #eeeeee; + --sl-color-gray-7: #f6f6f6; + --sl-color-black: #ffffff; +} + +:root { + --card-radius: 7px; +} + +article.card { + border-radius: var(--card-radius); + background-color: color-mix(in srgb, var(--sl-color-black), var(--sl-color-white) 2%); + border-color: var(--sl-color-gray-6); +} + +/* landing page gradient */ +:root { + --overlay-gradient: color-mix(in srgb, var(--sl-color-accent), transparent 85%); +} + +:root[data-theme='light'] { + --overlay-gradient: color-mix(in srgb, var(--sl-color-accent), transparent 55%); +} + +[data-has-hero] .page { + background: + linear-gradient(215deg, var(--overlay-gradient), transparent 40%), + radial-gradient(var(--overlay-gradient), transparent 40%) no-repeat -60vw -40vh / 105vw 200vh, + radial-gradient(var(--overlay-gradient), transparent 65%) no-repeat 50% calc(100% + 20rem) / 60rem 30rem; +} + +[data-has-hero] header { + border-bottom: 1px solid transparent; + background-color: transparent; + -webkit-backdrop-filter: blur(16px); + backdrop-filter: blur(16px); +} + +[data-has-hero] .hero>img { + filter: drop-shadow(0 0 3rem var(--overlay-gradient)); +} + +div.showcases { + display: flex; + flex-direction: column; +} |