23 Commits

Author SHA1 Message Date
ca421b313d bump: v0.0.24 -> v0.0.25 2025-05-14 04:38:55 -04:00
71df7b4711 fix: assign git root 2025-05-14 04:32:02 -04:00
106a43aaf1 style: rename release 2025-05-14 04:30:28 -04:00
5077682fa5 style: break out check from release 2025-05-14 04:28:27 -04:00
634bff4411 feat: readme 2025-05-14 04:15:58 -04:00
bce4d598fb build(nix): updated nix hashes 2025-05-14 01:45:17 -04:00
3fd1e1f4a3 build(client): updated npm dependencies 2025-05-14 01:43:45 -04:00
de1baa4517 build(nix): updated nix hashes 2025-05-14 00:11:08 -04:00
be309409ad build(client): updated npm dependencies 2025-05-14 00:09:42 -04:00
b6ef0cab53 license 2025-05-13 21:31:58 -04:00
e8d9a4adff feat: bump openapi version 2025-05-13 18:19:47 -04:00
fc90905dcf bump: v0.0.23 -> v0.0.24 2025-05-13 18:12:26 -04:00
6494d74ab2 style: rename workflows 2025-05-13 18:09:44 -04:00
ca313960c4 style: rename openapi.yaml 2025-05-13 18:01:54 -04:00
0cb262524c fix: format sql and proto 2025-05-13 17:59:22 -04:00
05aff14703 feat: generate release notes 2025-05-13 17:41:38 -04:00
73cf074d6d bump: v0.0.22 -> v0.0.23 2025-05-13 17:27:05 -04:00
3e545d4fb1 build(nix): updated nix hashes 2025-05-13 17:22:51 -04:00
b07364f146 build(client): updated npm dependencies 2025-05-13 17:21:24 -04:00
c9dd6d9061 style: pretty imports 2025-05-13 17:19:12 -04:00
06dc437033 fix: better mobile support 2025-05-13 10:07:35 -04:00
d91c90a5c2 fix: display version number 2025-05-12 13:42:23 -04:00
e6ab5700de fix: check lock and not nix 2025-05-12 12:26:12 -04:00
105 changed files with 792 additions and 471 deletions

View File

@ -1,14 +1,19 @@
name: Lint Workflow name: Check
on: on:
push: push:
branches: branches:
- main - main
pull_request: pull_request:
types: [opened, reopened, edited]
jobs: jobs:
lint: check:
name: check
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: |
contains(github.event.head_commit.message, 'bump:') == false &&
contains(github.event.head_commit.message, 'Merge pull request') == false
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -22,7 +27,7 @@ jobs:
uses: cachix/cachix-action@v16 uses: cachix/cachix-action@v16
with: with:
name: trevstack name: trevstack
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Run checks - name: Check
run: nix flake check run: nix flake check

View File

