summaryrefslogtreecommitdiff
path: root/docs/src
diff options
context:
space:
mode:
Diffstat (limited to 'docs/src')
-rw-r--r--docs/src/assets/front-image.pngbin138489 -> 0 bytes
-rw-r--r--docs/src/components/Showcase.astro37
-rw-r--r--docs/src/content/config.ts6
-rw-r--r--docs/src/content/docs/ags/cli-app.md129
-rw-r--r--docs/src/content/docs/ags/faq.md159
-rw-r--r--docs/src/content/docs/ags/first-widgets.mdx429
-rw-r--r--docs/src/content/docs/ags/theming.md113
-rw-r--r--docs/src/content/docs/ags/utilities.md179
-rw-r--r--docs/src/content/docs/ags/variable.md142
-rw-r--r--docs/src/content/docs/ags/widget.md150
-rw-r--r--docs/src/content/docs/getting-started/installation.mdx103
-rw-r--r--docs/src/content/docs/getting-started/introduction.md28
-rw-r--r--docs/src/content/docs/getting-started/languages.md64
-rw-r--r--docs/src/content/docs/getting-started/nix.md8
-rw-r--r--docs/src/content/docs/index.mdx67
-rw-r--r--docs/src/content/docs/libraries/references.md49
-rw-r--r--docs/src/content/showcases.ts13
-rw-r--r--docs/src/env.d.ts2
-rw-r--r--docs/src/style.css72
19 files changed, 0 insertions, 1750 deletions
diff --git a/docs/src/assets/front-image.png b/docs/src/assets/front-image.png
deleted file mode 100644
index 0fbfcca..0000000
--- a/docs/src/assets/front-image.png
+++ /dev/null
Binary files differ
diff --git a/docs/src/components/Showcase.astro b/docs/src/components/Showcase.astro
deleted file mode 100644
index 7eea178..0000000
--- a/docs/src/components/Showcase.astro
+++ /dev/null
@@ -1,37 +0,0 @@
----
-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
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" },
-]
diff --git a/docs/src/env.d.ts b/docs/src/env.d.ts
deleted file mode 100644
index acef35f..0000000
--- a/docs/src/env.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-/// <reference path="../.astro/types.d.ts" />
-/// <reference types="astro/client" />
diff --git a/docs/src/style.css b/docs/src/style.css
deleted file mode 100644
index b6a0047..0000000
--- a/docs/src/style.css
+++ /dev/null
@@ -1,72 +0,0 @@
-/* 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;
-}