diff options
Diffstat (limited to 'docs')
48 files changed, 4216 insertions, 1205 deletions
diff --git a/docs/default.nix b/docs/default.nix index 3a75834..0d79ce1 100644 --- a/docs/default.nix +++ b/docs/default.nix @@ -7,47 +7,45 @@ toTOML = (pkgs.formats.toml {}).generate; - genRefForPkg = { - name, - pkg, - outPath, - metaData, - }: let - data = toTOML name metaData; - output = self.packages.${pkgs.system}.${pkg}.dev; - in '' - mkdir -p $out/${outPath} - cat ${urlmap} > urlmap.js - gi-docgen generate -C ${data} ${output}/share/gir-1.0/${name}-0.1.gir - cp -r ${name}-0.1/* $out/${outPath} - ''; + docgen = pkgs.gi-docgen.overrideAttrs { + patches = [../nix/doc/gi-docgen.patch]; + }; - genLib = name: namespace: { - description, + genLib = { + flakepkg, + gir, version, + description, + api-ver ? "0.1", authors ? "Aylur", dependencies ? {}, - out ? "libastal/${name}", - }: - genRefForPkg { - name = "Astal${namespace}"; - pkg = name; - outPath = out; - metaData = { - library = { - inherit description authors; - version = readVer version; - license = "LGPL-2.1"; - browse_url = "https://github.com/aylur/astal"; - repository_url = "https://github.com/aylur/aylur.git"; - website_url = "https://aylur.github.io/astal"; - dependencies = ["GObject-2.0"] ++ (builtins.attrNames dependencies); - }; + out ? "libastal/${flakepkg}", + browse ? flakepkg, + website ? flakepkg, + }: let + name = "Astal${gir}-${api-ver}"; + src = self.packages.${pkgs.system}.${flakepkg}.dev; - extra.urlmap_file = "urlmap.js"; - dependencies = {inherit (dependency) "GObject-2.0";} // dependencies; + data = toTOML gir { + library = { + inherit description authors; + version = readVer version; + license = "LGPL-2.1"; + browse_url = "https://github.com/Aylur/astal/tree/main/lib/${browse}"; + repository_url = "https://github.com/aylur/aylur.git"; + website_url = "https://aylur.github.io/astal/guide/libraries/${website}"; + dependencies = ["GObject-2.0"] ++ (builtins.attrNames dependencies); }; + + extra.urlmap_file = "urlmap.js"; + dependencies = {inherit (dependency) "GObject-2.0";} // dependencies; }; + in '' + mkdir -p $out/${out} + cat ${urlmap} > urlmap.js + gi-docgen generate -C ${data} ${src}/share/gir-1.0/${name}.gir + cp -r ${name}/* $out/${out} + ''; dependency = { "GObject-2.0" = { @@ -60,6 +58,11 @@ description = "The GTK toolkit"; docs_url = "https://docs.gtk.org/gtk3/"; }; + "AstalIO-0.1" = { + name = "AstalIO"; + description = "Astal Core library"; + docs_url = "https://aylur.github.io/libastal/io"; + }; "NM-1.0" = { name = "NetworkManager"; description = "The standard Linux network configuration tool suite"; @@ -80,6 +83,7 @@ ["Gdk" "https://docs.gtk.org/gdk3/"] ["Gtk" "https://docs.gtk.org/gtk3/"] ["GdkPixbuf" "https://docs.gtk.org/gdk-pixbuf/"] + ["AstalIO" "https://aylur.github.io/libastal/io"] # FIXME: these are not gi-docgen generated, therefore links are broken ["NM" "https://networkmanager.dev/docs/libnm/latest/"] @@ -88,11 +92,11 @@ ''; in pkgs.stdenvNoCC.mkDerivation { - name = "library-reference"; + name = "reference"; src = ./.; nativeBuildInputs = with pkgs; [ - gi-docgen + docgen glib json-glib gobject-introspection @@ -102,65 +106,101 @@ in libdbusmenu-gtk3 wireplumber networkmanager + self.packages.${system}.io ]; installPhase = '' runHook preInstall - ${genLib "astal" "" { - out = "libastal"; - description = "Astal core library"; - version = ../core/version; - dependencies = {inherit (dependency) "Gtk-3.0";}; + ${genLib { + flakepkg = "io"; + gir = "IO"; + api-ver = "0.1"; + browse = "astal/io"; + description = "Astal Core library"; + version = ../lib/astal/io/version; + }} + ${genLib { + flakepkg = "astal3"; + gir = ""; + api-ver = "3.0"; + browse = "astal/gtk3"; + description = "Astal GTK3 widget library"; + version = ../lib/astal/gtk3/version; + dependencies = {inherit (dependency) "AstalIO-0.1" "Gtk-3.0";}; }} - ${genLib "apps" "Apps" { + ${genLib { + flakepkg = "apps"; + gir = "Apps"; description = "Application query library"; version = ../lib/apps/version; }} - ${genLib "auth" "Auth" { + ${genLib { + flakepkg = "auth"; + gir = "Auth"; authors = "kotontrion"; description = "Authentication using pam"; version = ../lib/auth/version; }} - ${genLib "battery" "Battery" { + ${genLib { + flakepkg = "battery"; + gir = "Battery"; description = "DBus proxy for upowerd devices"; version = ../lib/battery/version; }} - ${genLib "bluetooth" "Bluetooth" { + ${genLib { + flakepkg = "bluetooth"; + gir = "Bluetooth"; description = "DBus proxy for bluez"; version = ../lib/bluetooth/version; }} - ${genLib "hyprland" "Hyprland" { + ${genLib { + flakepkg = "hyprland"; + gir = "Hyprland"; description = "IPC client for Hyprland"; version = ../lib/hyprland/version; }} - ${genLib "mpris" "Mpris" { + ${genLib { + flakepkg = "mpris"; + gir = "Mpris"; description = "Control mpris players"; version = ../lib/mpris/version; }} - ${genLib "network" "Network" { + ${genLib { + flakepkg = "network"; + gir = "Network"; description = "NetworkManager wrapper library"; version = ../lib/network/version; dependencies = {inherit (dependency) "NM-1.0";}; # FIXME: why does this not work? }} - ${genLib "notifd" "Notifd" { + ${genLib { + flakepkg = "notifd"; + gir = "Notifd"; description = "Notification daemon library"; version = ../lib/notifd/version; }} - ${genLib "powerprofiles" "PowerProfiles" { + ${genLib { + flakepkg = "powerprofiles"; + gir = "PowerProfiles"; description = "DBus proxy for upowerd profiles"; version = ../lib/powerprofiles/version; }} - ${genLib "river" "River" { + ${genLib { + flakepkg = "river"; + gir = "River"; description = "IPC client for River"; version = ../lib/river/version; authors = "kotontrion"; }} - ${genLib "tray" "Tray" { + ${genLib { + flakepkg = "tray"; + gir = "Tray"; description = "StatusNotifierItem implementation"; version = ../lib/tray/version; authors = "kotontrion"; }} - ${genLib "wireplumber" "Wp" { + ${genLib { + flakepkg = "wireplumber"; + gir = "Wp"; description = "Wrapper library over the wireplumber API"; version = ../lib/wireplumber/version; authors = "kotontrion"; diff --git a/docs/eslint.config.js b/docs/eslint.config.js new file mode 100644 index 0000000..847a9dc --- /dev/null +++ b/docs/eslint.config.js @@ -0,0 +1,30 @@ +import eslint from "@eslint/js" +import tseslint from "typescript-eslint" +import stylistic from "@stylistic/eslint-plugin" +import pluginVue from "eslint-plugin-vue" + +export default tseslint.config({ + ignores: [".vitepress/cache/*"], + extends: [ + eslint.configs.recommended, + ...tseslint.configs.recommended, + ...pluginVue.configs["flat/recommended"], + stylistic.configs.customize({ + semi: false, + indent: 4, + quotes: "double", + }), + ], + rules: { + "vue/multi-word-component-names": ["off"], + "vue/html-indent": ["error", 4], + "vue/max-attributes-per-line": ["error", { + singleline: { + max: 2, + }, + multiline: { + max: 1, + }, + }], + }, +}) diff --git a/docs/guide/ags/installation.md b/docs/guide/ags/installation.md deleted file mode 100644 index 0adcf68..0000000 --- a/docs/guide/ags/installation.md +++ /dev/null @@ -1,65 +0,0 @@ -# Installation - -## Nix - -maintainer: [@Aylur](https://github.com/Aylur) - -Read more about it on the [nix page](../getting-started/nix#ags) - -You can try without installing. - -<!--TODO: remove v2 after merge--> -```sh -nix run github:aylur/ags/v2 -- --help -``` - -## Bulding AGS from source - -1. [Install Astal](../getting-started/installation.md) if you have not already - -2. Install the following dependencies - -:::code-group - -```sh [<i class="devicon-archlinux-plain"></i> Arch] -sudo pacman -Syu go npm gjs -``` - -```sh [<i class="devicon-fedora-plain"></i> Fedora] -sudo dnf install golang npm gjs -``` - -```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu] -sudo apt install golang-go npm gjs -``` - -::: - -3. Clone the repo and Install - -<!--TODO: remove v2 after merge--> -```sh -git clone https://github.com/aylur/ags.git -cd ags/src -git checkout v2 # https://github.com/Aylur/ags/pull/504 -go install -``` - -:::info -If you have installed Astal **not** in `/usr` make sure to set its path. - -```sh -go install -ldflags "-X main.astalGjs=$(pkg-config --variable prefix astal-0.1)/share/astal/gjs" -``` - -::: - -:::tip -`go install` installs the `ags` binary to `$GOPATH/bin` so make sure its in your `$PATH`. -You can move it to another directory if you like. For example - -```sh -mv $GOPATH/bin/ags ~/.local/bin/ags -``` - -::: diff --git a/docs/guide/getting-started/installation.md b/docs/guide/getting-started/installation.md index ef5c6e8..844de25 100644 --- a/docs/guide/getting-started/installation.md +++ b/docs/guide/getting-started/installation.md @@ -13,7 +13,7 @@ maintainer: [@kotontrion](https://github.com/kotontrion) :::code-group ```sh [Core Library] -yay -S libastal-git +yay -S libastal-io-git libastal-git ``` ```sh [Every Library] @@ -24,14 +24,7 @@ yay -S libastal-meta ## Bulding libastal from source -1. Clone the repo - -```sh -git clone https://github.com/aylur/astal.git -cd astal/core -``` - -2. Install the following dependencies +1. Install the following dependencies :::code-group @@ -44,26 +37,31 @@ sudo dnf install meson gcc valac gtk3-devel gtk-layer-shell-devel gobject-intros ``` ```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu] -sudo apt install meson valac libgtk3-dev libgtk-layer-shell-dev gobject-introspection +sudo apt install meson valac libgtk-3-dev libgtk-layer-shell-dev gobject-introspection libgirepository1.0-dev ``` ::: +2. Clone the repo + +```sh +git clone https://github.com/aylur/astal.git /tmp/astal +``` + 3. Build and install with `meson` +- astal-io + ```sh -meson setup build +cd /tmp/astal/lib/astal/io +meson setup --prefix /usr build meson install -C build ``` -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: +- astal3 ```sh +cd /tmp/astal/lib/astal/gtk3 meson setup --prefix /usr build meson install -C build ``` - -::: diff --git a/docs/guide/getting-started/introduction.md b/docs/guide/getting-started/introduction.md index 92d2ff1..782c069 100644 --- a/docs/guide/getting-started/introduction.md +++ b/docs/guide/getting-started/introduction.md @@ -2,22 +2,25 @@ ## What is Astal? -Astal (_meaning "desk"_) is a bundle of libraries built using [GLib](https://docs.gtk.org/glib/) in Vala and C. -The core library [libastal](https://aylur.github.io/libastal) has some Gtk widgets that come packaged, -the most important one is the [Window](https://aylur.github.io/libastal/class.Window.html) which is the main toplevel component using [gtk-layer-shell](https://github.com/wmww/gtk-layer-shell). +Astal (_meaning "desk"_) is a suite of libraries in Vala and C. +The core library [astal3](https://aylur.github.io/libastal/astal3) and +[astal4](https://aylur.github.io/libastal/astal4) (not yet available) +has some Gtk widgets that come packaged, +the most important one being the [Window](https://aylur.github.io/libastal/astal3/class.Window.html) which is the main toplevel component using [gtk-layer-shell](https://github.com/wmww/gtk-layer-shell). This is what allows us to use Gtk as shell components on Wayland. -libastal also comes with some utility functions such as running external processes, -reading, writing and monitoring files. +The other part of the core library [astal-io](https://aylur.github.io/libastal/astal-io) +which contains some utility GLib shortcut for running external processes, +reading, writing and monitoring files, timeout and interval functions. ## Why Astal? -What makes Astal convenient to use is not the core library, as it could easily be replaced +What makes Astal convenient to use is not the core libraries, as they can easily be replaced by the standard library of any of your favorite language that has bindings to Gtk, it is the -accompanying libraries (_formerly known as "services" in AGS_) +accompanying libraries (_formerly known as "services" in AGS_). Have you ever wanted to write a custom bar, custom notification popups or an applauncher, but gave up because writing a workspace widget, implementing the notification daemon or handling a search filter was too much of a hassle? -Astal libraries have you [covered](/guide/libraries/references), you don't have to worry about these, +Astal libraries have you [covered](../libraries/references#astal-libraries), you don't have to worry about these, you just define the layout, style it with CSS and that's it. diff --git a/docs/guide/getting-started/nix.md b/docs/guide/getting-started/nix.md index c9ed270..1e0572e 100644 --- a/docs/guide/getting-started/nix.md +++ b/docs/guide/getting-started/nix.md @@ -1,3 +1,8 @@ +--- +next: + link: '/guide/getting-started/supported-languages' + text: 'Supported Languages' +--- # Nix ## Astal @@ -20,7 +25,7 @@ Using Astal on Nix will require you to package your project. system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; in { - packages.${system}.default = astal.lib.mkLuaPacakge { + packages.${system}.default = astal.lib.mkLuaPackage { inherit pkgs; src = ./path/to/project; # should contain init.lua @@ -74,11 +79,16 @@ Using Astal on Nix will require you to package your project. } ``` +```nix [<i class="devicon-typescript-plain"></i> TypeScript] +# The usage of AGS (read below) is recommended +# Usage without AGS is not yet documented +``` + ::: ## AGS -The recommended way to use AGS on NixOS is through the home-manager module. +The recommended way to use [AGS](../typescript/first-widgets#first-widgets) on NixOS is through the home-manager module. Example content of a `flake.nix` file that contains your `homeConfigurations`. @@ -144,7 +154,7 @@ Example content of `home.nix` file ::: -AGS by default only includes the core `libastal` library. +AGS by default only includes the core `astal3/astal4` and `astal-io` libraries. If you want to include any other [library](../libraries/references) you have to add them to `extraPackages`. You can also add binaries which will be added to the gjs runtime. @@ -158,7 +168,11 @@ The AGS flake does not expose the `astal` cli to the home environment, you have :::code-group ```nix [<i class="devicon-nixos-plain"></i> home.nix] -home.packages = [ inputs.ags.packages.${pkgs.system}.astal ]; +home.packages = [ inputs.ags.packages.${pkgs.system}.io ]; +``` + +```sh [<i class="devicon-bash-plain"></i> sh] +astal --help ``` ::: diff --git a/docs/guide/getting-started/supported-languages.md b/docs/guide/getting-started/supported-languages.md index 4cb7f3a..d6d669d 100644 --- a/docs/guide/getting-started/supported-languages.md +++ b/docs/guide/getting-started/supported-languages.md @@ -1,9 +1,15 @@ # Supported Languages +There are currently two languages that have an additional +Astal package: Lua and Gjs. Their purpose is to abstract away +Gtk by implementing a state management and UI declaring solution. + ## JavaScript -The main intended usage of Astal is in TypeScript with [AGS](/guide/ags/first-widgets). -It supports JSX and has a state management solution similar to web frameworks. +The main intended usage of Astal is in TypeScript+JSX. +It is recommended to use [AGS](/guide/typescript/first-widgets) to scaffold and run projects in TypeScript. +However, if you are familiar with JavaScript's tooling +ecosystem you can also setup an environment yourself. Only a minimal knowledge of JavaScript's syntax is needed to get started. :::info @@ -17,11 +23,7 @@ Examples: ## Lua -Similar to how there is a [TypeScript](https://github.com/Aylur/astal/tree/main/core/gjs) lib for GJS, there is also an accompanying library for [Lua](https://github.com/Aylur/astal/tree/main/core/lua). -<!--TODO: open issue and link performance issue--> -Unfortunately, I have encountered very heavy [performance issues](https://github.com/aylur/astal) with [lgi](https://github.com/lgi-devs/lgi), -and so currently I don't recommend using Lua for full desktop shells, but only for static -components that don't render child nodes dynamically, bars and panels for example. +Lua is well-supported, but I would still recommend TypeScript, as Lua lacks a type system, which in turn limits editor support. Examples: @@ -30,10 +32,9 @@ Examples: ## Python -There was a WIP [library for python](https://github.com/aylur/astal/tree/feat/python), to make it behave similar to the above two -but I don't plan on finishing it, because I'm not a fan of python. -If you are interested in picking it up, feel free to open a PR. -Nonetheless you can still use python the OOP way [pygobject](https://pygobject.gnome.org/tutorials/gobject/subclassing.html) intended it. +There is a WIP [package for python](https://github.com/aylur/astal/tree/feat/python), +to bring declaritivity to Python similar to the above two languages. +However, you can still use python the OOP way [pygobject](https://pygobject.gnome.org/tutorials/gobject/subclassing.html) intended it in the meantime. Examples: @@ -44,7 +45,7 @@ Examples: Vala is a language that simply put uses C# syntax and compiles to C. It is the language most of Astal is written in. I would still recommend -using TypeScript or Lua over Vala as they don't need a build step. +using TypeScript or Lua over Vala as they are simpler to work with. Examples: diff --git a/docs/guide/libraries/apps.md b/docs/guide/libraries/apps.md index c53daf0..7f9ee6e 100644 --- a/docs/guide/libraries/apps.md +++ b/docs/guide/libraries/apps.md @@ -33,21 +33,10 @@ cd astal/lib/apps 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Apps reference](https://aylur.github.io/libastal/apps). @@ -106,8 +95,3 @@ end ``` ::: - -:::info -The fuzzy query uses [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance). I am not a mathematician, but if you know how to reimplement -the logic of [fzf](https://github.com/junegunn/fzf) to make it better feel free to open PRs. -::: diff --git a/docs/guide/libraries/auth.md b/docs/guide/libraries/auth.md index 1f07a17..d5f0a49 100644 --- a/docs/guide/libraries/auth.md +++ b/docs/guide/libraries/auth.md @@ -43,21 +43,10 @@ cd astal/lib/auth 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Auth reference](https://aylur.github.io/libastal/auth). diff --git a/docs/guide/libraries/battery.md b/docs/guide/libraries/battery.md index b42d747..7f94297 100644 --- a/docs/guide/libraries/battery.md +++ b/docs/guide/libraries/battery.md @@ -37,21 +37,10 @@ cd astal/lib/battery 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Battery reference](https://aylur.github.io/libastal/battery). diff --git a/docs/guide/libraries/bluetooth.md b/docs/guide/libraries/bluetooth.md index 04d9db2..672f66d 100644 --- a/docs/guide/libraries/bluetooth.md +++ b/docs/guide/libraries/bluetooth.md @@ -37,21 +37,10 @@ cd astal/lib/bluetooth 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Bluetooth reference](https://aylur.github.io/libastal/bluetooth). diff --git a/docs/guide/libraries/hyprland.md b/docs/guide/libraries/hyprland.md index faf9e50..672faad 100644 --- a/docs/guide/libraries/hyprland.md +++ b/docs/guide/libraries/hyprland.md @@ -32,21 +32,10 @@ cd astal/lib/hyprland 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Hyprland reference](https://aylur.github.io/libastal/hyprland). diff --git a/docs/guide/libraries/mpris.md b/docs/guide/libraries/mpris.md index dfe7956..8f28924 100644 --- a/docs/guide/libraries/mpris.md +++ b/docs/guide/libraries/mpris.md @@ -6,6 +6,18 @@ exposing an mpris interface through dbus. An alternative for [playerctl](https://github.com/altdesktop/playerctl) that better integrates with astal. +:::warning +In order for network cover art urls to be cached (spotify for example) +make sure `gvfs` is enabled. + +:::code-group + +```nix [<i class="devicon-nixos-plain"></i> configuration.nix] +services.gvfs.enable = true; +``` + +::: + ## Installation 1. install dependencies @@ -13,15 +25,15 @@ with astal. :::code-group ```sh [<i class="devicon-archlinux-plain"></i> Arch] -sudo pacman -Syu meson vala json-glib gobject-introspection +sudo pacman -Syu meson vala gvfs json-glib gobject-introspection ``` ```sh [<i class="devicon-fedora-plain"></i> Fedora] -sudo dnf install meson gcc valac json-glib-devel gobject-introspection-devel +sudo dnf install meson gcc valac gvfs json-glib-devel gobject-introspection-devel ``` ```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu] -sudo apt install meson valac libjson-glib-dev gobject-introspection +sudo apt install meson valac gvfs libjson-glib-dev gobject-introspection ``` ::: @@ -36,21 +48,10 @@ cd astal/lib/mpris 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Mpris reference](https://aylur.github.io/libastal/mpris). diff --git a/docs/guide/libraries/network.md b/docs/guide/libraries/network.md index afeb5d2..e076950 100644 --- a/docs/guide/libraries/network.md +++ b/docs/guide/libraries/network.md @@ -32,21 +32,10 @@ cd astal/lib/network 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Network reference](https://aylur.github.io/libastal/network). diff --git a/docs/guide/libraries/notifd.md b/docs/guide/libraries/notifd.md index 7e02149..094b770 100644 --- a/docs/guide/libraries/notifd.md +++ b/docs/guide/libraries/notifd.md @@ -36,21 +36,10 @@ cd astal/lib/notifd 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Notifd reference](https://aylur.github.io/libastal/notifd). diff --git a/docs/guide/libraries/powerprofiles.md b/docs/guide/libraries/powerprofiles.md index 8571c29..159f3ff 100644 --- a/docs/guide/libraries/powerprofiles.md +++ b/docs/guide/libraries/powerprofiles.md @@ -37,21 +37,10 @@ cd astal/lib/powerprofiles 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [PowerProfiles reference](https://aylur.github.io/libastal/powerprofiles). diff --git a/docs/guide/libraries/references.md b/docs/guide/libraries/references.md index 8f2bd02..3a85d73 100644 --- a/docs/guide/libraries/references.md +++ b/docs/guide/libraries/references.md @@ -29,7 +29,6 @@ Reading their documentation will vary depending on the language they are used in ## Astal Libraries -- [Astal](https://aylur.github.io/libastal): libastal the core library, which has the widgets and utilites - [Apps](https://aylur.github.io/libastal/apps): Library and cli tool for querying applications - [Auth](https://aylur.github.io/libastal/auth): Authentication library using PAM - [Battery](https://aylur.github.io/libastal/battery): DBus proxy library for upower daemon diff --git a/docs/guide/libraries/river.md b/docs/guide/libraries/river.md index 4818d0b..299aa8c 100644 --- a/docs/guide/libraries/river.md +++ b/docs/guide/libraries/river.md @@ -32,21 +32,10 @@ cd astal/lib/river 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [River reference](https://aylur.github.io/libastal/river). diff --git a/docs/guide/libraries/tray.md b/docs/guide/libraries/tray.md index c8d093b..b5cccc7 100644 --- a/docs/guide/libraries/tray.md +++ b/docs/guide/libraries/tray.md @@ -32,21 +32,10 @@ cd astal/lib/tray 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Tray reference](https://aylur.github.io/libastal/tray). diff --git a/docs/guide/libraries/wireplumber.md b/docs/guide/libraries/wireplumber.md index 5f1daab..0592628 100644 --- a/docs/guide/libraries/wireplumber.md +++ b/docs/guide/libraries/wireplumber.md @@ -32,21 +32,10 @@ cd astal/lib/wireplumber 3. install ```sh -meson setup build -meson install -C build -``` - -:::tip -Most distros recommend manual installs in `/usr/local`, -which is what `meson` defaults to. If you want to install to `/usr` -instead which most package managers do, set the `prefix` option: - -```sh meson setup --prefix /usr build +meson install -C build ``` -::: - ## Usage You can browse the [Wireplumber reference](https://aylur.github.io/libastal/wireplumber). diff --git a/docs/guide/lua/binding.md b/docs/guide/lua/binding.md new file mode 100644 index 0000000..f4d5f0b --- /dev/null +++ b/docs/guide/lua/binding.md @@ -0,0 +1,139 @@ +# Binding + +As mentioned before binding an object's state to another - +so in most cases a `Variable` or a `GObject.Object` property to a widget's property - +is done through the `bind` function which returns a `Binding` object. + +`Binding` objects simply hold information about the source and how it should be transformed +which Widget constructors can use to setup a connection between themselves and the source. + +```lua +---@class Binding<T> +---@field private transform_fn fun(value: T): any +---@field private emitter Connectable | Subscribable<T> +---@field private property? string +---@field as fun(transform: fun(value: T): any): Binding +---@field get fun(): T +---@field subscribe fun(self, callback: fun(value: T)): function +``` + +A `Binding` can be constructed from an object implementing +the `Subscribable` interface (usually a `Variable`) +or an object implementing the `Connectable` interface and one of its properties +(usually a `GObject.Object` instance). + +Lua type annotations are not expressive enough to explain this, +so I'll use TypeScript to demonstrate it. + +<!--TODO: use Teal maybe?--> + +```ts +function bind<T>(obj: Subscribable<T>): Binding<T> + +function bind< + Obj extends Connectable, + Prop extends keyof Obj, +>(obj: Obj, prop: Prop): Binding<Obj[Prop]> +``` + +## Subscribable and Connectable interface + +Any object implementing one of these interfaces can be used with `bind`. + +```ts +interface Subscribable<T> { + subscribe(callback: (value: T) => void): () => void + get(): T +} + +interface Connectable { + connect(signal: string, callback: (...args: any[]) => unknown): number + disconnect(id: number): void +} +``` + +`Connectable` is usually used for GObjects coming from [libraries](../libraries/references) +You won't be implementing it in Lua code. + +## Example Custom Subscribable + +When binding the children of a box from an array, usually not all elements +of the array changes each time, so it would make sense to not destroy +the widget which represents the element. + +::: code-group + +```lua :line-numbers [varmap.lua] +local Gtk = require("astal.gtk3").Gtk +local Variable = require("astal.variable") + +---@param initial table +return function(initial) + local map = initial + local var = Variable() + + local function notify() + local arr + for _, value in pairs(map) do + table.insert(arr, value) + end + var:set(arr) + end + + local function delete(key) + if Gtk.Widget:is_type_of(map[key]) then + map[key]:destroy() + end + + map[key] = nil + end + + notify() -- init + + return { + set = function(key, value) + delete(key) + map[key] = value + notify() + end, + delete = function(key) + delete(key) + notify() + end, + get = function() + return var:get() + end, + subscribe = function(callback) + return var:subscribe(callback) + end, + } +end +``` + +::: + +And this `VarMap<key, Widget>` can be used as an alternative to `Variable<Array<Widget>>`. + +```lua +function MappedBox() + local map = varmap({ + ["1"] = Widget.Label({ label = "1" }), + ["2"] = Widget.Label({ label = "2" }), + }) + + return Widget.Box({ + setup = function (self) + self:hook(gobject, "added", function (_, id) + map.set(id, Widget.Label({ label = id })) + end) + self:hook(gobject, "removed", function (_, id) + map.delete(id) + end) + end, + bind(map):as(function (arr) + -- can be sorted here + return arr + end), + }) +end +``` diff --git a/docs/guide/lua/cli-app.md b/docs/guide/lua/cli-app.md new file mode 100644 index 0000000..6bfaa9e --- /dev/null +++ b/docs/guide/lua/cli-app.md @@ -0,0 +1,131 @@ +# CLI and App + +`App` is a singleton **instance** of an [Astal.Application](https://aylur.github.io/libastal/astal3/class.Application.html). + +Depending on gtk version require paths will differ + +<!--TODO: remove gtk4 notice when its available--> + +```lua +local App = require("astal.gtk3.app") + +local App = require("astal.gtk4.app") -- not yet available +``` + +## Entry point + +`App:start` is a wrapper function for `App:run` +that will only run the application if there is no +instance already running with the specified name. + +:::code-group + +```lua [init.lua] +App:start({ + instance_name = "my-instance", -- defaults to "astal" + main = function() + -- setup anything + -- instantiate widgets + end, +}) +``` + +::: + +## Messaging from CLI + +If you want to interact with an instance from the CLI, +you can do so by sending a request. + +```lua +App:start({ + main = function() end, + + ---@param request string + ---@param res fun(response: any): nil + request_handler = function(request, res) + if request == "say hi" then + return res("hi cli") + end + res("unknown command") + end +}) +``` + +```sh +astal say hi +# hi cli +``` + +## Toggling Windows by their name + +In order for Astal to know about your windows, you have to register them. +You can do this by specifying a **unique** `name` and calling `App:add_window`. + +```lua +local App = require("astal.gtk3.app") + +local function Bar() + return Widget.Window({ + name = "Bar", + setup = function(self) + App:add_window(self) + end, + Widget.Box() + }) +end +``` + +You can also invoke `App:add_window` by simply passing the `App` to the `application` prop. + +```lua +local App = require("astal.gtk3.app") + +local function Bar() + return Widget.Window({ + name = "Bar", + application = App, + Widget.Box() + }) +end +``` + +```sh +astal -t Bar +``` + +:::warning +When assigning the `application` prop make sure `name` comes before. +Props are set sequentially and if name is applied after application it won't work. +::: + +## Client instances + +The first time `App:start` is invoked the `main` function gets called. +While that instance is running any subsequent execution of the script will call +the `client` function. + +:::code-group + +```lua [init.lua] +App:start({ + -- main instance + main = function(...) + local args = { ... } + print(string.format("{%s}", table.concat(args, ", "))) + end, + + -- client instance + client = function(request, ...) + local res = request("you can send a request to the main instance") + print(res) + end, + + -- this runs in the main instance + request_handler = function(request, res) + res("response from main instance") + end +}) +``` + +::: diff --git a/docs/guide/lua/first-widgets.md b/docs/guide/lua/first-widgets.md new file mode 100644 index 0000000..efc1c4f --- /dev/null +++ b/docs/guide/lua/first-widgets.md @@ -0,0 +1,265 @@ +# First Widgets + +## Getting Started + +Start by importing the singleton +[Astal.Application](https://aylur.github.io/libastal/astal3/class.Application.html) instance. + +:::code-group + +```lua [init.lua] +local App = require("astal.gtk3.app") + +App:start({ + main = function() + -- you will instantiate Widgets here + -- or setup anything else if you need + print("hi") + end +}) +``` + +::: + +Then run `lua init.lua` in the terminal, and that's it! +Now you have an instance running with Lua. + +## Root of every shell component: Window + +Astal apps are composed of widgets. A widget is a piece of UI that has its own logic and style. +A widget can be as small as a button or an entire bar. +The top level widget is always a [Window](https://aylur.github.io/libastal/astal3/class.Window.html) +which will hold all widgets. + +::: code-group + +```lua [widget/Bar.lua] +local Widget = require("astal.gtk3.widget") +local Anchor = require("astal.gtk3").Astal.WindowAnchor + +return function(monitor) + return Widget.Window({ + monitor = monitor, + anchor = Anchor.TOP + Anchor.LEFT + Anchor.RIGHT, + exclusivity = "EXCLUSIVE", + Widget.Label({ + label = "Example label content", + }), + }) +end +``` + +::: + +::: code-group + +```lua [init.lua] +local App = require("astal.gtk3.app") +local Bar = require("widget.Bar") + +App:start { + main = function() + Bar(0) + Bar(1) -- instantiate for each monitor + end, +} +``` + +::: + +## Creating and nesting widgets + +Widgets are simply Lua functions that return Gtk widgets, +you can nest widgets by passing them as arguments to the table in the function. + +:::code-group + +```lua [widget/MyButton.lua] +local Widget = require("astal.gtk3.widget") + +return function(text) + return Widget.Button({ + on_click_release = function(_, event) + if event.button == "PRIMARY" then + print("Left click") + elseif event.button == "SECONDARY" then + print("Right click") + end + end, + Widget.Label({ + label = text, + }), + }) +end +``` + +::: + +Now, you should be able to nest it into another widgets. + +::: code-group + +```lua [widget/Bar.lua] {13} +local MyButton = require("widget.MyButton") +local Anchor = require("astal.gtk3").Astal.WindowAnchor + +return function(monitor) + return Widget.Window({ + monitor = monitor, + anchor = Anchor.TOP + Anchor.LEFT + Anchor.RIGHT, + exclusivity = "EXCLUSIVE", + Widget.Box({ + Widget.Label({ + label = "Click the button", + }), + MyButton("hi, im a button"), + }), + }) +end +``` + +::: + +## Widget signal handlers + +You can respond to events by declaring event handler functions inside your widget: + +```lua +local function MyButton() + return Widget.Button({ + on_click_release = function(_, event) + print(event.button) + end, + }) +end +``` + +:::info +Keys prefixed with `on_` will connect to a `signal` of the widget. +Refer to the Gtk and Astal docs to have a full list of them. +::: + +## State management + +The state of widgets are handled with Bindings. A [Binding](./binding) lets you +connect the state of an [object](./binding#subscribable-and-connectable-interface) +to a widget so it re-renders when that state changes. + +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: + +```lua +local astal = require("astal") +local bind = astal.bind +local Variable = astal.Variable +local Widget = require("astal.gtk3.widget") + +local function Counter() + local count = Variable(0) + return Widget.Box({ + Widget.Label({ + label = bind(count):as(tostring), + }), + Widget.Button({ + label = "Click to increment", + on_click_release = function() + count:set(count:get() + 1) + end, + }), + }) +end +``` + +:::info +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 +converted into a string first. +::: + +:::tip +`Variables` have a shorthand for `bind(variable):as(transform)` + +```lua +local v = Variable(0) + +return Widget.Box { + -- these three are equivalent + Widget.Label({ label = bind(v):as(tostring) }), + Widget.Label({ label = v():as(tostring) }), + Widget.Label({ label = v(tostring) }), +} +``` + +::: + +Here is an example of a battery percent label that binds the `percentage` +property of the Battery object from the [Battery Library](/guide/libraries/battery): + +```lua +local astal = require("astal") +local bind = astal.bind +local Battery = astal.require("AstalBattery") +local Widget = require("astal.gtk3.widget") + +local function BatteryPercentage() + local bat = Battery.get_default() + + return Widget.Label({ + label = bind(bat, "percentage"):as(function(p) + return string.format("%.0f%%", p * 100) + end), + }) +end +``` + +## Dynamic children + +You can also use a `Binding` for `child` and `children` properties. + +```lua +local astal = require("astal") +local Variable = astal.Variable +local Widget = require("astal.gtk3.widget") + +local child = Variable(Widget.Box()) + +return Widget.Box({ + child(), +}) +``` + +```lua +local num = Variable(3) + +return Widget.Box { + num():as(function(n) + local tbl = {} + for i = 1, n do + table.insert(tbl, Widget.Button({ + label = tostring(i) + })) + end + return tbl + end) +} +``` + +:::tip +Binding children of widgets will implicitly call `:destroy()` on widgets +that would be left without a parent. You can opt out of this behavior +by setting `no_implicity_destroy` property on the container widget. +::: + +:::info +You can pass the followings as children: + +- widgets +- deeply nested arrays of widgets +- bindings of widgets, +- bindings of deeply nested arrays of widgets + +`nil` is the only value that is not rendered and anything not from this list +will be coerced into a string and rendered as a label. +::: diff --git a/docs/guide/lua/installation.md b/docs/guide/lua/installation.md new file mode 100644 index 0000000..b99d8df --- /dev/null +++ b/docs/guide/lua/installation.md @@ -0,0 +1,25 @@ +# Installation + +## Nix + +maintainer: [@Aylur](https://github.com/Aylur) + +Read more about it on the [nix page](../getting-started/nix) + +## Arch + +```sh +yay -S lua-libastal-git +``` + +## From Source + +1. [Install Astal](../getting-started/installation.md) if you have not already + +2. Install the Astal Lua package + +```sh +git clone https://github.com/aylur/astal.git +cd lang/lua +sudo luarocks make +``` diff --git a/docs/guide/lua/theming.md b/docs/guide/lua/theming.md new file mode 100644 index 0000000..502e8e9 --- /dev/null +++ b/docs/guide/lua/theming.md @@ -0,0 +1,130 @@ +# Theming + +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) + +:::warning 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` + +:::code-group + +```lua [init.lua] +local inline_css = [[ + window { + background-color: transparent; + } +]] + +App:start({ + css = inline_css, + css = "/path/to/style.css", + css = "./style.css", +}) +``` + +::: + +:::warning +When using relative paths, so for example `./style.css` keep in mind that they +will be relative to the current working directory. +::: + +## Css Property on Widgets + +```lua +Widget.Label({ + css = "color: blue; padding: 1em;", + label = "hello" +}) +``` + +:::info +The `css` property of a widget will not cascade to its children. +::: + +## Apply Stylesheets at Runtime + +You can apply additional styles at runtime. + +```lua +App:apply_css("/path/to/file.css") +``` + +```lua +App:apply_css([[ + window { + background-color: transparent; + } +]]) +``` + +```lua +App:reset_css() -- reset if need +``` + +:::warning +`App:apply_css` will apply on top of other stylesheets applied before. +You can reset stylesheets with `App:reset_css` +or by passing `true` as a second parameter to `App:apply_css`. +::: + +## 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) + +```sh +# to bring up the inspector run +astal --inspector +``` + +## Using SCSS + +Gtk's CSS only supports a subset of what the web offers. +Most notably nested selectors are unsupported by Gtk, but this can be +workaround by using preprocessors like [SCSS](https://sass-lang.com/). + +:::code-group + +```sh [<i class="devicon-archlinux-plain"></i> Arch] +sudo pacman -Syu dart-sass +``` + +```sh [<i class="devicon-fedora-plain"></i> Fedora] +npm install -g sass # not packaged on Fedora +``` + +```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu] +npm install -g sass # not packaged on Ubuntu +``` + +::: + +:::code-group + +```lua [init.lua] +local scss = "./style.scss" +local css = "/tmp/style.css" + +astal.exec(string.format("sass %s %s", scss, css)) + +App:start({ + css = css, +}) +``` + +::: diff --git a/docs/guide/lua/utilities.md b/docs/guide/lua/utilities.md new file mode 100644 index 0000000..1ef70c7 --- /dev/null +++ b/docs/guide/lua/utilities.md @@ -0,0 +1,191 @@ +# Utilities + +## File functions + +```lua +local read_file = astal.read_file +local read_file_async = astal.read_file_async +local write_file = astal.write_file +local write_file_async = astal.write_file_async +local monitor_file = astal.monitor_file +``` + +### Reading files + +```lua +---@param path string +---@return string +local function read_file(path) end + +---@param path string +---@param callback fun(content: string, err: string): nil +local function read_file_async(path, callback) end +``` + +### Writing files + +```lua +---@param path string +---@param content string +local function write_file(path, content) end + +---@param path string +---@param content string +---@param callback? fun(err: string): nil +local function write_file_async(path, content, callback) end +``` + +### Monitoring files + +```lua +---@param path string +---@param callback fun(file: string, event: Gio.FileMonitorEvent): nil +local function monitor_file(path, callback) end +``` + +## Timeouts and Intervals + +```lua +local interval = astal.interval +local timeout = astal.timeout +local idle = astal.idle +``` + +### Interval + +Will immediately execute the function and every `interval` millisecond. + +```lua +---@param interval number +---@param callback? function +---@return Astal.Time +local function interval(interval, callback) end +``` + +### Timeout + +Will execute the `callback` after `timeout` millisecond. + +```lua +---@param timeout number +---@param callback? function +---@return Astal.Time +local function timeout(timeout, callback) end +``` + +### Idle + +Executes `callback` whenever there are no higher priority events pending. + +```lua +---@param callback? function +---@return Astal.Time +local function idle(callback) end +``` + +Example: + +```lua +local timer = interval(1000, function() + print("optional callback") +end) + +timer.on_now = function() + print("now") +end + +timer.on_cancelled = function() + print("cancelled") +end + +timer:cancel() +``` + +## Process functions + +```lua +local subprocess = astal.subprocess +local exec = astal.exec +local exec_async = astal.exec_async +``` + +### Subprocess + +You can start a subprocess and run callback functions whenever it outputs to +stdout or stderr. [Astal.Process](https://aylur.github.io/libastal/io/class.Process.html) has a `stdout` and `stderr` signal. + +```lua +---@param commandline string | string[] +---@param on_stdout? fun(out: string): nil +---@param on_stderr? fun(err: string): nil +---@return Astal.Process | nil +local function subprocess(commandline, on_stdout, on_stderr) end +``` + +Example: + +```lua +local proc = subprocess( + "some-command", + function(out) print(out) end, + function(err) print(err) end, +) + +-- with signals +local proc = subprocess("some-command") + +proc.on_stdout = function(_, stdout) + print(stdout) +end + +proc.on_stderr = function(_, stderr) + print(stderr) +end +``` + +### Executing external commands and scripts + +```lua +---@param commandline string | string[] +---@return string, string +local function exec(commandline) end + +---@param commandline string | string[] +---@param callback? fun(out: string, err: string): nil +local function exec_async(commandline, callback) end +``` + +Example: + +```lua +local out, err = exec("/path/to/script") + +if err ~= nil then + print(err) +else + print(out) +end + +exec_async({ "bash", "-c", "/path/to/script.sh" }, function(out, err) + if err ~= nil then + print(err) + else + print(out) + end +end) +``` + +:::warning +`subprocess`, `exec`, and `exec_async` 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. + +```lua +exec({ "bash", "-c", "command $VAR && command" }) +exec("bash -c 'command $VAR' && command") +``` + +::: diff --git a/docs/guide/lua/variable.md b/docs/guide/lua/variable.md new file mode 100644 index 0000000..915632c --- /dev/null +++ b/docs/guide/lua/variable.md @@ -0,0 +1,162 @@ +# Variable + +```lua +local Variable = require("astal").Variable +local Variable = require("astal.variable") +``` + +Variable is just a simple object which holds a single value. +It also has some shortcuts for hooking up subprocesses, intervals and other gobjects. + +## Example Usage + +```lua +local my_var = Variable("initial-value") + +-- whenever its value changes, callback will be executed +my_var:subscribe(function(value) + print(value) +end) + +-- settings its value +my_var:set("new value") + +-- getting its value +local value = my_var:get() + +-- binding them to widgets +Widget.Label({ + label = bind(my_var):as(function(value) + return string.format("transformed %s", value) + end), + -- shorthand for the above + label = my_var(function(value) + return string.format("transformed %s", value) + end) +}) +``` + +:::warning +Make sure to the transform functions you pass to `:as()` are pure. +The `:get()` function can be called anytime by `astal` especially when `deriving`, +so make sure there are no sideeffects. +::: + +## Variable Composition + +Using `Variable.derive` any `Subscribable` object can be composed. + +```lua +local v1 = Variable(1) -- Variable +local v2 = bind(obj, "prop") -- Binding +local v3 = { -- Subscribable + get = function() + return 3 + end, + subscribe = function() + return function() end + end, +} + +-- 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 +local v4 = Variable.derive({ v1, v2, v3 }, function(v1, v2, v3) + return v1 * v2 * v3 +end) +``` + +## Subprocess shorthands + +Using `:poll` and `:watch` you can start subprocesses and capture their +output. They can poll and watch at the same time, but they +can only poll/watch once. + +:::warning +The command parameter is passed to [exec_async](/guide/lua/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. + +```lua +Variable(""):poll(1000, { "bash", "-c", "command $VAR && command" }) +``` + +::: + +```lua +local my_var = Variable(0) + :poll(1000, "command", function(out, prev) + return tonumber(out) + end) + :poll(1000, { "bash", "-c", "command" }, function(out, prev) + return tonumber(out) + end) + :poll(1000, function(prev) + return prev + 1 + end) +``` + +```lua +local my_var = Variable(0) + :watch("command", function(out, prev) + return tonumber(out) + end) + :watch({ "bash", "-c", "command" }, function(out, prev) + return tonumber(out) + end) +``` + +You can temporarily stop them and restart them whenever. + +```lua +my_var:stop_watch() -- this kills the subprocess +my_var:stop_poll() + +my_var:start_listen() -- launches the subprocess again +my_var:start_poll() + +print(my_var:is_listening()) +print(my_var:is_polling()) +``` + +## Gobject connection shorthands + +Using `:observe` you can connect gobject signals and capture their value. + +```lua +local my_var = Variable("") + :observe(obj1, "signal", function() + return "" + end):observe(obj2, "signal", function() + return "" + end) +``` + +## Dispose if no longer needed + +This will stop the interval, force exit the subprocess and disconnect gobjects. + +```lua +my_var:drop() +``` + +:::warning +Don't forget to drop derived variables or variables with +either `:poll`, `:watch` or `:observe` when they are defined inside closures. + +```lua +local function MyWidget() + local my_var = Variable():poll() + + return Widget.Box({ + on_destroy = function() + my_var:drop() + end + }) +end +``` + +::: diff --git a/docs/guide/lua/widget.md b/docs/guide/lua/widget.md new file mode 100644 index 0000000..d9f99fa --- /dev/null +++ b/docs/guide/lua/widget.md @@ -0,0 +1,158 @@ +# Widget + +## Gtk3 + +### Additional widget properties + +These are properties that Astal additionally adds to Gtk.Widgets + +- class_name: `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). +- click_through: `boolean` - Lets click events through. + +To have a full list of available properties, reference the documentation of the widget. + +- [Astal3 widgets](https://aylur.github.io/libastal/astal3/index.html#classes) +- [Gtk widgets](https://docs.gtk.org/gtk3/#classes) + +### Additional widget methods + +#### setup + +`setup` is a convenience prop to remove the need to predefine widgets +before returning them in cases where a reference is needed. + +without `setup` + +```lua +local function MyWidget() + local button = Widget.Button() + -- setup button + return button +end +``` + +using `setup` + +```lua +local function MyWidget() + return Widget.Button({ + setup = function(self) + -- setup button + end, + }) +end +``` + +#### hook + +Shorthand for connecting and disconnecting to [Subscribable and Connectable](./binding#subscribable-and-connectable-interface) objects. + +without `hook` + +```lua +local function MyWidget() + local id = gobject.on_signal:connect(callback) + local unsub = variable:subscribe(callback) + + return Widget.Box({ + on_destroy = function() + GObject.signal_handler_disconnect(gobject, id) + unsub() + end, + }) +end +``` + +with `hook` + +```lua +local function MyWidget() + return Widget.Box({ + setup = function(self) + self:hook(gobject, "signal", callback) + self:hook(variable, callback) + end, + }) +end +``` + +#### toggle_class_name + +Toggle class names based on a condition. + +```lua +local function MyWidget() + return Widget.Box({ + setup = function(self) + self:toggle_class_name("classname", some_condition) + end, + }) +end +``` + +### How to use non builtin Gtk widgets + +Using the `astalify` function you can wrap widgets +to behave like builtin widgets. +It 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 + +```lua +local astal = require("astal.gtk3") +local astalify = astal.astalify +local Gtk = astal.Gtk +local Gdk = astal.Gdk + +local ColorButton = astalify(Gtk.ColorButton) + +local function MyWidget() + return ColorButton({ + setup = function(self) + -- setup ColorButton instance + end, + use_alpha = true, + rgba = Gdk.RGBA({ + red = 1, + green = 0, + blue = 0, + alpha = 0.5, + }), + on_color_set = function(self) + print(self.rgba:to_string()) + end + }) +end +``` + +### Builtin Widgets + +You can check the [source code](https://github.com/Aylur/astal/blob/main/lang/lua/astal/gtk3/widget.lua) to have a full list of builtin widgets. + +These widgets are available by default in Lua. + +- Box: [Astal.Box](https://aylur.github.io/libastal/astal3/class.Box.html) +- Button: [Astal.Button](https://aylur.github.io/libastal/astal3/class.Button.html) +- CenterBox: [Astal.CenterBox](https://aylur.github.io/libastal/astal3/class.CenterBox.html) +- CircularProgress: [Astal.CircularProgress](https://aylur.github.io/libastal/astal3/class.CircularProgress.html) +- DrawingArea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/astal3/class.DrawingArea.html) +- Entry: [Gtk.Entry](https://docs.gtk.org/gtk3/astal3/class.Entry.html) +- Eventbox: [Astal.EventBox](https://aylur.github.io/libastal/astal3/class.EventBox.html) +- Icon: [Astal.Icon](https://aylur.github.io/libastal/astal3/class.Icon.html) +- Label: [Astal.Label](https://aylur.github.io/libastal/astal3/class.Label.html) +- Levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/astal3/class.LevelBar.html) +- Overlay: [Astal.Overlay](https://aylur.github.io/libastal/astal3/class.Overlay.html) +- Revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/astal3/class.Revealer.html) +- Scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/astal3/class.Scrollable.html) +- Slider: [Astal.Slider](https://aylur.github.io/libastal/astal3/class.Slider.html) +- Stack: [Astal.Stack](https://aylur.github.io/libastal/astal3/class.Stack.html) +- Switch: [Gtk.Switch](https://docs.gtk.org/gtk3/astal3/class.Switch.html) +- Window: [Astal.Window](https://aylur.github.io/libastal/astal3/class.Window.html) + +## Gtk4 + +🚧 Work in Progress 🚧 diff --git a/docs/guide/typescript/binding.md b/docs/guide/typescript/binding.md new file mode 100644 index 0000000..15fe3cc --- /dev/null +++ b/docs/guide/typescript/binding.md @@ -0,0 +1,235 @@ +# Binding + +As mentioned before binding an object's state to another - +so in most cases a `Variable` or a `GObject.Object` property to a widget's property - +is done through the `bind` function which returns a `Binding` object. + +`Binding` objects simply hold information about the source and how it should be transformed +which Widget constructors can use to setup a connection between themselves and the source. + +```ts +class Binding<Value> { + private transformFn: (v: any) => unknown + private emitter: Subscribable<Value> | Connectable + private prop?: string + + as<T>(fn: (v: Value) => T): Binding<T> + get(): Value + subscribe(callback: (value: Value) => void): () => void +} +``` + +A `Binding` can be constructed from an object implementing +the `Subscribable` interface (usually a `Variable`) +or an object implementing the `Connectable` interface and one of its properties +(usually a `GObject.Object` instance). + +```ts +function bind<T>(obj: Subscribable<T>): Binding<T> + +function bind< + Obj extends Connectable, + Prop extends keyof Obj, +>(obj: Obj, prop: Prop): Binding<Obj[Prop]> +``` + +## Subscribable and Connectable interface + +Any object implementing one of these interfaces can be used with `bind`. + +```ts +interface Subscribable<T> { + subscribe(callback: (value: T) => void): () => void + get(): T +} + +interface Connectable { + connect(signal: string, callback: (...args: any[]) => unknown): number + disconnect(id: number): void +} +``` + +## Example Custom Subscribable + +When binding the children of a box from an array, usually not all elements +of the array changes each time, so it would make sense to not destroy +the widget which represents the element. + +::: code-group + +```ts :line-numbers [varmap.ts] +import { type Subscribable } from "astal/binding" +import { Gtk } from "astal" + +export class VarMap<K, T = Gtk.Widget> implements Subscribable { + #subs = new Set<(v: Array<[K, T]>) => void>() + #map: Map<K, T> + + #notifiy() { + const value = this.get() + for (const sub of this.#subs) { + sub(value) + } + } + + #delete(key: K) { + const v = this.#map.get(key) + + if (v instanceof Gtk.Widget) { + v.destroy() + } + + this.#map.delete(key) + } + + constructor(initial?: Iterable<[K, T]>) { + this.#map = new Map(initial) + } + + set(key: K, value: T) { + this.#delete(key) + this.#map.set(key, value) + this.#notifiy() + } + + delete(key: K) { + this.#delete(key) + this.#notifiy() + } + + get() { + return [...this.#map.entries()] + } + + subscribe(callback: (v: Array<[K, T]>) => void) { + this.#subs.add(callback) + return () => this.#subs.delete(callback) + } +} +``` + +::: + +And this `VarMap<key, Widget>` can be used as an alternative to `Variable<Array<Widget>>`. + +```tsx +function MappedBox() { + const map = new VarMap([ + [1, <MyWidget id={id} />] + [2, <MyWidget id={id} />] + ]) + + const conns = [ + gobject.connect("added", (_, id) => map.set(id, MyWidget({ id }))), + gobject.connect("removed", (_, id) => map.delete(id, MyWidget({ id }))), + ] + + return <box onDestroy={() => conns.map(id => gobject.disconnect(id))}> + {bind(map).as(arr => arr.sort(([a], [b]) => a - b).map(([,w]) => w))} + </box> +} +``` + +## Example Custom Connectable + +Astal provides [decorator functions](./gobject#example-usage) +that make it easy to subclass gobjects, however +you can read more about GObjects and subclassing +on [gjs.guide](https://gjs.guide/guides/gobject/subclassing.html#gobject-subclassing). + +Objects coming from [libraries](../libraries/references#astal-libraries) +usually have a singleton gobject you can access with `.get_default()`. + +Here is an example of a Brightness library by wrapping the `brightnessctl` cli utility +and by monitoring `/sys/class/backlight` + +::: code-group + +```ts :line-numbers [brightness.ts] +import GObject, { register, property } from "astal/gobject" +import { monitorFile, readFileAsync } from "astal/file" +import { exec, execAsync } from "astal/process" + +const get = (args: string) => Number(exec(`brightnessctl ${args}`)) +const screen = exec(`bash -c "ls -w1 /sys/class/backlight | head -1"`) +const kbd = exec(`bash -c "ls -w1 /sys/class/leds | head -1"`) + +@register({ GTypeName: "Brightness" }) +export default class Brightness extends GObject.Object { + static instance: Brightness + static get_default() { + if (!this.instance) + this.instance = new Brightness() + + return this.instance + } + + #kbdMax = get(`--device ${kbd} max`) + #kbd = get(`--device ${kbd} get`) + #screenMax = get("max") + #screen = get("get") / (get("max") || 1) + + @property(Number) + get kbd() { return this.#kbd } + + set kbd(value) { + if (value < 0 || value > this.#kbdMax) + return + + execAsync(`brightnessctl -d ${kbd} s ${value} -q`).then(() => { + this.#kbd = value + this.notify("kbd") + }) + } + + @property(Number) + get screen() { return this.#screen } + + set screen(percent) { + if (percent < 0) + percent = 0 + + if (percent > 1) + percent = 1 + + execAsync(`brightnessctl set ${Math.floor(percent * 100)}% -q`).then(() => { + this.#screen = percent + this.notify("screen") + }) + } + + constructor() { + super() + + const screenPath = `/sys/class/backlight/${screen}/brightness` + const kbdPath = `/sys/class/leds/${kbd}/brightness` + + monitorFile(screenPath, async f => { + const v = await readFileAsync(f) + this.#screen = Number(v) / this.#screenMax + this.notify("screen") + }) + + monitorFile(kbdPath, async f => { + const v = await readFileAsync(f) + this.#kbd = Number(v) / this.#kbdMax + this.notify("kbd") + }) + } +} +``` + +::: + +And it can be used like any other library object. + +```tsx +function BrightnessSlider() { + const brightness = Brightness.get_default() + + return <slider + value={bind(brightness, "screen")} + onDragged={({ value }) => brightness.screen = value} + /> +} +``` diff --git a/docs/guide/ags/cli-app.md b/docs/guide/typescript/cli-app.md index ec6d174..f409176 100644 --- a/docs/guide/ags/cli-app.md +++ b/docs/guide/typescript/cli-app.md @@ -1,9 +1,13 @@ # CLI and App -`App` is a singleton **instance** of [Astal.Application](https://aylur.github.io/libastal/class.Application.html). +`App` is a singleton **instance** of an [Astal.Application](https://aylur.github.io/libastal/astal3/class.Application.html). + +Depending on gtk version import paths will differ ```ts -import { App } from "astal" +import { App } from "astal/gtk3" + +import { App } from "astal/gtk4" ``` ## Entry point @@ -21,10 +25,6 @@ App.start({ ::: -:::warning -You can not instantiate widgets outside of the main function. -::: - ## Instance identifier You can run multiple instance by defining a unique instance name. @@ -32,47 +32,48 @@ You can run multiple instance by defining a unique instance name. ```ts App.start({ instanceName: "my-instance", // defaults to "astal" - main() {}, + main() { }, }) ``` ## Messaging from CLI -If you want to interact with an instance from the cli, you can do so by sending a message. +If you want to interact with an instance from the CLI, +you can do so by sending a message. ```ts App.start({ - main() {}, requestHandler(request: string, res: (response: any) => void) { if (request == "say hi") { res("hi cli") } res("unknown command") }, + main() { }, }) ``` :::code-group -```sh [ags] -ags -m "say hi" +```sh [astal] +astal say hi # hi cli ``` -```sh [astal] -astal say hi +```sh [ags] +ags -m "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. +If you want to run arbitrary JavaScript from CLI, you can use `App.eval` +which will evaluate the passed string as the body of an `async` function. ```ts App.start({ main() {}, - requestHandler(js: string, res) { + requestHandler(js, res) { App.eval(js).then(res).catch(res) }, }) @@ -81,23 +82,23 @@ App.start({ If the string does not contain a semicolon, a single expression is assumed and returned implicity. ```sh -ags -m "'hello'" +astal "'hello'" # hello ``` If the string contains a semicolon, you have to return explicitly ```sh -ags -m "'hello';" +astal "'hello';" # undefined -ags -m "return 'hello';" +astal "return 'hello';" # hello ``` ## Toggling Windows by their name -In order for AGS to know about your windows, you have to register them. +In order for Astal to know about your windows, you have to register them. You can do this by specifying a **unique** `name` and calling `App.add_window` ```tsx {4} @@ -127,18 +128,24 @@ When assigning the `application` prop make sure `name` comes before. Props are set sequentially and if name is applied after application it won't work. ::: -```sh +:::code-group + +```sh [astal] +astal -t Bar +``` + +```sh [ags] ags -t Bar ``` -## App without AGS +::: + +## Bundled scripts -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 +The produced scripts when bundling can run as the main instance and a "client" instance. -The first time you run your bundled script the `main` function gets executed. +The first time you execute your bundled script the `main` function gets called. While that instance is running any subsequent execution of the script will call the `client` function. diff --git a/docs/guide/ags/faq.md b/docs/guide/typescript/faq.md index cb5d609..48c802c 100644 --- a/docs/guide/ags/faq.md +++ b/docs/guide/typescript/faq.md @@ -2,22 +2,22 @@ ## Monitor id does not match compositor -The monitor property that windows expect is mapped by Gdk, which is not always +The monitor id property that windows expect is mapped by Gdk, which is not always the same as the compositor. Instead use the `gdkmonitor` property which expects -a `Gdk.Monitor` object which you can get from compositor libraries. - -Example with Hyprland +a `Gdk.Monitor` object. ```tsx -import Hyprland from "gi://AstalHyprland" +import { App } from "astal" function Bar(gdkmonitor) { return <window gdkmonitor={gdkmonitor} /> } function main() { - for (const m of Hyprland.get_default().get_monitors()) { - Bar(m.gdk_monitor) + for (const monitor of App.get_monitors()) { + if (monitor.model == "your-desired-model") { + Bar(monitor) + } } } @@ -53,7 +53,7 @@ import GLib from "gi://GLib" const HOME = GLib.getenv("HOME") ``` -## Custom svg symbolic icons +## 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` @@ -90,74 +90,6 @@ print("print this line to stdout") printerr("print this line to stderr") ``` -## Binding custom structures - -The `bind` function can take two types of objects. - -```ts -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. - -```ts -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 MyVariable() - const label = bind(myvar).as(({ string, number }) => { - return `${string} ${number}` - }) - - return <label label={label} /> -} -``` - ## Populate the global scope with frequently accessed variables It might be annoying to always import Gtk only for `Gtk.Align` enums. @@ -272,7 +204,7 @@ notifd.get_notifications() // ✅ ## How to create regular floating windows -Use `Gtk.Window` with [Widget.astalify](/guide/ags/widget#how-to-use-non-builtin-gtk-widgets). +Use `Gtk.Window` with [Widget.astalify](/guide/typescript/widget#how-to-use-non-builtin-gtk-widgets). By default `Gtk.Window` is destroyed on close. To prevent this add a handler for `delete-event`. @@ -289,91 +221,46 @@ return <RegularWindow </RegularWindow> ``` -## Avoiding unnecessary re-rendering - -As mentioned before, any object can be bound that implements the `Subscribable` interface. - -```ts -interface Subscribable<T = unknown> { - subscribe(callback: (value: T) => void): () => void - get(): T -} -``` - -This can be used to our advantage to create a reactive `Map` object. - -```ts -import { type Subscribable } from "astal/binding" -import { Gtk } from "astal" - -export class VarMap<K, T = Gtk.Widget> implements Subscribable { - #subs = new Set<(v: Array<[K, T]>) => void>() - #map: Map<K, T> - - #notifiy() { - const value = this.get() - for (const sub of this.#subs) { - sub(value) - } - } - - #delete(key: K) { - const v = this.#map.get(key) - - if (v instanceof Gtk.Widget) { - v.destroy() - } - - this.#map.delete(key) - } +## Is there a way to limit the width/height of a widget? - constructor(initial?: Iterable<[K, T]>) { - this.#map = new Map(initial) - } +Unfortunately not. You can set a minimum size with `min-width` and `min-heigth` css attributes, +but you can not set max size. - add(key: K, value: T) { - this.#delete(key) - this.#map.set(key, value) - this.#notifiy() - } +## Custom widgets with bindable properties - delete(key: K) { - this.#delete(key) - this.#notifiy() - } +In function components you can wrap any primitive to handle both +binding and value cases as one. - get() { - return [...this.#map.entries()] +```tsx +function MyWidget(props: { prop: string | Binding<string> }) { + const prop = props.prop instanceof Binding + ? props.prop + : bind({ get: () => props.prop, subscribe: () => () => {} }) + + function setup(self: Widget.Box) { + self.hook(prop, () => { + const value = prop.get() + // handler + }) } - subscribe(callback: (v: Array<[K, T]>) => void) { - this.#subs.add(callback) - return () => this.#subs.delete(callback) - } + return <box setup={setup}> + </box> } ``` -And this `VarMap<key, Widget>` can be used as an alternative to `Variable<Array<Widget>>`. +You can pass the prop the super constructor in subclasses ```tsx -function MappedBox() { - const map = new VarMap([ - [1, <MyWidget id={id} />] - [2, <MyWidget id={id} />] - ]) - - const conns = [ - gobject.connect("added", (_, id) => map.set(id, MyWidget({ id }))), - gobject.connect("removed", (_, id) => map.delete(id, MyWidget({ id }))), - ] - - return <box onDestroy={() => conns.map(id => gobject.disconnect(id))}> - {bind(map).as(arr => arr.sort(([a], [b]) => a - b).map(([,w]) => w))} - </box> +@register() +class MyWidget extends Widget.Box { + @property(String) + set prop(v: string) { + // handler + } + + constructor(props: { prop: string | Binding<string> }) { + super(props) + } } ``` - -## Is there a way to limit the width/height of a widget? - -Unfortunately not. You can set a minimum size with `min-width` and `min-heigth` css attributes, -but you can not set max size. diff --git a/docs/guide/ags/first-widgets.md b/docs/guide/typescript/first-widgets.md index c4c4436..a7372a8 100644 --- a/docs/guide/ags/first-widgets.md +++ b/docs/guide/typescript/first-widgets.md @@ -1,15 +1,5 @@ # First Widgets -AGS is the predecessor of Astal, which was written purely in TypeScript and so only supported -JavaScript/TypeScript. Now it serves as a scaffolding tool for Astal projects in TypeScript. -While what made AGS what it is, is now part of the Astal project, for simplicity we will -refer to the Astal TypeScript lib as AGS. - -:::tip -If you are not familiar with the JavaScript syntax [MDN](https://developer.mozilla.org/en-US/) -and [javascript.info](https://javascript.info/) have great references. -::: - ## Getting Started Start by initializing a project @@ -24,19 +14,35 @@ then run `ags` in the terminal ags ``` -Done! You have now a custom written bar using Gtk. +:::details Usage without AGS +🚧 Not yet documented. 🚧 +::: + +That's it! You have now a custom written bar using Gtk. :::tip -AGS will transpile every `.ts`, `.jsx` and `.tsx` files into regular javascript then -it will bundle everything into a single javascript file which then GJS can execute. -The bundler used is [esbuild](https://esbuild.github.io/). +AGS will transpile every `.ts`, `.jsx` and `.tsx` files into regular JavaScript, then +it will bundle everything into a single JavaScript file which then GJS can execute. ::: +The AGS init command will generate the following files + +```txt +. +├── @girs/ # generated types +├── widget/ +│ └── Bar.tsx +├── app.ts # entry proint +├── env.d.ts # additional types +├── style.css +└── tsconfig.json # needed by LSPs +``` + ## Root of every shell component: Window Astal apps are composed of widgets. A widget is a piece of UI that has its own logic and style. A widget can be as small as a button or an entire bar. -The top level widget is always a [Window](https://aylur.github.io/libastal/class.Window.html) which will hold all widgets. +The top level widget is always a [Window](https://aylur.github.io/libastal/astal3/class.Window.html) which will hold all widgets. ::: code-group @@ -75,19 +81,19 @@ either by using JSX or using a widget constructor. ```tsx [MyButton.tsx] function MyButton(): JSX.Element { return <button onClicked="echo hello"> - Clicke Me! + <label label="Click me!" /> </button> } ``` ```ts [MyButton.ts] -import { Widget } from "astal" +import { Widget } from "astal/gtk3" function MyButton(): Widget.Button { - return Widget.Button({ - onClicked: "echo hello", - label: "Click Me!", - }) + return new Widget.Button( + { onClicked: "echo hello" }, + new Widget.Label({ label: "Click me!" }), + ) } ``` @@ -96,7 +102,7 @@ function MyButton(): Widget.Button { :::info The only difference between the two is the return type. Using markup the return type is always `Gtk.Widget` (globally available as `JSX.Element`), -while using constructors the return type is the type of the widget. +while using constructors the return type is the actual type of the widget. It is rare to need the actual return type, so most if not all of the time, you can use markup. ::: @@ -261,13 +267,12 @@ return <MyWidget myprop="hello"> ## State management -The state of widgets are handled with Bindings. A `Binding` lets you -connect the state of one [GObject](https://docs.gtk.org/gobject/class.Object.html) 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](./variable) or it can be from a [Library](../libraries/references). +The state of widgets are handled with Bindings. A [Binding](./binding) lets you +connect the state of an [object](./binding#subscribable-and-connectable-interface) +to a widget so it re-renders when that state changes. -We use the `bind` function to create a `Binding` object from a `Variable` or -a regular GObject and one of its properties. +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: @@ -349,26 +354,32 @@ return <box> <box> ``` -:::warning -Only bind children of the `box` or the `stack` 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. +:::tip +Binding children of widgets will implicitly call `.destroy()` on widgets +that would be left without a parent. You can opt out of this behavior +by setting `noImplicityDestroy` property on the container widget. ::: :::info -The above example destroys and recreates every widget in the list everytime +The above example destroys and recreates every widget in the list **every time** the value of the `Variable` changes. There might be cases where you would -want to [handle child creation and deletion](/guide/ags/faq#avoiding-unnecessary-re-rendering) +want to [handle child creation and deletion](/guide/typescript/faq#avoiding-unnecessary-re-rendering) yourself, because you don't want to lose the -inner state of widgets that does not need to be recreated. +inner state of widgets that does not need to be recreated. In this case +you can create a [custom reactive structure](./binding#example-custom-subscribable) ::: When there is at least one `Binding` passed as a child, the `children` -parameter will always be a flattened `Binding<Array<JSX.Element>>` +parameter will always be a flattened `Binding<Array<JSX.Element>>`. +When there is a single `Binding` passed as a child, the `child` parameter will +be a `Binding<JSX.Element>` or a flattened `Binding<Array<JSX.Element>>`. ```tsx -function MyContainer({ children }) { +import { type Binding } from "astal" + +function MyContainer({ children }: { + children?: Binding<Array<JSX.Element>> +}) { // children is a Binding over an Array of widgets } diff --git a/docs/guide/typescript/gobject.md b/docs/guide/typescript/gobject.md new file mode 100644 index 0000000..f7f001d --- /dev/null +++ b/docs/guide/typescript/gobject.md @@ -0,0 +1,165 @@ +# Subclassing GObject.Object + +Astal provides decorator functions that make it easy to subclass gobjects. + +## Example Usage + +```ts +import GObject, { register, property } from "astal/gobject" + +@register() +class MyObj extends GObject.Object { + @property(String) + declare myProp: string + + @signal(String, Number) + declare mySignal: (a: string, b: number) => void +} +``` + +## Property decorator + +```ts +type PropertyDeclaration = + | GObject.ParamSpec + | { $gtype: GObject.GType } + +function property(declaration: PropertyDeclaration) +``` + +The `property` decorator can take any class that has a registered GType. +This includes the globally available `String`, `Number`, `Boolean` and `Object` +javascript constructors. They are mapped to their relative `GObject.ParamSpec`. + +The property decorator can be applied in the following ways: + +1. On a property declaration + +```ts {3,4} +@register() +class MyObj extends GObject.Object { + @property(String) + declare myProp: string +} +``` + +This will create a getter and setter for the property and will also +emit the notify signal when the value is set to a new value. + +:::info +The `declare` keyword is required so that the property declaration +is not transpiled into JavaScript, otherwise the initial value of the +property would be `undefined`. +::: + +:::warning +The value is checked by reference, this is important if your +property is an object type. + +```ts +const dict = obj.prop +dict["key"] = 0 +obj.prop = dict // This will not emit notify::prop // [!code error] +obj.prop = { ...dict } // This will emit notify::prop +``` + +::: + +If you want to set a custom default value, do so in the constructor of your class. + +```ts {7} +@register() +class MyObj extends GObject.Object { + @property(String) + declare myProp: string + + constructor() { + super({ myProp: "default-value" }) + } +} +``` + +2. On a getter + +```ts {3,4} +@register() +class MyObj extends GObject.Object { + @property(String) + get myProp () { + return "value" + } +} +``` + +This will create a read-only property. + +3. On a getter and setter + +```ts {5,6,10} +@register() +class MyObj extends GObject.Object { + declare private _prop: string + + @property(String) + get myProp () { + return "value" + } + + set myProp (v: string) { + if (v !== this._prop) { + this._prop = v + this.notify("my-prop") + } + } +} +``` + +This will create a read-write property. + +:::info +When defining getter/setters for the property, notify signal emission has to be done explicitly. +::: + +## Signal decorator + +```ts +function signal(...params: Array<{ $gtype: GObject.GType }) + +function signal(declaration?: SignalDeclaration) // Object you would pass to GObject.registerClass +``` + +You can apply the signal decorator to either a property declaration or a method. + +```ts {3,4,6,7} +@register() +class MyObj extends GObject.Object { + @signal(String, String) + declare mySig: (a: String, b: String) => void + + @signal(String, String) + mySig(a: string, b: string) { + // default signal handler + } +} +``` + +You can emit the signal by calling the signal method or using `emit`. + +```ts +const obj = new MyObj() +obj.connect("my-sig", (obj, a: string, b: string) => {}) + +obj.mySig("a", "b") +obj.emit("my-sig", "a", "b") +``` + +## Register decorator + +Every GObject subclass has to be registered. You can pass the same options +to this decorator as you would to `GObject.registerClass` + +```ts +@register({ GTypeName: "MyObj" }) +class MyObj extends GObject.Object { +} +``` diff --git a/docs/guide/typescript/installation.md b/docs/guide/typescript/installation.md new file mode 100644 index 0000000..f1d20c5 --- /dev/null +++ b/docs/guide/typescript/installation.md @@ -0,0 +1,90 @@ +# Installation + +It is recommended to use [AGS](https://github.com/aylur/ags) +to scaffold and run projects in TypeScript. + +It lets you + +- generate TypeScript types using [ts-for-gir](https://github.com/gjsify/ts-for-gir) +- generate a tsconfig which is used by LSPs +- bundle your TypeScript and JavaScript code using [esbuild](https://esbuild.github.io/). + +:::details Trivia +AGS is the predecessor of Astal, which was written purely in TypeScript and so only supported +JavaScript/TypeScript. Now it serves as a scaffolding tool for Astal+TypeScript+JSX projects. +::: + +## Nix + +maintainer: [@Aylur](https://github.com/Aylur) + +Read more about it on the [nix page](../getting-started/nix#ags) + +You can try without installing. + +<!--TODO: remove v2 after merge--> +```sh +nix run github:aylur/ags/v2#agsFull -- --help +``` + +## From source + +1. [Install Astal](../getting-started/installation.md) if you have not already + +2. Install the Astal GJS package + +```sh +git clone https://github.com/aylur/astal /tmp/astal +cd /tmp/astal/lang/gjs +meson setup --prefix /usr build +meson install -C build +``` + +:::tip +You might be wondering why it is recommended to install a JavaScript +package on the system instead of installing it as a node module. +It is solely to keep it in **sync** with the core `astal-io` and `astal3`/`astal4` package. +::: + +3. Install the following dependencies + +:::code-group + +```sh [<i class="devicon-archlinux-plain"></i> Arch] +sudo pacman -Syu go npm gjs +``` + +```sh [<i class="devicon-fedora-plain"></i> Fedora] +sudo dnf install golang npm gjs +``` + +```sh [<i class="devicon-ubuntu-plain"></i> Ubuntu] +sudo apt install golang-go npm gjs +``` + +::: + +3. Clone the repo and Install + +<!--TODO: remove v2 after merge--> +```sh +git clone https://github.com/aylur/ags.git /tmp/ags +cd /tmp/ags +git checkout v2 # https://github.com/Aylur/ags/pull/504 +cd src +go install +``` + +:::tip +`go install` installs the `ags` binary to `$GOPATH/bin` so make sure its in your `$PATH`. +You can move it to another directory if you like. For example + +```sh +sudo mv $GOPATH/bin/ags /usr/bin/ags +``` + +::: + +## Without AGS + +🚧 Setting up a dev environment without AGS is not yet documented. 🚧 diff --git a/docs/guide/ags/theming.md b/docs/guide/typescript/theming.md index cb0ebff..10a3981 100644 --- a/docs/guide/ags/theming.md +++ b/docs/guide/typescript/theming.md @@ -23,7 +23,9 @@ You can pass a path to a file or css as a string in `App.start` :::code-group ```ts [app.ts] -const inlineCss = ` +import style from "inline:./style.css" + +const inlineCssInCode = ` window { background-color: transparent; } @@ -31,6 +33,7 @@ window { App.start({ css: "./style.css", + css: style, css: `${SRC}/style.css'`, css: inlineCss, }) @@ -39,8 +42,9 @@ App.start({ ::: :::info -The global `SRC` will point to the directory `app.ts` is in. +When using AGS the global `SRC` will point to the directory `app.ts` is in. AGS will set the current working directory to `--config`, so `./style.css` also works. +If you are not using AGS you should inline import CSS instead. ::: ## Css Property on Widgets @@ -86,11 +90,20 @@ You can reset stylesheets with `App.resetCss` 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) -```sh +::: code-group + +```sh [astal] +# to bring up the inspector run +astal --inspector +``` + +```sh [ags] # to bring up the inspector run ags --inspector ``` +::: + ## Using SCSS Gtk's CSS only supports a subset of what the web offers. @@ -128,6 +141,11 @@ App.start({ ::: +:::details Without AGS +AGS uses a plugin to transpile scss files before importing them. +If you are not using AGS, you can use a plugin for your chosen bundler. +::: + :::tip If you for example want to set scss varibles from JS, You can inline import, compose, and transpile yourself. diff --git a/docs/guide/ags/utilities.md b/docs/guide/typescript/utilities.md index 42589d3..361c33b 100644 --- a/docs/guide/ags/utilities.md +++ b/docs/guide/typescript/utilities.md @@ -2,16 +2,10 @@ ## File functions -Import them from `astal` or `astal/file` +Import from `astal` or `astal/file` ```ts -import { - readFile, - readFileAsync, - writeFile, - writeFileAsync, - monitorFile, -} from "astal" +import { readFile, readFileAsync, writeFile, writeFileAsync, monitorFile, } from "astal/file" ``` ### Reading files @@ -30,6 +24,8 @@ function writeFileAsync(path: string, content: string): Promise<void> ### Monitoring files +If `path` is a directory it will be recursively monitored. + ```ts function monitorFile( path: string, @@ -39,25 +35,25 @@ function monitorFile( ## Timeouts and Intervals -Import them from `astal` or `astal/time` +Import from `astal` or `astal/time` ```ts -import { interval, timeout, idle } from "astal" +import { interval, timeout, idle } from "astal/time" ``` You can use javascript native `setTimeout` or `setInterval` they return a [GLib.Source](https://docs.gtk.org/glib/struct.Source.html) instance. Alternatively you can use these functions provided by Astal, -which return an [Astal.Time](https://aylur.github.io/libastal/class.Time.html) instance. +which return an [AstalIO.Time](https://aylur.github.io/libastal/io/class.Time.html) instance. -`Astal.Time` has a `now` signal and a `cancelled` signal. +`AstalIO.Time` has a `now` signal and a `cancelled` signal. ### Interval Will immediately execute the function and every `interval` millisecond. ```ts -function interval(interval: number, callback?: () => void): Astal.Time +function interval(interval: number, callback?: () => void): AstalIO.Time ``` ### Timeout @@ -65,7 +61,7 @@ function interval(interval: number, callback?: () => void): Astal.Time Will execute the `callback` after `timeout` millisecond. ```ts -function timeout(timeout: number, callback?: () => void): Astal.Time +function timeout(timeout: number, callback?: () => void): AstalIO.Time ``` ### Idle @@ -73,7 +69,7 @@ function timeout(timeout: number, callback?: () => void): Astal.Time Executes `callback` whenever there are no higher priority events pending. ```ts -function idle(callback?: () => void): Astal.Time +function idle(callback?: () => void): AstalIO.Time ``` Example: @@ -96,29 +92,29 @@ timer.cancel() ## Process functions -Import them from `astal` or `astal/proc` +Import from `astal` or `astal/process` ```ts -import { subprocess, exec, execAsync } from "astal" +import { subprocess, exec, execAsync } from "astal/process" ``` ### Subprocess You can start a subprocess and run callback functions whenever it outputs to -stdout or stderr. [Astal.Process](https://aylur.github.io/libastal/class.Process.html) has a `stdout` and `stderr` signal. +stdout or stderr. [AstalIO.Process](https://aylur.github.io/libastal/io/class.Process.html) has a `stdout` and `stderr` signal. ```ts function subprocess(args: { cmd: string | string[] out?: (stdout: string) => void err?: (stderr: string) => void -}): Astal.Process +}): AstalIO.Process function subprocess( cmd: string | string[], onOut?: (stdout: string) => void, onErr?: (stderr: string) => void, -): Astal.Process +): AstalIO.Process ``` Example: @@ -132,8 +128,8 @@ const proc = subprocess( // or with signals const proc = subprocess("some-command") -proc.connect("stdout", (out) => console.log(out)) -proc.connect("stderr", (err) => console.error(err)) +proc.connect("stdout", (_, out) => console.log(out)) +proc.connect("stderr", (_, err) => console.error(err)) ``` ### Executing external commands and scripts @@ -161,7 +157,7 @@ execAsync(["bash", "-c", "/path/to/script.sh"]) :::warning `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`, +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. diff --git a/docs/guide/ags/variable.md b/docs/guide/typescript/variable.md index 96e8d38..e6f3434 100644 --- a/docs/guide/ags/variable.md +++ b/docs/guide/typescript/variable.md @@ -4,17 +4,17 @@ import { Variable } from "astal" ``` -Variable is just a simple `GObject` that holds a value. -And has shortcuts for hooking up subprocesses. +Variable is just a simple object which holds a single value. +It also has some shortcuts for hooking up subprocesses, intervals and other gobjects. :::info -The `Variable` object imported from the `"astal"` package is **not** [Astal.Variable](https://aylur.github.io/libastal/class.Variable.html). +The `Variable` object imported from the `"astal"` package is **not** [Astal.Variable](https://aylur.github.io/libastal/io/class.Variable.html). ::: -## Variable as state +## Example Usage ```typescript -const myvar = Variable<string>("initial-value") +const myvar = Variable("initial-value") // whenever its value changes, callback will be executed myvar.subscribe((value: string) => { @@ -35,43 +35,49 @@ Widget.Label({ ``` :::warning -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. +Make sure to the transform functions you pass to `:as()` are pure. +The `.get()` function can be called anytime by `astal` especially when `deriving`, +so make sure there are no sideeffects. ::: -## Composing variables +## Variable Composition -Using `Variable.derive` we can compose both Variables and Bindings. +Using `Variable.derive` any `Subscribable` object can be composed. ```typescript -const v1: Variable<number> = Variable(2) -const v2: Variable<number> = Variable(3) +const v1: Variable<number> = Variable(1) +const v2: Binding<number> = bind(obj, "prop") +const v3: Subscribable<number> = { + get: () => 3, + subscribe: () => () => {}, +} // 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}` -}) +const v4: Variable<number> = Variable.derive( + [v1, v2, v3], + (v1: number, v2: number, v3: number) => { + return v1 * v2 * v3 + } +) ``` +:::info +The types are only for demonstration purposes, you do not have to declare +the type of a Variable, they will be inferred from their initial value. +::: + ## 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. +Using `.poll` and `.watch` we can start subprocesses and capture their +output. They can poll and watch at the same time, but they +can only poll/watch once. :::warning -The command parameter is passed to [execAsync](/guide/ags/utilities#executing-external-commands-and-scripts) +The command parameter is passed to [execAsync](/guide/typescript/utilities#executing-external-commands-and-scripts) which means they are **not** executed in a shell environment, -they do **not** expand env variables like `$HOME`, +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. @@ -83,14 +89,14 @@ Variable("").poll(1000, ["bash", "-c", "command $VAR && command"]) ::: ```typescript -const myVar = Variable<number>(0) +const myVar = Variable(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) +const myVar = Variable(0) .watch("command", (out: string, prev: number) => parseInt(out)) .watch(["bash", "-c", "command"], (out, prev) => parseInt(out)) ``` @@ -120,21 +126,27 @@ const myvar = Variable("") ## Dispose if no longer needed -This will stop the interval and force exit the subprocess and disconnect gobjects. +This will stop the interval, force exit the subprocess and disconnect gobjects. ```js myVar.drop() ``` :::warning -Don't forget to drop them when they are defined inside widgets -with either `.poll`, `.watch` or `.observe` +Don't forget to drop derived variables or variables with +either `.poll`, `.watch` or `.observe` when they are defined inside closures. ```tsx function MyWidget() { const myvar = Variable().poll() - - return <box onDestroy={() => myvar.drop()} /> + const derived = Variable.derive() + + return <box + onDestroy={() => { + myvar.drop() + derived.drop() + }} + /> } ``` diff --git a/docs/guide/ags/widget.md b/docs/guide/typescript/widget.md index 1fe755f..7ed69e3 100644 --- a/docs/guide/ags/widget.md +++ b/docs/guide/typescript/widget.md @@ -1,8 +1,10 @@ # Widget -## AGS widget properties +## Gtk3 -These are properties that Astal.js additionally adds to Gtk.Widgets +### Additional widget properties + +These are properties that Astal 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; }`. @@ -11,16 +13,15 @@ These are properties that Astal.js additionally adds to Gtk.Widgets To have a full list of available properties, reference the documentation of the widget. -- [Astal widgets](https://aylur.github.io/libastal/index.html#classes) +- [Astal3 widgets](https://aylur.github.io/libastal/astal3/index.html#classes) - [Gtk widgets](https://docs.gtk.org/gtk3/#classes) -## AGS widget methods - -Additional methods that Astal.js adds to Gtk.Widget instances +### Additional widget methods -### setup +#### setup -`setup` is a convenience prop to not have predefine widgets before returning them +`setup` is a convenience prop to remove the need to predefine widgets +before returning them in cases where a reference is needed. without `setup` @@ -44,19 +45,21 @@ function MyWidget() { } ``` -### hook +#### hook -Shorthand for connection and disconnecting to gobjects. +Shorthand for connection and disconnecting to [Subscribable and Connectable](./binding#subscribable-and-connectable-interface) objects. without `hook` ```tsx function MyWidget() { const id = gobject.connect("signal", callback) + const unsub = variable.subscribe(callback) return <box onDestroy={() => { gobject.disconnect(id) + unsub() }} /> } @@ -69,12 +72,13 @@ function MyWidget() { return <box setup={(self) => { self.hook(gobject, "signal", callback) + self.hook(variable, callback) }} /> } ``` -### toggleClassName +#### toggleClassName Toggle classNames based on a condition @@ -88,35 +92,38 @@ function MyWidget() { } ``` -## How to use non builtin Gtk widgets +### 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: +Using the `Widget.astalify` mixin you can subclass widgets +to behave like builtin widgets. +The `astalify` mixin 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> +import GObject from "gi://GObject" +import { Gtk, Gdk, Widget, astalify, type ConstructProps } from "astal/gtk3" + +// subclass, register, define constructor props +class ColorButton extends astalify(Gtk.ColorButton) { + static { GObject.registerClass(this) } + + constructor(props: ConstructProps< + ColorButton, + Gtk.ColorButton.ConstructorProps, + { onColorSet: [] } // signals of Gtk.ColorButton have to be manually typed + >) { + super(props as any) + } +} function MyWidget() { - function setup(button: ColorButton) {} + function setup(button: ColorButton) { + + } return <ColorButton setup={setup} @@ -140,36 +147,14 @@ You can reference [Gtk3](https://gjs-docs.gnome.org/gtk30~3.0/) and [Astal](https://aylur.github.io/libastal/index.html#classes) for available signals. ::: -:::tip - -As stated before children are passed as either `child` or `children` property, -when passing a container widget with `Widget.astalify` these rules still apply. -While subclasses of `Gtk.Bin` *can* take a `child` property in gjs, you might notice -a warning that it is deprecated. You can workaround this with a simple wrapper function. - -```tsx -const GtkFrame = Widget.astalify< - typeof Gtk.Frame, - FrameProps, - "Frame" ->(Gtk.Frame) - -export function Frame({ child, ...props }: FrameProps) { - const frame = GtkFrame(props) - frame.add(child) // use the widget's child adding function - return frame -} -``` - -::: - -## TypeScript +### TypeScript Type of widgets are available through `Widget`. Here is an example Widget that takes in and handles a possibly `Binding` prop. ```tsx -import { Binding, Variable, Widget } from "astal" +import { Binding, Variable } from "astal" +import { Widget } from "astal/gtk3" export interface ToggleButtonProps extends Widget.ButtonProps { onToggled?: (self: Widget.Button, on: boolean) => void @@ -202,26 +187,30 @@ export default function ToggleButton(btnprops: ToggleButtonProps) { } ``` -## Builtin Widgets +### Builtin Widgets -You can check the [source code](https://github.com/aylur/astal/blob/main/core/gjs/src/widgets.ts) to have a full list of builtin widgets. +You can check the [source code](https://github.com/aylur/astal/blob/main/lang/gjs/src/gtk3/index.ts) to have a full list of builtin widgets. These widgets are available by default in JSX. -- box: [Astal.Box](https://aylur.github.io/libastal/class.Box.html) -- button: [Astal.Button](https://aylur.github.io/libastal/class.Button.html) -- centerbox: [Astal.CenterBox](https://aylur.github.io/libastal/class.CenterBox.html) -- circularprogress: [Astal.CircularProgress](https://aylur.github.io/libastal/class.CircularProgress.html) +- box: [Astal.Box](https://aylur.github.io/libastal/astal3/class.Box.html) +- button: [Astal.Button](https://aylur.github.io/libastal/astal3/class.Button.html) +- centerbox: [Astal.CenterBox](https://aylur.github.io/libastal/astal3/class.CenterBox.html) +- circularprogress: [Astal.CircularProgress](https://aylur.github.io/libastal/astal3/class.CircularProgress.html) - drawingarea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/class.DrawingArea.html) - entry: [Gtk.Entry](https://docs.gtk.org/gtk3/class.Entry.html) -- eventbox: [Astal.EventBox](https://aylur.github.io/libastal/class.EventBox.html) -- icon: [Astal.Icon](https://aylur.github.io/libastal/class.Icon.html) -- label: [Astal.Label](https://aylur.github.io/libastal/class.Label.html) -- levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/class.LevelBar.html) -- overlay: [Astal.Overlay](https://aylur.github.io/libastal/class.Overlay.html) +- eventbox: [Astal.EventBox](https://aylur.github.io/libastal/astal3/class.EventBox.html) +- icon: [Astal.Icon](https://aylur.github.io/libastal/astal3/class.Icon.html) +- label: [Astal.Label](https://aylur.github.io/libastal/astal3/class.Label.html) +- levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/astal3/class.LevelBar.html) +- overlay: [Astal.Overlay](https://aylur.github.io/libastal/astal3/class.Overlay.html) - revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/class.Revealer.html) -- scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/class.Scrollable.html) -- slider: [Astal.Slider](https://aylur.github.io/libastal/class.Slider.html) -- stack: [Astal.Stack](https://aylur.github.io/libastal/class.Stack.html) +- scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/astal3/class.Scrollable.html) +- slider: [Astal.Slider](https://aylur.github.io/libastal/astal3/class.Slider.html) +- stack: [Astal.Stack](https://aylur.github.io/libastal/astal3/class.Stack.html) - switch: [Gtk.Switch](https://docs.gtk.org/gtk3/class.Switch.html) -- window: [Astal.Window](https://aylur.github.io/libastal/class.Window.html) +- window: [Astal.Window](https://aylur.github.io/libastal/astal3/class.Window.html) + +## Gtk4 + +🚧 Work in Progress 🚧 diff --git a/docs/index.md b/docs/index.md index f22ae19..8f5287b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,7 +5,7 @@ pageClass: home-page hero: name: "Astal" text: "Create Beautiful Widgets With Ease" - tagline: "The Framework to Craft Desktop Shells and <i>beautiful</i> <i>functional</i> Wayland Widgets with GTK!" + tagline: "The Linux Suite and Framework to Craft Desktop Shells and <i>beautiful</i> <i>functional</i> Wayland Widgets with GTK!" image: /icon.svg actions: - theme: brand @@ -21,10 +21,10 @@ hero: features: - title: Use Your Preferred Language icon: <i style="color:var(--vp-c-brand-3)" class="devicon-typescript-plain"></i> - details: The main focus of Astal is TypeScript using JSX. But you can use the libraries in any language that supports <a href="https://en.wikipedia.org/wiki/List_of_language_bindings_for_GTK">Gobject Introspection</a>. + details: The main focus of Astal is TypeScript+JSX. But you can use the libraries in any language that supports <a href="https://en.wikipedia.org/wiki/List_of_language_bindings_for_GTK">Gobject Introspection</a>. - title: No bash scripts needed icon: <i style="color:var(--vp-c-brand-3)" class="devicon-bash-plain"></i> - details: Includes modules to work with Network, Bluetooth, Battery, Audio and more. + details: Includes modules to work with Network, Bluetooth, Battery, Audio and <a href="/astal/guide/libraries/references#astal-libraries">more</a>. - title: Use any Gtk widget icon: <i style="color:var(--vp-c-brand-3)" class="fl-gtk"></i> details: With Astal you work with Gtk directly. You are not limited to only a set of them. @@ -56,6 +56,7 @@ features: .VPFeature a { font-weight: bold; + color: var(--vp-c-brand-2); } .VPFooter { diff --git a/docs/package-lock.json b/docs/package-lock.json index 30daaa4..1f821b0 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -10,6 +10,11 @@ "font-logos": "^1.2.0" }, "devDependencies": { + "@eslint/js": "^9.12.0", + "@stylistic/eslint-plugin": "^2.9.0", + "eslint-plugin-vue": "^9.28.0", + "typescript": "^5.6.3", + "typescript-eslint": "^8.8.1", "vitepress": "^1.3.4", "vitepress-plugin-auto-sidebar": "^1.2.0", "vue": "^3.4.38" @@ -456,61 +461,10 @@ } } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { + "node_modules/@esbuild/linux-x64": { "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -518,333 +472,266 @@ "license": "MIT", "optional": true, "os": [ - "android" + "linux" ], "engines": { "node": ">=12" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], "engines": { - "node": ">=12" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=12" + "node": "*" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], + "node_modules/@eslint/core": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", + "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "peer": true, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } + "license": "Python-2.0", + "peer": true }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=12" + "node": "*" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/js": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", + "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "license": "Apache-2.0", + "peer": true, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/plugin-kit": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", + "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "levn": "^0.4.1" + }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], + "node_modules/@humanfs/core": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", + "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], + "license": "Apache-2.0", + "peer": true, "engines": { - "node": ">=12" + "node": ">=18.18.0" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], + "node_modules/@humanfs/node": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", + "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@humanfs/core": "^0.19.0", + "@humanwhocodes/retry": "^0.3.0" + }, "engines": { - "node": ">=12" + "node": ">=18.18.0" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "Apache-2.0", + "peer": true, "engines": { - "node": ">=12" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], + "node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "Apache-2.0", + "peer": true, "engines": { - "node": ">=12" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@jridgewell/sourcemap-codec": { @@ -854,159 +741,43 @@ "dev": true, "license": "MIT" }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz", - "integrity": "sha512-SU5cvamg0Eyu/F+kLeMXS7GoahL+OoizlclVFX3l5Ql6yNlywJJ0OuqTzUx0v+aHhPHEB/56CT06GQrRrGNYww==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.5.tgz", - "integrity": "sha512-S4pit5BP6E5R5C8S6tgU/drvgjtYW76FBuG6+ibG3tMvlD1h9LHVF9KmlmaUBQ8Obou7hEyS+0w+IR/VtxwNMQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.5.tgz", - "integrity": "sha512-250ZGg4ipTL0TGvLlfACkIxS9+KLtIbn7BCZjsZj88zSg2Lvu3Xdw6dhAhfe/FjjXPVNCtcSp+WZjVsD3a/Zlw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.5.tgz", - "integrity": "sha512-D8brJEFg5D+QxFcW6jYANu+Rr9SlKtTenmsX5hOSzNYVrK5oLAEMTUgKWYJP+wdKyCdeSwnapLsn+OVRFycuQg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.5.tgz", - "integrity": "sha512-PNqXYmdNFyWNg0ma5LdY8wP+eQfdvyaBAojAXgO7/gs0Q/6TQJVXAXe8gwW9URjbS0YAammur0fynYGiWsKlXw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.5.tgz", - "integrity": "sha512-kSSCZOKz3HqlrEuwKd9TYv7vxPYD77vHSUvM2y0YaTGnFc8AdI5TTQRrM1yIp3tXCKrSL9A7JLoILjtad5t8pQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.5.tgz", - "integrity": "sha512-oTXQeJHRbOnwRnRffb6bmqmUugz0glXaPyspp4gbQOPVApdpRrY/j7KP3lr7M8kTfQTyrBUzFjj5EuHAhqH4/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.5.tgz", - "integrity": "sha512-qnOTIIs6tIGFKCHdhYitgC2XQ2X25InIbZFor5wh+mALH84qnFHvc+vmWUpyX97B0hNvwNUL4B+MB8vJvH65Fw==", - "cpu": [ - "arm64" - ], + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.5.tgz", - "integrity": "sha512-TMYu+DUdNlgBXING13rHSfUc3Ky5nLPbWs4bFnT+R6Vu3OvXkTkixvvBKk8uO4MT5Ab6lC3U7x8S8El2q5o56w==", - "cpu": [ - "ppc64" - ], + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">= 8" + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.5.tgz", - "integrity": "sha512-PTQq1Kz22ZRvuhr3uURH+U/Q/a0pbxJoICGSprNLAoBEkyD3Sh9qP5I0Asn0y0wejXQBbsVMRZRxlbGFD9OK4A==", - "cpu": [ - "riscv64" - ], + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.5.tgz", - "integrity": "sha512-bR5nCojtpuMss6TDEmf/jnBnzlo+6n1UhgwqUvRoe4VIotC7FG1IKkyJbwsT7JDsF2jxR+NTnuOwiGv0hLyDoQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.22.5", @@ -1036,48 +807,6 @@ "linux" ] }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.5.tgz", - "integrity": "sha512-RXT8S1HP8AFN/Kr3tg4fuYrNxZ/pZf1HemC5Tsddc6HzgGnJm0+Lh5rAHJkDuW3StI0ynNXukidROMXYl6ew8w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.5.tgz", - "integrity": "sha512-ElTYOh50InL8kzyUD6XsnPit7jYCKrphmddKAe1/Ytt74apOxDq5YEcbsiKs0fR3vff3jEneMM+3I7jbqaMyBg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.5.tgz", - "integrity": "sha512-+lvL/4mQxSV8MukpkKyyvfwhH266COcWlXE/1qxwN08ajovta3459zrjLghYMgDerlzNwLAcFpvU+WWE5y6nAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@shikijs/core": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.21.0.tgz", @@ -1144,6 +873,26 @@ "dev": true, "license": "MIT" }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.9.0.tgz", + "integrity": "sha512-OrDyFAYjBT61122MIY1a3SfEgy3YCMgt2vL4eoPmvTwDBwyQhAXurxNQznlRD/jESNfYWfID8Ej+31LljvF7Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.8.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -1161,6 +910,14 @@ "@types/unist": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", @@ -1210,6 +967,209 @@ "dev": true, "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz", + "integrity": "sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.8.1", + "@typescript-eslint/type-utils": "8.8.1", + "@typescript-eslint/utils": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.1.tgz", + "integrity": "sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.8.1", + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/typescript-estree": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz", + "integrity": "sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz", + "integrity": "sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.8.1", + "@typescript-eslint/utils": "8.8.1", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.1.tgz", + "integrity": "sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz", + "integrity": "sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/visitor-keys": "8.8.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.1.tgz", + "integrity": "sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.8.1", + "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/typescript-estree": "8.8.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz", + "integrity": "sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.8.1", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -1563,6 +1523,47 @@ } } }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/algoliasearch": { "version": "4.24.0", "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.24.0.tgz", @@ -1630,6 +1631,23 @@ "@algolia/requester-common": "4.24.0" } }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1640,6 +1658,13 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/birpc": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.17.tgz", @@ -1650,6 +1675,47 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -1661,6 +1727,24 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/character-entities-html4": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", @@ -1683,6 +1767,28 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -1694,6 +1800,14 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/copy-anything": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", @@ -1710,6 +1824,35 @@ "url": "https://github.com/sponsors/mesqueeb" } }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -1717,6 +1860,32 @@ "dev": true, "license": "MIT" }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -1799,6 +1968,196 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz", + "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.6.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.12.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.5", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.1.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.29.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.29.0.tgz", + "integrity": "sha512-hamyjrBhNH6Li6R1h1VF9KHfshJlKgKEg3ARbGTn72CMNDSMhWbgC7NdkRDEh25AFW+4SDATzyNM+3gWuZii8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.3", + "vue-eslint-parser": "^9.4.3", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-vue/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", + "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1813,6 +2172,42 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -1820,6 +2215,149 @@ "dev": true, "license": "MIT" }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC", + "peer": true + }, "node_modules/focus-trap": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.0.tgz", @@ -1846,19 +2384,50 @@ "js-yaml": "^3.13.1" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "peer": true, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" } }, "node_modules/hast-util-to-html": { @@ -1917,6 +2486,78 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-what": { "version": "4.1.16", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", @@ -1930,6 +2571,14 @@ "url": "https://github.com/sponsors/mesqueeb" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC", + "peer": true + }, "node_modules/js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", @@ -1944,6 +2593,88 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -1983,6 +2714,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/micromark-util-character": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", @@ -2077,6 +2818,49 @@ ], "license": "MIT" }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/minisearch": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.1.0.tgz", @@ -2091,6 +2875,13 @@ "dev": true, "license": "MIT" }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -2110,6 +2901,26 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/oniguruma-to-js": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/oniguruma-to-js/-/oniguruma-to-js-0.4.3.tgz", @@ -2123,6 +2934,95 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/perfect-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", @@ -2137,6 +3037,19 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/postcss": { "version": "8.4.47", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", @@ -2166,6 +3079,20 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/preact": { "version": "10.24.1", "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.1.tgz", @@ -2177,6 +3104,17 @@ "url": "https://opencollective.com/preact" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/property-information": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", @@ -2188,6 +3126,38 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/regex": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/regex/-/regex-4.3.2.tgz", @@ -2195,6 +3165,28 @@ "dev": true, "license": "MIT" }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -2238,6 +3230,30 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/search-insights": { "version": "2.17.2", "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.2.tgz", @@ -2246,6 +3262,44 @@ "license": "MIT", "peer": true }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/shiki": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.21.0.tgz", @@ -2314,6 +3368,20 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/superjson": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.1.tgz", @@ -2327,6 +3395,20 @@ "node": ">=16" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tabbable": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", @@ -2334,6 +3416,14 @@ "dev": true, "license": "MIT" }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -2344,6 +3434,19 @@ "node": ">=4" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -2355,6 +3458,84 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.1.tgz", + "integrity": "sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.8.1", + "@typescript-eslint/parser": "8.8.1", + "@typescript-eslint/utils": "8.8.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/unist-util-is": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", @@ -2428,6 +3609,24 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -2593,6 +3792,131 @@ } } }, + "node_modules/vue-eslint-parser": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", + "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/docs/package.json b/docs/package.json index 0bc5ce1..fea7e8f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -2,6 +2,11 @@ "name": "docs", "type": "module", "devDependencies": { + "@eslint/js": "^9.12.0", + "@stylistic/eslint-plugin": "^2.9.0", + "eslint-plugin-vue": "^9.28.0", + "typescript": "^5.6.3", + "typescript-eslint": "^8.8.1", "vitepress": "^1.3.4", "vitepress-plugin-auto-sidebar": "^1.2.0", "vue": "^3.4.38" @@ -10,7 +15,8 @@ "dev": "vitepress dev", "build": "vitepress build", "preview": "vitepress preview", - "vitepress": "vitepress" + "vitepress": "vitepress", + "lint": "eslint . --fix" }, "dependencies": { "devicon": "^2.16.0", diff --git a/docs/public/showcase/aylur1.png b/docs/public/showcase/aylur.png Binary files differindex 5dc5dd7..5dc5dd7 100644 --- a/docs/public/showcase/aylur1.png +++ b/docs/public/showcase/aylur.png diff --git a/docs/public/showcase/kotontrion-kompass.webp b/docs/public/showcase/kotontrion-kompass.webp Binary files differnew file mode 100644 index 0000000..f622cfd --- /dev/null +++ b/docs/public/showcase/kotontrion-kompass.webp diff --git a/docs/public/showcase/tokyob0t-super-duper-hiper-mega-ultra-contribution.webp b/docs/public/showcase/tokyob0t-super-duper-hiper-mega-ultra-contribution.webp Binary files differnew file mode 100644 index 0000000..94f6080 --- /dev/null +++ b/docs/public/showcase/tokyob0t-super-duper-hiper-mega-ultra-contribution.webp diff --git a/docs/showcases/Showcase.vue b/docs/showcases/Showcase.vue index a5a1e01..d58986b 100644 --- a/docs/showcases/Showcase.vue +++ b/docs/showcases/Showcase.vue @@ -1,38 +1,149 @@ <script setup> -const props = defineProps({ - src: { type: String, required: true }, - label: { type: String, required: true }, - url: { type: String, required: true } -}); +import { VPButton } from "vitepress/theme" +defineProps({ + image: { type: String, required: true }, + url: { type: String, required: true }, + icon: { type: String, required: false, default: "" }, + title: { type: String, required: false, default: "" }, + description: { type: String, required: false, default: "" }, + author: { type: String, required: true }, +}) </script> <template> <figure> - <a :href="url"> - <img :src="src" :alt="label" /> - </a> - <figcaption> - <span>{{ label }}</span> - </figcaption> + <div class="image-wrapper"> + <img :src="image" :alt="title"> + <div class="overlay"> + <div class="text-content"> + <h3 v-if="title.length"> + {{ title }} + </h3> + <h3 v-else> + {{ author }}'s dotfiles + </h3> + <p v-if="description"> + {{ description }} + </p> + <span class="author">— {{ author }}</span> + <VPButton + tag + :href="url" + target="_blank" + size="medium" + text="View Setup" + /> + </div> + </div> + <i + v-if="icon" + :class="icon" + class="language-icon" + /> + </div> </figure> </template> <style scoped> -img { - border-radius: 4px; -} - -/* same as VPFeature */ figure { - padding: 0.8rem; - padding-bottom: 0; - border-radius: 12px; + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 1rem; + border-radius: 1rem; background-color: var(--vp-c-bg-soft); + transition: + box-shadow 0.3s ease, + transform 0.3s ease; +} + +figure:hover { + box-shadow: 0 1.5rem 3rem rgba(0, 0, 0, 0.2); + transform: translateY(-1rem); +} + +.image-wrapper { + position: relative; + width: 100%; + border-radius: 0.5rem; + overflow: hidden; +} + +figure img { + width: 100%; + transition: filter 0.3s ease; +} + +figure .overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: flex-start; + padding: 1rem; + opacity: 0; + transition: + opacity 0.3s ease, + backdrop-filter 0.01s ease; +} + +figure:hover .overlay { + opacity: 1; + backdrop-filter: blur(1rem); +} + +.text-content { + color: white; + text-align: left; + opacity: 0; + transform: translateX(-5rem); + transition: + transform 0.6s cubic-bezier(0.22, 1, 0.36, 1), + opacity 0.6s ease; +} + +figure:hover .text-content { + transform: translateX(2.5rem); + opacity: 1; +} + +.text-content h3 { + margin: 0; + font-size: 2rem; +} + +.text-content p { + margin: 0.5rem 0; + font-size: 1.1rem; +} + +.text-content .author { + margin-top: 0.5rem; + text-align: left; + display: block; + position: relative; + font-style: italic; + font-size: 1rem; + color: #f0f0f0; +} + +figure .language-icon { + position: absolute; + bottom: 0.5rem; + right: 0.5rem; + padding: 0.5rem; + background: var(--vp-c-bg-soft); + border-radius: 100%; + font-size: 1rem; + z-index: 1; } -figcaption { - text-align: center; - padding-top: .4em; - padding-bottom: .6em; +.VPButton { + margin-top: 2rem; + text-decoration: none; } </style> diff --git a/docs/showcases/Showcases.vue b/docs/showcases/Showcases.vue index 86a17bf..57cf5fa 100644 --- a/docs/showcases/Showcases.vue +++ b/docs/showcases/Showcases.vue @@ -1,18 +1,36 @@ <script setup lang="ts"> -import showcases from './showcases' -import Showcase from './Showcase.vue' +import showcases from "./showcases" +import Showcase from "./Showcase.vue" </script> - <template> <div class="Showcases"> <template v-for="(showcase, index) in showcases" :key="index"> <div v-if="Array.isArray(showcase)" class="row"> - <div v-for="(elem, elemIndex) in showcase" :key="elemIndex" class="item" - :class="`grid-${showcase.length}`"> - <Showcase v-bind="elem" /> + <div + v-for="(elem, elemIndex) in showcase" + :key="elemIndex" + class="item" + :class="`grid-${showcase.length}`" + > + <Showcase + :image="elem.image" + :url="elem.url" + :icon="elem.icon" + :title="elem.title" + :description="elem.description" + :author="elem.author" + /> </div> </div> - <Showcase v-else v-bind="showcase" /> + <Showcase + v-else + :image="showcase.image" + :url="showcase.url" + :icon="showcase.icon" + :title="showcase.title" + :description="showcase.description" + :author="showcase.author" + /> </template> </div> </template> diff --git a/docs/showcases/showcases.ts b/docs/showcases/showcases.ts index 138ae7f..2aea04a 100644 --- a/docs/showcases/showcases.ts +++ b/docs/showcases/showcases.ts @@ -1,15 +1,38 @@ type Showcase = { - label: string - src: string + image: string url: string + icon?: string // https://devicon.dev/ + title?: string + description?: string + author: string } -type Grid<T> = T - | [T, T] - | [T, T, T] - | [T, T, T, T] +// TODO: support more layouts +type Grid<T> = T | [T, T] export default [ - { label: "Placeholder (this is an ags v1 screenshot)", src: "/astal/showcase/aylur1.png", url: "https://github.com/Aylur/dotfiles" }, - // add more showcases here + { + image: "/astal/showcase/aylur.png", + url: "https://github.com/Aylur/dotfiles", + icon: "devicon-typescript-plain", + description: "Placeholder (this is an ags v1 screenshot)", + author: "Aylur", + }, + { + image: "/astal/showcase/tokyob0t-super-duper-hiper-mega-ultra-contribution.webp", + url: "https://github.com/tokyob0t/dotfiles", + icon: "devicon-lua-plain", + title: "Tokyob0t's Desktop", + description: "Abandonad toda esperanza, vosotros que entráis aquí.", + author: "tokyob0t", + }, + { + image: "/astal/showcase/kotontrion-kompass.webp", + url: "https://github.com/kotontrion/kompass", + icon: "devicon-vala-plain", + title: "kompass", + author: "kotontrion", + }, + + // add more showcases here~ ] satisfies Array<Grid<Showcase>> diff --git a/docs/vitepress.config.ts b/docs/vitepress.config.ts index a76388b..f542a68 100644 --- a/docs/vitepress.config.ts +++ b/docs/vitepress.config.ts @@ -20,10 +20,11 @@ export default defineConfig({ themeConfig: { logo: "/icon.svg", + outline: "deep", footer: { - message: 'Released under the LGPL v2.1 License', - copyright: 'Logo is created by VDawg' + message: "Released under the LGPL v2.1 License", + copyright: "Logo is created by VDawg", }, nav: [ @@ -43,7 +44,7 @@ export default defineConfig({ { text: "Contributing", link: github("/blob/main/CONTRIBUTING.md") }, { text: "Changelog", link: github("/blob/main/CHANGELOG.md") }, ], - } + }, ], sidebar: [ @@ -58,26 +59,47 @@ export default defineConfig({ ], }, { - text: "AGS", - base: "/guide/ags", - collapsed: false, + text: "TypeScript", + base: "/guide/typescript", + collapsed: true, items: [ { text: "Installation", link: "/installation" }, { text: "First Widgets", link: "/first-widgets" }, { text: "Theming", link: "/theming" }, { text: "CLI and App", link: "/cli-app" }, { text: "Widget", link: "/widget" }, - { text: "Utilities", link: "/utilities" }, { text: "Variable", link: "/variable" }, + { text: "Binding", link: "/binding" }, + { text: "GObject", link: "/gobject" }, + { text: "Utilities", link: "/utilities" }, { text: "FAQ", link: "/faq" }, ], }, { + text: "Lua", + base: "/guide/lua", + collapsed: true, + items: [ + { text: "Installation", link: "/installation" }, + { text: "First Widgets", link: "/first-widgets" }, + { text: "Theming", link: "/theming" }, + { text: "CLI and App", link: "/cli-app" }, + { text: "Widget", link: "/widget" }, + { text: "Variable", link: "/variable" }, + { text: "Binding", link: "/binding" }, + // { text: "GObject", link: "/gobject" }, + { text: "Utilities", link: "/utilities" }, + // { text: "FAQ", link: "/faq" }, + ], + }, + { text: "Libraries", collapsed: true, items: [ { text: "References", link: "/guide/libraries/references" }, - { text: "Astal", link: "https://aylur.github.io/libastal" }, + { text: "IO", link: "https://aylur.github.io/libastal/io" }, + { text: "Astal3", link: "https://aylur.github.io/libastal/astal3" }, + // { text: "Astal4", link: "https://aylur.github.io/libastal/astal4" }, { text: "Apps", link: "/guide/libraries/apps" }, { text: "Auth", link: "/guide/libraries/auth" }, { text: "Battery", link: "/guide/libraries/battery" }, @@ -111,6 +133,6 @@ export default defineConfig({ search: { provider: "local", - } + }, }, }) |