@ -1,16 +1,16 @@
name: Release Workflow name: Release
on: on:
push: push:
tags: tags:
- '*' - "*"
permissions: permissions:
contents: write contents: write
packages: write packages: write
jobs: jobs:
release: check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
@ -25,7 +25,28 @@ jobs:
uses: cachix/cachix-action@v16 uses: cachix/cachix-action@v16
with: with:
name: trevstack name: trevstack
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Check
run: nix flake check
release:
runs-on: ubuntu-latest
needs: check
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: Use Cachix
uses: cachix/cachix-action@v16
with:
name: trevstack
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Build - name: Build
run: > run: >
@ -37,9 +58,10 @@ jobs:
.#trevstack-darwin-amd64 .#trevstack-darwin-amd64
.#trevstack-darwin-arm64 .#trevstack-darwin-arm64
- name: Create Release - name: Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:
generate_release_notes: true
files: |- files: |-
result*/bin/* result*/bin/*

View File

@ -1,4 +1,4 @@
name: Update Workflow name: Update
on: on:
schedule: schedule:
@ -21,7 +21,7 @@ jobs:
uses: cachix/cachix-action@v16 uses: cachix/cachix-action@v16
with: with:
name: trevstack name: trevstack
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
# https://github.com/actions/checkout/issues/13 # https://github.com/actions/checkout/issues/13
- name: Set Git Config - name: Set Git Config
@ -37,5 +37,3 @@ jobs:
with: with:
delete-branch: true delete-branch: true
title: Bump deps title: Bump deps

4
.gitignore vendored
View File

@ -1,5 +1,7 @@
.env .env
/docker-compose.* /docker-compose.*
/build/
# Nix
/result* /result*
/.direnv/ /.direnv/
/build/

View File

@ -3,7 +3,23 @@
git_root=$(git rev-parse --show-toplevel) git_root=$(git rev-parse --show-toplevel)
git_version=$(git describe --tags --abbrev=0) git_version=$(git describe --tags --abbrev=0)
version=${git_version#v} version=${git_version#v}
next_version=$(echo "${version}" | awk -F. -v OFS=. '{$NF += 1 ; print}')
major=$(echo "${version}" | cut -d . -f1)
minor=$(echo "${version}" | cut -d . -f2)
patch=$(echo "${version}" | cut -d . -f3)
case "${1}" in
major) major=$((major + 1)) ;;
minor) minor=$((minor + 1)) ;;
*) patch=$((patch + 1)) ;;
esac
next_version="${major}.${minor}.${patch}"
echo "${version} -> ${next_version}"
echo "bumping openapi"
cd "${git_root}"
sed -i -e "s/${version}/${next_version}/g" openapi.yaml
git add openapi.yaml
echo "bumping client" echo "bumping client"
cd "${git_root}/client" cd "${git_root}/client"

View File

@ -6,8 +6,7 @@ updated=false
echo "updating nix flake" echo "updating nix flake"
cd "${git_root}" cd "${git_root}"
nix flake update nix flake update
if ! git diff --exit-code flake.nix; then if ! git diff --exit-code flake.lock; then
git add flake.nix
git add flake.lock git add flake.lock
git commit -m "build(nix): updated nix dependencies" git commit -m "build(nix): updated nix dependencies"
fi fi
@ -29,7 +28,7 @@ go mod tidy
if ! git diff --exit-code go.mod go.sum; then if ! git diff --exit-code go.mod go.sum; then
git add go.mod git add go.mod
git add go.sum git add go.sum
git commit -m "build(go): updated go dependencies" git commit -m "build(server): updated go dependencies"
updated=true updated=true
fi fi

View File

@ -39,7 +39,7 @@ apps:
- ts - ts
- svelte - svelte
onstart: npx prettier --check . onstart: npx prettier --check .
onchange: npx prettier --check . || npx prettier --write . onchange: npx prettier --check .
revive: revive:
color: "#89dceb" color: "#89dceb"

10
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
"recommendations": [
"golang.go",
"dorzey.vscode-sqlfluff",
"zxh404.vscode-proto3",
"dbaeumer.vscode-eslint",
"svelte.svelte-vscode",
"esbenp.prettier-vscode"
]
}

49
.vscode/settings.json vendored
View File

@ -1,7 +1,46 @@
{ {
"go.lintTool": "revive", "editor.formatOnSave": true,
"go.lintFlags": [
"--config=server/revive.toml" // Go
], "go.lintTool": "revive",
"sqlfluff.config": "server/db/.sqlfluff", "go.formatTool": "goimports",
"go.buildTags": "dev",
"go.lintFlags": ["--config=server/revive.toml"],
"gopls": { "ui.semanticTokens": true },
"[go]": {
"editor.defaultFormatter": "golang.go"
},
// SQLFluff
"sqlfluff.config": "server/db/.sqlfluff",
"[sql]": {
"editor.defaultFormatter": "dorzey.vscode-sqlfluff"
},
// Proto
"[proto3]": {
"editor.defaultFormatter": "zxh404.vscode-proto3"
},
// ESLint
"eslint.workingDirectories": ["./client"],
"eslint.validate": ["svelte", "javascript", "typescript"],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
// Svelte
"svelte.enable-ts-plugin": true,
"[svelte]": {
"editor.defaultFormatter": "svelte.svelte-vscode"
},
// Prettier
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
} }

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) Trev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

83
README.md Normal file
View File

@ -0,0 +1,83 @@
## TrevStack
This is a CRUD app to use as a template for starting projects
### Features
- **Communicate anywhere**. Define a [protocol buffer](https://protobuf.dev/), and [Connect](https://connectrpc.com/) generates type-safe code to facilitate communication between the server and any client (web, mobile, embedded, etc). The protocol buffers can contain annotations to validate fields on the client and server. For clients that cannot use Connect, an OpenAPI spec is also generated
- **Build anywhere**. The dev environment, testing and building is all declared in a single [Nix](https://nixos.org/) flake. Every developer and server can use the same environment
- **Deploy anywhere**. CI/CD is already set up using github actions. New versions are automatically released for every major platform, along with a docker image. The binaries created require zero run-time dependencies and are relatively small (this app is 26 MiB)
- Authentication is rolled in, including API key, fingerprint & passkey
- Automatic database migration on startup
- Light & dark modes with the [catppuccin](https://catppuccin.com/palette/) color palette
- Really good at running as a [progressive web app](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps)
While I personally prefer using a Svelte frontend and Go backend, feel free to swap them out with whatever you like, you'll be surprised how easy it is.
## Getting Started
1. [Install Nix](https://nixos.org/download/)
2. Run `nix develop`
3. Create a `server/.env` file that looks something like
```env
KEY=changeme
PORT=8080
URL=http://localhost:5173
DATABASE_URL=sqlite:/home/trev/.config/trevstack/sqlite.db
```
4. Run `treli`
It's that simple. If you're feeling fancy, install [direnv](https://direnv.net/) and the dev environment will load automatically.
### Useful Commands
- `nix run #update`: updates all of the dependencies
- `nix run #bump [major | minor]`: bumps the current version up one. Defaults to "patch" (0.0.1 -> 0.0.2)
- `buf lint` & `buf generate`: Lints and generates code from protocol buffers
- `sqlc vet` & `sqlc generate`: Verifies and generates code from SQL files
- `dbmate new` & `dbmate up`: Creates a new migration file and runs pending migrations
## Components
### Client
- **svelte 5** [[docs](https://svelte.dev/docs/svelte)] UI framework
- **tailwind 4** [[docs](https://tailwindcss.com/)] CSS framework
- **bits ui** [[docs](https://bits-ui.com/docs/)] headless components
- [components](https://github.com/spotdemo4/trevstack/tree/main/client/src/lib/ui) from **shadcn-svelte** [[docs](https://www.shadcn-svelte.com/docs)] altered to work with tailwind 4, fit the [catppuccin](https://catppuccin.com/palette/) color palette, and use [shallow routing](https://svelte.dev/docs/kit/shallow-routing)
- **connect rpc** [[docs](https://connectrpc.com/docs/web/)] to communicating with the server
- **protovalidate-es** [[docs](https://github.com/bufbuild/protovalidate-es)], along with a function [coolforms](https://github.com/spotdemo4/trevstack/blob/main/client/src/lib/coolforms/) to emulate the library [sveltekit-superforms](https://superforms.rocks/)
- **simplewebauthn** [[docs](https://simplewebauthn.dev/docs/packages/browser)] for passkey authentication
- **scalar** [[docs](https://github.com/scalar/scalar)] for displaying openapi specs
- **tw-animate-css** [[docs](https://github.com/Wombosvideo/tw-animate-css)] to animate with just tailwind classes
- vite [[docs](https://vite.dev/)] for dev server and bundling
- eslint [[docs](https://eslint.org/)] for linting
- prettier [[docs](https://prettier.io/)] for formatting
- prettier-plugin-svelte [[docs](https://github.com/sveltejs/prettier-plugin-svelte)]
- prettier-plugin-tailwindcss [[docs](https://github.com/tailwindlabs/prettier-plugin-tailwindcss)]
- prettier-plugin-sort-imports [[docs](https://github.com/IanVS/prettier-plugin-sort-imports)]
### Server
- **go** [[docs](https://go.dev/doc/)]
- **connect rpc** [[docs](https://connectrpc.com/docs/go/)] to serve gRPC & HTTP requests
- **protovalidate-go** [[docs](https://github.com/bufbuild/protovalidate-go)] for validating those requests
- **sqlc** [[docs](https://docs.sqlc.dev/en/latest/)] because writing the SQL yourself is better than an ORM
- **go-webauthn** [[docs](https://github.com/go-webauthn/webauthn)] because webauthn is hard
- **dbmate** [[docs](https://github.com/amacneil/dbmate)] for database migrations
- revive [[docs](https://github.com/mgechev/revive)] for linting
### Protocol Buffers / gRPC
- **buf** [[docs](https://buf.build/docs/)] CLI for linting & code generation
- **protovalidate** [[docs](https://buf.build/docs/protovalidate/)] provides annotations to validate proto messages & fields
- **protoc-gen-connect-openapi** [[docs](https://github.com/sudorandom/protoc-gen-connect-openapi)] generates openapi specs
- protoc-gen-go [[docs](https://pkg.go.dev/google.golang.org/protobuf)]
- protoc-gen-connect-go [[docs](https://connectrpc.com/docs/go)]
- protoc-gen-es [[docs](https://connectrpc.com/docs/web/)]

View File

@ -27,5 +27,5 @@ plugins:
out: client/static/openapi out: client/static/openapi
strategy: all strategy: all
opt: opt:
- base=openapi.base.yaml - base=openapi.yaml
- path=openapi.yaml - path=openapi.yaml

View File

@ -3,8 +3,21 @@
"singleQuote": true, "singleQuote": true,
"trailingComma": "none", "trailingComma": "none",
"printWidth": 100, "printWidth": 100,
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], "plugins": [
"prettier-plugin-svelte",
"prettier-plugin-tailwindcss",
"@ianvs/prettier-plugin-sort-imports"
],
"tailwindFunctions": ["tv", "cn", "clsx"], "tailwindFunctions": ["tv", "cn", "clsx"],
"importOrder": [
"<TYPES>^(node:)",
"<TYPES>",
"<TYPES>^[.]",
"<BUILTIN_MODULES>",
"^(\\$lib/ui)(/.*)$",
"<THIRD_PARTY_MODULES>",
"^[.]"
],
"overrides": [ "overrides": [
{ {
"files": "*.svelte", "files": "*.svelte",

View File

@ -1,11 +1,12 @@
import prettier from 'eslint-config-prettier'; import { fileURLToPath } from 'node:url';
import js from '@eslint/js';
import { includeIgnoreFile } from '@eslint/compat'; import { includeIgnoreFile } from '@eslint/compat';
import js from '@eslint/js';
import prettier from 'eslint-config-prettier';
import svelte from 'eslint-plugin-svelte'; import svelte from 'eslint-plugin-svelte';
import globals from 'globals'; import globals from 'globals';
import { fileURLToPath } from 'node:url';
import ts from 'typescript-eslint'; import ts from 'typescript-eslint';
import svelteConfig from './svelte.config.js'; import svelteConfig from './svelte.config.js';
const gitignorePath = fileURLToPath(new URL('./.prettierignore', import.meta.url)); const gitignorePath = fileURLToPath(new URL('./.prettierignore', import.meta.url));
export default ts.config( export default ts.config(

437
client/package-lock.json generated
View File

@ -1,37 +1,37 @@
{ {
"name": "trevstack", "name": "trevstack",
"version": "0.0.22", "version": "0.0.25",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "trevstack", "name": "trevstack",
"version": "0.0.22", "version": "0.0.25",
"devDependencies": { "devDependencies": {
"@bufbuild/protovalidate": "^0.1.1", "@bufbuild/protovalidate": "^0.1.1",
"@connectrpc/connect": "^2.0.2", "@connectrpc/connect": "^2.0.2",
"@connectrpc/connect-web": "^2.0.2", "@connectrpc/connect-web": "^2.0.2",
"@eslint/compat": "^1.2.9", "@eslint/compat": "^1.2.9",
"@eslint/js": "^9.18.0", "@eslint/js": "^9.18.0",
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
"@lucide/svelte": "^0.479.0", "@lucide/svelte": "^0.479.0",
"@scalar/api-reference": "^1.28.32", "@scalar/api-reference": "^1.28.33",
"@simplewebauthn/browser": "^13.1.0", "@simplewebauthn/browser": "^13.1.0",
"@sveltejs/adapter-static": "^3.0.8", "@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.20.8", "@sveltejs/kit": "^2.21.0",
"@sveltejs/vite-plugin-svelte": "^5.0.3", "@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tailwindcss/vite": "^4.1.6", "@tailwindcss/vite": "^4.1.6",
"bits-ui": "^1.4.8", "bits-ui": "^1.4.8",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"eslint": "^9.26.0", "eslint": "^9.26.0",
"eslint-config-prettier": "^10.1.5", "eslint-config-prettier": "^10.1.5",
"eslint-plugin-svelte": "^3.5.1", "eslint-plugin-svelte": "^3.6.0",
"fast-deep-equal": "^3.1.3",
"globals": "^16.1.0", "globals": "^16.1.0",
"mode-watcher": "^1.0.7", "mode-watcher": "^1.0.7",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3", "prettier-plugin-svelte": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.11", "prettier-plugin-tailwindcss": "^0.6.11",
"svelte": "^5.28.2", "svelte": "^5.28.6",
"svelte-check": "^4.1.7", "svelte-check": "^4.1.7",
"svelte-sonner": "^0.3.28", "svelte-sonner": "^0.3.28",
"tailwind-merge": "^3.3.0", "tailwind-merge": "^3.3.0",
@ -39,7 +39,7 @@
"tailwindcss": "^4.0.13", "tailwindcss": "^4.0.13",
"tw-animate-css": "^1.2.9", "tw-animate-css": "^1.2.9",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.32.0", "typescript-eslint": "^8.32.1",
"vite": "^6.3.5" "vite": "^6.3.5"
} }
}, },
@ -57,6 +57,38 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@babel/code-frame": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.27.1",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/generator": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz",
"integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.27.1",
"@babel/types": "^7.27.1",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": { "node_modules/@babel/helper-string-parser": {
"version": "7.27.1", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
@ -93,6 +125,50 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@babel/template": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/parser": "^7.27.2",
"@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz",
"integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.27.1",
"@babel/parser": "^7.27.1",
"@babel/template": "^7.27.1",
"@babel/types": "^7.27.1",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse/node_modules/globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.27.1", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz",
@ -1205,6 +1281,29 @@
"url": "https://github.com/sponsors/jdesrosiers" "url": "https://github.com/sponsors/jdesrosiers"
} }
}, },
"node_modules/@ianvs/prettier-plugin-sort-imports": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/@ianvs/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.4.1.tgz",
"integrity": "sha512-F0/Hrcfpy8WuxlQyAWJTEren/uxKhYonOGY4OyWmwRdeTvkh9mMSCxowZLjNkhwi/2ipqCgtXwwOk7tW0mWXkA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@babel/generator": "^7.26.2",
"@babel/parser": "^7.26.2",
"@babel/traverse": "^7.25.9",
"@babel/types": "^7.26.0",
"semver": "^7.5.2"
},
"peerDependencies": {
"@vue/compiler-sfc": "2.7.x || 3.x",
"prettier": "2 || 3"
},
"peerDependenciesMeta": {
"@vue/compiler-sfc": {
"optional": true
}
}
},
"node_modules/@internationalized/date": { "node_modules/@internationalized/date": {
"version": "3.8.0", "version": "3.8.0",
"resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.8.0.tgz", "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.8.0.tgz",
@ -1785,28 +1884,28 @@
] ]
}, },
"node_modules/@scalar/api-client": { "node_modules/@scalar/api-client": {
"version": "2.3.32", "version": "2.3.33",
"resolved": "https://registry.npmjs.org/@scalar/api-client/-/api-client-2.3.32.tgz", "resolved": "https://registry.npmjs.org/@scalar/api-client/-/api-client-2.3.33.tgz",
"integrity": "sha512-N5zhCQs4ktrwme4rgnKM1s22PUGfKq0tkSqR6jQ9gKD7FSraLgQaB8uEb9BNoV5kkNeouhLqXFOJ3KB/wsJ4hw==", "integrity": "sha512-kkdBdXkWmclB+CNpNquoVPjVmyKTStbNMi6K/XS55aA5sg0cHJmkpuwCPUI+N3rjt1kB453BvyI81+ji7kHjcw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@headlessui/tailwindcss": "^0.2.0", "@headlessui/tailwindcss": "^0.2.0",
"@headlessui/vue": "^1.7.20", "@headlessui/vue": "^1.7.20",
"@scalar/components": "0.13.57", "@scalar/components": "0.13.58",
"@scalar/draggable": "0.1.11", "@scalar/draggable": "0.1.11",
"@scalar/icons": "0.3.5", "@scalar/icons": "0.3.6",
"@scalar/import": "0.3.25", "@scalar/import": "0.3.26",
"@scalar/oas-utils": "0.2.142", "@scalar/oas-utils": "0.2.143",
"@scalar/object-utils": "1.1.14", "@scalar/object-utils": "1.1.14",
"@scalar/openapi-parser": "0.10.17", "@scalar/openapi-parser": "0.10.17",
"@scalar/openapi-types": "0.2.2", "@scalar/openapi-types": "0.2.3",
"@scalar/postman-to-openapi": "0.2.15", "@scalar/postman-to-openapi": "0.2.16",
"@scalar/snippetz": "0.2.20", "@scalar/snippetz": "0.2.20",
"@scalar/themes": "0.11.1", "@scalar/themes": "0.11.2",
"@scalar/types": "0.1.14", "@scalar/types": "0.1.15",
"@scalar/use-codemirror": "0.11.102", "@scalar/use-codemirror": "0.11.103",
"@scalar/use-hooks": "0.1.48", "@scalar/use-hooks": "0.1.49",
"@scalar/use-toasts": "0.7.10", "@scalar/use-toasts": "0.7.10",
"@scalar/use-tooltip": "1.0.7", "@scalar/use-tooltip": "1.0.7",
"@vueuse/core": "^10.10.0", "@vueuse/core": "^10.10.0",
@ -1830,25 +1929,25 @@
} }
}, },
"node_modules/@scalar/api-reference": { "node_modules/@scalar/api-reference": {
"version": "1.28.32", "version": "1.28.33",
"resolved": "https://registry.npmjs.org/@scalar/api-reference/-/api-reference-1.28.32.tgz", "resolved": "https://registry.npmjs.org/@scalar/api-reference/-/api-reference-1.28.33.tgz",
"integrity": "sha512-VHU+KrNwM33bzq4O2JHKdWPDzG0eZINxJwwp856Nzpy1LE3lkqz9z+2BNHJ2CoPwsxzkLS7hEyG3qE2HwFFuTg==", "integrity": "sha512-50BNZARDh+fNaUZT4Wm3LNb3/kVUJtpdGEiQ1vulrDKY4F/BWvFFfIUeXBy9Zfee8RyNxtukFO2cllbqzQJzHw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@floating-ui/vue": "^1.0.2", "@floating-ui/vue": "^1.0.2",
"@headlessui/vue": "^1.7.20", "@headlessui/vue": "^1.7.20",
"@scalar/api-client": "2.3.32", "@scalar/api-client": "2.3.33",
"@scalar/code-highlight": "0.0.29", "@scalar/code-highlight": "0.0.29",
"@scalar/components": "0.13.57", "@scalar/components": "0.13.58",
"@scalar/icons": "0.3.5", "@scalar/icons": "0.3.6",
"@scalar/oas-utils": "0.2.142", "@scalar/oas-utils": "0.2.143",
"@scalar/openapi-parser": "0.10.17", "@scalar/openapi-parser": "0.10.17",
"@scalar/openapi-types": "0.2.2", "@scalar/openapi-types": "0.2.3",
"@scalar/snippetz": "0.2.20", "@scalar/snippetz": "0.2.20",
"@scalar/themes": "0.11.1", "@scalar/themes": "0.11.2",
"@scalar/types": "0.1.14", "@scalar/types": "0.1.15",
"@scalar/use-hooks": "0.1.48", "@scalar/use-hooks": "0.1.49",
"@scalar/use-toasts": "0.7.10", "@scalar/use-toasts": "0.7.10",
"@unhead/vue": "^1.11.11", "@unhead/vue": "^1.11.11",
"@vueuse/core": "^10.10.0", "@vueuse/core": "^10.10.0",
@ -1894,9 +1993,9 @@
} }
}, },
"node_modules/@scalar/components": { "node_modules/@scalar/components": {
"version": "0.13.57", "version": "0.13.58",
"resolved": "https://registry.npmjs.org/@scalar/components/-/components-0.13.57.tgz", "resolved": "https://registry.npmjs.org/@scalar/components/-/components-0.13.58.tgz",
"integrity": "sha512-U4MWHqPe1ARPhvK9xNkYpixHy7iY3HDIi3HeLWtJbrwPam+Ofz9I6LJiWyuhkNSkFVUSrawm0rYbDemPt9lKVw==", "integrity": "sha512-uuL9FV3pc2mEW3+3/XTv3AcnpPvaXzYxIFcgUsTtWyoJ+S4/ismeJYrOCTzRxPrfIpjA0U1rhCaLW4t973rcMA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1904,9 +2003,9 @@
"@floating-ui/vue": "^1.0.2", "@floating-ui/vue": "^1.0.2",
"@headlessui/vue": "^1.7.20", "@headlessui/vue": "^1.7.20",
"@scalar/code-highlight": "0.0.29", "@scalar/code-highlight": "0.0.29",
"@scalar/icons": "0.3.5", "@scalar/icons": "0.3.6",
"@scalar/themes": "0.11.1", "@scalar/themes": "0.11.2",
"@scalar/use-hooks": "0.1.48", "@scalar/use-hooks": "0.1.49",
"@scalar/use-toasts": "0.7.10", "@scalar/use-toasts": "0.7.10",
"@vueuse/core": "^10.10.0", "@vueuse/core": "^10.10.0",
"cva": "1.0.0-beta.2", "cva": "1.0.0-beta.2",
@ -1933,14 +2032,14 @@
} }
}, },
"node_modules/@scalar/icons": { "node_modules/@scalar/icons": {
"version": "0.3.5", "version": "0.3.6",
"resolved": "https://registry.npmjs.org/@scalar/icons/-/icons-0.3.5.tgz", "resolved": "https://registry.npmjs.org/@scalar/icons/-/icons-0.3.6.tgz",
"integrity": "sha512-exzLWScBVopIBqI64+kMOpuoVzDYFplciW+rizl4Fv5XwagV3oErQySRgPLKgWlgr59USge2ogBpwsc/4e6Bmw==", "integrity": "sha512-Er3zt/0+i8rbS0mPTe/N39uBC7stISE9DSZPIdgDl4onG9eFb4sodCyInA7mAxF7NQftHXGuK6VKjry9iAP0OA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@phosphor-icons/core": "^2.1.1", "@phosphor-icons/core": "^2.1.1",
"@scalar/use-hooks": "0.1.48", "@scalar/use-hooks": "0.1.49",
"@types/node": "^20.17.10", "@types/node": "^20.17.10",
"chalk": "^5.4.1", "chalk": "^5.4.1",
"vue": "^3.5.12" "vue": "^3.5.12"
@ -1950,13 +2049,13 @@
} }
}, },
"node_modules/@scalar/import": { "node_modules/@scalar/import": {
"version": "0.3.25", "version": "0.3.26",
"resolved": "https://registry.npmjs.org/@scalar/import/-/import-0.3.25.tgz", "resolved": "https://registry.npmjs.org/@scalar/import/-/import-0.3.26.tgz",
"integrity": "sha512-hZj+wQHg65prYorzYJGxrslnL/xavGFKIUpWqk6w+JsmXxYhkrS6ob64GjCKfaGIype42mG+Ef1ylqZpqL5NCw==", "integrity": "sha512-UIOPduLhpJCHmQ8bCzlY/btnJ0qWOLVMRX0ZtVVd2gEC4qyKnaiWB1fHweQW5rrWtO7CK90X8Z28n5wY5f365w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@scalar/oas-utils": "0.2.142", "@scalar/oas-utils": "0.2.143",
"@scalar/openapi-parser": "0.10.17", "@scalar/openapi-parser": "0.10.17",
"yaml": "^2.4.5" "yaml": "^2.4.5"
}, },
@ -1965,18 +2064,18 @@
} }
}, },
"node_modules/@scalar/oas-utils": { "node_modules/@scalar/oas-utils": {
"version": "0.2.142", "version": "0.2.143",
"resolved": "https://registry.npmjs.org/@scalar/oas-utils/-/oas-utils-0.2.142.tgz", "resolved": "https://registry.npmjs.org/@scalar/oas-utils/-/oas-utils-0.2.143.tgz",
"integrity": "sha512-n9aTk9oD2BOv43brFIIvkT8OSnT+wqOiT0HO9lO4/JjihT8Zkh12b2+Dc4lXZfgDwhAb3FcUnjVw8BGgOzmkFQ==", "integrity": "sha512-6waFLR2Nhz/+YUXAHmiupi1r32jHsdIXpEszqjzbGuKjyEmYJwR5rT638Il1CfHVrfIZnmMy60EAw/jmzQtm2A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@hyperjump/browser": "^1.1.0", "@hyperjump/browser": "^1.1.0",
"@hyperjump/json-schema": "^1.9.6", "@hyperjump/json-schema": "^1.9.6",
"@scalar/object-utils": "1.1.14", "@scalar/object-utils": "1.1.14",
"@scalar/openapi-types": "0.2.2", "@scalar/openapi-types": "0.2.3",
"@scalar/themes": "0.11.1", "@scalar/themes": "0.11.2",
"@scalar/types": "0.1.14", "@scalar/types": "0.1.15",
"flatted": "^3.3.1", "flatted": "^3.3.1",
"microdiff": "^1.4.0", "microdiff": "^1.4.0",
"nanoid": "^5.1.5", "nanoid": "^5.1.5",
@ -2023,9 +2122,9 @@
} }
}, },
"node_modules/@scalar/openapi-types": { "node_modules/@scalar/openapi-types": {
"version": "0.2.2", "version": "0.2.3",
"resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.2.2.tgz", "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.2.3.tgz",
"integrity": "sha512-fwWboUf3W5U4qWU7nj4jrs+KYilnfKyVp0d6LC1ejB2aROgWXIAscRtVaPLPaNLpTZOBsMC8XpiAPm3/SlU+mA==", "integrity": "sha512-O1GwqLpcRc3GKXTbeBZ5E12fXR2ltpqGWk4RfhoN4ebKZsPVknV5at5425G97E1SwMy12BporRvn90k1Z+MruQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2036,14 +2135,14 @@
} }
}, },
"node_modules/@scalar/postman-to-openapi": { "node_modules/@scalar/postman-to-openapi": {
"version": "0.2.15", "version": "0.2.16",
"resolved": "https://registry.npmjs.org/@scalar/postman-to-openapi/-/postman-to-openapi-0.2.15.tgz", "resolved": "https://registry.npmjs.org/@scalar/postman-to-openapi/-/postman-to-openapi-0.2.16.tgz",
"integrity": "sha512-pBxuY1kiLkIoDEXGBgnOALRPqDFq7G4z1ngLbIiovql+wa4V9D5hLPQ20r+7p8P6d/Gu6EcRun4OxVJFjHNymQ==", "integrity": "sha512-gcC8VRwltFn+BrvSXi3nguzcu62c5KIOHgogOUVRpeNF2taYL16MJl4s8kkB9V4C3f4lZqozYml8MJJe/1K5pw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@scalar/oas-utils": "0.2.142", "@scalar/oas-utils": "0.2.143",
"@scalar/openapi-types": "0.2.2" "@scalar/openapi-types": "0.2.3"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@ -2063,13 +2162,13 @@
} }
}, },
"node_modules/@scalar/themes": { "node_modules/@scalar/themes": {
"version": "0.11.1", "version": "0.11.2",
"resolved": "https://registry.npmjs.org/@scalar/themes/-/themes-0.11.1.tgz", "resolved": "https://registry.npmjs.org/@scalar/themes/-/themes-0.11.2.tgz",
"integrity": "sha512-bPOO10L2JZQdwoirpTp3CWEsLqapU7x/EwydivY1WtU4/FOObluLdjmCQ7Ijw2fzY5t6I/BvTsZbWZRWrLvuUQ==", "integrity": "sha512-3LOKmOzWzpWZHBqqVP62MDLa9QLmsjvb1DpAevMrMc6mSkSSnKU53+BxOZcrBb8CgB1694Lm9eOf4BRBywufaw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@scalar/types": "0.1.14", "@scalar/types": "0.1.15",
"nanoid": "^5.1.5" "nanoid": "^5.1.5"
}, },
"engines": { "engines": {
@ -2077,13 +2176,13 @@
} }
}, },
"node_modules/@scalar/types": { "node_modules/@scalar/types": {
"version": "0.1.14", "version": "0.1.15",
"resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.1.14.tgz", "resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.1.15.tgz",
"integrity": "sha512-N7qZ9qARJfi4Gl5MEsRfwPHFWs68qDXWQ+jGi05LGExDqErAJStc4PPkEmxt44uSO4+TVx4ADxWB6xNoGMG/Zg==", "integrity": "sha512-qb/kYWD7MKthL9flHEH/FPDgE3uWkkq8os9+M3CwyYMo2OpyXLbnzZ47LiCJ+hfdCx/hfIiSEOum2eNsYM8Lfg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@scalar/openapi-types": "0.2.2", "@scalar/openapi-types": "0.2.3",
"nanoid": "^5.1.5", "nanoid": "^5.1.5",
"zod": "3.24.1" "zod": "3.24.1"
}, },
@ -2092,9 +2191,9 @@
} }
}, },
"node_modules/@scalar/use-codemirror": { "node_modules/@scalar/use-codemirror": {
"version": "0.11.102", "version": "0.11.103",
"resolved": "https://registry.npmjs.org/@scalar/use-codemirror/-/use-codemirror-0.11.102.tgz", "resolved": "https://registry.npmjs.org/@scalar/use-codemirror/-/use-codemirror-0.11.103.tgz",
"integrity": "sha512-6ya9TMYX8UQ5mV09cOHKOnk8uytR/K0aUzIeLPlIaTEVlmzIcLiZXR34ThK5fN3XgmL1rXRzihgrooZDhTpEOQ==", "integrity": "sha512-rwa2dn2L6R/Q2vdYp4kNx5kV1zZ7TIhoxXoYREqVOlbqypl7ASAyNot2icuAIozSzA4oyL7mhsSsYtaBhJ3C1A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2113,7 +2212,7 @@
"@lezer/highlight": "^1.2.1", "@lezer/highlight": "^1.2.1",
"@lezer/lr": "^1.4.2", "@lezer/lr": "^1.4.2",
"@replit/codemirror-css-color-picker": "^6.3.0", "@replit/codemirror-css-color-picker": "^6.3.0",
"@scalar/components": "0.13.57", "@scalar/components": "0.13.58",
"codemirror": "^6.0.0", "codemirror": "^6.0.0",
"style-mod": "^4.1.2", "style-mod": "^4.1.2",
"vue": "^3.5.12" "vue": "^3.5.12"
@ -2123,13 +2222,13 @@
} }
}, },
"node_modules/@scalar/use-hooks": { "node_modules/@scalar/use-hooks": {
"version": "0.1.48", "version": "0.1.49",
"resolved": "https://registry.npmjs.org/@scalar/use-hooks/-/use-hooks-0.1.48.tgz", "resolved": "https://registry.npmjs.org/@scalar/use-hooks/-/use-hooks-0.1.49.tgz",
"integrity": "sha512-ueAs0caWTFbrVW9jRuKpj+hZYe3r25dnFBkSSbMIhkx5OQkMmgfq0q3Rao2azyXWsA067K+Nujsu7G6hE1ujiw==", "integrity": "sha512-RV/ks0xBdj2e5MUmdto0dJIL3zviixfmaY87fzVkJwU/ptzi50AyppXGFWsmRyatOwB/KYlUy6D2NoNQA8bdDQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@scalar/themes": "0.11.1", "@scalar/themes": "0.11.2",
"@scalar/use-toasts": "0.7.10", "@scalar/use-toasts": "0.7.10",
"@vueuse/core": "^10.10.0", "@vueuse/core": "^10.10.0",
"cva": "1.0.0-beta.2", "cva": "1.0.0-beta.2",
@ -2209,17 +2308,18 @@
} }
}, },
"node_modules/@sveltejs/kit": { "node_modules/@sveltejs/kit": {
"version": "2.20.8", "version": "2.21.0",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.20.8.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.21.0.tgz",
"integrity": "sha512-ep9qTxL7WALhfm0kFecL3VHeuNew8IccbYGqv5TqL/KSqWRKzEgDG8blNlIu1CkLTTua/kHjI+f5T8eCmWIxKw==", "integrity": "sha512-kvu4h9qXduiPk1Q1oqFKDLFGu/7mslEYbVaqpbBcBxjlRJnvNCFwEvEwKt0Mx9TtSi8J77xRelvJobrGlst4nQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sveltejs/acorn-typescript": "^1.0.5",
"@types/cookie": "^0.6.0", "@types/cookie": "^0.6.0",
"acorn": "^8.14.1",
"cookie": "^0.6.0", "cookie": "^0.6.0",
"devalue": "^5.1.0", "devalue": "^5.1.0",
"esm-env": "^1.2.2", "esm-env": "^1.2.2",
"import-meta-resolve": "^4.1.0",
"kleur": "^4.1.5", "kleur": "^4.1.5",
"magic-string": "^0.30.5", "magic-string": "^0.30.5",
"mrmime": "^2.0.0", "mrmime": "^2.0.0",
@ -2653,9 +2753,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.17.46", "version": "20.17.47",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.46.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.47.tgz",
"integrity": "sha512-0PQHLhZPWOxGW4auogW0eOQAuNIlCYvibIpG67ja0TOJ6/sehu+1en7sfceUn+QQtx4Rk3GxbLNwPh0Cav7TWw==", "integrity": "sha512-3dLX0Upo1v7RvUimvxLeXqwrfyKxUINk0EAM83swP2mlSUcwV73sZy8XhNz8bcZ3VbsfQyC/y6jRdL5tgCNpDQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2677,19 +2777,19 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.32.0", "version": "8.32.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz",
"integrity": "sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==", "integrity": "sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/scope-manager": "8.32.1",
"@typescript-eslint/type-utils": "8.32.0", "@typescript-eslint/type-utils": "8.32.1",
"@typescript-eslint/utils": "8.32.0", "@typescript-eslint/utils": "8.32.1",
"@typescript-eslint/visitor-keys": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.1",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^5.3.1", "ignore": "^7.0.0",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
"ts-api-utils": "^2.1.0" "ts-api-utils": "^2.1.0"
}, },
@ -2706,17 +2806,27 @@
"typescript": ">=4.8.4 <5.9.0" "typescript": ">=4.8.4 <5.9.0"
} }
}, },
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz",
"integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.32.0", "version": "8.32.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz",
"integrity": "sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==", "integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/scope-manager": "8.32.1",
"@typescript-eslint/types": "8.32.0", "@typescript-eslint/types": "8.32.1",
"@typescript-eslint/typescript-estree": "8.32.0", "@typescript-eslint/typescript-estree": "8.32.1",
"@typescript-eslint/visitor-keys": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.1",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@ -2732,14 +2842,14 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.32.0", "version": "8.32.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.1.tgz",
"integrity": "sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ==", "integrity": "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.32.0", "@typescript-eslint/types": "8.32.1",
"@typescript-eslint/visitor-keys": "8.32.0" "@typescript-eslint/visitor-keys": "8.32.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -2750,14 +2860,14 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.32.0", "version": "8.32.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.1.tgz",
"integrity": "sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg==", "integrity": "sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/typescript-estree": "8.32.0", "@typescript-eslint/typescript-estree": "8.32.1",
"@typescript-eslint/utils": "8.32.0", "@typescript-eslint/utils": "8.32.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^2.1.0" "ts-api-utils": "^2.1.0"
}, },
@ -2774,9 +2884,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.32.0", "version": "8.32.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.1.tgz",
"integrity": "sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA==", "integrity": "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -2788,14 +2898,14 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.32.0", "version": "8.32.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.1.tgz",
"integrity": "sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ==", "integrity": "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.32.0", "@typescript-eslint/types": "8.32.1",
"@typescript-eslint/visitor-keys": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@ -2841,16 +2951,16 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.32.0", "version": "8.32.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.1.tgz",
"integrity": "sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw==", "integrity": "sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.7.0", "@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/scope-manager": "8.32.1",
"@typescript-eslint/types": "8.32.0", "@typescript-eslint/types": "8.32.1",
"@typescript-eslint/typescript-estree": "8.32.0" "@typescript-eslint/typescript-estree": "8.32.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -2865,13 +2975,13 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.32.0", "version": "8.32.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.1.tgz",
"integrity": "sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w==", "integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.32.0", "@typescript-eslint/types": "8.32.1",
"eslint-visitor-keys": "^4.2.0" "eslint-visitor-keys": "^4.2.0"
}, },
"engines": { "engines": {
@ -3856,9 +3966,9 @@
} }
}, },
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.0", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -4195,16 +4305,16 @@
} }
}, },
"node_modules/eslint-plugin-svelte": { "node_modules/eslint-plugin-svelte": {
"version": "3.5.1", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.5.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.6.0.tgz",
"integrity": "sha512-Qn1slddZHfqYiDO6IN8/iN3YL+VuHlgYjm30FT+hh0Jf/TX0jeZMTJXQMajFm5f6f6hURi+XO8P+NPYD+T4jkg==", "integrity": "sha512-IIf6Cj6yQuCwL7Qd8bX13BZspz+DQsOkClozMF9EkW20FSxI75Ndd5ZzbviCn32DdXRo9FUWXn+YMIL46qPOOg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.4.1", "@eslint-community/eslint-utils": "^4.4.1",
"@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/sourcemap-codec": "^1.5.0",
"esutils": "^2.0.3", "esutils": "^2.0.3",
"known-css-properties": "^0.35.0", "known-css-properties": "^0.36.0",
"postcss": "^8.4.49", "postcss": "^8.4.49",
"postcss-load-config": "^3.1.4", "postcss-load-config": "^3.1.4",
"postcss-safe-parser": "^7.0.0", "postcss-safe-parser": "^7.0.0",
@ -5316,17 +5426,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/import-meta-resolve": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
"integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==",
"dev": true,
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/imurmurhash": { "node_modules/imurmurhash": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@ -5480,6 +5579,13 @@
"jiti": "lib/jiti-cli.mjs" "jiti": "lib/jiti-cli.mjs"
} }
}, },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true,
"license": "MIT"
},
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
@ -5493,6 +5599,19 @@
"js-yaml": "bin/js-yaml.js" "js-yaml": "bin/js-yaml.js"
} }
}, },
"node_modules/jsesc": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"dev": true,
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
},
"engines": {
"node": ">=6"
}
},
"node_modules/json-buffer": { "node_modules/json-buffer": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@ -5569,9 +5688,9 @@
} }
}, },
"node_modules/known-css-properties": { "node_modules/known-css-properties": {
"version": "0.35.0", "version": "0.36.0",
"resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.36.0.tgz",
"integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", "integrity": "sha512-A+9jP+IUmuQsNdsLdcg6Yt7voiMF/D4K83ew0OpJtpu+l34ef7LaohWV0Rc6KNvzw6ZDizkqfyB5JznZnzuKQA==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@ -7988,9 +8107,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/semver": { "node_modules/semver": {
"version": "7.7.1", "version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"bin": { "bin": {
@ -8288,9 +8407,9 @@
} }
}, },
"node_modules/svelte": { "node_modules/svelte": {
"version": "5.28.2", "version": "5.28.6",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.28.2.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.28.6.tgz",
"integrity": "sha512-FbWBxgWOpQfhKvoGJv/TFwzqb4EhJbwCD17dB0tEpQiw1XyUEKZJtgm4nA4xq3LLsMo7hu5UY/BOFmroAxKTMg==", "integrity": "sha512-9qqr7mw8YR9PAnxGFfzCK6PUlNGtns7wVavrhnxyf3fpB1mP/Ol55Z2UnIapsSzNNl3k9qw7cZ22PdE8+xT/jQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -8656,15 +8775,15 @@
} }
}, },
"node_modules/typescript-eslint": { "node_modules/typescript-eslint": {
"version": "8.32.0", "version": "8.32.1",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.32.0.tgz", "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.32.1.tgz",
"integrity": "sha512-UMq2kxdXCzinFFPsXc9o2ozIpYCCOiEC46MG3yEh5Vipq6BO27otTtEBZA1fQ66DulEUgE97ucQ/3YY66CPg0A==", "integrity": "sha512-D7el+eaDHAmXvrZBy1zpzSNIRqnCOrkwTgZxTu3MUqRWk8k0q9m9Ho4+vPf7iHtgUfrK/o8IZaEApsxPlHTFCg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "8.32.0", "@typescript-eslint/eslint-plugin": "8.32.1",
"@typescript-eslint/parser": "8.32.0", "@typescript-eslint/parser": "8.32.1",
"@typescript-eslint/utils": "8.32.0" "@typescript-eslint/utils": "8.32.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"

View File

@ -1,7 +1,7 @@
{ {
"name": "trevstack", "name": "trevstack",
"private": true, "private": true,
"version": "0.0.22", "version": "0.0.25",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
@ -19,25 +19,25 @@
"@connectrpc/connect-web": "^2.0.2", "@connectrpc/connect-web": "^2.0.2",
"@eslint/compat": "^1.2.9", "@eslint/compat": "^1.2.9",
"@eslint/js": "^9.18.0", "@eslint/js": "^9.18.0",
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
"@lucide/svelte": "^0.479.0", "@lucide/svelte": "^0.479.0",
"@scalar/api-reference": "^1.28.32", "@scalar/api-reference": "^1.28.33",
"@simplewebauthn/browser": "^13.1.0", "@simplewebauthn/browser": "^13.1.0",
"@sveltejs/adapter-static": "^3.0.8", "@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.20.8", "@sveltejs/kit": "^2.21.0",
"@sveltejs/vite-plugin-svelte": "^5.0.3", "@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tailwindcss/vite": "^4.1.6", "@tailwindcss/vite": "^4.1.6",
"bits-ui": "^1.4.8", "bits-ui": "^1.4.8",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"eslint": "^9.26.0", "eslint": "^9.26.0",
"eslint-config-prettier": "^10.1.5", "eslint-config-prettier": "^10.1.5",
"eslint-plugin-svelte": "^3.5.1", "eslint-plugin-svelte": "^3.6.0",
"fast-deep-equal": "^3.1.3",
"globals": "^16.1.0", "globals": "^16.1.0",
"mode-watcher": "^1.0.7", "mode-watcher": "^1.0.7",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3", "prettier-plugin-svelte": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.11", "prettier-plugin-tailwindcss": "^0.6.11",
"svelte": "^5.28.2", "svelte": "^5.28.6",
"svelte-check": "^4.1.7", "svelte-check": "^4.1.7",
"svelte-sonner": "^0.3.28", "svelte-sonner": "^0.3.28",
"tailwind-merge": "^3.3.0", "tailwind-merge": "^3.3.0",
@ -45,7 +45,7 @@
"tailwindcss": "^4.0.13", "tailwindcss": "^4.0.13",
"tw-animate-css": "^1.2.9", "tw-animate-css": "^1.2.9",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.32.0", "typescript-eslint": "^8.32.1",
"vite": "^6.3.5" "vite": "^6.3.5"
} }
} }

View File

@ -8,7 +8,7 @@
<title>TrevStack</title> <title>TrevStack</title>
%sveltekit.head% %sveltekit.head%
</head> </head>
<body data-sveltekit-preload-data="tap" class="bg-crust text-text min-h-screen"> <body data-sveltekit-preload-data="tap" class="bg-crust text-text min-h-dvh">
<div style="display: contents">%sveltekit.body%</div> <div style="display: contents">%sveltekit.body%</div>
</body> </body>
</html> </html>

View File

@ -1,14 +1,11 @@
import { import type { DescMessage, DescService, MessageInitShape, MessageShape } from '@bufbuild/protobuf';
create, import type { Violation } from '@bufbuild/protovalidate';
type DescMessage, import type { Client } from '@connectrpc/connect';
type DescService,
type MessageShape,
type MessageInitShape
} from '@bufbuild/protobuf';
import { ValidationError, type Violation } from '@bufbuild/protovalidate';
import { Validator } from '../transport';
import { ConnectError, type Client } from '@connectrpc/connect';
import type { Action } from 'svelte/action'; import type { Action } from 'svelte/action';
import { create } from '@bufbuild/protobuf';
import { ValidationError } from '@bufbuild/protovalidate';
import { ConnectError } from '@connectrpc/connect';
import { Validator } from '../transport';
type Options<Input extends DescMessage, Output extends DescMessage> = { type Options<Input extends DescMessage, Output extends DescMessage> = {
init?: MessageInitShape<Input>; init?: MessageInitShape<Input>;
@ -30,9 +27,7 @@ export function coolForm<Service extends DescService, Method extends Service['me
) { ) {
const input = $state(create(method.input as Method['input'], options?.init)); const input = $state(create(method.input as Method['input'], options?.init));
const output = $state(create(method.output as Method['output'])); const output = $state(create(method.output as Method['output']));
const errors: Violations<Method['input']['field']> & { const errors: Violations<Method['input']['field']> & { form?: ConnectError } = $state({});
form?: ConnectError;
} = $state({});
let loading = $state(false); let loading = $state(false);
const validate = () => { const validate = () => {

View File

@ -1,4 +1,4 @@
import { coolForm } from './coolforms.svelte';
import { newState } from './conststate.svelte'; import { newState } from './conststate.svelte';
import { coolForm } from './coolforms.svelte';
export { coolForm, newState }; export { coolForm, newState };

View File

@ -1,11 +1,12 @@
import { createConnectTransport } from '@connectrpc/connect-web'; import type { Interceptor } from '@connectrpc/connect';
import { createValidator } from '@bufbuild/protovalidate'; import { createValidator } from '@bufbuild/protovalidate';
import { Code, ConnectError, createClient, type Interceptor } from '@connectrpc/connect'; import { Code, ConnectError, createClient } from '@connectrpc/connect';
import { AuthService } from '$lib/connect/user/v1/auth_pb'; import { createConnectTransport } from '@connectrpc/connect-web';
import { UserService } from '$lib/connect/user/v1/user_pb';
import { ItemService } from '$lib/connect/item/v1/item_pb';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { page } from '$app/state'; import { page } from '$app/state';
import { ItemService } from '$lib/connect/item/v1/item_pb';
import { AuthService } from '$lib/connect/user/v1/auth_pb';
import { UserService } from '$lib/connect/user/v1/user_pb';
const redirector: Interceptor = (next) => async (req) => { const redirector: Interceptor = (next) => async (req) => {
try { try {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Avatar as AvatarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),
@ -13,7 +13,7 @@
bind:ref bind:ref
data-slot="avatar-fallback" data-slot="avatar-fallback"
class={cn( class={cn(
'bg-surface outline-surface-2 flex size-full items-center justify-center rounded-full text-sm transition-all select-none', 'bg-surface flex size-full items-center justify-center rounded-full text-sm transition-all select-none',
className className
)} )}
{...restProps} {...restProps}

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Avatar as AvatarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Avatar as AvatarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),
@ -13,7 +13,8 @@
bind:ref bind:ref
data-slot="avatar" data-slot="avatar"
class={cn( class={cn(
'outline-surface-1 relative flex size-9 shrink-0 overflow-hidden rounded-full outline outline-offset-2', 'outline-surface-1 relative flex size-9 shrink-0 overflow-hidden rounded-full shadow-xs outline outline-offset-2',
className className
)} )}
{...restProps} {...restProps}

View File

@ -1,6 +1,6 @@
import Root from './avatar.svelte';
import Image from './avatar-image.svelte';
import Fallback from './avatar-fallback.svelte'; import Fallback from './avatar-fallback.svelte';
import Image from './avatar-image.svelte';
import Root from './avatar.svelte';
export { export {
Root, Root,

View File

@ -1,13 +1,14 @@
<script lang="ts" module> <script lang="ts" module>
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements'; import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
import { type VariantProps, tv } from 'tailwind-variants'; import type { VariantProps } from 'tailwind-variants';
import { cn } from '$lib/utils';
import { LoaderCircle } from '@lucide/svelte'; import { LoaderCircle } from '@lucide/svelte';
import { cn } from '$lib/utils';
import { tv } from 'tailwind-variants';
export const buttonVariants = tv({ export const buttonVariants = tv({
base: cn( base: cn(
'inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap shadow-xs transition-all', 'inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all',
// Focus // Focus
'focus-visible:outline-accent focus-visible:outline-2 focus-visible:outline-offset-2', 'focus-visible:outline-accent focus-visible:outline-2 focus-visible:outline-offset-2',
@ -24,7 +25,7 @@
red: 'text-crust bg-red hover:bg-red/90 shadow-xs', red: 'text-crust bg-red hover:bg-red/90 shadow-xs',
outline: 'text-text border-surface-1 hover:bg-surface border bg-transparent shadow-xs', outline: 'text-text border-surface-1 hover:bg-surface border bg-transparent shadow-xs',
input: 'text-text border-surface-1 hover:border-overlay border bg-transparent shadow-xs', input: 'text-text border-surface-1 hover:border-overlay border bg-transparent shadow-xs',
ghost: 'text-text hover:bg-surface shadow-xs' ghost: 'text-text hover:bg-surface'
}, },
size: { size: {
default: 'h-9 px-4 py-2 has-[>svg]:px-3', default: 'h-9 px-4 py-2 has-[>svg]:px-3',

View File

@ -1,9 +1,5 @@
import Root, { import type { ButtonProps, ButtonSize, ButtonVariant } from './button.svelte';
type ButtonProps, import Root, { buttonVariants } from './button.svelte';
type ButtonSize,
type ButtonVariant,
buttonVariants
} from './button.svelte';
export { export {
Root, Root,

View File

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { cn } from '$lib/utils';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements'; import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils';
type Props = WithElementRef<HTMLAttributes<HTMLDivElement>>; type Props = WithElementRef<HTMLAttributes<HTMLDivElement>>;

View File

@ -1,16 +1,12 @@
<script lang="ts"> <script lang="ts">
import CalendarIcon from '@lucide/svelte/icons/calendar'; import type { DateValue } from '@internationalized/date';
import type { DateRange } from 'bits-ui'; import type { DateRange } from 'bits-ui';
import {
CalendarDate,
DateFormatter,
type DateValue,
getLocalTimeZone
} from '@internationalized/date';
import { cn } from '$lib/utils.js';
import { buttonVariants } from '$lib/ui/button'; import { buttonVariants } from '$lib/ui/button';
import { RangeCalendar } from '$lib/ui/range-calendar';
import * as Popover from '$lib/ui/popover'; import * as Popover from '$lib/ui/popover';
import { RangeCalendar } from '$lib/ui/range-calendar';
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date';
import CalendarIcon from '@lucide/svelte/icons/calendar';
import { cn } from '$lib/utils.js';
let { let {
className, className,
@ -41,7 +37,11 @@
<div class={cn('grid gap-2', className)}> <div class={cn('grid gap-2', className)}>
<Popover.Root> <Popover.Root>
<Popover.Trigger <Popover.Trigger
class={cn(buttonVariants({ variant: 'input' }), 'bg-based', !value && 'text-subtext')} class={cn(
buttonVariants({ variant: 'input' }),
'bg-based text-md md:text-sm',
!value && 'text-subtext'
)}
> >
<CalendarIcon class="mr-2 size-4" /> <CalendarIcon class="mr-2 size-4" />
{#if value && value.start} {#if value && value.start}

View File

@ -1,9 +1,10 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive, type WithoutChildrenOrChild } from 'bits-ui'; import type { WithoutChildrenOrChild } from 'bits-ui';
import X from '@lucide/svelte/icons/x';
import type { Snippet } from 'svelte'; import type { Snippet } from 'svelte';
import * as Dialog from './index.js'; import X from '@lucide/svelte/icons/x';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Dialog as DialogPrimitive } from 'bits-ui';
import * as Dialog from './index.js';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Dialog as DialogPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Dialog as DialogPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Dialog as DialogPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,14 +1,13 @@
import { Dialog as DialogPrimitive } from 'bits-ui'; import { Dialog as DialogPrimitive } from 'bits-ui';
import Close from './dialog-close.svelte';
import Root from './dialog.svelte'; import Content from './dialog-content.svelte';
import Title from './dialog-title.svelte'; import Description from './dialog-description.svelte';
import Footer from './dialog-footer.svelte'; import Footer from './dialog-footer.svelte';
import Header from './dialog-header.svelte'; import Header from './dialog-header.svelte';
import Overlay from './dialog-overlay.svelte'; import Overlay from './dialog-overlay.svelte';
import Content from './dialog-content.svelte'; import Title from './dialog-title.svelte';
import Description from './dialog-description.svelte';
import Trigger from './dialog-trigger.svelte'; import Trigger from './dialog-trigger.svelte';
import Close from './dialog-close.svelte'; import Root from './dialog.svelte';
const Portal = DialogPrimitive.Portal; const Portal = DialogPrimitive.Portal;

View File

@ -1,9 +1,10 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive, type WithoutChildrenOrChild } from 'bits-ui'; import type { WithoutChildrenOrChild } from 'bits-ui';
import type { Snippet } from 'svelte';
import Check from '@lucide/svelte/icons/check'; import Check from '@lucide/svelte/icons/check';
import Minus from '@lucide/svelte/icons/minus'; import Minus from '@lucide/svelte/icons/minus';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import type { Snippet } from 'svelte'; import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { type WithElementRef } from 'bits-ui'; import { type WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,7 +1,8 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive, type WithoutChild } from 'bits-ui'; import type { WithoutChild } from 'bits-ui';
import Circle from '@lucide/svelte/icons/circle'; import Circle from '@lucide/svelte/icons/circle';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements'; import type { HTMLAttributes } from 'svelte/elements';
import { type WithElementRef } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { type WithElementRef } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import ChevronRight from '@lucide/svelte/icons/chevron-right'; import ChevronRight from '@lucide/svelte/icons/chevron-right';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -3,15 +3,15 @@ import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
import Content from './dropdown-menu-content.svelte'; import Content from './dropdown-menu-content.svelte';
import Group from './dropdown-menu-group.svelte'; import Group from './dropdown-menu-group.svelte';
import Item from './dropdown-menu-item.svelte'; import Item from './dropdown-menu-item.svelte';
import Link from './dropdown-menu-link.svelte';
import Label from './dropdown-menu-label.svelte'; import Label from './dropdown-menu-label.svelte';
import Link from './dropdown-menu-link.svelte';
import RadioGroup from './dropdown-menu-radio-group.svelte'; import RadioGroup from './dropdown-menu-radio-group.svelte';
import RadioItem from './dropdown-menu-radio-item.svelte'; import RadioItem from './dropdown-menu-radio-item.svelte';
import Separator from './dropdown-menu-separator.svelte'; import Separator from './dropdown-menu-separator.svelte';
import Shortcut from './dropdown-menu-shortcut.svelte'; import Shortcut from './dropdown-menu-shortcut.svelte';
import Trigger from './dropdown-menu-trigger.svelte';
import SubContent from './dropdown-menu-sub-content.svelte'; import SubContent from './dropdown-menu-sub-content.svelte';
import SubTrigger from './dropdown-menu-sub-trigger.svelte'; import SubTrigger from './dropdown-menu-sub-trigger.svelte';
import Trigger from './dropdown-menu-trigger.svelte';
const Sub = DropdownMenuPrimitive.Sub; const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root; const Root = DropdownMenuPrimitive.Root;

View File

@ -1,10 +1,10 @@
<script lang="ts"> <script lang="ts">
import { cn } from '$lib/utils';
import { getFormContext } from './context.svelte';
import type { WithElementRef, WithoutChildren } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
import type { Violation } from '@bufbuild/protovalidate'; import type { Violation } from '@bufbuild/protovalidate';
import type { ConnectError } from '@connectrpc/connect'; import type { ConnectError } from '@connectrpc/connect';
import type { WithElementRef, WithoutChildren } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils';
import { getFormContext } from './context.svelte';
type Props = WithoutChildren<WithElementRef<HTMLAttributes<HTMLDivElement>>> & { type Props = WithoutChildren<WithElementRef<HTMLAttributes<HTMLDivElement>>> & {
errors?: Violation[] | ConnectError; errors?: Violation[] | ConnectError;

View File

@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { cn } from '$lib/utils';
import { setFormContext } from './context.svelte';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements'; import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils';
import { setFormContext } from './context.svelte';
type Props = WithElementRef<HTMLAttributes<HTMLDivElement>> & { type Props = WithElementRef<HTMLAttributes<HTMLDivElement>> & {
name?: string; name?: string;

View File

@ -1,5 +1,5 @@
import Field from './field.svelte';
import Errors from './errors.svelte'; import Errors from './errors.svelte';
import Field from './field.svelte';
import Label from './label.svelte'; import Label from './label.svelte';
export { Field, Errors, Label }; export { Field, Errors, Label };

View File

@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { cn } from '$lib/utils';
import { getFormContext } from './context.svelte';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements'; import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils';
import { getFormContext } from './context.svelte';
type Props = WithElementRef<HTMLAttributes<HTMLLabelElement>>; type Props = WithElementRef<HTMLAttributes<HTMLLabelElement>>;
let { ref = $bindable(null), class: className, children, ...restProps }: Props = $props(); let { ref = $bindable(null), class: className, children, ...restProps }: Props = $props();

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLInputAttributes, HTMLInputTypeAttribute } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLInputAttributes, HTMLInputTypeAttribute } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { getFormContext } from '../form/context.svelte'; import { getFormContext } from '../form/context.svelte';

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Label as LabelPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Label as LabelPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,10 +1,10 @@
import Root from './pagination.svelte';
import Content from './pagination-content.svelte'; import Content from './pagination-content.svelte';
import Ellipsis from './pagination-ellipsis.svelte';
import Item from './pagination-item.svelte'; import Item from './pagination-item.svelte';
import Link from './pagination-link.svelte'; import Link from './pagination-link.svelte';
import PrevButton from './pagination-prev-button.svelte';
import NextButton from './pagination-next-button.svelte'; import NextButton from './pagination-next-button.svelte';
import Ellipsis from './pagination-ellipsis.svelte'; import PrevButton from './pagination-prev-button.svelte';
import Root from './pagination.svelte';
export { export {
Root, Root,

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import Ellipsis from '@lucide/svelte/icons/ellipsis';
import type { WithElementRef, WithoutChildren } from 'bits-ui'; import type { WithElementRef, WithoutChildren } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements'; import type { HTMLAttributes } from 'svelte/elements';
import Ellipsis from '@lucide/svelte/icons/ellipsis';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLLiAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLLiAttributes } from 'svelte/elements';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,7 +1,8 @@
<script lang="ts"> <script lang="ts">
import { Pagination as PaginationPrimitive } from 'bits-ui'; import type { Props } from '$lib/ui/button';
import { buttonVariants } from '$lib/ui/button';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { type Props, buttonVariants } from '$lib/ui/button'; import { Pagination as PaginationPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),
@ -33,7 +34,7 @@
size size
}), }),
'text-text', 'text-text',
isActive && 'bg-surface-1', isActive && 'bg-surface',
className className
)} )}
children={children || Fallback} children={children || Fallback}

View File

@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { Pagination as PaginationPrimitive } from 'bits-ui';
import ChevronRight from '@lucide/svelte/icons/chevron-right';
import { buttonVariants } from '$lib/ui/button/index.js'; import { buttonVariants } from '$lib/ui/button/index.js';
import ChevronRight from '@lucide/svelte/icons/chevron-right';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Pagination as PaginationPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { Pagination as PaginationPrimitive } from 'bits-ui';
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
import { buttonVariants } from '$lib/ui/button/index.js'; import { buttonVariants } from '$lib/ui/button/index.js';
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Pagination as PaginationPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
import { Pagination as PaginationPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { pushState } from '$app/navigation'; import { pushState } from '$app/navigation';
import { cn } from '$lib/utils.js';
import { Pagination as PaginationPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,7 @@
import { Popover as PopoverPrimitive } from 'bits-ui'; import { Popover as PopoverPrimitive } from 'bits-ui';
import Content from './popover-content.svelte'; import Content from './popover-content.svelte';
import Trigger from './popover-trigger.svelte'; import Trigger from './popover-trigger.svelte';
const Root = PopoverPrimitive.Root; const Root = PopoverPrimitive.Root;
const Close = PopoverPrimitive.Close; const Close = PopoverPrimitive.Close;

View File

@ -1,15 +1,15 @@
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui'; import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
import Root from './range-calendar.svelte';
import Cell from './range-calendar-cell.svelte'; import Cell from './range-calendar-cell.svelte';
import Day from './range-calendar-day.svelte'; import Day from './range-calendar-day.svelte';
import Grid from './range-calendar-grid.svelte';
import Header from './range-calendar-header.svelte';
import Months from './range-calendar-months.svelte';
import GridRow from './range-calendar-grid-row.svelte'; import GridRow from './range-calendar-grid-row.svelte';
import Heading from './range-calendar-heading.svelte'; import Grid from './range-calendar-grid.svelte';
import HeadCell from './range-calendar-head-cell.svelte'; import HeadCell from './range-calendar-head-cell.svelte';
import Header from './range-calendar-header.svelte';
import Heading from './range-calendar-heading.svelte';
import Months from './range-calendar-months.svelte';
import NextButton from './range-calendar-next-button.svelte'; import NextButton from './range-calendar-next-button.svelte';
import PrevButton from './range-calendar-prev-button.svelte'; import PrevButton from './range-calendar-prev-button.svelte';
import Root from './range-calendar.svelte';
const GridHead = RangeCalendarPrimitive.GridHead; const GridHead = RangeCalendarPrimitive.GridHead;
const GridBody = RangeCalendarPrimitive.GridBody; const GridBody = RangeCalendarPrimitive.GridBody;

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
import { buttonVariants } from '$lib/ui/button/index.js'; import { buttonVariants } from '$lib/ui/button/index.js';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),
@ -17,7 +17,7 @@
class={cn( class={cn(
buttonVariants({ variant: 'ghost' }), buttonVariants({ variant: 'ghost' }),
'size-9 p-0 font-normal', 'size-9 p-0 font-normal',
'[&[data-today]:not([data-selected])]:bg-blue [&[data-today]:not([data-selected])]:text-crust [&[data-today]:not([data-selected])]:rounded-md', '[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-crust [&[data-today]:not([data-selected])]:rounded-md',
// Selected // Selected
'data-[selected]:bg-surface data-[selected]:hover:bg-surface-1 data-[selected]:rounded-none data-[selected]:opacity-100', 'data-[selected]:bg-surface data-[selected]:hover:bg-surface-1 data-[selected]:rounded-none data-[selected]:opacity-100',
// Selection Start // Selection Start

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
import ChevronRight from '@lucide/svelte/icons/chevron-right';
import { buttonVariants } from '$lib/ui/button/index.js'; import { buttonVariants } from '$lib/ui/button/index.js';
import ChevronRight from '@lucide/svelte/icons/chevron-right';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
import { buttonVariants } from '$lib/ui/button/index.js'; import { buttonVariants } from '$lib/ui/button/index.js';
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,7 +1,8 @@
<script lang="ts"> <script lang="ts">
import { RangeCalendar as RangeCalendarPrimitive, type WithoutChildrenOrChild } from 'bits-ui'; import type { WithoutChildrenOrChild } from 'bits-ui';
import * as RangeCalendar from './index.js';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
import * as RangeCalendar from './index.js';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,11 +1,10 @@
import { Select as SelectPrimitive } from 'bits-ui'; import { Select as SelectPrimitive } from 'bits-ui';
import Group from './select-group.svelte';
import Label from './select-label.svelte';
import Item from './select-item.svelte';
import Content from './select-content.svelte'; import Content from './select-content.svelte';
import Trigger from './select-trigger.svelte'; import Group from './select-group.svelte';
import Item from './select-item.svelte';
import Label from './select-label.svelte';
import Separator from './select-separator.svelte'; import Separator from './select-separator.svelte';
import Trigger from './select-trigger.svelte';
const Root = SelectPrimitive.Root; const Root = SelectPrimitive.Root;

View File

@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import { Select as SelectPrimitive, type WithoutChild } from 'bits-ui'; import type { WithoutChild } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Select as SelectPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,7 +1,8 @@
<script lang="ts"> <script lang="ts">
import type { WithoutChild } from 'bits-ui';
import Check from '@lucide/svelte/icons/check'; import Check from '@lucide/svelte/icons/check';
import { Select as SelectPrimitive, type WithoutChild } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Select as SelectPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { type WithElementRef } from 'bits-ui'; import { type WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,7 +1,8 @@
<script lang="ts"> <script lang="ts">
import { Select as SelectPrimitive, type WithoutChild } from 'bits-ui'; import type { WithoutChild } from 'bits-ui';
import ChevronDown from '@lucide/svelte/icons/chevron-down'; import ChevronDown from '@lucide/svelte/icons/chevron-down';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Select as SelectPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Separator as SeparatorPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Separator as SeparatorPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,13 +1,13 @@
import { Dialog as SheetPrimitive } from 'bits-ui'; import { Dialog as SheetPrimitive } from 'bits-ui';
import Root from './sheet.svelte';
import Trigger from './sheet-trigger.svelte';
import Close from './sheet-close.svelte'; import Close from './sheet-close.svelte';
import Overlay from './sheet-overlay.svelte';
import Content from './sheet-content.svelte'; import Content from './sheet-content.svelte';
import Header from './sheet-header.svelte';
import Footer from './sheet-footer.svelte';
import Title from './sheet-title.svelte';
import Description from './sheet-description.svelte'; import Description from './sheet-description.svelte';
import Footer from './sheet-footer.svelte';
import Header from './sheet-header.svelte';
import Overlay from './sheet-overlay.svelte';
import Title from './sheet-title.svelte';
import Trigger from './sheet-trigger.svelte';
import Root from './sheet.svelte';
const Portal = SheetPrimitive.Portal; const Portal = SheetPrimitive.Portal;

View File

@ -1,5 +1,7 @@
<script lang="ts" module> <script lang="ts" module>
import { tv, type VariantProps } from 'tailwind-variants'; import type { VariantProps } from 'tailwind-variants';
import { tv } from 'tailwind-variants';
export const sheetVariants = tv({ export const sheetVariants = tv({
base: 'bg-mantle border-surface data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 gap-4 p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500', base: 'bg-mantle border-surface data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 gap-4 p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
variants: { variants: {
@ -21,11 +23,12 @@
</script> </script>
<script lang="ts"> <script lang="ts">
import { Dialog as SheetPrimitive, type WithoutChildrenOrChild } from 'bits-ui'; import type { WithoutChildrenOrChild } from 'bits-ui';
import X from '@lucide/svelte/icons/x';
import type { Snippet } from 'svelte'; import type { Snippet } from 'svelte';
import SheetOverlay from './sheet-overlay.svelte'; import X from '@lucide/svelte/icons/x';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Dialog as SheetPrimitive } from 'bits-ui';
import SheetOverlay from './sheet-overlay.svelte';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Dialog as SheetPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Dialog as SheetPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Dialog as SheetPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Dialog as SheetPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Dialog as SheetPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Dialog as SheetPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Toaster as Sonner, type ToasterProps as SonnerProps } from 'svelte-sonner'; import type { ToasterProps as SonnerProps } from 'svelte-sonner';
import { Toaster as Sonner } from 'svelte-sonner';
let { ...restProps }: SonnerProps = $props(); let { ...restProps }: SonnerProps = $props();
</script> </script>
@ -12,7 +13,7 @@
'bg-based text-sm flex gap-2 px-4 border border-surface-1 p-2 rounded-md items-center text-text w-full min-h-12', 'bg-based text-sm flex gap-2 px-4 border border-surface-1 p-2 rounded-md items-center text-text w-full min-h-12',
title: 'text-text', title: 'text-text',
description: 'text-subtext text-xs', description: 'text-subtext text-xs',
actionButton: 'bg-blue', actionButton: 'bg-accent',
cancelButton: 'bg-red', cancelButton: 'bg-red',
closeButton: 'bg-green' closeButton: 'bg-green'
} }

View File

@ -1,4 +1,3 @@
import Root from './table.svelte';
import Body from './table-body.svelte'; import Body from './table-body.svelte';
import Caption from './table-caption.svelte'; import Caption from './table-caption.svelte';
import Cell from './table-cell.svelte'; import Cell from './table-cell.svelte';
@ -6,6 +5,7 @@ import Footer from './table-footer.svelte';
import Head from './table-head.svelte'; import Head from './table-head.svelte';
import Header from './table-header.svelte'; import Header from './table-header.svelte';
import Row from './table-row.svelte'; import Row from './table-row.svelte';
import Root from './table.svelte';
export { export {
Root, Root,

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLTdAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLTdAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLThAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLThAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { HTMLTableAttributes } from 'svelte/elements';
import type { WithElementRef } from 'bits-ui'; import type { WithElementRef } from 'bits-ui';
import type { HTMLTableAttributes } from 'svelte/elements';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
let { let {

View File

@ -1,7 +1,7 @@
import Root from './tabs.svelte';
import Content from './tabs-content.svelte'; import Content from './tabs-content.svelte';
import List from './tabs-list.svelte'; import List from './tabs-list.svelte';
import Trigger from './tabs-trigger.svelte'; import Trigger from './tabs-trigger.svelte';
import Root from './tabs.svelte';
export { export {
Root, Root,

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Tabs as TabsPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Tabs as TabsPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Tabs as TabsPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Tabs as TabsPrimitive } from 'bits-ui';
let { ref = $bindable(null), class: className, ...restProps }: TabsPrimitive.ListProps = $props(); let { ref = $bindable(null), class: className, ...restProps }: TabsPrimitive.ListProps = $props();
</script> </script>
@ -9,7 +9,7 @@
bind:ref bind:ref
data-slot="tabs-list" data-slot="tabs-list"
class={cn( class={cn(
'bg-based inline-flex h-9 w-fit items-center justify-center gap-1 rounded-lg p-[3px]', 'bg-based inline-flex h-11 w-fit items-center justify-center gap-1 rounded-lg p-[3px]',
className className
)} )}
{...restProps} {...restProps}

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Tabs as TabsPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Tabs as TabsPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Tabs as TabsPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import { Tabs as TabsPrimitive } from 'bits-ui';
let { let {
ref = $bindable(null), ref = $bindable(null),

View File

@ -1,4 +1,5 @@
import { type ClassValue, clsx } from 'clsx'; import type { ClassValue } from 'clsx';
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {

View File

@ -1,26 +1,27 @@
<script lang="ts"> <script lang="ts">
import * as Sheet from '$lib/ui/sheet';
import * as DropdownMenu from '$lib/ui/dropdown-menu';
import * as Avatar from '$lib/ui/avatar';
import {
LayoutGrid,
LogOut,
Menu,
LayoutList,
Book,
House,
Sun,
Moon,
Settings
} from '@lucide/svelte';
import { Button } from '$lib/ui/button';
import { toggleMode } from 'mode-watcher';
import { toast } from 'svelte-sonner';
import { goto } from '$app/navigation';
import { AuthClient, UserClient } from '$lib/transport';
import { userState } from '$lib/sharedState.svelte';
import type { Snippet } from 'svelte'; import type { Snippet } from 'svelte';
import type { PageData } from './$types'; import type { PageData } from './$types';
import * as Avatar from '$lib/ui/avatar';
import { Button } from '$lib/ui/button';
import * as DropdownMenu from '$lib/ui/dropdown-menu';
import * as Sheet from '$lib/ui/sheet';
import {
Book,
House,
LayoutGrid,
LayoutList,
LogOut,
Menu,
Moon,
Settings,
Sun
} from '@lucide/svelte';
import { goto } from '$app/navigation';
import { userState } from '$lib/sharedState.svelte';
import { AuthClient, UserClient } from '$lib/transport';
import { toggleMode } from 'mode-watcher';
import { toast } from 'svelte-sonner';
import pkg from '../../../package.json' with { type: 'json' };
interface Props { interface Props {
data: PageData | undefined; data: PageData | undefined;
@ -46,9 +47,9 @@
} }
</script> </script>
<div class="flex min-h-screen flex-col justify-between gap-2"> <div class="flex min-h-dvh flex-col justify-between gap-2">
<header <header
class="bg-mantle border-surface text-text flex h-14 w-full items-center justify-between border-b px-4 py-4 lg:px-10" class="bg-mantle border-surface text-text sticky top-0 z-50 flex h-14 w-full items-center justify-between border-b px-4 py-4 lg:px-10"
> >
<!-- Left --> <!-- Left -->
<a href="/" class="flex items-center gap-2 text-2xl font-bold tracking-wider select-none"> <a href="/" class="flex items-center gap-2 text-2xl font-bold tracking-wider select-none">
@ -57,7 +58,7 @@
</a> </a>
<!-- Center --> <!-- Center -->
<div class="bg-crust hidden items-center gap-3 rounded-md p-1 lg:flex"> <div class="bg-crust hidden items-center gap-2 rounded-md p-1 lg:flex">
<Button variant="ghost" class="hover:bg-based" href="/"> <Button variant="ghost" class="hover:bg-based" href="/">
<House /> <House />
Home Home
@ -80,6 +81,7 @@
<Avatar.Root {...props}> <Avatar.Root {...props}>
{#if userState.user?.profilePictureId} {#if userState.user?.profilePictureId}
<Avatar.Image <Avatar.Image
class="hover:brightness-125"
src={`/file/${userState.user.profilePictureId}`} src={`/file/${userState.user.profilePictureId}`}
alt={`${userState.user?.username}'s avatar`} alt={`${userState.user?.username}'s avatar`}
/> />
@ -223,6 +225,6 @@
</div> </div>
<footer class="border-surface text-subtext bg-mantle flex justify-center border-t py-1 text-xs"> <footer class="border-surface text-subtext bg-mantle flex justify-center border-t py-1 text-xs">
v. version v. {pkg.version}
</footer> </footer>
</div> </div>

View File

@ -1,19 +1,20 @@
<script lang="ts"> <script lang="ts">
import * as Select from '$lib/ui/select'; import type { Item } from '$lib/connect/item/v1/item_pb';
import { Button } from '$lib/ui/button';
import { Card } from '$lib/ui/card';
import { DateRangePicker } from '$lib/ui/daterangepicker';
import * as Dialog from '$lib/ui/dialog'; import * as Dialog from '$lib/ui/dialog';
import * as Form from '$lib/ui/form'; import * as Form from '$lib/ui/form';
import * as Table from '$lib/ui/table';
import { ItemClient } from '$lib/transport';
import { Skeleton } from '$lib/ui/skeleton';
import { Plus, Trash, Pencil, LoaderCircle } from '@lucide/svelte';
import { Button } from '$lib/ui/button';
import { timestampFromDate, timestampDate } from '@bufbuild/protobuf/wkt';
import { Input } from '$lib/ui/input'; import { Input } from '$lib/ui/input';
import { ItemService, type Item } from '$lib/connect/item/v1/item_pb';
import { DateRangePicker } from '$lib/ui/daterangepicker';
import { coolForm, newState } from '$lib/coolforms';
import { Card } from '$lib/ui/card';
import { Pager } from '$lib/ui/pager'; import { Pager } from '$lib/ui/pager';
import * as Select from '$lib/ui/select';
import { Skeleton } from '$lib/ui/skeleton';
import * as Table from '$lib/ui/table';
import { timestampDate, timestampFromDate } from '@bufbuild/protobuf/wkt';
import { LoaderCircle, Pencil, Plus, Trash } from '@lucide/svelte';
import { ItemService } from '$lib/connect/item/v1/item_pb';
import { coolForm, newState } from '$lib/coolforms';
import { ItemClient } from '$lib/transport';
import { cn } from '$lib/utils'; import { cn } from '$lib/utils';
const get = coolForm(ItemClient, ItemService.method.getItems, { const get = coolForm(ItemClient, ItemService.method.getItems, {
@ -27,11 +28,9 @@
</script> </script>
<div class="mx-4 my-2 flex flex-wrap items-center justify-center gap-2"> <div class="mx-4 my-2 flex flex-wrap items-center justify-center gap-2">
<LoaderCircle class={cn('invisible animate-spin', get.loading() && 'visible')} />
<Input <Input
bind:value={get.input.filter} bind:value={get.input.filter}
class="bg-based w-md" class="bg-based max-w-sm"
placeholder="Filter" placeholder="Filter"
onchange={() => { onchange={() => {
get.submit(); get.submit();
@ -65,6 +64,8 @@
get.submit(); get.submit();
}} }}
/> />
<LoaderCircle class={cn('invisible animate-spin', get.loading() && 'visible')} />
</div> </div>
{#snippet editModal(item: Item)} {#snippet editModal(item: Item)}
@ -260,9 +261,7 @@
</div> </div>
<div class="flex flex-wrap justify-center gap-2 px-4 sm:hidden"> <div class="flex flex-wrap justify-center gap-2 px-4 sm:hidden">
{#if get.loading() && get.output.items.length == 0} {#if get.output.items.length > 0}
<span>Loading</span>
{:else}
{#each get.output.items as item (item.id)} {#each get.output.items as item (item.id)}
<Card class="flex flex-wrap gap-4"> <Card class="flex flex-wrap gap-4">
<div class="flex flex-col"> <div class="flex flex-col">
@ -296,7 +295,7 @@
{/if} {/if}
</div> </div>
<div class="mx-4 mt-2 mb-4 flex justify-end sm:mt-1"> <div class="mx-4 my-2 flex justify-end">
{@render createModal()} {@render createModal()}
</div> </div>

View File

@ -1,18 +1,18 @@
<script lang="ts"> <script lang="ts">
import * as Avatar from '$lib/ui/avatar'; import * as Avatar from '$lib/ui/avatar';
import { Button } from '$lib/ui/button';
import { Card } from '$lib/ui/card';
import * as Dialog from '$lib/ui/dialog'; import * as Dialog from '$lib/ui/dialog';
import * as Form from '$lib/ui/form'; import * as Form from '$lib/ui/form';
import { UserClient } from '$lib/transport';
import { Button } from '$lib/ui/button';
import { Input } from '$lib/ui/input'; import { Input } from '$lib/ui/input';
import { toast } from 'svelte-sonner';
import { userState } from '$lib/sharedState.svelte';
import { coolForm, newState } from '$lib/coolforms';
import { UserService } from '$lib/connect/user/v1/user_pb';
import { Card } from '$lib/ui/card';
import { Separator } from '$lib/ui/separator'; import { Separator } from '$lib/ui/separator';
import { startRegistration } from '@simplewebauthn/browser';
import { ConnectError } from '@connectrpc/connect'; import { ConnectError } from '@connectrpc/connect';
import { startRegistration } from '@simplewebauthn/browser';
import { UserService } from '$lib/connect/user/v1/user_pb';
import { coolForm, newState } from '$lib/coolforms';
import { userState } from '$lib/sharedState.svelte';
import { UserClient } from '$lib/transport';
import { toast } from 'svelte-sonner';
const updatePassword = coolForm(UserClient, UserService.method.updatePassword, { const updatePassword = coolForm(UserClient, UserService.method.updatePassword, {
reset: true, reset: true,

View File

@ -1,22 +1,25 @@
<script lang="ts"> <script lang="ts">
import * as Tabs from '$lib/ui/tabs'; import { Button } from '$lib/ui/button';
import { Card } from '$lib/ui/card';
import * as Form from '$lib/ui/form'; import * as Form from '$lib/ui/form';
import { Input } from '$lib/ui/input'; import { Input } from '$lib/ui/input';
import { Button } from '$lib/ui/button'; import * as Tabs from '$lib/ui/tabs';
import { AuthClient } from '$lib/transport';
import { toast } from 'svelte-sonner';
import { AuthService } from '$lib/connect/user/v1/auth_pb';
import { coolForm } from '$lib/coolforms';
import { Card } from '$lib/ui/card';
import { goto } from '$app/navigation';
import { page } from '$app/state';
import { startAuthentication } from '@simplewebauthn/browser';
import { ConnectError } from '@connectrpc/connect'; import { ConnectError } from '@connectrpc/connect';
import { Fingerprint } from '@lucide/svelte'; import { Fingerprint } from '@lucide/svelte';
import { startAuthentication } from '@simplewebauthn/browser';
import { goto } from '$app/navigation';
import { page } from '$app/state';
import { AuthService } from '$lib/connect/user/v1/auth_pb';
import { coolForm } from '$lib/coolforms';
import { AuthClient } from '$lib/transport';
import { toast } from 'svelte-sonner';
let tabValue = $state('login'); let tabValue = $state('login');
async function redirect() { async function redirect() {
localStorage.setItem('username', login.input.username);
login.input.password = '';
if (page.url.searchParams.has('redir')) { if (page.url.searchParams.has('redir')) {
const uri = decodeURIComponent(page.url.searchParams.get('redir')!); const uri = decodeURIComponent(page.url.searchParams.get('redir')!);
await goto(uri); await goto(uri);
@ -27,6 +30,10 @@
} }
const login = coolForm(AuthClient, AuthService.method.login, { const login = coolForm(AuthClient, AuthService.method.login, {
init: {
username: localStorage.getItem('username') ?? ''
},
reset: false,
onResult: () => { onResult: () => {
redirect(); redirect();
} }
@ -67,7 +74,7 @@
} }
</script> </script>
<div class="flex h-screen flex-col items-center justify-center"> <div class="flex h-dvh flex-col items-center justify-center">
<Tabs.Root bind:value={tabValue} class="min-w-full px-2 sm:min-w-sm"> <Tabs.Root bind:value={tabValue} class="min-w-full px-2 sm:min-w-sm">
<Tabs.List class="w-full"> <Tabs.List class="w-full">
<Tabs.Trigger value="login">Log In</Tabs.Trigger> <Tabs.Trigger value="login">Log In</Tabs.Trigger>
@ -93,7 +100,7 @@
<div class="flex gap-1"> <div class="flex gap-1">
<Button type="submit" loading={login.loading()} class="grow">Submit</Button> <Button type="submit" loading={login.loading()} class="grow">Submit</Button>
{#if login.input.username} {#if login.input.username}
<Button type="button" onclick={passkeyLogin}><Fingerprint /></Button> <Button type="button" onclick={passkeyLogin} class="min-w-18"><Fingerprint /></Button>
{/if} {/if}
</div> </div>
</form> </form>

Some files were not shown because too many files have changed in this diff Show More