Compare commits
111 Commits
Author | SHA1 | Date | |
---|---|---|---|
e6b378c170 | |||
![]() |
fe05a64eb0 | ||
![]() |
7b3d66886d | ||
![]() |
bc74994ac4 | ||
![]() |
e20a67f7a4 | ||
![]() |
01e2f3eca3 | ||
![]() |
95a2a00cec | ||
![]() |
b6058aa434 | ||
![]() |
0adbbc3f06 | ||
![]() |
46058ae5d6 | ||
![]() |
94b367c2fb | ||
![]() |
548efa254c | ||
68166c8d3a | |||
3a5fa69bf6 | |||
23be247cdb | |||
9a204d3808 | |||
00e36b6c77 | |||
3b34d50120 | |||
13b652d425 | |||
3bdef16173 | |||
968378e8bb | |||
6767df7f91 | |||
f9245c4145 | |||
e20156a2de | |||
4f9dee1e27 | |||
fe8a1376fa | |||
7619be6d11 | |||
1062595d7f | |||
d829c1efb2 | |||
a1f22433a0 | |||
43fc67ded6 | |||
8e7781a346 | |||
68dd90048f | |||
7bf54bbd8c | |||
9fa5818860 | |||
77859b3d94 | |||
9e26479f67 | |||
000797f930 | |||
1e8e06738b | |||
28dbf76789 | |||
93aa1ebd3b | |||
bf13344cbe | |||
62358e100c | |||
7ee1cd94dc | |||
893aa4db51 | |||
6b9da9dc15 | |||
44e08b62fd | |||
3feb35ea7b | |||
849fec6f01 | |||
d27ee1202b | |||
32ac21afd2 | |||
39959f041d | |||
124d702ec4 | |||
2587483733 | |||
575ec574dd | |||
815cf96374 | |||
2b6c24bc86 | |||
632774d051 | |||
1d6b419a15 | |||
2da7526265 | |||
92877b669e | |||
10168843e1 | |||
0889f9c7b1 | |||
084010e38c | |||
8158c195f5 | |||
174d15de5b | |||
56523795d5 | |||
32bdb3d709 | |||
b30d14af9a | |||
1220a37b60 | |||
a3e008c317 | |||
58498c87af | |||
fd9abb948a | |||
2b07f74cc1 | |||
ee4d2984dd | |||
dd80776bb1 | |||
d0e7ae9284 | |||
63433be0bb | |||
1a856e575e | |||
a3e4154fb6 | |||
4839b74bf7 | |||
dcf5a16c3f | |||
932d82c1fc | |||
db509ffa8a | |||
c4392601b1 | |||
ca421b313d | |||
71df7b4711 | |||
106a43aaf1 | |||
5077682fa5 | |||
634bff4411 | |||
bce4d598fb | |||
3fd1e1f4a3 | |||
de1baa4517 | |||
be309409ad | |||
b6ef0cab53 | |||
e8d9a4adff | |||
fc90905dcf | |||
6494d74ab2 | |||
ca313960c4 | |||
0cb262524c | |||
05aff14703 | |||
73cf074d6d | |||
3e545d4fb1 | |||
b07364f146 | |||
c9dd6d9061 | |||
06dc437033 | |||
d91c90a5c2 | |||
e6ab5700de | |||
20726c55d5 | |||
95ce559ff3 | |||
bfc1580218 |
21
.actions/init/action.yaml
Normal file
21
.actions/init/action.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
name: "Initialize"
|
||||||
|
description: "Install nix & use cachix"
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
token:
|
||||||
|
description: "cachix auth token"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- 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: "${{ inputs.token }}"
|
63
.actions/push/action.yaml
Normal file
63
.actions/push/action.yaml
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
name: "Docker Push"
|
||||||
|
description: "Push to docker registry"
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
server_url:
|
||||||
|
required: true
|
||||||
|
repository:
|
||||||
|
required: true
|
||||||
|
tag:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Set env
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
REGISTRY=$(basename ${{ inputs.server_url }})
|
||||||
|
|
||||||
|
NR=${{ inputs.repository }}
|
||||||
|
NAMESPACE="${NR%%/*}"
|
||||||
|
REPOSITORY="${NR##*/}"
|
||||||
|
|
||||||
|
TAG=${{ inputs.tag }}
|
||||||
|
VERSION=${TAG#v}
|
||||||
|
|
||||||
|
echo "REGISTRY=${REGISTRY}" >> $GITHUB_ENV
|
||||||
|
echo "NAMESPACE=${NAMESPACE}" >> $GITHUB_ENV
|
||||||
|
echo "REPOSITORY=${REPOSITORY}" >> $GITHUB_ENV
|
||||||
|
echo "VERSION=${VERSION}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Push images
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
docker image tag $REPOSITORY:$VERSION-amd64 $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-amd64
|
||||||
|
docker push $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-amd64
|
||||||
|
|
||||||
|
docker image tag $REPOSITORY:$VERSION-arm64 $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm64
|
||||||
|
docker push $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm64
|
||||||
|
|
||||||
|
docker image tag $REPOSITORY:$VERSION-arm $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm
|
||||||
|
docker push $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm
|
||||||
|
|
||||||
|
- name: Push manifest
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
docker manifest create $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION \
|
||||||
|
$REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-amd64 \
|
||||||
|
$REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm64 \
|
||||||
|
$REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm
|
||||||
|
docker manifest annotate $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-amd64 --arch amd64
|
||||||
|
docker manifest annotate $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm64 --arch arm64
|
||||||
|
docker manifest annotate $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm --arch arm
|
||||||
|
docker manifest push $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION
|
||||||
|
|
||||||
|
docker manifest create $REGISTRY/$NAMESPACE/$REPOSITORY:latest \
|
||||||
|
$REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-amd64 \
|
||||||
|
$REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm64 \
|
||||||
|
$REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm
|
||||||
|
docker manifest annotate $REGISTRY/$NAMESPACE/$REPOSITORY:latest $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-amd64 --arch amd64
|
||||||
|
docker manifest annotate $REGISTRY/$NAMESPACE/$REPOSITORY:latest $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm64 --arch arm64
|
||||||
|
docker manifest annotate $REGISTRY/$NAMESPACE/$REPOSITORY:latest $REGISTRY/$NAMESPACE/$REPOSITORY:$VERSION-arm --arch arm
|
||||||
|
docker manifest push $REGISTRY/$NAMESPACE/$REPOSITORY:latest
|
@ -1,14 +0,0 @@
|
|||||||
.env
|
|
||||||
/docker-compose.*
|
|
||||||
/result*
|
|
||||||
/.direnv/
|
|
||||||
/build/
|
|
||||||
|
|
||||||
# Client
|
|
||||||
/client/node_modules/
|
|
||||||
/client/.svelte-kit/
|
|
||||||
|
|
||||||
# Server
|
|
||||||
/server/client/
|
|
||||||
/server/tmp/
|
|
||||||
/server/build/
|
|
23
.gitea/workflows/check.yaml
Normal file
23
.gitea/workflows/check.yaml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
name: Check
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened, edited, auto_merge_enabled]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
name: check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: |
|
||||||
|
contains(github.event.head_commit.message, 'bump:') == false &&
|
||||||
|
contains(github.event.head_commit.message, 'Merge pull request') == false
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: ./.actions/init
|
||||||
|
with:
|
||||||
|
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
|
- run: nix flake check
|
68
.gitea/workflows/release.yaml
Normal file
68
.gitea/workflows/release.yaml
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: ./.actions/init
|
||||||
|
with:
|
||||||
|
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
|
- run: nix flake check
|
||||||
|
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: check
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: ./.actions/init
|
||||||
|
with:
|
||||||
|
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
|
- run: >
|
||||||
|
nix build
|
||||||
|
.#trevstack-linux-amd64
|
||||||
|
.#trevstack-linux-arm64
|
||||||
|
.#trevstack-linux-arm
|
||||||
|
.#trevstack-windows-amd64
|
||||||
|
.#trevstack-darwin-amd64
|
||||||
|
.#trevstack-darwin-arm64
|
||||||
|
|
||||||
|
- uses: akkuman/gitea-release-action@v1
|
||||||
|
with:
|
||||||
|
files: |-
|
||||||
|
result*/bin/*
|
||||||
|
|
||||||
|
package:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: release
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: ./.actions/init
|
||||||
|
with:
|
||||||
|
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
|
- uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ github.server_url }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.PAT }}
|
||||||
|
|
||||||
|
- name: Build & load images
|
||||||
|
run: |
|
||||||
|
nix build .#trevstack-linux-amd64-image && ./result | docker load
|
||||||
|
nix build .#trevstack-linux-arm64-image && ./result | docker load
|
||||||
|
nix build .#trevstack-linux-arm-image && ./result | docker load
|
||||||
|
|
||||||
|
- name: Push images
|
||||||
|
uses: ./.actions/push
|
||||||
|
with:
|
||||||
|
server_url: ${{ github.server_url }}
|
||||||
|
repository: ${{ github.repository }}
|
||||||
|
tag: ${{ github.ref_name }}
|
50
.gitea/workflows/update.yaml
Normal file
50
.gitea/workflows/update.yaml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
name: Update
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: ./.actions/init
|
||||||
|
with:
|
||||||
|
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
|
# https://github.com/actions/checkout/issues/13
|
||||||
|
- name: Set git config
|
||||||
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
git checkout -B update
|
||||||
|
|
||||||
|
- run: nix run .#update
|
||||||
|
|
||||||
|
- name: Create pull request
|
||||||
|
env:
|
||||||
|
PAT: ${{ secrets.PAT }}
|
||||||
|
run: |
|
||||||
|
URL="${{ gitea.server_url }}"
|
||||||
|
REPO_OWNER_SLASH_NAME="${{ gitea.repository }}"
|
||||||
|
|
||||||
|
if ! git ls-remote --exit-code origin update; then
|
||||||
|
git push origin update --force
|
||||||
|
|
||||||
|
PR_RESPONSE=$(curl -s -X POST -H "Authorization: token $PAT" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"title":"update","body":"automatic update","head":"update","base":"main"}' \
|
||||||
|
"$URL/api/v1/repos/$REPO_OWNER_SLASH_NAME/pulls")
|
||||||
|
|
||||||
|
PR_NUMBER=$(echo "$PR_RESPONSE" | jq -r '.number')
|
||||||
|
|
||||||
|
curl -s -X POST -H "Authorization: token $PAT" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"Do":"merge","merge_when_checks_succeed":true,"delete_branch_after_merge":true}' \
|
||||||
|
"$URL/api/v1/repos/$REPO_OWNER_SLASH_NAME/pulls/$PR_NUMBER/merge"
|
||||||
|
|
||||||
|
else
|
||||||
|
git push origin update --force
|
||||||
|
fi
|
23
.github/workflows/check.yaml
vendored
Normal file
23
.github/workflows/check.yaml
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
name: Check
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened, edited, auto_merge_enabled]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
name: check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: |
|
||||||
|
contains(github.event.head_commit.message, 'bump:') == false &&
|
||||||
|
contains(github.event.head_commit.message, 'Merge pull request') == false
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: ./.actions/init
|
||||||
|
with:
|
||||||
|
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
|
- run: nix flake check
|
28
.github/workflows/lint.yaml
vendored
28
.github/workflows/lint.yaml
vendored
@ -1,28 +0,0 @@
|
|||||||
name: Lint Workflow
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
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: Run checks
|
|
||||||
run: nix flake check
|
|
81
.github/workflows/release.yaml
vendored
81
.github/workflows/release.yaml
vendored
@ -1,34 +1,35 @@
|
|||||||
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
|
- uses: actions/checkout@v4
|
||||||
uses: actions/checkout@v4
|
- uses: ./.actions/init
|
||||||
|
|
||||||
- name: Install Nix
|
|
||||||
uses: cachix/install-nix-action@v31
|
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
- name: Use Cachix
|
- run: nix flake check
|
||||||
uses: cachix/cachix-action@v16
|
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: check
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: ./.actions/init
|
||||||
with:
|
with:
|
||||||
name: trevstack
|
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
|
||||||
|
|
||||||
- name: Build
|
- run: >
|
||||||
run: >
|
|
||||||
nix build
|
nix build
|
||||||
.#trevstack-linux-amd64
|
.#trevstack-linux-amd64
|
||||||
.#trevstack-linux-arm64
|
.#trevstack-linux-arm64
|
||||||
@ -37,52 +38,36 @@ jobs:
|
|||||||
.#trevstack-darwin-amd64
|
.#trevstack-darwin-amd64
|
||||||
.#trevstack-darwin-arm64
|
.#trevstack-darwin-arm64
|
||||||
|
|
||||||
- name: Create 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/*
|
||||||
|
|
||||||
# https://docs.docker.com/build/ci/github-actions/manage-tags-labels/
|
|
||||||
package:
|
package:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: release # Wait for binary cache to propagate
|
needs: release
|
||||||
steps:
|
steps:
|
||||||
- name: Docker meta
|
- uses: actions/checkout@v4
|
||||||
id: meta
|
- uses: ./.actions/init
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
with:
|
||||||
# list of Docker images to use as base name for tags
|
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
images: |
|
|
||||||
${{ github.repository }}
|
|
||||||
ghcr.io/${{ github.repository }}
|
|
||||||
# generate Docker tags based on the following events/attributes
|
|
||||||
tags: |
|
|
||||||
type=ref,event=branch
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- uses: docker/login-action@v3
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Build & load images
|
||||||
uses: docker/setup-qemu-action@v3
|
run: |
|
||||||
|
nix build .#trevstack-linux-amd64-image && ./result | docker load
|
||||||
|
nix build .#trevstack-linux-arm64-image && ./result | docker load
|
||||||
|
nix build .#trevstack-linux-arm-image && ./result | docker load
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Push images
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: ./.actions/push
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
with:
|
||||||
push: true
|
server_url: ghcr.io
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
repository: ${{ github.repository }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
tag: ${{ github.ref_name }}
|
||||||
|
39
.github/workflows/update.yaml
vendored
39
.github/workflows/update.yaml
vendored
@ -1,41 +1,40 @@
|
|||||||
name: Update Workflow
|
name: Update
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 0 * * *"
|
- cron: "0 0 * * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update:
|
update:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- uses: actions/checkout@v4
|
||||||
uses: actions/checkout@v4
|
- uses: ./.actions/init
|
||||||
|
|
||||||
- name: Install Nix
|
|
||||||
uses: cachix/install-nix-action@v31
|
|
||||||
with:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||||
|
|
||||||
- name: Use Cachix
|
|
||||||
uses: cachix/cachix-action@v16
|
|
||||||
with:
|
|
||||||
name: trevstack
|
|
||||||
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
|
||||||
run: |
|
run: |
|
||||||
git config user.name "github-actions[bot]"
|
git config user.name "github-actions[bot]"
|
||||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
- name: Update
|
- run: nix run .#update
|
||||||
run: nix run .#update
|
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create pull request
|
||||||
|
id: cpr
|
||||||
uses: peter-evans/create-pull-request@v7
|
uses: peter-evans/create-pull-request@v7
|
||||||
with:
|
with:
|
||||||
delete-branch: true
|
branch: update
|
||||||
title: Bump deps
|
title: update
|
||||||
|
body: automatic update
|
||||||
|
|
||||||
|
- name: Enable automerge
|
||||||
|
run: gh pr merge --merge --auto "${{ steps.cpr.outputs.pull-request-number }}"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.PAT }}
|
||||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,5 +1,7 @@
|
|||||||
.env
|
.env
|
||||||
/docker-compose.*
|
/docker-compose.*
|
||||||
|
/build/
|
||||||
|
|
||||||
|
# Nix
|
||||||
/result*
|
/result*
|
||||||
/.direnv/
|
/.direnv/
|
||||||
/build/
|
|
@ -3,7 +3,25 @@
|
|||||||
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-patch}" 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
|
||||||
|
sed -i -e "s/${version}/${next_version}/g" client/static/openapi/openapi.yaml
|
||||||
|
git add openapi.yaml
|
||||||
|
git add client/static/openapi/openapi.yaml
|
||||||
|
|
||||||
echo "bumping client"
|
echo "bumping client"
|
||||||
cd "${git_root}/client"
|
cd "${git_root}/client"
|
||||||
|
@ -6,11 +6,19 @@ 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 commit -m "build(nix): updated nix dependencies"
|
git commit -m "build(nix): updated nix dependencies"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "updating protobuf deps"
|
||||||
|
cd "${git_root}/proto"
|
||||||
|
buf dep update
|
||||||
|
if ! git diff --exit-code buf.lock; then
|
||||||
|
git add buf.lock
|
||||||
|
git commit -m "build(buf): updated buf dependencies"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "updating client"
|
echo "updating client"
|
||||||
cd "${git_root}/client"
|
cd "${git_root}/client"
|
||||||
npm update --save && npm i
|
npm update --save && npm i
|
||||||
@ -28,7 +36,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
|
||||||
|
|
||||||
|
@ -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
10
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"golang.go",
|
||||||
|
"dorzey.vscode-sqlfluff",
|
||||||
|
"bufbuild.vscode-buf",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"svelte.svelte-vscode",
|
||||||
|
"esbenp.prettier-vscode"
|
||||||
|
]
|
||||||
|
}
|
45
.vscode/settings.json
vendored
45
.vscode/settings.json
vendored
@ -1,7 +1,46 @@
|
|||||||
{
|
{
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
|
||||||
|
// Go
|
||||||
"go.lintTool": "revive",
|
"go.lintTool": "revive",
|
||||||
"go.lintFlags": [
|
"go.formatTool": "goimports",
|
||||||
"--config=server/revive.toml"
|
"go.buildTags": "dev",
|
||||||
],
|
"go.lintFlags": ["--config=server/revive.toml"],
|
||||||
|
"gopls": { "ui.semanticTokens": true },
|
||||||
|
"[go]": {
|
||||||
|
"editor.defaultFormatter": "golang.go"
|
||||||
|
},
|
||||||
|
|
||||||
|
// SQLFluff
|
||||||
"sqlfluff.config": "server/db/.sqlfluff",
|
"sqlfluff.config": "server/db/.sqlfluff",
|
||||||
|
"[sql]": {
|
||||||
|
"editor.defaultFormatter": "dorzey.vscode-sqlfluff"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
"[proto]": {
|
||||||
|
"editor.defaultFormatter": "bufbuild.vscode-buf"
|
||||||
|
},
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
}
|
||||||
}
|
}
|
29
Dockerfile
29
Dockerfile
@ -1,29 +0,0 @@
|
|||||||
# Nix builder
|
|
||||||
FROM nixos/nix:latest AS builder
|
|
||||||
|
|
||||||
# Copy our source and setup our working dir.
|
|
||||||
COPY . /tmp/build
|
|
||||||
WORKDIR /tmp/build
|
|
||||||
|
|
||||||
# Build our Nix environment
|
|
||||||
RUN nix \
|
|
||||||
--extra-experimental-features "nix-command flakes" \
|
|
||||||
--option filter-syscalls false \
|
|
||||||
--accept-flake-config \
|
|
||||||
build
|
|
||||||
|
|
||||||
# Copy the Nix store closure into a directory. The Nix store closure is the
|
|
||||||
# entire set of Nix store values that we need for our build.
|
|
||||||
RUN mkdir /tmp/nix-store-closure
|
|
||||||
RUN cp -R $(nix-store -qR result/) /tmp/nix-store-closure
|
|
||||||
|
|
||||||
# Final image is based on scratch. We copy a bunch of Nix dependencies
|
|
||||||
# but they're fully self-contained so we don't need Nix anymore.
|
|
||||||
FROM scratch
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Copy /nix/store
|
|
||||||
COPY --from=builder /tmp/nix-store-closure /nix/store
|
|
||||||
COPY --from=builder /tmp/build/result /app
|
|
||||||
CMD ["/app/bin/trevstack"]
|
|
21
LICENSE
Normal file
21
LICENSE
Normal 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.
|
125
README.md
Normal file
125
README.md
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
## 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)
|
||||||
|
- Can be entirely self-hosted
|
||||||
|
- 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` to start the server & client
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
- `nix build [#trevstack-(GOOS)-(GOARCH)]`: builds the application. Defaults to building for your current platform, but can be built to many by specifying the GOOS and GOARCH values
|
||||||
|
|
||||||
|
- `nix flake check`: runs all validations
|
||||||
|
|
||||||
|
- `buf lint proto` & `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
|
||||||
|
|
||||||
|
### Github Actions
|
||||||
|
|
||||||
|
To use github actions for CI/CD, you'll need to create a fine-grained personal access token for the repository with the permissions:
|
||||||
|
|
||||||
|
- Contents (read and write)
|
||||||
|
- Pull requests (read and write)
|
||||||
|
|
||||||
|
And change some settings for the repository:
|
||||||
|
|
||||||
|
- General -> Allow auto-merge: true
|
||||||
|
- Rules -> Rulesets -> New ruleset
|
||||||
|
- Branch targeting criteria: Default
|
||||||
|
- Branch rules
|
||||||
|
- Require status checks to pass -> Add checks -> "check"
|
||||||
|
- Actions -> General -> Workflow permissions
|
||||||
|
- Read and write permissions: true
|
||||||
|
- Allow GitHub Actions to create and approve pull requests: true
|
||||||
|
- Secrets and variables -> Actions -> Repository secrets
|
||||||
|
- PAT: (personal access token)
|
||||||
|
|
||||||
|
### Gitea Actions
|
||||||
|
|
||||||
|
To use gitea actions for CI/CD, you'll need to create an [API token](https://docs.gitea.com/development/api-usage) with the scopes:
|
||||||
|
|
||||||
|
- write:repository
|
||||||
|
- write:package
|
||||||
|
|
||||||
|
And change some settings for the repository:
|
||||||
|
|
||||||
|
- Repository -> Delete pull request branch after merge by default: true
|
||||||
|
- Branches -> Add New Rule
|
||||||
|
- Protected Branch Name Pattern: main
|
||||||
|
- Enable Status Check: true
|
||||||
|
- Status check patterns: Check / check\*
|
||||||
|
- Actions -> Secrets
|
||||||
|
- PAT: (API token)
|
||||||
|
|
||||||
|
## 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/)]
|
@ -1,5 +1,8 @@
|
|||||||
version: v2
|
version: v2
|
||||||
clean: true
|
clean: true
|
||||||
|
inputs:
|
||||||
|
- directory: proto
|
||||||
|
|
||||||
managed:
|
managed:
|
||||||
enabled: true
|
enabled: true
|
||||||
override:
|
override:
|
||||||
@ -27,5 +30,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
|
||||||
|
@ -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",
|
||||||
|
@ -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(
|
||||||
|
2025
client/package-lock.json
generated
2025
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "trevstack",
|
"name": "trevstack",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.21",
|
"version": "0.0.47",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
@ -19,33 +19,33 @@
|
|||||||
"@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.34",
|
||||||
"@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.1",
|
||||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||||
"@tailwindcss/vite": "^4.1.6",
|
"@tailwindcss/vite": "^4.1.7",
|
||||||
"bits-ui": "^1.4.8",
|
"bits-ui": "^1.5.3",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"eslint": "^9.26.0",
|
"eslint": "^9.27.0",
|
||||||
"eslint-config-prettier": "^10.1.5",
|
"eslint-config-prettier": "^10.1.5",
|
||||||
"eslint-plugin-svelte": "^3.5.1",
|
"eslint-plugin-svelte": "^3.8.1",
|
||||||
"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.4.0",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
"svelte": "^5.28.2",
|
"svelte": "^5.31.1",
|
||||||
"svelte-check": "^4.1.7",
|
"svelte-check": "^4.2.1",
|
||||||
"svelte-sonner": "^0.3.28",
|
"svelte-sonner": "^0.3.28",
|
||||||
"tailwind-merge": "^3.3.0",
|
"tailwind-merge": "^3.3.0",
|
||||||
"tailwind-variants": "^1.0.0",
|
"tailwind-variants": "^1.0.0",
|
||||||
"tailwindcss": "^4.0.13",
|
"tailwindcss": "^4.0.13",
|
||||||
"tw-animate-css": "^1.2.9",
|
"tw-animate-css": "^1.3.0",
|
||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
@import "tw-animate-css";
|
@import 'tw-animate-css';
|
||||||
|
|
||||||
@custom-variant dark (&:where(.dark, .dark *));
|
@custom-variant dark (&:where(.dark, .dark *));
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
export function newState<T>(s: T) {
|
export function newState<T>(s: T) {
|
||||||
const state = $state(s);
|
const state = $state(s);
|
||||||
|
|
||||||
|
@ -1,35 +1,33 @@
|
|||||||
import { create, type DescMessage, type DescService, type MessageShape, type MessageInitShape } from "@bufbuild/protobuf";
|
import type { DescMessage, DescService, MessageInitShape, MessageShape } from '@bufbuild/protobuf';
|
||||||
import { ValidationError, type Violation } from "@bufbuild/protovalidate";
|
import type { Violation } from '@bufbuild/protovalidate';
|
||||||
import { Validator } from "../transport";
|
import type { Client } from '@connectrpc/connect';
|
||||||
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>;
|
||||||
start?: boolean,
|
start?: boolean;
|
||||||
reset?: boolean,
|
reset?: boolean;
|
||||||
onSubmit?: (formData: FormData, input: MessageShape<Input>) => Promise<MessageShape<Input>>,
|
onSubmit?: (formData: FormData, input: MessageShape<Input>) => Promise<MessageShape<Input>>;
|
||||||
onResult?: (result: MessageShape<Output>) => void,
|
onResult?: (result: MessageShape<Output>) => void;
|
||||||
onError?: (err: Violation[] | ConnectError) => void
|
onError?: (err: Violation[] | ConnectError) => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
type Violations<Field> = {
|
type Violations<Field> = {
|
||||||
[field in keyof Field]?: Violation[];
|
[field in keyof Field]?: Violation[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function coolForm<
|
export function coolForm<Service extends DescService, Method extends Service['methods'][number]>(
|
||||||
Service extends DescService,
|
|
||||||
Method extends Service['methods'][number]
|
|
||||||
>(
|
|
||||||
client: Client<Service>,
|
client: Client<Service>,
|
||||||
method: Method,
|
method: Method,
|
||||||
options?: Options<Method['input'], Method['output']>
|
options?: Options<Method['input'], Method['output']>
|
||||||
) {
|
) {
|
||||||
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 = () => {
|
||||||
@ -48,7 +46,7 @@ export function coolForm<
|
|||||||
// Map violation errors to errors rune
|
// Map violation errors to errors rune
|
||||||
for (const violation of e.violations) {
|
for (const violation of e.violations) {
|
||||||
for (const field of violation.field) {
|
for (const field of violation.field) {
|
||||||
if (!("localName" in field)) {
|
if (!('localName' in field)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +54,7 @@ export function coolForm<
|
|||||||
if (!errors[field.localName]) {
|
if (!errors[field.localName]) {
|
||||||
Object.assign(errors, {
|
Object.assign(errors, {
|
||||||
[field.localName]: [violation]
|
[field.localName]: [violation]
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
errors[field.localName]?.push(violation);
|
errors[field.localName]?.push(violation);
|
||||||
}
|
}
|
||||||
@ -81,13 +79,13 @@ export function coolForm<
|
|||||||
|
|
||||||
// If we want to reset the input
|
// If we want to reset the input
|
||||||
if (options && (options.reset == undefined || options.reset)) {
|
if (options && (options.reset == undefined || options.reset)) {
|
||||||
const cleared = create(method.input as Method['input'], options?.init)
|
const cleared = create(method.input as Method['input'], options?.init);
|
||||||
Object.assign(input, cleared);
|
Object.assign(input, cleared);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// When a request fails
|
// When a request fails
|
||||||
const fail = (err: Violation[] | ConnectError | any) => {
|
const fail = (err: Violation[] | ConnectError | Error) => {
|
||||||
loading = false;
|
loading = false;
|
||||||
|
|
||||||
// It's a Violation[]
|
// It's a Violation[]
|
||||||
@ -108,7 +106,7 @@ export function coolForm<
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw err;
|
throw err;
|
||||||
}
|
};
|
||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
loading = true;
|
loading = true;
|
||||||
@ -121,18 +119,21 @@ export function coolForm<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send response
|
// Send response
|
||||||
if (method.methodKind == "unary") {
|
if (method.methodKind == 'unary') {
|
||||||
// @ts-ignore I can't figure out how to make this typescript compliant
|
// @ts-expect-error I can't figure out how to make this typescript compliant
|
||||||
const response = client[method.localName]($state.snapshot(input)) as Promise<MessageShape<Method['output']>>
|
const response = client[method.localName]($state.snapshot(input)) as Promise<
|
||||||
|
MessageShape<Method['output']>
|
||||||
|
>;
|
||||||
|
|
||||||
response
|
response
|
||||||
.then((resp) => {
|
.then((resp) => {
|
||||||
success(resp);
|
success(resp);
|
||||||
}).catch(err => {
|
})
|
||||||
|
.catch((err) => {
|
||||||
fail(err);
|
fail(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// A nice action to give to forms to run submit() on submit
|
// A nice action to give to forms to run submit() on submit
|
||||||
const impair: Action<HTMLFormElement> = (form) => {
|
const impair: Action<HTMLFormElement> = (form) => {
|
||||||
@ -151,10 +152,10 @@ export function coolForm<
|
|||||||
}
|
}
|
||||||
|
|
||||||
submit();
|
submit();
|
||||||
}
|
};
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
form.onsubmit = () => { };
|
form.onsubmit = () => {};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -171,5 +172,5 @@ export function coolForm<
|
|||||||
submit,
|
submit,
|
||||||
validate,
|
validate,
|
||||||
impair
|
impair
|
||||||
}
|
};
|
||||||
}
|
}
|
@ -1,7 +1,4 @@
|
|||||||
import { coolForm } from "./coolforms.svelte";
|
import { newState } from './conststate.svelte';
|
||||||
import { newState } from "./conststate.svelte";
|
import { coolForm } from './coolforms.svelte';
|
||||||
|
|
||||||
export {
|
export { coolForm, newState };
|
||||||
coolForm,
|
|
||||||
newState
|
|
||||||
};
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
|
import type { Interceptor } from '@connectrpc/connect';
|
||||||
|
import { createValidator } from '@bufbuild/protovalidate';
|
||||||
|
import { Code, ConnectError, createClient } from '@connectrpc/connect';
|
||||||
import { createConnectTransport } from '@connectrpc/connect-web';
|
import { createConnectTransport } from '@connectrpc/connect-web';
|
||||||
import { createValidator } from "@bufbuild/protovalidate";
|
|
||||||
import { Code, ConnectError, createClient, type Interceptor } from '@connectrpc/connect';
|
|
||||||
import { AuthService } from '$lib/connect/user/v1/auth_pb';
|
|
||||||
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 {
|
||||||
@ -15,7 +16,10 @@ const redirector: Interceptor = (next) => async (req) => {
|
|||||||
if (error.code === Code.Unauthenticated) {
|
if (error.code === Code.Unauthenticated) {
|
||||||
const redirectURL = new URL(page.url);
|
const redirectURL = new URL(page.url);
|
||||||
redirectURL.pathname = '/auth';
|
redirectURL.pathname = '/auth';
|
||||||
redirectURL.searchParams.append('redir', encodeURIComponent(page.url.pathname + page.url.search));
|
redirectURL.searchParams.append(
|
||||||
|
'redir',
|
||||||
|
encodeURIComponent(page.url.pathname + page.url.search)
|
||||||
|
);
|
||||||
|
|
||||||
await goto(redirectURL);
|
await goto(redirectURL);
|
||||||
}
|
}
|
||||||
|
@ -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 select-none items-center justify-center rounded-full text-sm transition-all',
|
'bg-surface flex size-full items-center justify-center rounded-full text-sm transition-all select-none',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
@ -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),
|
||||||
@ -12,6 +12,6 @@
|
|||||||
<AvatarPrimitive.Image
|
<AvatarPrimitive.Image
|
||||||
bind:ref
|
bind:ref
|
||||||
data-slot="avatar-image"
|
data-slot="avatar-image"
|
||||||
class={cn("aspect-square size-full", className)}
|
class={cn('aspect-square size-full', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -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),
|
||||||
@ -12,6 +12,10 @@
|
|||||||
<AvatarPrimitive.Root
|
<AvatarPrimitive.Root
|
||||||
bind:ref
|
bind:ref
|
||||||
data-slot="avatar"
|
data-slot="avatar"
|
||||||
class={cn("relative outline outline-offset-2 outline-surface-1 flex size-9 shrink-0 overflow-hidden rounded-full", className)}
|
class={cn(
|
||||||
|
'outline-surface-1 relative flex size-9 shrink-0 overflow-hidden rounded-full shadow-xs outline outline-offset-2',
|
||||||
|
|
||||||
|
className
|
||||||
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Root from "./avatar.svelte";
|
import Fallback from './avatar-fallback.svelte';
|
||||||
import Image from "./avatar-image.svelte";
|
import Image from './avatar-image.svelte';
|
||||||
import Fallback from "./avatar-fallback.svelte";
|
import Root from './avatar.svelte';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
@ -9,5 +9,5 @@ export {
|
|||||||
//
|
//
|
||||||
Root as Avatar,
|
Root as Avatar,
|
||||||
Image as AvatarImage,
|
Image as AvatarImage,
|
||||||
Fallback as AvatarFallback,
|
Fallback as AvatarFallback
|
||||||
};
|
};
|
||||||
|
@ -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(
|
||||||
'shadow-xs inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium 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',
|
||||||
@ -16,15 +17,15 @@
|
|||||||
'disabled:pointer-events-none disabled:opacity-50',
|
'disabled:pointer-events-none disabled:opacity-50',
|
||||||
|
|
||||||
// Images
|
// Images
|
||||||
"[&_svg:not([class*='size-'])]:size-5 [&_svg]:pointer-events-none [&_svg]:shrink-0"
|
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-5"
|
||||||
),
|
),
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: 'text-crust bg-accent hover:bg-accent/90 shadow-xs',
|
default: 'text-crust bg-accent hover:bg-accent/90 shadow-xs',
|
||||||
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 shadow-xs border bg-transparent',
|
outline: 'text-text border-surface-1 hover:bg-surface border bg-transparent shadow-xs',
|
||||||
input: 'text-text border-surface-1 hover:border-overlay shadow-xs border bg-transparent',
|
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',
|
||||||
@ -47,7 +48,6 @@
|
|||||||
variant?: ButtonVariant;
|
variant?: ButtonVariant;
|
||||||
size?: ButtonSize;
|
size?: ButtonSize;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
scan?: boolean;
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -60,7 +60,6 @@
|
|||||||
href = undefined,
|
href = undefined,
|
||||||
type = 'button',
|
type = 'button',
|
||||||
loading,
|
loading,
|
||||||
scan,
|
|
||||||
children,
|
children,
|
||||||
...restProps
|
...restProps
|
||||||
}: ButtonProps = $props();
|
}: ButtonProps = $props();
|
||||||
|
@ -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,
|
||||||
@ -13,5 +9,5 @@ export {
|
|||||||
buttonVariants,
|
buttonVariants,
|
||||||
type ButtonProps,
|
type ButtonProps,
|
||||||
type ButtonSize,
|
type ButtonSize,
|
||||||
type ButtonVariant,
|
type ButtonVariant
|
||||||
};
|
};
|
@ -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>>;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Root from "./card.svelte";
|
import Root from './card.svelte';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
//
|
//
|
||||||
Root as Card,
|
Root as Card
|
||||||
};
|
};
|
@ -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}
|
||||||
@ -58,7 +58,7 @@
|
|||||||
Pick a date range
|
Pick a date range
|
||||||
{/if}
|
{/if}
|
||||||
</Popover.Trigger>
|
</Popover.Trigger>
|
||||||
<Popover.Content class="w-auto p-0 bg-based" align="start">
|
<Popover.Content class="bg-based w-auto p-0" align="start">
|
||||||
<RangeCalendar
|
<RangeCalendar
|
||||||
bind:value
|
bind:value
|
||||||
onStartValueChange={(v) => {
|
onStartValueChange={(v) => {
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import Root from "./daterangepicker.svelte";
|
import Root from './daterangepicker.svelte';
|
||||||
|
|
||||||
export {
|
export { Root, Root as DateRangePicker };
|
||||||
Root,
|
|
||||||
Root as DateRangePicker
|
|
||||||
};
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
import { Dialog as DialogPrimitive } from 'bits-ui';
|
||||||
|
|
||||||
let { ref = $bindable(null), ...restProps }: DialogPrimitive.CloseProps = $props();
|
let { ref = $bindable(null), ...restProps }: DialogPrimitive.CloseProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
@ -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),
|
||||||
@ -34,7 +35,7 @@
|
|||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
<DialogPrimitive.Close
|
<DialogPrimitive.Close
|
||||||
class={cn(
|
class={cn(
|
||||||
'text-text absolute top-4 right-4 cursor-pointer p-1 rounded hover:bg-crust transition-all disabled:pointer-events-none',
|
'text-text hover:bg-crust absolute top-4 right-4 cursor-pointer rounded p-1 transition-all disabled:pointer-events-none',
|
||||||
|
|
||||||
// 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',
|
||||||
|
@ -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),
|
||||||
@ -12,6 +12,6 @@
|
|||||||
<DialogPrimitive.Description
|
<DialogPrimitive.Description
|
||||||
bind:ref
|
bind:ref
|
||||||
data-slot="dialog-description"
|
data-slot="dialog-description"
|
||||||
class={cn("text-muted-foreground text-sm", className)}
|
class={cn('text-muted-foreground text-sm', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
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.js";
|
import { cn } from '$lib/utils.js';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<div
|
<div
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
data-slot="dialog-footer"
|
data-slot="dialog-footer"
|
||||||
class={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
|
class={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<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 {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<div
|
<div
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
data-slot="dialog-header"
|
data-slot="dialog-header"
|
||||||
class={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
class={cn('flex flex-col gap-2 text-center sm:text-left', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
|
@ -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),
|
||||||
@ -13,7 +13,7 @@
|
|||||||
bind:ref
|
bind:ref
|
||||||
data-slot="dialog-overlay"
|
data-slot="dialog-overlay"
|
||||||
class={cn(
|
class={cn(
|
||||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
@ -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),
|
||||||
@ -12,6 +12,6 @@
|
|||||||
<DialogPrimitive.Title
|
<DialogPrimitive.Title
|
||||||
bind:ref
|
bind:ref
|
||||||
data-slot="dialog-title"
|
data-slot="dialog-title"
|
||||||
class={cn("text-lg font-semibold leading-none", className)}
|
class={cn('text-lg leading-none font-semibold', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
import { Dialog as DialogPrimitive } from 'bits-ui';
|
||||||
|
|
||||||
let { ref = $bindable(null), ...restProps }: DialogPrimitive.TriggerProps = $props();
|
let { ref = $bindable(null), ...restProps }: DialogPrimitive.TriggerProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
@ -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 Content from './dialog-content.svelte';
|
||||||
|
import Description from './dialog-description.svelte';
|
||||||
|
import Footer from './dialog-footer.svelte';
|
||||||
|
import Header from './dialog-header.svelte';
|
||||||
|
import Overlay from './dialog-overlay.svelte';
|
||||||
|
import Title from './dialog-title.svelte';
|
||||||
|
import Trigger from './dialog-trigger.svelte';
|
||||||
import Root from './dialog.svelte';
|
import Root from './dialog.svelte';
|
||||||
import Title from "./dialog-title.svelte";
|
|
||||||
import Footer from "./dialog-footer.svelte";
|
|
||||||
import Header from "./dialog-header.svelte";
|
|
||||||
import Overlay from "./dialog-overlay.svelte";
|
|
||||||
import Content from "./dialog-content.svelte";
|
|
||||||
import Description from "./dialog-description.svelte";
|
|
||||||
import Trigger from "./dialog-trigger.svelte";
|
|
||||||
import Close from "./dialog-close.svelte";
|
|
||||||
|
|
||||||
const Portal = DialogPrimitive.Portal;
|
const Portal = DialogPrimitive.Portal;
|
||||||
|
|
||||||
@ -33,5 +32,5 @@ export {
|
|||||||
Overlay as DialogOverlay,
|
Overlay as DialogOverlay,
|
||||||
Content as DialogContent,
|
Content as DialogContent,
|
||||||
Description as DialogDescription,
|
Description as DialogDescription,
|
||||||
Close as DialogClose,
|
Close as DialogClose
|
||||||
};
|
};
|
||||||
|
@ -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 Check from "@lucide/svelte/icons/check";
|
import type { Snippet } from 'svelte';
|
||||||
import Minus from "@lucide/svelte/icons/minus";
|
import Check from '@lucide/svelte/icons/check';
|
||||||
import { cn } from "$lib/utils.js";
|
import Minus from '@lucide/svelte/icons/minus';
|
||||||
import type { Snippet } from "svelte";
|
import { cn } from '$lib/utils.js';
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
@ -23,13 +24,13 @@
|
|||||||
bind:indeterminate
|
bind:indeterminate
|
||||||
data-slot="dropdown-menu-checkbox-item"
|
data-slot="dropdown-menu-checkbox-item"
|
||||||
class={cn(
|
class={cn(
|
||||||
"focus:bg-surface outline-hidden relative flex cursor-pointer select-none items-center gap-2 rounded-sm py-2 pl-8 pr-2 text-sm",
|
'focus:bg-surface relative flex cursor-pointer items-center gap-2 rounded-sm py-2 pr-2 pl-8 text-sm outline-hidden select-none',
|
||||||
|
|
||||||
// Disabled
|
// Disabled
|
||||||
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
|
|
||||||
// Images
|
// Images
|
||||||
"[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
@ -39,7 +40,7 @@
|
|||||||
{#if indeterminate}
|
{#if indeterminate}
|
||||||
<Minus class="size-4" />
|
<Minus class="size-4" />
|
||||||
{:else}
|
{:else}
|
||||||
<Check class={cn("size-4", !checked && "text-transparent")} />
|
<Check class={cn('size-4', !checked && 'text-transparent')} />
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
{@render childrenProp?.()}
|
{@render childrenProp?.()}
|
||||||
|
@ -12,6 +12,6 @@
|
|||||||
<DropdownMenuPrimitive.Group
|
<DropdownMenuPrimitive.Group
|
||||||
bind:ref
|
bind:ref
|
||||||
data-slot="dropdown-menu-group"
|
data-slot="dropdown-menu-group"
|
||||||
class={cn('border-b border-surface first:pt-0 last:pb-0 last:border-none', className)}
|
class={cn('border-surface border-b first:pt-0 last:border-none last:pb-0', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { cn } from "$lib/utils.js";
|
import type { HTMLAttributes } from 'svelte/elements';
|
||||||
import { type WithElementRef } from "bits-ui";
|
import { cn } from '$lib/utils.js';
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import { type WithElementRef } from 'bits-ui';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
@ -17,7 +17,7 @@
|
|||||||
<div
|
<div
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
data-slot="dropdown-menu-label"
|
data-slot="dropdown-menu-label"
|
||||||
class={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
|
class={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
|
@ -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),
|
||||||
@ -15,10 +16,10 @@
|
|||||||
bind:ref
|
bind:ref
|
||||||
data-slot="dropdown-menu-radio-item"
|
data-slot="dropdown-menu-radio-item"
|
||||||
class={cn(
|
class={cn(
|
||||||
"focus:bg-surface text-text relative flex cursor-pointer items-center gap-2 py-2 pr-2 pl-8 text-sm select-none",
|
'focus:bg-surface text-text relative flex cursor-pointer items-center gap-2 py-2 pr-2 pl-8 text-sm select-none',
|
||||||
|
|
||||||
// Disabled
|
// Disabled
|
||||||
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
|
|
||||||
// Images
|
// Images
|
||||||
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
|
@ -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),
|
||||||
@ -12,6 +12,6 @@
|
|||||||
<DropdownMenuPrimitive.Separator
|
<DropdownMenuPrimitive.Separator
|
||||||
bind:ref
|
bind:ref
|
||||||
data-slot="dropdown-menu-separator"
|
data-slot="dropdown-menu-separator"
|
||||||
class={cn("bg-surface-1 -mx-1 my-1 h-px", className)}
|
class={cn('bg-surface-1 -mx-1 my-1 h-px', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -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),
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<span
|
<span
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
data-slot="dropdown-menu-shortcut"
|
data-slot="dropdown-menu-shortcut"
|
||||||
class={cn("text-text ml-auto text-xs tracking-widest", className)}
|
class={cn('text-text ml-auto text-xs tracking-widest', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
|
@ -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),
|
||||||
@ -13,7 +13,7 @@
|
|||||||
bind:ref
|
bind:ref
|
||||||
data-slot="dropdown-menu-sub-content"
|
data-slot="dropdown-menu-sub-content"
|
||||||
class={cn(
|
class={cn(
|
||||||
'bg-based text-text origin-(--radix-dropdown-menu-content-transform-origin) z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg',
|
'bg-based text-text z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
|
||||||
|
|
||||||
// Animations
|
// Animations
|
||||||
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
|
@ -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),
|
||||||
@ -18,8 +18,8 @@
|
|||||||
bind:ref
|
bind:ref
|
||||||
data-slot="dropdown-menu-sub-trigger"
|
data-slot="dropdown-menu-sub-trigger"
|
||||||
class={cn(
|
class={cn(
|
||||||
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground outline-hidden flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm",
|
'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none',
|
||||||
inset && "pl-8",
|
inset && 'pl-8',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||||
import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
|
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 Label from './dropdown-menu-label.svelte';
|
||||||
import Link from './dropdown-menu-link.svelte';
|
import Link from './dropdown-menu-link.svelte';
|
||||||
import Label from "./dropdown-menu-label.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 SubContent from './dropdown-menu-sub-content.svelte';
|
||||||
import Trigger from "./dropdown-menu-trigger.svelte";
|
import SubTrigger from './dropdown-menu-sub-trigger.svelte';
|
||||||
import SubContent from "./dropdown-menu-sub-content.svelte";
|
import Trigger from './dropdown-menu-trigger.svelte';
|
||||||
import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
|
|
||||||
|
|
||||||
const Sub = DropdownMenuPrimitive.Sub;
|
const Sub = DropdownMenuPrimitive.Sub;
|
||||||
const Root = DropdownMenuPrimitive.Root;
|
const Root = DropdownMenuPrimitive.Root;
|
||||||
@ -46,5 +46,5 @@ export {
|
|||||||
Sub,
|
Sub,
|
||||||
SubContent,
|
SubContent,
|
||||||
SubTrigger,
|
SubTrigger,
|
||||||
Trigger,
|
Trigger
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,7 @@ import { getContext, hasContext, setContext } from 'svelte';
|
|||||||
type Item = {
|
type Item = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const key = 'form';
|
const key = 'form';
|
||||||
export function setFormContext(id: string, name: string) {
|
export function setFormContext(id: string, name: string) {
|
||||||
@ -11,7 +11,7 @@ export function setFormContext(id: string, name: string) {
|
|||||||
if (!item) {
|
if (!item) {
|
||||||
const item: Item = $state({
|
const item: Item = $state({
|
||||||
id,
|
id,
|
||||||
name,
|
name
|
||||||
});
|
});
|
||||||
setContext(key, item);
|
setContext(key, item);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<div bind:this={ref} class={cn('text-red text-sm', className)} {...restProps}>
|
<div bind:this={ref} class={cn('text-red text-sm', className)} {...restProps}>
|
||||||
{#if errors && Array.isArray(errors)}
|
{#if errors && Array.isArray(errors)}
|
||||||
{#each errors as error}
|
{#each errors as error (error)}
|
||||||
<label for={item?.id}>{error.message}</label>
|
<label for={item?.id}>{error.message}</label>
|
||||||
{/each}
|
{/each}
|
||||||
{:else if errors}
|
{:else if errors}
|
||||||
|
@ -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;
|
||||||
@ -16,6 +16,6 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:this={ref} class={cn('flex flex-col gap-1')} {...restProps}>
|
<div bind:this={ref} class={cn('flex flex-col gap-1', className)} {...restProps}>
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +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 {
|
export { Field, Errors, Label };
|
||||||
Field,
|
|
||||||
Errors,
|
|
||||||
Label
|
|
||||||
};
|
|
||||||
|
@ -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();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Root from "./input.svelte";
|
import Root from './input.svelte';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
//
|
//
|
||||||
Root as Input,
|
Root as Input
|
||||||
};
|
};
|
@ -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';
|
||||||
|
|
||||||
@ -8,9 +8,7 @@
|
|||||||
|
|
||||||
type Props = WithElementRef<
|
type Props = WithElementRef<
|
||||||
Omit<HTMLInputAttributes, 'type'> &
|
Omit<HTMLInputAttributes, 'type'> &
|
||||||
({ type: 'file'; files?: FileList } | { type?: InputType; files?: undefined }) & {
|
({ type: 'file'; files?: FileList } | { type?: InputType; files?: undefined })
|
||||||
scan?: boolean;
|
|
||||||
}
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@ -19,7 +17,6 @@
|
|||||||
type,
|
type,
|
||||||
files = $bindable(),
|
files = $bindable(),
|
||||||
class: className,
|
class: className,
|
||||||
scan,
|
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
...restProps
|
...restProps
|
||||||
@ -40,7 +37,7 @@
|
|||||||
{name}
|
{name}
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
class={cn(
|
class={cn(
|
||||||
'border-surface-1 file:bg-surface hover:border-overlay placeholder:text-subtext text-text shadow-xs flex h-9 w-full min-w-0 cursor-pointer rounded-md border text-sm font-medium transition-all file:mr-2 file:px-3 file:py-2 md:text-sm',
|
'border-surface-1 file:bg-surface hover:border-overlay placeholder:text-subtext text-text flex h-9 w-full min-w-0 cursor-pointer rounded-md border text-sm font-medium shadow-xs transition-all file:mr-2 file:px-3 file:py-2 md:text-sm',
|
||||||
|
|
||||||
// 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',
|
||||||
@ -61,7 +58,7 @@
|
|||||||
{name}
|
{name}
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
class={cn(
|
class={cn(
|
||||||
'border-surface-1 hover:border-overlay placeholder:text-subtext text-text shadow-xs flex h-9 w-full min-w-0 rounded-md border px-3 py-1 transition-all md:text-sm',
|
'border-surface-1 hover:border-overlay placeholder:text-subtext text-text flex h-9 w-full min-w-0 rounded-md border px-3 py-1 shadow-xs transition-all md:text-sm',
|
||||||
|
|
||||||
// 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',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Root from "./label.svelte";
|
import Root from './label.svelte';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
//
|
//
|
||||||
Root as Label,
|
Root as Label
|
||||||
};
|
};
|
||||||
|
@ -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),
|
||||||
@ -13,7 +13,7 @@
|
|||||||
bind:ref
|
bind:ref
|
||||||
data-slot="label"
|
data-slot="label"
|
||||||
class={cn(
|
class={cn(
|
||||||
'flex items-center gap-2 text-sm text-text leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
|
'text-text flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import Pager from './pager.svelte'
|
import Pager from './pager.svelte';
|
||||||
|
|
||||||
export {
|
export { Pager };
|
||||||
Pager
|
|
||||||
}
|
|
||||||
|
@ -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 PrevButton from './pagination-prev-button.svelte';
|
||||||
import Ellipsis from "./pagination-ellipsis.svelte";
|
import Root from './pagination.svelte';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
@ -21,5 +21,5 @@ export {
|
|||||||
Link as PaginationLink,
|
Link as PaginationLink,
|
||||||
PrevButton as PaginationPrevButton,
|
PrevButton as PaginationPrevButton,
|
||||||
NextButton as PaginationNextButton,
|
NextButton as PaginationNextButton,
|
||||||
Ellipsis as PaginationEllipsis,
|
Ellipsis as PaginationEllipsis
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<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 {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<ul
|
<ul
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
data-slot="pagination-content"
|
data-slot="pagination-content"
|
||||||
class={cn("flex flex-row items-center gap-1", className)}
|
class={cn('flex flex-row items-center gap-1', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<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 {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
@ -15,7 +15,7 @@
|
|||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
data-slot="pagination-ellipsis"
|
data-slot="pagination-ellipsis"
|
||||||
class={cn("flex size-9 items-center justify-center text-text", className)}
|
class={cn('text-text flex size-9 items-center justify-center', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
<Ellipsis class="size-4" />
|
<Ellipsis class="size-4" />
|
||||||
|
@ -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),
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
import type { Props } from '$lib/ui/button';
|
||||||
import { cn } from "$lib/utils.js";
|
import { buttonVariants } from '$lib/ui/button';
|
||||||
import { type Props, buttonVariants } from "$lib/ui/button";
|
import { cn } from '$lib/utils.js';
|
||||||
|
import { Pagination as PaginationPrimitive } from 'bits-ui';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
class: className,
|
class: className,
|
||||||
size = "icon",
|
size = 'icon',
|
||||||
isActive = false,
|
isActive = false,
|
||||||
page,
|
page,
|
||||||
children,
|
children,
|
||||||
@ -24,16 +25,16 @@
|
|||||||
<PaginationPrimitive.Page
|
<PaginationPrimitive.Page
|
||||||
bind:ref
|
bind:ref
|
||||||
{page}
|
{page}
|
||||||
aria-current={isActive ? "page" : undefined}
|
aria-current={isActive ? 'page' : undefined}
|
||||||
data-slot="pagination-link"
|
data-slot="pagination-link"
|
||||||
data-active={isActive}
|
data-active={isActive}
|
||||||
class={cn(
|
class={cn(
|
||||||
buttonVariants({
|
buttonVariants({
|
||||||
variant: "ghost",
|
variant: 'ghost',
|
||||||
size,
|
size
|
||||||
}),
|
}),
|
||||||
'text-text',
|
'text-text',
|
||||||
isActive && 'bg-surface-1',
|
isActive && 'bg-surface',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
children={children || Fallback}
|
children={children || Fallback}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||||
import ChevronRight from "@lucide/svelte/icons/chevron-right";
|
import ChevronRight from '@lucide/svelte/icons/chevron-right';
|
||||||
import { buttonVariants } from "$lib/ui/button/index.js";
|
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),
|
||||||
@ -23,9 +23,9 @@
|
|||||||
aria-label="Go to next page"
|
aria-label="Go to next page"
|
||||||
class={cn(
|
class={cn(
|
||||||
buttonVariants({
|
buttonVariants({
|
||||||
size: "default",
|
size: 'default',
|
||||||
variant: "ghost",
|
variant: 'ghost',
|
||||||
class: "gap-1 px-2.5 sm:pr-2.5",
|
class: 'gap-1 px-2.5 sm:pr-2.5'
|
||||||
}),
|
}),
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||||
import ChevronLeft from "@lucide/svelte/icons/chevron-left";
|
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
|
||||||
import { buttonVariants } from "$lib/ui/button/index.js";
|
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),
|
||||||
@ -22,9 +22,9 @@
|
|||||||
aria-label="Go to previous page"
|
aria-label="Go to previous page"
|
||||||
class={cn(
|
class={cn(
|
||||||
buttonVariants({
|
buttonVariants({
|
||||||
size: "default",
|
size: 'default',
|
||||||
variant: "ghost",
|
variant: 'ghost',
|
||||||
class: "gap-1 px-2.5 sm:pl-2.5",
|
class: 'gap-1 px-2.5 sm:pl-2.5'
|
||||||
}),
|
}),
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
@ -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),
|
||||||
@ -18,7 +17,7 @@
|
|||||||
|
|
||||||
<svelte:window
|
<svelte:window
|
||||||
onpopstate={(state) => {
|
onpopstate={(state) => {
|
||||||
const sks = state.state['sveltekit:states'] as {} | string;
|
const sks = state.state['sveltekit:states'] as object | string;
|
||||||
if (typeof sks === 'string' && sks.includes('#pagination-')) {
|
if (typeof sks === 'string' && sks.includes('#pagination-')) {
|
||||||
page = Number(sks.split('#pagination-')[1]);
|
page = Number(sks.split('#pagination-')[1]);
|
||||||
onPageChange?.(page);
|
onPageChange?.(page);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
@ -13,5 +14,5 @@ export {
|
|||||||
Root as Popover,
|
Root as Popover,
|
||||||
Content as PopoverContent,
|
Content as PopoverContent,
|
||||||
Trigger as PopoverTrigger,
|
Trigger as PopoverTrigger,
|
||||||
Close as PopoverClose,
|
Close as PopoverClose
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { cn } from "$lib/utils.js";
|
import { cn } from '$lib/utils.js';
|
||||||
import { Popover as PopoverPrimitive } from "bits-ui";
|
import { Popover as PopoverPrimitive } from 'bits-ui';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
class: className,
|
class: className,
|
||||||
sideOffset = 4,
|
sideOffset = 4,
|
||||||
align = "center",
|
align = 'center',
|
||||||
portalProps,
|
portalProps,
|
||||||
...restProps
|
...restProps
|
||||||
}: PopoverPrimitive.ContentProps & {
|
}: PopoverPrimitive.ContentProps & {
|
||||||
@ -21,10 +21,10 @@
|
|||||||
{sideOffset}
|
{sideOffset}
|
||||||
{align}
|
{align}
|
||||||
class={cn(
|
class={cn(
|
||||||
"bg-based text-text outline-hidden z-50 w-72 rounded-md border border-surface-1 p-4 shadow-md",
|
'bg-based text-text border-surface-1 z-50 w-72 rounded-md border p-4 shadow-md outline-hidden',
|
||||||
|
|
||||||
// Animation
|
// Animation
|
||||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--bits-popover-content-transform-origin)",
|
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--bits-popover-content-transform-origin)',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { cn } from "$lib/utils.js";
|
import { cn } from '$lib/utils.js';
|
||||||
import { Popover as PopoverPrimitive } from "bits-ui";
|
import { Popover as PopoverPrimitive } from 'bits-ui';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
@ -12,6 +12,6 @@
|
|||||||
<PopoverPrimitive.Trigger
|
<PopoverPrimitive.Trigger
|
||||||
bind:ref
|
bind:ref
|
||||||
data-slot="popover-trigger"
|
data-slot="popover-trigger"
|
||||||
class={cn("", className)}
|
class={cn('', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -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 GridRow from './range-calendar-grid-row.svelte';
|
||||||
import Grid from "./range-calendar-grid.svelte";
|
import Grid from './range-calendar-grid.svelte';
|
||||||
import Header from "./range-calendar-header.svelte";
|
import HeadCell from './range-calendar-head-cell.svelte';
|
||||||
import Months from "./range-calendar-months.svelte";
|
import Header from './range-calendar-header.svelte';
|
||||||
import GridRow from "./range-calendar-grid-row.svelte";
|
import Heading from './range-calendar-heading.svelte';
|
||||||
import Heading from "./range-calendar-heading.svelte";
|
import Months from './range-calendar-months.svelte';
|
||||||
import HeadCell from "./range-calendar-head-cell.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;
|
||||||
@ -28,5 +28,5 @@ export {
|
|||||||
NextButton,
|
NextButton,
|
||||||
PrevButton,
|
PrevButton,
|
||||||
//
|
//
|
||||||
Root as RangeCalendar,
|
Root as RangeCalendar
|
||||||
};
|
};
|
||||||
|
@ -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),
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<RangeCalendarPrimitive.Cell
|
<RangeCalendarPrimitive.Cell
|
||||||
bind:ref
|
bind:ref
|
||||||
class={cn(
|
class={cn(
|
||||||
"[&:has([data-selected])]:bg-accent [&:has([data-selected][data-outside-month])]:bg-accent/50 relative size-9 p-0 text-center text-sm focus-within:relative focus-within:z-20 first:[&:has([data-selected])]:rounded-l-md last:[&:has([data-selected])]:rounded-r-md [&:has([data-selected][data-selection-end])]:rounded-r-md [&:has([data-selected][data-selection-start])]:rounded-l-md",
|
'[&:has([data-selected])]:bg-accent [&:has([data-selected][data-outside-month])]:bg-accent/50 relative size-9 p-0 text-center text-sm focus-within:relative focus-within:z-20 first:[&:has([data-selected])]:rounded-l-md last:[&:has([data-selected])]:rounded-r-md [&:has([data-selected][data-selection-end])]:rounded-r-md [&:has([data-selected][data-selection-start])]:rounded-l-md',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
@ -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
|
||||||
|
@ -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),
|
||||||
@ -9,4 +9,4 @@
|
|||||||
}: RangeCalendarPrimitive.GridRowProps = $props();
|
}: RangeCalendarPrimitive.GridRowProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<RangeCalendarPrimitive.GridRow bind:ref class={cn("flex", className)} {...restProps} />
|
<RangeCalendarPrimitive.GridRow bind:ref class={cn('flex', className)} {...restProps} />
|
||||||
|
@ -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),
|
||||||
@ -11,6 +11,6 @@
|
|||||||
|
|
||||||
<RangeCalendarPrimitive.Grid
|
<RangeCalendarPrimitive.Grid
|
||||||
bind:ref
|
bind:ref
|
||||||
class={cn("w-full border-collapse space-y-1", className)}
|
class={cn('w-full border-collapse space-y-1', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -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),
|
||||||
@ -11,6 +11,6 @@
|
|||||||
|
|
||||||
<RangeCalendarPrimitive.HeadCell
|
<RangeCalendarPrimitive.HeadCell
|
||||||
bind:ref
|
bind:ref
|
||||||
class={cn("text-muted-foreground w-9 rounded-md text-[0.8rem] font-normal", className)}
|
class={cn('text-muted-foreground w-9 rounded-md text-[0.8rem] font-normal', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -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),
|
||||||
@ -11,6 +11,6 @@
|
|||||||
|
|
||||||
<RangeCalendarPrimitive.Header
|
<RangeCalendarPrimitive.Header
|
||||||
bind:ref
|
bind:ref
|
||||||
class={cn("relative flex w-full items-center justify-between pt-1", className)}
|
class={cn('relative flex w-full items-center justify-between pt-1', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -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),
|
||||||
@ -11,6 +11,6 @@
|
|||||||
|
|
||||||
<RangeCalendarPrimitive.Heading
|
<RangeCalendarPrimitive.Heading
|
||||||
bind:ref
|
bind:ref
|
||||||
class={cn("text-sm font-medium", className)}
|
class={cn('text-sm font-medium', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
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.js";
|
import { cn } from '$lib/utils.js';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
class={cn("mt-4 flex flex-col space-y-4 sm:flex-row sm:space-x-4 sm:space-y-0", className)}
|
class={cn('mt-4 flex flex-col space-y-4 sm:flex-row sm:space-y-0 sm:space-x-4', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { RangeCalendar as RangeCalendarPrimitive } from "bits-ui";
|
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||||
import ChevronRight from "@lucide/svelte/icons/chevron-right";
|
import ChevronRight from '@lucide/svelte/icons/chevron-right';
|
||||||
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),
|
||||||
@ -19,8 +19,8 @@
|
|||||||
<RangeCalendarPrimitive.NextButton
|
<RangeCalendarPrimitive.NextButton
|
||||||
bind:ref
|
bind:ref
|
||||||
class={cn(
|
class={cn(
|
||||||
buttonVariants({ variant: "outline" }),
|
buttonVariants({ variant: 'outline' }),
|
||||||
"size-7 bg-transparent p-0 opacity-50 hover:opacity-100",
|
'size-7 bg-transparent p-0 opacity-50 hover:opacity-100',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
children={children || Fallback}
|
children={children || Fallback}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { RangeCalendar as RangeCalendarPrimitive } from "bits-ui";
|
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||||
import ChevronLeft from "@lucide/svelte/icons/chevron-left";
|
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
|
||||||
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),
|
||||||
@ -19,8 +19,8 @@
|
|||||||
<RangeCalendarPrimitive.PrevButton
|
<RangeCalendarPrimitive.PrevButton
|
||||||
bind:ref
|
bind:ref
|
||||||
class={cn(
|
class={cn(
|
||||||
buttonVariants({ variant: "outline" }),
|
buttonVariants({ variant: 'outline' }),
|
||||||
"size-7 bg-transparent p-0 opacity-50 hover:opacity-100",
|
'size-7 bg-transparent p-0 opacity-50 hover:opacity-100',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
children={children || Fallback}
|
children={children || Fallback}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
<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),
|
||||||
value = $bindable(),
|
value = $bindable(),
|
||||||
placeholder = $bindable(),
|
placeholder = $bindable(),
|
||||||
weekdayFormat = "short",
|
weekdayFormat = 'short',
|
||||||
class: className,
|
class: className,
|
||||||
...restProps
|
...restProps
|
||||||
}: WithoutChildrenOrChild<RangeCalendarPrimitive.RootProps> = $props();
|
}: WithoutChildrenOrChild<RangeCalendarPrimitive.RootProps> = $props();
|
||||||
@ -18,7 +19,7 @@
|
|||||||
bind:value
|
bind:value
|
||||||
bind:placeholder
|
bind:placeholder
|
||||||
{weekdayFormat}
|
{weekdayFormat}
|
||||||
class={cn("p-3", className)}
|
class={cn('p-3', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{#snippet children({ months, weekdays })}
|
{#snippet children({ months, weekdays })}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { Select as SelectPrimitive } from "bits-ui";
|
import { Select as SelectPrimitive } from 'bits-ui';
|
||||||
|
import Content from './select-content.svelte';
|
||||||
import Group from "./select-group.svelte";
|
import Group from './select-group.svelte';
|
||||||
import Label from "./select-label.svelte";
|
import Item from './select-item.svelte';
|
||||||
import Item from "./select-item.svelte";
|
import Label from './select-label.svelte';
|
||||||
import Content from "./select-content.svelte";
|
import Separator from './select-separator.svelte';
|
||||||
import Trigger from "./select-trigger.svelte";
|
import Trigger from './select-trigger.svelte';
|
||||||
import Separator from "./select-separator.svelte";
|
|
||||||
|
|
||||||
const Root = SelectPrimitive.Root;
|
const Root = SelectPrimitive.Root;
|
||||||
|
|
||||||
@ -24,5 +23,5 @@ export {
|
|||||||
Item as SelectItem,
|
Item as SelectItem,
|
||||||
Content as SelectContent,
|
Content as SelectContent,
|
||||||
Trigger as SelectTrigger,
|
Trigger as SelectTrigger,
|
||||||
Separator as SelectSeparator,
|
Separator as SelectSeparator
|
||||||
};
|
};
|
||||||
|
@ -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),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Select as SelectPrimitive } from "bits-ui";
|
import { Select as SelectPrimitive } from 'bits-ui';
|
||||||
|
|
||||||
let { ref = $bindable(null), ...restProps }: SelectPrimitive.GroupProps = $props();
|
let { ref = $bindable(null), ...restProps }: SelectPrimitive.GroupProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
@ -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),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { cn } from "$lib/utils.js";
|
import type { HTMLAttributes } from 'svelte/elements';
|
||||||
import { type WithElementRef } from "bits-ui";
|
import { cn } from '$lib/utils.js';
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import { type WithElementRef } from 'bits-ui';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<div
|
<div
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
data-slot="select-label"
|
data-slot="select-label"
|
||||||
class={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
|
class={cn('text-muted-foreground px-2 py-1.5 text-xs', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Separator as SeparatorPrimitive } from "bits-ui";
|
import type { Separator as SeparatorPrimitive } from 'bits-ui';
|
||||||
import { Separator } from "$lib/ui/separator/index.js";
|
import { Separator } from '$lib/ui/separator/index.js';
|
||||||
import { cn } from "$lib/utils.js";
|
import { cn } from '$lib/utils.js';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
ref = $bindable(null),
|
ref = $bindable(null),
|
||||||
@ -13,6 +13,6 @@
|
|||||||
<Separator
|
<Separator
|
||||||
bind:ref
|
bind:ref
|
||||||
data-slot="select-separator"
|
data-slot="select-separator"
|
||||||
class={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
|
class={cn('bg-border pointer-events-none -mx-1 my-1 h-px', className)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
@ -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),
|
||||||
@ -19,7 +20,7 @@
|
|||||||
data-slot="select-trigger"
|
data-slot="select-trigger"
|
||||||
data-size={size}
|
data-size={size}
|
||||||
class={cn(
|
class={cn(
|
||||||
'border-surface-1 bg-based hover:border-overlay text-text flex flex-row-reverse w-full cursor-pointer items-center justify-between gap-2 rounded-md border px-3 py-2 md:text-sm whitespace-nowrap shadow-xs transition-all',
|
'border-surface-1 bg-based hover:border-overlay text-text flex w-full cursor-pointer flex-row-reverse items-center justify-between gap-2 rounded-md border px-3 py-2 whitespace-nowrap shadow-xs transition-all md:text-sm',
|
||||||
|
|
||||||
// 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',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Root from "./separator.svelte";
|
import Root from './separator.svelte';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
//
|
//
|
||||||
Root as Separator,
|
Root as Separator
|
||||||
};
|
};
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user