[CI SKIP] dev (#5)
ci/woodpecker/tag/build Pipeline was successful Details
ci/woodpecker/tag/publish Pipeline failed Details

Co-authored-by: emerald <emerald_actual@proton.me>
Reviewed-on: https://gitea.greenboi.me/emerald/cathode/pulls/5
This commit is contained in:
emerald 2022-10-21 02:21:37 -04:00
parent c3be26e5fa
commit e3fdda3f0f
24 changed files with 1283 additions and 250 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
node_modules/
dist/
bundle/

3
.helix/languages.toml Normal file
View File

@ -0,0 +1,3 @@
[[language]]
name = "svelte"
auto-format = true

View File

@ -1,4 +1,4 @@
branches: main
branches: [main, dev]
pipeline:
build:
image: gitea.greenboi.me/emerald/cathode-build:latest
@ -7,4 +7,5 @@ pipeline:
event: [push, pull_request]
commands:
- npm ci
- npm run tauri build
- npm run build
- cd src-tauri && cargo build

View File

@ -6,11 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [v0.1.0]
### Added
- Load last selected ray file at launch
- Add `blink_interval` to config file
- Add `mic_sens` to config file
- Add `new` button to reset the loaded ray
- Add icon to indicate an image is being loaded
- Add shift-click to clear a frame
### Changed
- Loading rays at launch should be more consistent
### Fixed
- Fixed config not being respected on launch

View File

@ -1,4 +1,4 @@
FROM node
FROM node:bullseye
RUN apt update -yy && apt upgrade -yy
RUN apt install -yy libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
RUN apt install -yy libasound2-dev

View File

@ -1,4 +1,40 @@
# Cathode [![status-badge](https://ci.greenboi.me/api/badges/emerald/cathode/status.svg)](https://ci.greenboi.me/emerald/cathode)
a small app for PNG tubing. Think Veadotube-mini but completely FOSS.
Built with Tauri and Svelte.
Built with Tauri and Svelte.
## Installation
### Packages
There are a few prebuilt packages available [here](https://gitea.greenboi.me/emerald/-/packages/generic/cathode-tube/) for the latest stable release. They are built on Bullseye Debian, so should be compatible with most up to date systems. Debian derived distros will want the `.deb` file, and Fedora users will want the `.rpm` file. Download the correct file and install it with your package manager.
Alternatively, download the AppImage, which should work on any glibc linux distro at the cost of being a considerable larger file. Once you download the `.AppImage` file, give it execution permissions (eg: `chmod +x cathode-tube.AppImage`) and run it like a command or script.
### Building from source
#### Prerequisites
In order to build from source you will need a few things to get started
- Nodejs/npm (I recommend using [nvm](https://github.com/nvm-sh/nvm) for this)
- [Rust](https://rustup.rs/)
- Tauri's [development dependencies](https://tauri.app/v1/guides/getting-started/prerequisites#installing)
#### Building
Once all of these are installed, clone the repo and run
```
npm install
```
This will install everything needed to build the frontend, as well as the tauri cli. Building the project itself is then as simple as
```
npm run tauri build
```
This will build the frontend and backend, and bundle the `.deb` and `.AppImage` packages, found in `src-tauri/target/release/bundle`.
The binary itself (at `src-tauri/target/release/cathode-tube`) is all that is needed to run the program, so if neither bundle works for you simply copy the executable to somewhere in your path, or run
```
cargo install --path src-tauri
```
#### Just
If you have the [just](https://github.com/casey/just) command runner installed, as well as the other prerequisites, then you can run
```
just install
```
Which will build the project and install it to `/usr/bin`, along with the `.desktop` file and icons

View File

@ -13,8 +13,29 @@ log RUST_LOG:
build:
cargo tauri build
cd src-tauri
cargo generate-rpm
cp -r target/release/bundle ..
cp -r target/generate-rpm ../bundle
cd src-tauri && cargo generate-rpm
cp -r src-tauri/target/release/bundle bundle
cp -r src-tauri/target/generate-rpm bundle
install:
@cargo tauri build -b none
@echo Copying binary to /usr/bin/cathode...
@sudo cp src-tauri/target/release/cathode /usr/bin/cathode
@echo Installing desktop file...
@sudo cp src-tauri/cathode-tube.desktop /usr/share/applications/cathode-tube.desktop
@sudo cp src-tauri/application-cathode.xml /usr/share/mime/packages/application-cathode.xml
@echo Installing icons...
@sudo cp src-tauri/icons/128x128.png /usr/share/icons/hicolor/128x128/apps/cathode-tube.png
@sudo cp src-tauri/icons/32x32.png /usr/share/icons/hicolor/32x32/apps/cathode-tube.png
@sudo cp src-tauri/icons/128x128@2x.png /usr/share/icons/hicolor/256x256/apps/cathode-tube.png
@sudo update-desktop-database
uninstall:
@echo Removing cathode...
@sudo rm -f /usr/bin/cathode
@sudo rm -f /usr/share/applications/cathode-tube.desktop
@sudo rm -f /usr/share/mime/packages/application-cathode.xml
@sudo rm -f /usr/share/icons/hicolor/128x128/apps/cathode-tube.png
@sudo rm -f /usr/share/icons/hicolor/32x32/apps/cathode-tube.png
@sudo rm -f /usr/share/icons/hicolor/256x256/apps/cathode-tube.png
@sudo update-desktop-database

837
package-lock.json generated
View File

@ -25,6 +25,38 @@
"vite": "^3.0.2"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.11.tgz",
"integrity": "sha512-PzMcQLazLBkwDEkrNPi9AbjFt6+3I7HKbiYF2XtWQ7wItrHvEOeO3T8Am434zAozWtVP7lrTue1bEfc2nYWeCA==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.11.tgz",
"integrity": "sha512-geWp637tUhNmhL3Xgy4Bj703yXB9dqiLJe05lCUfjSFDrQf9C/8pArusyPUbUbPwlC/EAUjBw32sxuIl/11dZw==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
@ -41,9 +73,9 @@
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.16",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz",
"integrity": "sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==",
"version": "0.3.17",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
"integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "3.1.0",
@ -171,6 +203,86 @@
"@tauri-apps/cli-win32-x64-msvc": "1.1.1"
}
},
"node_modules/@tauri-apps/cli-darwin-arm64": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.1.1.tgz",
"integrity": "sha512-qBG11ig525/qf0f5OQxn0ON3hT8YdpTfpa4Y4kVqBJhdW50R5fadPv6tv5Dpl2TS2X7nWh/zg5mEXYoCK3HZ9w==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tauri-apps/cli-darwin-x64": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.1.1.tgz",
"integrity": "sha512-M3dMsp78OdxisbTwAWGvy3jIb3uqThtQcUYVvqOu9LeEOHyldOBFDSht+6PTBpaJLAHFMQK2rmNxiWgigklJaA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.1.1.tgz",
"integrity": "sha512-LYlvdAd73cq+yTi6rw7j/DWIvDpeApwgQkIn+HYsNNeFhyFmABU7tmw+pekK3W3nHAkYAJ69Rl4ZdoxdNGKmHg==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.1.1.tgz",
"integrity": "sha512-o/hbMQIKuFI7cTNpeQBHD/OCNJOBIci78faKms/t6AstLXx0QJuRHDk477Rg6VVy/I3BBKbyATALbmcTq+ti0A==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.1.1.tgz",
"integrity": "sha512-8Ci4qlDnXIp93XqUrtzFCBDatUzPHpZq7L3bociUbWpvy/bnlzxp1C/C+vwdc4uS1MiAp9v3BFgrU4i0f0Z3QQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.1.1.tgz",
@ -203,6 +315,38 @@
"node": ">= 10"
}
},
"node_modules/@tauri-apps/cli-win32-ia32-msvc": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.1.1.tgz",
"integrity": "sha512-vw7VOmrQlywHhFV3pf54udf2FRNj9dg9WP1gL0My55FnB+w+PWS9Ipm871kX5qepmChdnZHKq9fsqE2uTjX//Q==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.1.1.tgz",
"integrity": "sha512-OukxlLLi3AoCN4ABnqCDTiiC7xJGWukAjrKCIx7wFISrLjNfsrnH7/UOzuopfGpZChSe2c+AamVmcpBfVsEmJA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tsconfig/svelte": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-3.0.0.tgz",
@ -210,9 +354,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "18.8.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.4.tgz",
"integrity": "sha512-WdlVphvfR/GJCLEMbNA8lJ0lhFNBj4SW3O+O5/cEGw9oYrv0al9zTwuQsq+myDUXgNx2jgBynoVgZ2MMJ6pbow==",
"version": "18.11.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz",
"integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==",
"dev": true
},
"node_modules/@types/pug": {
@ -373,9 +517,9 @@
"dev": true
},
"node_modules/esbuild": {
"version": "0.15.10",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.10.tgz",
"integrity": "sha512-N7wBhfJ/E5fzn/SpNgX+oW2RLRjwaL8Y0ezqNqhjD6w0H2p0rDuEz2FKZqpqLnO8DCaWumKe8dsC/ljvVSSxng==",
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.11.tgz",
"integrity": "sha512-OgHGuhlfZ//mToxjte1D5iiiQgWfJ2GByVMwEC/IuoXsBGkuyK1+KrjYu0laSpnN/L1UmLUCv0s25vObdc1bVg==",
"dev": true,
"hasInstallScript": true,
"bin": {
@ -385,34 +529,146 @@
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/android-arm": "0.15.10",
"@esbuild/linux-loong64": "0.15.10",
"esbuild-android-64": "0.15.10",
"esbuild-android-arm64": "0.15.10",
"esbuild-darwin-64": "0.15.10",
"esbuild-darwin-arm64": "0.15.10",
"esbuild-freebsd-64": "0.15.10",
"esbuild-freebsd-arm64": "0.15.10",
"esbuild-linux-32": "0.15.10",
"esbuild-linux-64": "0.15.10",
"esbuild-linux-arm": "0.15.10",
"esbuild-linux-arm64": "0.15.10",
"esbuild-linux-mips64le": "0.15.10",
"esbuild-linux-ppc64le": "0.15.10",
"esbuild-linux-riscv64": "0.15.10",
"esbuild-linux-s390x": "0.15.10",
"esbuild-netbsd-64": "0.15.10",
"esbuild-openbsd-64": "0.15.10",
"esbuild-sunos-64": "0.15.10",
"esbuild-windows-32": "0.15.10",
"esbuild-windows-64": "0.15.10",
"esbuild-windows-arm64": "0.15.10"
"@esbuild/android-arm": "0.15.11",
"@esbuild/linux-loong64": "0.15.11",
"esbuild-android-64": "0.15.11",
"esbuild-android-arm64": "0.15.11",
"esbuild-darwin-64": "0.15.11",
"esbuild-darwin-arm64": "0.15.11",
"esbuild-freebsd-64": "0.15.11",
"esbuild-freebsd-arm64": "0.15.11",
"esbuild-linux-32": "0.15.11",
"esbuild-linux-64": "0.15.11",
"esbuild-linux-arm": "0.15.11",
"esbuild-linux-arm64": "0.15.11",
"esbuild-linux-mips64le": "0.15.11",
"esbuild-linux-ppc64le": "0.15.11",
"esbuild-linux-riscv64": "0.15.11",
"esbuild-linux-s390x": "0.15.11",
"esbuild-netbsd-64": "0.15.11",
"esbuild-openbsd-64": "0.15.11",
"esbuild-sunos-64": "0.15.11",
"esbuild-windows-32": "0.15.11",
"esbuild-windows-64": "0.15.11",
"esbuild-windows-arm64": "0.15.11"
}
},
"node_modules/esbuild-android-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.11.tgz",
"integrity": "sha512-rrwoXEiuI1kaw4k475NJpexs8GfJqQUKcD08VR8sKHmuW9RUuTR2VxcupVvHdiGh9ihxL9m3lpqB1kju92Ialw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-android-arm64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.11.tgz",
"integrity": "sha512-/hDubOg7BHOhUUsT8KUIU7GfZm5bihqssvqK5PfO4apag7YuObZRZSzViyEKcFn2tPeHx7RKbSBXvAopSHDZJQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-darwin-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.11.tgz",
"integrity": "sha512-1DqHD0ms3AhiwkKnjRUzmiW7JnaJJr5FKrPiR7xuyMwnjDqvNWDdMq4rKSD9OC0piFNK6n0LghsglNMe2MwJtA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-darwin-arm64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.11.tgz",
"integrity": "sha512-OMzhxSbS0lwwrW40HHjRCeVIJTURdXFA8c3GU30MlHKuPCcvWNUIKVucVBtNpJySXmbkQMDJdJNrXzNDyvoqvQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-freebsd-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.11.tgz",
"integrity": "sha512-8dKP26r0/Qyez8nTCwpq60QbuYKOeBygdgOAWGCRalunyeqWRoSZj9TQjPDnTTI9joxd3QYw3UhVZTKxO9QdRg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-freebsd-arm64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.11.tgz",
"integrity": "sha512-aSGiODiukLGGnSg/O9+cGO2QxEacrdCtCawehkWYTt5VX1ni2b9KoxpHCT9h9Y6wGqNHmXFnB47RRJ8BIqZgmQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-32": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.11.tgz",
"integrity": "sha512-lsrAfdyJBGx+6aHIQmgqUonEzKYeBnyfJPkT6N2dOf1RoXYYV1BkWB6G02tjsrz1d5wZzaTc3cF+TKmuTo/ZwA==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-64": {
"version": "0.15.10",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.10.tgz",
"integrity": "sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==",
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.11.tgz",
"integrity": "sha512-Y2Rh+PcyVhQqXKBTacPCltINN3uIw2xC+dsvLANJ1SpK5NJUtxv8+rqWpjmBgaNWKQT1/uGpMmA9olALy9PLVA==",
"cpu": [
"x64"
],
@ -425,6 +681,198 @@
"node": ">=12"
}
},
"node_modules/esbuild-linux-arm": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.11.tgz",
"integrity": "sha512-TJllTVk5aSyqPFvvcHTvf6Wu1ZKhWpJ/qNmZO8LL/XeB+LXCclm7HQHNEIz6MT7IX8PmlC1BZYrOiw2sXSB95A==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-arm64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.11.tgz",
"integrity": "sha512-uhcXiTwTmD4OpxJu3xC5TzAAw6Wzf9O1XGWL448EE9bqGjgV1j+oK3lIHAfsHnuIn8K4nDW8yjX0Sv5S++oRuw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-mips64le": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.11.tgz",
"integrity": "sha512-WD61y/R1M4BLe4gxXRypoQ0Ci+Vjf714QYzcPNkiYv5I8K8WDz2ZR8Bm6cqKxd6rD+e/rZgPDbhQ9PCf7TMHmA==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-ppc64le": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.11.tgz",
"integrity": "sha512-JVleZS9oPVLTlBhPTWgOwxFWU/wMUdlBwTbGA4GF8c38sLbS13cupj+C8bLq929jU7EMWry4SaL+tKGIaTlqKg==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-riscv64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.11.tgz",
"integrity": "sha512-9aLIalZ2HFHIOZpmVU11sEAS9F8TnHw49daEjcgMpBXHFF57VuT9f9/9LKJhw781Gda0P9jDkuCWJ0tFbErvJw==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-s390x": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.11.tgz",
"integrity": "sha512-sZHtiXXOKsLI3XGBGoYO4qKBzJlb8xNsWmvFiwFMHFzA4AXgDP1KDp7Dawe9C2pavTRBDvl+Ok4n/DHQ59oaTg==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-netbsd-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.11.tgz",
"integrity": "sha512-hUC9yN06K9sg7ju4Vgu9ChAPdsEgtcrcLfyNT5IKwKyfpLvKUwCMZSdF+gRD3WpyZelgTQfJ+pDx5XFbXTlB0A==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-openbsd-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.11.tgz",
"integrity": "sha512-0bBo9SQR4t66Wd91LGMAqmWorzO0TTzVjYiifwoFtel8luFeXuPThQnEm5ztN4g0fnvcp7AnUPPzS/Depf17wQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-sunos-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.11.tgz",
"integrity": "sha512-EuBdTGlsMTjEl1sQnBX2jfygy7iR6CKfvOzi+gEOfhDqbHXsmY1dcpbVtcwHAg9/2yUZSfMJHMAgf1z8M4yyyw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-32": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.11.tgz",
"integrity": "sha512-O0/Wo1Wk6dc0rZSxkvGpmTNIycEznHmkObTFz2VHBhjPsO4ZpCgfGxNkCpz4AdAIeMczpTXt/8d5vdJNKEGC+Q==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.11.tgz",
"integrity": "sha512-x977Q4HhNjnHx00b4XLAnTtj5vfbdEvkxaQwC1Zh5AN8g5EX+izgZ6e5QgqJgpzyRNJqh4hkgIJF1pyy1be0mQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-arm64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.11.tgz",
"integrity": "sha512-VwUHFACuBahrvntdcMKZteUZ9HaYrBRODoKe4tIWxguQRvvYoYb7iu5LrcRS/FQx8KPZNaa72zuqwVtHeXsITw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
@ -474,6 +922,20 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@ -798,9 +1260,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.17",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz",
"integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==",
"version": "8.4.18",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz",
"integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==",
"dev": true,
"funding": [
{
@ -1035,9 +1497,9 @@
}
},
"node_modules/svelte": {
"version": "3.51.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.51.0.tgz",
"integrity": "sha512-PBITYIrsNOuW+Dtds00gSY68raNZQn7i59Dg/fjgf6WwyawPKeBwle692coO7ILZqSO+UJe9899aDn9sMdeOHA==",
"version": "3.52.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.52.0.tgz",
"integrity": "sha512-FxcnEUOAVfr10vDU5dVgJN19IvqeHQCS1zfe8vayTfis9A2t5Fhx+JDe5uv/C3j//bB1umpLJ6quhgs9xyUbCQ==",
"dev": true,
"engines": {
"node": ">= 8"
@ -1184,9 +1646,9 @@
}
},
"node_modules/vite": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/vite/-/vite-3.1.7.tgz",
"integrity": "sha512-5vCAmU4S8lyVdFCInu9M54f/g8qbOMakVw5xJ4pjoaDy5wgy9sLLZkGdSLN52dlsBqh0tBqxjaqqa8LgPqwRAA==",
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/vite/-/vite-3.1.8.tgz",
"integrity": "sha512-m7jJe3nufUbuOfotkntGFupinL/fmuTNuQmiVE7cH2IZMuf4UbfbGYMUT3jVWgGYuRVLY9j8NnrRqgw5rr5QTg==",
"dev": true,
"dependencies": {
"esbuild": "^0.15.9",
@ -1232,6 +1694,20 @@
}
},
"dependencies": {
"@esbuild/android-arm": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.11.tgz",
"integrity": "sha512-PzMcQLazLBkwDEkrNPi9AbjFt6+3I7HKbiYF2XtWQ7wItrHvEOeO3T8Am434zAozWtVP7lrTue1bEfc2nYWeCA==",
"dev": true,
"optional": true
},
"@esbuild/linux-loong64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.11.tgz",
"integrity": "sha512-geWp637tUhNmhL3Xgy4Bj703yXB9dqiLJe05lCUfjSFDrQf9C/8pArusyPUbUbPwlC/EAUjBw32sxuIl/11dZw==",
"dev": true,
"optional": true
},
"@jridgewell/resolve-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
@ -1245,9 +1721,9 @@
"dev": true
},
"@jridgewell/trace-mapping": {
"version": "0.3.16",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz",
"integrity": "sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==",
"version": "0.3.17",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
"integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
"dev": true,
"requires": {
"@jridgewell/resolve-uri": "3.1.0",
@ -1331,6 +1807,41 @@
"@tauri-apps/cli-win32-x64-msvc": "1.1.1"
}
},
"@tauri-apps/cli-darwin-arm64": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.1.1.tgz",
"integrity": "sha512-qBG11ig525/qf0f5OQxn0ON3hT8YdpTfpa4Y4kVqBJhdW50R5fadPv6tv5Dpl2TS2X7nWh/zg5mEXYoCK3HZ9w==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-darwin-x64": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.1.1.tgz",
"integrity": "sha512-M3dMsp78OdxisbTwAWGvy3jIb3uqThtQcUYVvqOu9LeEOHyldOBFDSht+6PTBpaJLAHFMQK2rmNxiWgigklJaA==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-linux-arm-gnueabihf": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.1.1.tgz",
"integrity": "sha512-LYlvdAd73cq+yTi6rw7j/DWIvDpeApwgQkIn+HYsNNeFhyFmABU7tmw+pekK3W3nHAkYAJ69Rl4ZdoxdNGKmHg==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-linux-arm64-gnu": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.1.1.tgz",
"integrity": "sha512-o/hbMQIKuFI7cTNpeQBHD/OCNJOBIci78faKms/t6AstLXx0QJuRHDk477Rg6VVy/I3BBKbyATALbmcTq+ti0A==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-linux-arm64-musl": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.1.1.tgz",
"integrity": "sha512-8Ci4qlDnXIp93XqUrtzFCBDatUzPHpZq7L3bociUbWpvy/bnlzxp1C/C+vwdc4uS1MiAp9v3BFgrU4i0f0Z3QQ==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-linux-x64-gnu": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.1.1.tgz",
@ -1345,6 +1856,20 @@
"dev": true,
"optional": true
},
"@tauri-apps/cli-win32-ia32-msvc": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.1.1.tgz",
"integrity": "sha512-vw7VOmrQlywHhFV3pf54udf2FRNj9dg9WP1gL0My55FnB+w+PWS9Ipm871kX5qepmChdnZHKq9fsqE2uTjX//Q==",
"dev": true,
"optional": true
},
"@tauri-apps/cli-win32-x64-msvc": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.1.1.tgz",
"integrity": "sha512-OukxlLLi3AoCN4ABnqCDTiiC7xJGWukAjrKCIx7wFISrLjNfsrnH7/UOzuopfGpZChSe2c+AamVmcpBfVsEmJA==",
"dev": true,
"optional": true
},
"@tsconfig/svelte": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-3.0.0.tgz",
@ -1352,9 +1877,9 @@
"dev": true
},
"@types/node": {
"version": "18.8.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.4.tgz",
"integrity": "sha512-WdlVphvfR/GJCLEMbNA8lJ0lhFNBj4SW3O+O5/cEGw9oYrv0al9zTwuQsq+myDUXgNx2jgBynoVgZ2MMJ6pbow==",
"version": "18.11.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz",
"integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==",
"dev": true
},
"@types/pug": {
@ -1475,39 +2000,172 @@
"dev": true
},
"esbuild": {
"version": "0.15.10",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.10.tgz",
"integrity": "sha512-N7wBhfJ/E5fzn/SpNgX+oW2RLRjwaL8Y0ezqNqhjD6w0H2p0rDuEz2FKZqpqLnO8DCaWumKe8dsC/ljvVSSxng==",
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.11.tgz",
"integrity": "sha512-OgHGuhlfZ//mToxjte1D5iiiQgWfJ2GByVMwEC/IuoXsBGkuyK1+KrjYu0laSpnN/L1UmLUCv0s25vObdc1bVg==",
"dev": true,
"requires": {
"@esbuild/android-arm": "0.15.10",
"@esbuild/linux-loong64": "0.15.10",
"esbuild-android-64": "0.15.10",
"esbuild-android-arm64": "0.15.10",
"esbuild-darwin-64": "0.15.10",
"esbuild-darwin-arm64": "0.15.10",
"esbuild-freebsd-64": "0.15.10",
"esbuild-freebsd-arm64": "0.15.10",
"esbuild-linux-32": "0.15.10",
"esbuild-linux-64": "0.15.10",
"esbuild-linux-arm": "0.15.10",
"esbuild-linux-arm64": "0.15.10",
"esbuild-linux-mips64le": "0.15.10",
"esbuild-linux-ppc64le": "0.15.10",
"esbuild-linux-riscv64": "0.15.10",
"esbuild-linux-s390x": "0.15.10",
"esbuild-netbsd-64": "0.15.10",
"esbuild-openbsd-64": "0.15.10",
"esbuild-sunos-64": "0.15.10",
"esbuild-windows-32": "0.15.10",
"esbuild-windows-64": "0.15.10",
"esbuild-windows-arm64": "0.15.10"
"@esbuild/android-arm": "0.15.11",
"@esbuild/linux-loong64": "0.15.11",
"esbuild-android-64": "0.15.11",
"esbuild-android-arm64": "0.15.11",
"esbuild-darwin-64": "0.15.11",
"esbuild-darwin-arm64": "0.15.11",
"esbuild-freebsd-64": "0.15.11",
"esbuild-freebsd-arm64": "0.15.11",
"esbuild-linux-32": "0.15.11",
"esbuild-linux-64": "0.15.11",
"esbuild-linux-arm": "0.15.11",
"esbuild-linux-arm64": "0.15.11",
"esbuild-linux-mips64le": "0.15.11",
"esbuild-linux-ppc64le": "0.15.11",
"esbuild-linux-riscv64": "0.15.11",
"esbuild-linux-s390x": "0.15.11",
"esbuild-netbsd-64": "0.15.11",
"esbuild-openbsd-64": "0.15.11",
"esbuild-sunos-64": "0.15.11",
"esbuild-windows-32": "0.15.11",
"esbuild-windows-64": "0.15.11",
"esbuild-windows-arm64": "0.15.11"
}
},
"esbuild-android-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.11.tgz",
"integrity": "sha512-rrwoXEiuI1kaw4k475NJpexs8GfJqQUKcD08VR8sKHmuW9RUuTR2VxcupVvHdiGh9ihxL9m3lpqB1kju92Ialw==",
"dev": true,
"optional": true
},
"esbuild-android-arm64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.11.tgz",
"integrity": "sha512-/hDubOg7BHOhUUsT8KUIU7GfZm5bihqssvqK5PfO4apag7YuObZRZSzViyEKcFn2tPeHx7RKbSBXvAopSHDZJQ==",
"dev": true,
"optional": true
},
"esbuild-darwin-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.11.tgz",
"integrity": "sha512-1DqHD0ms3AhiwkKnjRUzmiW7JnaJJr5FKrPiR7xuyMwnjDqvNWDdMq4rKSD9OC0piFNK6n0LghsglNMe2MwJtA==",
"dev": true,
"optional": true
},
"esbuild-darwin-arm64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.11.tgz",
"integrity": "sha512-OMzhxSbS0lwwrW40HHjRCeVIJTURdXFA8c3GU30MlHKuPCcvWNUIKVucVBtNpJySXmbkQMDJdJNrXzNDyvoqvQ==",
"dev": true,
"optional": true
},
"esbuild-freebsd-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.11.tgz",
"integrity": "sha512-8dKP26r0/Qyez8nTCwpq60QbuYKOeBygdgOAWGCRalunyeqWRoSZj9TQjPDnTTI9joxd3QYw3UhVZTKxO9QdRg==",
"dev": true,
"optional": true
},
"esbuild-freebsd-arm64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.11.tgz",
"integrity": "sha512-aSGiODiukLGGnSg/O9+cGO2QxEacrdCtCawehkWYTt5VX1ni2b9KoxpHCT9h9Y6wGqNHmXFnB47RRJ8BIqZgmQ==",
"dev": true,
"optional": true
},
"esbuild-linux-32": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.11.tgz",
"integrity": "sha512-lsrAfdyJBGx+6aHIQmgqUonEzKYeBnyfJPkT6N2dOf1RoXYYV1BkWB6G02tjsrz1d5wZzaTc3cF+TKmuTo/ZwA==",
"dev": true,
"optional": true
},
"esbuild-linux-64": {
"version": "0.15.10",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.10.tgz",
"integrity": "sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==",
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.11.tgz",
"integrity": "sha512-Y2Rh+PcyVhQqXKBTacPCltINN3uIw2xC+dsvLANJ1SpK5NJUtxv8+rqWpjmBgaNWKQT1/uGpMmA9olALy9PLVA==",
"dev": true,
"optional": true
},
"esbuild-linux-arm": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.11.tgz",
"integrity": "sha512-TJllTVk5aSyqPFvvcHTvf6Wu1ZKhWpJ/qNmZO8LL/XeB+LXCclm7HQHNEIz6MT7IX8PmlC1BZYrOiw2sXSB95A==",
"dev": true,
"optional": true
},
"esbuild-linux-arm64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.11.tgz",
"integrity": "sha512-uhcXiTwTmD4OpxJu3xC5TzAAw6Wzf9O1XGWL448EE9bqGjgV1j+oK3lIHAfsHnuIn8K4nDW8yjX0Sv5S++oRuw==",
"dev": true,
"optional": true
},
"esbuild-linux-mips64le": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.11.tgz",
"integrity": "sha512-WD61y/R1M4BLe4gxXRypoQ0Ci+Vjf714QYzcPNkiYv5I8K8WDz2ZR8Bm6cqKxd6rD+e/rZgPDbhQ9PCf7TMHmA==",
"dev": true,
"optional": true
},
"esbuild-linux-ppc64le": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.11.tgz",
"integrity": "sha512-JVleZS9oPVLTlBhPTWgOwxFWU/wMUdlBwTbGA4GF8c38sLbS13cupj+C8bLq929jU7EMWry4SaL+tKGIaTlqKg==",
"dev": true,
"optional": true
},
"esbuild-linux-riscv64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.11.tgz",
"integrity": "sha512-9aLIalZ2HFHIOZpmVU11sEAS9F8TnHw49daEjcgMpBXHFF57VuT9f9/9LKJhw781Gda0P9jDkuCWJ0tFbErvJw==",
"dev": true,
"optional": true
},
"esbuild-linux-s390x": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.11.tgz",
"integrity": "sha512-sZHtiXXOKsLI3XGBGoYO4qKBzJlb8xNsWmvFiwFMHFzA4AXgDP1KDp7Dawe9C2pavTRBDvl+Ok4n/DHQ59oaTg==",
"dev": true,
"optional": true
},
"esbuild-netbsd-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.11.tgz",
"integrity": "sha512-hUC9yN06K9sg7ju4Vgu9ChAPdsEgtcrcLfyNT5IKwKyfpLvKUwCMZSdF+gRD3WpyZelgTQfJ+pDx5XFbXTlB0A==",
"dev": true,
"optional": true
},
"esbuild-openbsd-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.11.tgz",
"integrity": "sha512-0bBo9SQR4t66Wd91LGMAqmWorzO0TTzVjYiifwoFtel8luFeXuPThQnEm5ztN4g0fnvcp7AnUPPzS/Depf17wQ==",
"dev": true,
"optional": true
},
"esbuild-sunos-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.11.tgz",
"integrity": "sha512-EuBdTGlsMTjEl1sQnBX2jfygy7iR6CKfvOzi+gEOfhDqbHXsmY1dcpbVtcwHAg9/2yUZSfMJHMAgf1z8M4yyyw==",
"dev": true,
"optional": true
},
"esbuild-windows-32": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.11.tgz",
"integrity": "sha512-O0/Wo1Wk6dc0rZSxkvGpmTNIycEznHmkObTFz2VHBhjPsO4ZpCgfGxNkCpz4AdAIeMczpTXt/8d5vdJNKEGC+Q==",
"dev": true,
"optional": true
},
"esbuild-windows-64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.11.tgz",
"integrity": "sha512-x977Q4HhNjnHx00b4XLAnTtj5vfbdEvkxaQwC1Zh5AN8g5EX+izgZ6e5QgqJgpzyRNJqh4hkgIJF1pyy1be0mQ==",
"dev": true,
"optional": true
},
"esbuild-windows-arm64": {
"version": "0.15.11",
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.11.tgz",
"integrity": "sha512-VwUHFACuBahrvntdcMKZteUZ9HaYrBRODoKe4tIWxguQRvvYoYb7iu5LrcRS/FQx8KPZNaa72zuqwVtHeXsITw==",
"dev": true,
"optional": true
},
@ -1554,6 +2212,13 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"optional": true
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@ -1797,9 +2462,9 @@
"dev": true
},
"postcss": {
"version": "8.4.17",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz",
"integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==",
"version": "8.4.18",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz",
"integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==",
"dev": true,
"requires": {
"nanoid": "^3.3.4",
@ -1944,9 +2609,9 @@
"dev": true
},
"svelte": {
"version": "3.51.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.51.0.tgz",
"integrity": "sha512-PBITYIrsNOuW+Dtds00gSY68raNZQn7i59Dg/fjgf6WwyawPKeBwle692coO7ILZqSO+UJe9899aDn9sMdeOHA==",
"version": "3.52.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.52.0.tgz",
"integrity": "sha512-FxcnEUOAVfr10vDU5dVgJN19IvqeHQCS1zfe8vayTfis9A2t5Fhx+JDe5uv/C3j//bB1umpLJ6quhgs9xyUbCQ==",
"dev": true
},
"svelte-check": {
@ -2019,9 +2684,9 @@
"dev": true
},
"vite": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/vite/-/vite-3.1.7.tgz",
"integrity": "sha512-5vCAmU4S8lyVdFCInu9M54f/g8qbOMakVw5xJ4pjoaDy5wgy9sLLZkGdSLN52dlsBqh0tBqxjaqqa8LgPqwRAA==",
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/vite/-/vite-3.1.8.tgz",
"integrity": "sha512-m7jJe3nufUbuOfotkntGFupinL/fmuTNuQmiVE7cH2IZMuf4UbfbGYMUT3jVWgGYuRVLY9j8NnrRqgw5rr5QTg==",
"dev": true,
"requires": {
"esbuild": "^0.15.9",

4
src-tauri/Cargo.lock generated
View File

@ -1674,9 +1674,9 @@ dependencies = [
[[package]]
name = "kqueue"
version = "1.0.6"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d6112e8f37b59803ac47a42d14f1f3a59bbf72fc6857ffc5be455e28a691f8e"
checksum = "2c8fc60ba15bf51257aa9807a48a61013db043fcf3a78cb0d916e8e396dcad98"
dependencies = [
"kqueue-sys",
"libc",

View File

@ -9,13 +9,18 @@ edition = "2021"
[package.metadata.generate-rpm]
assets = [
{source= "target/release/cathode-tube", dest= "/usr/bin/cathode", mode= "755"},
{source="cathode-tube.desktop", dest="/usr/share/applications/cathode-tube.desktop", mode="0644"},
{source="application-cathode.xml", dest="/usr/share/mime/packages/application-cathode.xml", mode="0644"},
{source="icons/128x128.png", dest="/usr/share/icons/hicolor/128x128/apps/cathode-tube.png", mode="0644"},
{source="icons/128x128@2x.png", dest="/usr/share/icons/hicolor/256x256@2/apps/cathode-tube.png", mode="0644"},
{source= "target/release/cathode", dest= "/usr/bin/cathode", mode= "755"},
{source="cathode-tube.desktop", dest="/usr/share/applications/cathode-tube.desktop", mode="0644"},
{source="application-cathode.xml", dest="/usr/share/mime/packages/application-cathode.xml", mode="0644"},
{source="icons/128x128.png", dest="/usr/share/icons/hicolor/128x128/apps/cathode-tube.png", mode="0644"},
{source="icons/128x128@2x.png", dest="/usr/share/icons/hicolor/256x256@2/apps/cathode-tube.png", mode="0644"},
]
auto-req = "no"
[package.metadata.generate-rpm.requires]
filesystem = ">= 3"
gtk3 = ">= 3"
webkit2gtk3 = ">= 2"
[workspace]

View File

@ -2,7 +2,7 @@
Type=Application
Icon=cathode-tube
Name=Cathode
Exec=cathode-tube %U
Exec=cathode %U
Terminal=false
Hidden=false
Categories=Graphics; Video

View File

@ -12,7 +12,12 @@ use cpal::InputCallbackInfo;
use log::debug;
use tauri::Window;
pub async fn monitor(window: Window, threshold: Arc<Mutex<f32>>, level: Arc<Mutex<f32>>) {
pub async fn monitor(
window: Window,
threshold: Arc<Mutex<f32>>,
level: Arc<Mutex<f32>>,
sens: Arc<Mutex<f32>>,
) {
let device = initialize().expect("Unable to init audio");
debug!("Using device {}", device.name().unwrap());
let config = device.default_input_config().unwrap();
@ -20,7 +25,10 @@ pub async fn monitor(window: Window, threshold: Arc<Mutex<f32>>, level: Arc<Mute
.build_input_stream(
&config.config(),
move |data: &[f32], _: &InputCallbackInfo| {
if data.iter().any(|e| e.abs() >= *threshold.lock().unwrap()) {
if data
.iter()
.any(|e| (e.abs() * *sens.lock().unwrap()) >= *threshold.lock().unwrap())
{
window.emit("mouth-open", "").unwrap();
} else {
window.emit("mouth-close", "").unwrap();
@ -28,10 +36,9 @@ pub async fn monitor(window: Window, threshold: Arc<Mutex<f32>>, level: Arc<Mute
*level.lock().unwrap() = data
.iter()
.map(|e| e.abs())
.map(|e| e.abs() * *sens.lock().unwrap())
.max_by(|a, b| a.total_cmp(&b))
.unwrap()
.clone();
.unwrap();
},
move |err| {
println!("Audio error: {:?}", err);
@ -43,7 +50,7 @@ pub async fn monitor(window: Window, threshold: Arc<Mutex<f32>>, level: Arc<Mute
// The stream will end if it goes out of scope, so just dwell here
loop {
sleep(Duration::from_secs(60));
sleep(Duration::from_secs(5000));
}
}
@ -52,3 +59,12 @@ fn initialize() -> Result<Device> {
host.default_input_device()
.ok_or_else(|| anyhow!("No default output device"))
}
#[tauri::command]
pub fn get_devices() -> Vec<String> {
let host = cpal::default_host();
host.input_devices()
.unwrap()
.filter_map(|e| e.name().ok())
.collect()
}

View File

@ -1,6 +1,7 @@
use std::fmt::Display;
use std::{fmt::Display, path::PathBuf};
use log::{debug, error};
use anyhow::Result;
use log::{debug, error, trace};
use serde::{Deserialize, Serialize};
use tauri::api::path::config_dir;
@ -10,6 +11,8 @@ pub struct Config {
pub background_color: BGColor,
#[serde(default = "default_interval")]
pub blink_interval: u64,
#[serde(default = "default_sens")]
pub mic_sens: f32,
}
#[inline(always)]
@ -17,6 +20,11 @@ fn default_interval() -> u64 {
1500
}
#[inline(always)]
fn default_sens() -> f32 {
1.0
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum BGColor {
@ -46,10 +54,14 @@ impl Display for BGColor {
}
}
#[inline]
pub fn get_config_dir() -> Option<PathBuf> {
Some(config_dir()?.join("cathode"))
}
pub fn load_config() -> Config {
if let Some(d) = config_dir() {
if let Some(path) = get_config_dir() {
use std::fs;
let path = d.join("cathode");
if !path.exists() {
if let Err(e) = fs::create_dir_all(&path) {
debug!("{:?}", e);
@ -64,9 +76,32 @@ pub fn load_config() -> Config {
error!("Failed to load config file: {}", f);
String::new()
});
toml::from_str::<Config>(&raw).unwrap_or_default()
trace!("Using config: {}", raw);
match toml::from_str::<Config>(&raw) {
Ok(c) => {
trace!("parsed config: {:#?}", c);
c
}
Err(e) => {
error!("Unable to parse config file: {}", e);
Config::default()
}
}
}
} else {
debug!("Using default config");
Config::default()
}
}
pub fn save_config(config: &Config) -> Result<()> {
let raw = toml::to_string_pretty(config)?;
if let Some(dir) = get_config_dir() {
use std::fs;
debug!("Writing config");
trace!("Config: {}", raw);
let path = dir.join("config.toml");
fs::write(&path, raw)?;
}
Ok(())
}

View File

@ -20,7 +20,8 @@ pub(crate) struct WebRay {
}
#[tauri::command]
pub(crate) fn open_image() -> Option<String> {
pub(crate) async fn open_image() -> Option<String> {
debug!("Opening iamge dialog...");
let path = FileDialogBuilder::new()
.add_filter("Images", &["png", "jpg"])
.set_directory(picture_dir().unwrap_or_else(|| home_dir().unwrap()))

View File

@ -16,7 +16,8 @@ use log::{debug, error, trace, warn};
use serde_json::Value;
use tauri::{
api::path::{cache_dir, config_dir},
Manager, State,
Manager,
State, //, WindowEvent,
};
use crate::config::Config;
@ -32,6 +33,7 @@ struct AudioLevel(Arc<Mutex<f32>>);
struct BlinkInterval(Arc<Mutex<u64>>);
struct CurrentConfig(Arc<Mutex<Config>>);
struct RayToLoad(Arc<Mutex<Option<PathBuf>>>);
struct MicSense(Arc<Mutex<f32>>);
fn main() {
env_logger::init();
@ -39,6 +41,7 @@ fn main() {
let level = Arc::new(Mutex::new(0.));
let blink_interval = Arc::new(Mutex::new(1500));
let ray = Arc::new(Mutex::new(None));
let sens = Arc::new(Mutex::new(1.0));
if let Some(d) = cache_dir() {
use std::fs;
@ -52,22 +55,34 @@ fn main() {
let config = config::load_config();
{
*blink_interval.lock().unwrap() = config.blink_interval
*blink_interval.lock().unwrap() = config.blink_interval;
*sens.lock().unwrap() = config.mic_sens;
}
let current_conf = Arc::new(Mutex::new(config));
let config = current_conf.clone();
// let c2 = current_conf.clone();
tauri::Builder::default()
.manage(MicThreshold(threshold.clone()))
.manage(AudioLevel(level.clone()))
.manage(BlinkInterval(blink_interval.clone()))
.manage(CurrentConfig(current_conf.clone()))
.manage(RayToLoad(ray.clone()))
.manage(MicSense(sens.clone()))
// .on_window_event(move |event| match event.event() {
// WindowEvent::CloseRequested { .. } => {
// debug!("close requested");
// if let Err(e) = config::save_config(&*c2.lock().unwrap()) {
// error!("Error writing config file: {}", e);
// }
// }
// _ => {}
// })
.setup(move |app| {
let window = app.get_window("main").unwrap();
tauri::async_runtime::spawn(async move {
monitor(window, threshold, level).await;
monitor(window, threshold, level, sens).await;
});
let window = app.get_window("main").unwrap();
@ -130,14 +145,19 @@ fn main() {
log,
set_mic_threshold,
get_mic_threshold,
set_mic_sens,
get_mic_sens,
get_audio_level,
get_blink_interval,
set_blink_interval,
get_config,
set_config,
save_current_config,
get_ray_to_load,
fs::open_image,
fs::save_ray,
fs::open_ray,
audio::get_devices,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
@ -169,6 +189,16 @@ fn get_mic_threshold(current: State<'_, MicThreshold>) -> f32 {
*current.0.lock().unwrap()
}
#[tauri::command]
fn set_mic_sens(sens: f32, current: State<'_, MicSense>) {
*current.0.lock().unwrap() = sens;
}
#[tauri::command]
fn get_mic_sens(current: State<'_, MicSense>) -> f32 {
*current.0.lock().unwrap()
}
#[tauri::command]
fn get_audio_level(level: State<'_, AudioLevel>) -> f32 {
*level.0.lock().unwrap()
@ -188,3 +218,13 @@ fn set_blink_interval(value: u64, current: State<'_, BlinkInterval>) {
fn get_config(current: State<'_, CurrentConfig>) -> Config {
current.0.lock().unwrap().clone()
}
#[tauri::command]
fn set_config(config: Config, current: State<'_, CurrentConfig>) {
*current.0.lock().unwrap() = config
}
#[tauri::command]
fn save_current_config(current: State<'_, CurrentConfig>) -> Result<(), String> {
config::save_config(&*current.0.lock().unwrap()).map_err(|e| format!("{}", e))
}

View File

@ -6,17 +6,19 @@
"distDir": "../dist"
},
"package": {
"productName": "cathode-tube",
"version": "0.0.1"
"productName": "cathode",
"version": "0.1.0"
},
"tauri": {
"cli": {
"description": "A small app for PNG-tubing",
"args": [{
"name": "file",
"index": 1,
"takesValue": true
}]
"args": [
{
"name": "file",
"index": 1,
"takesValue": true
}
]
},
"macOSPrivateApi": true,
"allowlist": {
@ -24,7 +26,10 @@
"all": true
},
"fs": {
"scope": ["$PUBLIC/*", "$CONFIG/*"],
"scope": [
"$PUBLIC/*",
"$CONFIG/*"
],
"readFile": true,
"readDir": true,
"createDir": true,
@ -42,10 +47,10 @@
"category": "DeveloperTool",
"copyright": "",
"deb": {
"files" : {
"/usr/share/applications/cathode-tube.desktop": "cathode-tube.desktop",
"/usr/share/mime/packages/application-cathode.xml": "application-cathode.xml",
"/usr/share/icons/hicolor/256x256/mimetypes/aplication-cathode.png": "icons/application-cathode-256.png"
"files": {
"/usr/share/applications/cathode-tube.desktop": "cathode-tube.desktop",
"/usr/share/mime/packages/application-cathode.xml": "application-cathode.xml",
"/usr/share/icons/hicolor/256x256/mimetypes/aplication-cathode.png": "icons/application-cathode-256.png"
},
"depends": []
},
@ -92,4 +97,4 @@
}
]
}
}
}

View File

@ -1,37 +1,47 @@
<script lang="ts">
import MainView from "./views/main.svelte";
import {listen} from "@tauri-apps/api/event";
import {invoke} from "@tauri-apps/api";
import {onMount} from "svelte";
import {config} from "./store";
import type {Config} from "./store";
$: transparent = $config.background_color === "transparent";
$: color = typeof $config.background_color === "object" ? $config.background_color.custom : $config.background_color;
$: {
import { listen } from "@tauri-apps/api/event";
import { invoke } from "@tauri-apps/api";
import { onDestroy, onMount } from "svelte";
import { config } from "./store";
import type { Config } from "./store";
invoke("log", {msg: `color: ${color} trasnparent: ${transparent}`
$: transparent = $config.background_color === "transparent";
$: color =
typeof $config.background_color === "object"
? $config.background_color.custom
: $config.background_color;
$: {
invoke("log", {
msg: `color: ${color} trasnparent: ${transparent}`,
}).catch();
}
onMount(async () => {
$config = await invoke("get_config") as Config;
$config = (await invoke("get_config")) as Config;
await listen("reload-config", async () => {
$config = await invoke("get_config") as Config;
$config = (await invoke("get_config")) as Config;
});
config.subscribe((value) => {
invoke("log", { msg: `setting config: ${JSON.stringify(value)}` });
invoke("set_config", { config: value });
});
});
onDestroy(async () => {
await invoke("save_current_config");
});
</script>
<main>
<MainView --active-color={transparent ? 'lightblue' : color} --inactive-color={color}/>
<MainView
--active-color={transparent ? "lightblue" : color}
--inactive-color={color}
/>
</main>
<style lang="scss">
:global(*) {
-moz-user-select: none;
-webkit-user-select: none;

View File

@ -1,12 +1,20 @@
<script lang="ts" context="module">
const hints = ["Eyes open | Mouth closed", "Eyes open | Mouth open", "Eyes closed | Mouth closed", "Eyes closed | Mouth open"];
const hints = [
"Eyes open | Mouth closed",
"Eyes open | Mouth open",
"Eyes closed | Mouth closed",
"Eyes closed | Mouth open",
];
let loading = [false, false, false, false];
</script>
<script lang="ts">
import { frames } from "../store";
import { invoke } from "@tauri-apps/api";
import { fade } from "svelte/transition";
import Context from "../components/context.svelte";
import Context from "./context.svelte";
import LoadingSVG from "/src/loading.svg";
export let index: number;
let menuTimeout: NodeJS.Timeout | null = null;
@ -18,20 +26,28 @@
}
const openImage = async () => {
loading[index] = true;
const path = (await invoke("open_image")) as string;
if (path) {
$frames[index] = path;
}
loading[index] = false;
};
const clearImage = () => {
$frames[index] = "";
};
//TODO: load frame from ray
</script>
<div class="box">
<div
<button
class="preview"
on:click={openImage}
on:contextmenu={openImage}
on:click={(e) => {
if (e.shiftKey) {
clearImage();
} else {
openImage();
}
}}
on:mouseenter={() =>
(menuTimeout = setTimeout(() => (showMenu = true), 200))}
on:mouseleave={() => {
@ -41,10 +57,12 @@
showMenu = false;
}}
>
{#if src}
{#if loading[index]}
<img class="loading" src={LoadingSVG} alt="Loading" />
{:else if src}
<img {src} alt="Frame {{ index }}" />
{/if}
</div>
</button>
{#if showMenu}
<div transition:fade={{ duration: 50 }} class="context">
<Context>
@ -55,6 +73,35 @@
</div>
<style lang="scss">
@-webkit-keyframes rotating {
from {
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes rotating {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.loading {
-webkit-animation: rotating 2s linear infinite;
-moz-animation: rotating 2s linear infinite;
-ms-animation: rotating 2s linear infinite;
-o-animation: rotating 2s linear infinite;
animation: rotating 2s linear infinite;
}
$bg: rgba(150, 150, 150, 0.5);
.preview {
&:hover {
@ -76,8 +123,13 @@
user-select: none;
gap: 10px;
display: flex;
align-content: center;
justify-content: center;
.context {
align-self: center;
z-index: 900;
position: absolute;
left: 105%;
width: max-content;
}
}

View File

@ -3,7 +3,7 @@
import { onMount } from "svelte";
import { tweened } from "svelte/motion";
import { sineIn, sineOut } from "svelte/easing";
import { invoke } from "@tauri-apps/api";
// import { invoke } from "@tauri-apps/api";
export let progress = 0;
export let withSetpoint = false;
@ -13,7 +13,7 @@
let bar: HTMLDivElement;
let point: HTMLDivElement;
let pos = { x: 0, y: 0 };
const tweenedProgress = tweened(0, { duration: 40, easing: sineOut });
const tweenedProgress = tweened(0, { duration: 100, easing: sineOut });
onMount(async () => {
let rect = bar.getBoundingClientRect();
@ -26,20 +26,21 @@
if (pxProgress > $tweenedProgress) {
tweenedProgress
.set(pxProgress, {
duration: 20,
duration: 30,
easing: sineOut,
})
.then();
} else {
$tweenedProgress = pxProgress;
}
$tweenedProgress = pxProgress;
}
</script>
<svelte:window
on:resize={async () => {
await invoke("log", {
msg: `Resized`,
});
// await invoke("log", {
// msg: `Resized`,
// });
pos = { x: 0, y: 0 };
let rect = bar.getBoundingClientRect();

View File

@ -0,0 +1,13 @@
<script lang="ts">
import { invoke } from "@tauri-apps/api";
const devices: Promise<string[]> = invoke("get_devices");
</script>
{#await devices}
<span>...</span>
{:then d}
{#each d as dev}
<p>{dev}</p>
{/each}
{/await}

View File

@ -1,75 +1,113 @@
<script lang="ts">
import {config} from "../store";
import {createEventDispatcher} from "svelte";
import {invoke} from "@tauri-apps/api";
import { config } from "../store";
import { createEventDispatcher } from "svelte";
import { invoke } from "@tauri-apps/api";
const dispatch = createEventDispatcher();
const dispatch = createEventDispatcher();
let org = $config;
let org = $config;
const onClose = () => {
if(org != $config) {
invoke("set_blink_interval", {value: $config.blink_interval});
org = $config;
$: {
invoke("set_mic_sens", { sens: $config.mic_sens }).catch(
async (e) => await invoke("log", { msg: JSON.stringify(e) })
);
}
dispatch('close');
}
const onClose = () => {
if (org != $config) {
invoke("set_blink_interval", { value: $config.blink_interval }).catch();
org = $config;
}
dispatch("close");
};
</script>
<div class="settings">
<span class="close" on:click={onClose}>X</span>
<div>
<label for="bg-color">Background color:</label>
<select bind:value={$config.background_color} id="bg-color">
<option value="transparent">Transparent</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
<option value="red">Red</option>
<option value="pink">Pink</option>
</select>
<button class="close" on:click={onClose}>X</button>
<div class="setting">
<label for="bg-color">Background color:</label>
<select bind:value={$config.background_color} id="bg-color">
<option value="transparent">Transparent</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
<option value="red">Red</option>
<option value="pink">Pink</option>
</select>
</div>
<div>
<label for="blink">Blink interval: </label>
<input value={$config.blink_interval} on:change={(e) => {$config.blink_interval = e.currentTarget.valueAsNumber}} id="blink" type="number" min="0"/>
<div class="setting">
<label for="blink">Blink interval: </label>
<input
value={$config.blink_interval}
on:input={(e) => {
$config.blink_interval = e.currentTarget.valueAsNumber;
}}
id="blink"
type="number"
min="0"
/>
</div>
<div class="setting">
<label for="sens">Mic sensitivity: </label>
<input
type="range"
id="sens"
step="0.01"
min="0.01"
max="1.0"
value={$config.mic_sens}
on:change={(e) => {
$config.mic_sens = e.currentTarget.valueAsNumber;
}}
/>
<span>{Math.trunc($config.mic_sens * 100)}%</span>
</div>
</div>
<style lang="scss" >
.settings {
position: absolute;
transform: translateX(-50%) translateY(-50%);
top: 50%;
left: 50%;
z-index: 1000;
width: 90%;
height: 90%;
display: flex;
flex-direction: column;
gap: 5vh;
background-color: rgba(63, 176, 252, 0.9);
border-radius: 15px;
border: solid black 2px;
padding: 15px;
label{
font-weight: bold;
}
.close {
<style lang="scss">
.settings {
position: absolute;
right: 15px;
top: 15px;
font-size: 20px;
cursor: pointer;
width: 2rem;
height: 2rem;
background-color: black;
color: white;
border: solid black 1px;
text-align: center;
vertical-align: center;
transform: translateX(-50%) translateY(-50%);
top: 50%;
left: 50%;
z-index: 1000;
width: 90%;
height: 90%;
display: flex;
flex-direction: column;
gap: 5vh;
background-color: rgba(63, 176, 252, 0.9);
border-radius: 15px;
border: solid black 2px;
padding: 20px;
label {
font-weight: bold;
}
.close {
&:focus {
border: solid white 2px;
}
position: absolute;
right: 15px;
top: 15px;
font-size: 20px;
cursor: pointer;
width: 2rem;
height: 2rem;
background-color: black;
color: white;
border: solid black 1px;
text-align: center;
vertical-align: center;
border-radius: 5px;
}
}
.setting {
display: flex;
align-content: center;
justify-content: space-between;
width: 50%;
}
}
</style>

56
src/loading.svg Normal file
View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 204.481 204.481" style="enable-background:new 0 0 204.481 204.481;" xml:space="preserve">
<g>
<path d="M162.116,38.31c0.163-0.215,0.315-0.438,0.454-0.67c0.033-0.055,0.068-0.109,0.1-0.164
c0.156-0.276,0.297-0.561,0.419-0.857c0.014-0.034,0.024-0.069,0.038-0.104c0.102-0.26,0.188-0.528,0.261-0.801
c0.019-0.069,0.037-0.137,0.053-0.207c0.068-0.288,0.124-0.581,0.157-0.881c0.002-0.017,0.006-0.034,0.008-0.052
c0.028-0.262,0.043-0.527,0.043-0.796V7.5c0-4.142-3.358-7.5-7.5-7.5H48.332c-4.142,0-7.5,3.358-7.5,7.5v26.279
c0,0.269,0.016,0.534,0.043,0.796c0.002,0.017,0.006,0.034,0.008,0.052c0.034,0.3,0.089,0.593,0.157,0.881
c0.016,0.069,0.035,0.138,0.053,0.207c0.073,0.273,0.159,0.541,0.261,0.801c0.013,0.034,0.024,0.069,0.038,0.104
c0.121,0.296,0.262,0.581,0.419,0.857c0.032,0.056,0.067,0.109,0.1,0.164c0.14,0.232,0.291,0.455,0.454,0.67
c0.027,0.035,0.047,0.074,0.074,0.109l50.255,63.821l-50.255,63.821c-0.028,0.035-0.047,0.074-0.074,0.109
c-0.163,0.215-0.315,0.438-0.454,0.67c-0.033,0.055-0.068,0.109-0.1,0.164c-0.156,0.276-0.297,0.561-0.419,0.857
c-0.014,0.034-0.024,0.069-0.038,0.104c-0.102,0.26-0.188,0.528-0.261,0.801c-0.019,0.069-0.037,0.137-0.053,0.207
c-0.068,0.288-0.124,0.581-0.157,0.881c-0.002,0.017-0.006,0.034-0.008,0.052c-0.028,0.262-0.043,0.527-0.043,0.796v26.279
c0,4.142,3.358,7.5,7.5,7.5h107.817c4.142,0,7.5-3.358,7.5-7.5v-26.279c0-0.269-0.016-0.534-0.043-0.796
c-0.002-0.017-0.006-0.034-0.008-0.052c-0.034-0.3-0.089-0.593-0.157-0.881c-0.016-0.069-0.035-0.138-0.053-0.207
c-0.073-0.273-0.159-0.541-0.261-0.801c-0.013-0.034-0.024-0.069-0.038-0.104c-0.121-0.296-0.262-0.581-0.419-0.857
c-0.032-0.056-0.067-0.109-0.1-0.164c-0.14-0.232-0.291-0.455-0.454-0.67c-0.027-0.035-0.047-0.074-0.074-0.109l-50.255-63.821
l50.255-63.821C162.07,38.385,162.089,38.346,162.116,38.31z M148.649,15v11.279H55.832V15H148.649z M55.832,189.481v-11.279
h92.817v11.279H55.832z M140.698,163.202H63.784l38.457-48.838L140.698,163.202z M102.241,90.118L63.784,41.279h76.914
L102.241,90.118z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,13 +1,33 @@
import {writable} from "svelte/store";
export type BGColor ="transparent" | "blue" | "green" | "pink" | {custom: string} ;
export type Meta = {
threshold: string | null;
closeThreshold: string | null;
};
export class WebRay {
meta: Meta;
frames: string[];
public constructor(
frames: string[] = [],
meta: Meta = { threshold: null, closeThreshold: null }
) {
this.frames = frames;
this.meta = meta;
}
}
export class Config {
background_color: BGColor;
blink_interval: number;
mic_sens: number;
constructor(){
this.background_color = "transparent";
this.blink_interval = 1500;
this.mic_sens = 1.0;
}
}

View File

@ -1,17 +1,9 @@
<script lang="ts" context="module">
import { writable, type Writable } from "svelte/store";
import { writable } from "svelte/store";
const transparent = writable(false);
const settings_open = writable(false);
const threshold: Writable<number> = writable(0.5);
const threshold = writable(0.5);
const level = writable(0);
type WebRay = {
frames: Array<string>;
meta: {
threshold: string | undefined;
closeThreshold: string | undefined;
};
};
</script>
<script lang="ts">
@ -21,24 +13,25 @@
import { fly } from "svelte/transition";
import { invoke } from "@tauri-apps/api/tauri";
import { tick } from "svelte";
import { frames } from "../store";
import { frames, WebRay } from "../store";
import { quintInOut } from "svelte/easing";
import type { UnlistenFn } from "@tauri-apps/api/event";
//components
import FramePreview from "../components/FramePreview.svelte";
import Tuber from "../components/tube.svelte";
import Bar from "../components/bar.svelte";
import Settings from "../components/settings.svelte";
// import Devices from "../components/devices.svelte";
let monitorTimer: NodeJS.Timer;
let active = false;
let activation = 0;
let closeThreshold = 75;
$: {
$transparent = $transparent && !$settings_open
$transparent = $transparent && !$settings_open;
}
$: {
@ -70,6 +63,7 @@
closeThreshold = parseFloat(ray.meta.closeThreshold);
}
};
onMount(async () => {
await appWindow.setMinSize(new PhysicalSize(720, 600));
@ -77,7 +71,6 @@
$transparent = !focused;
});
monitorTimer = setInterval(async () => {
if (!$transparent) {
$level = await invoke("get_audio_level");
@ -86,21 +79,22 @@
}, 40);
$threshold = await invoke("get_mic_threshold");
const ray = await invoke("get_ray_to_load");
if(ray) {
if (ray) {
openRay(ray as WebRay);
}
});
onDestroy(() => {
onDestroy(async () => {
if (monitorTimer) {
clearInterval(monitorTimer);
monitorTimer = undefined;
}
if (focusUnlisten) focusUnlisten();
await invoke("save_current_config");
});
const saveRay = async () => {
@ -137,7 +131,11 @@
/>
{#if !$transparent}
{#if $settings_open}
<Settings on:close={() => {$settings_open = false}} />
<Settings
on:close={() => {
$settings_open = false;
}}
/>
{/if}
<div
transition:fly={{
@ -193,11 +191,18 @@
}}
class="buttons"
>
<!-- svelte-ignore a11y-visible -->
<div on:click={saveRay}>Save</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events-->
<div on:click={loadRay}>Load</div>
<div on:click={() => {$settings_open = true}}>Settings</div>
<button
on:click={() => {
openRay(new WebRay());
}}>New</button
>
<button on:click={saveRay}>Save</button>
<button on:click={loadRay}>Load</button>
<button
on:click={() => {
$settings_open = true;
}}>Settings</button
>
</div>
{/if}
</div>
@ -214,7 +219,7 @@
align-items: center;
justify-items: center;
gap: 5vh;
div {
button {
color: white;
padding: 10px;
border-radius: 5px;