Compare commits
No commits in common. "main" and "v0.0.22" have entirely different histories.
@ -1,21 +0,0 @@
|
||||
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 }}"
|
@ -1,63 +0,0 @@
|
||||
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
|
14
.dockerignore
Normal file
14
.dockerignore
Normal file
@ -0,0 +1,14 @@
|
||||
.env
|
||||
/docker-compose.*
|
||||
/result*
|
||||
/.direnv/
|
||||
/build/
|
||||
|
||||
# Client
|
||||
/client/node_modules/
|
||||
/client/.svelte-kit/
|
||||
|
||||
# Server
|
||||
/server/client/
|
||||
/server/tmp/
|
||||
/server/build/
|
@ -1,23 +0,0 @@
|
||||
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
|
@ -1,68 +0,0 @@
|
||||
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 }}
|
@ -1,50 +0,0 @@
|
||||
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
23
.github/workflows/check.yaml
vendored
@ -1,23 +0,0 @@
|
||||
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
Normal file
28
.github/workflows/lint.yaml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
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
|
85
.github/workflows/release.yaml
vendored
85
.github/workflows/release.yaml
vendored
@ -1,35 +1,34 @@
|
||||
name: Release
|
||||
name: Release Workflow
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
- '*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
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 }}"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- run: >
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- name: Use Cachix
|
||||
uses: cachix/cachix-action@v16
|
||||
with:
|
||||
name: trevstack
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
|
||||
- name: Build
|
||||
run: >
|
||||
nix build
|
||||
.#trevstack-linux-amd64
|
||||
.#trevstack-linux-arm64
|
||||
@ -38,36 +37,52 @@ jobs:
|
||||
.#trevstack-darwin-amd64
|
||||
.#trevstack-darwin-arm64
|
||||
|
||||
- uses: softprops/action-gh-release@v2
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
generate_release_notes: true
|
||||
files: |-
|
||||
result*/bin/*
|
||||
|
||||
# https://docs.docker.com/build/ci/github-actions/manage-tags-labels/
|
||||
package:
|
||||
runs-on: ubuntu-latest
|
||||
needs: release
|
||||
needs: release # Wait for binary cache to propagate
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.actions/init
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
# list of Docker images to use as base name for tags
|
||||
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}}
|
||||
|
||||
- uses: docker/login-action@v3
|
||||
- name: Login to Docker Hub
|
||||
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:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- 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: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Push images
|
||||
uses: ./.actions/push
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
server_url: ghcr.io
|
||||
repository: ${{ github.repository }}
|
||||
tag: ${{ github.ref_name }}
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
39
.github/workflows/update.yaml
vendored
39
.github/workflows/update.yaml
vendored
@ -1,40 +1,41 @@
|
||||
name: Update
|
||||
name: Update Workflow
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.actions/init
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
token: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- name: Use Cachix
|
||||
uses: cachix/cachix-action@v16
|
||||
with:
|
||||
name: trevstack
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
|
||||
# https://github.com/actions/checkout/issues/13
|
||||
- name: Set git config
|
||||
- name: Set Git Config
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- run: nix run .#update
|
||||
- name: Update
|
||||
run: nix run .#update
|
||||
|
||||
- name: Create pull request
|
||||
id: cpr
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
branch: update
|
||||
title: update
|
||||
body: automatic update
|
||||
delete-branch: true
|
||||
title: Bump deps
|
||||
|
||||
|
||||
- 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,7 +1,5 @@
|
||||
.env
|
||||
/docker-compose.*
|
||||
/build/
|
||||
|
||||
# Nix
|
||||
/result*
|
||||
/.direnv/
|
||||
/build/
|
@ -3,25 +3,7 @@
|
||||
git_root=$(git rev-parse --show-toplevel)
|
||||
git_version=$(git describe --tags --abbrev=0)
|
||||
version=${git_version#v}
|
||||
|
||||
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
|
||||
next_version=$(echo "${version}" | awk -F. -v OFS=. '{$NF += 1 ; print}')
|
||||
|
||||
echo "bumping client"
|
||||
cd "${git_root}/client"
|
||||
|
@ -6,19 +6,12 @@ updated=false
|
||||
echo "updating nix flake"
|
||||
cd "${git_root}"
|
||||
nix flake update
|
||||
if ! git diff --exit-code flake.lock; then
|
||||
if ! git diff --exit-code flake.nix; then
|
||||
git add flake.nix
|
||||
git add flake.lock
|
||||
git commit -m "build(nix): updated nix dependencies"
|
||||
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"
|
||||
cd "${git_root}/client"
|
||||
npm update --save && npm i
|
||||
@ -36,7 +29,7 @@ go mod tidy
|
||||
if ! git diff --exit-code go.mod go.sum; then
|
||||
git add go.mod
|
||||
git add go.sum
|
||||
git commit -m "build(server): updated go dependencies"
|
||||
git commit -m "build(go): updated go dependencies"
|
||||
updated=true
|
||||
fi
|
||||
|
||||
|
@ -39,7 +39,7 @@ apps:
|
||||
- ts
|
||||
- svelte
|
||||
onstart: npx prettier --check .
|
||||
onchange: npx prettier --check .
|
||||
onchange: npx prettier --check . || npx prettier --write .
|
||||
|
||||
revive:
|
||||
color: "#89dceb"
|
||||
|
10
.vscode/extensions.json
vendored
10
.vscode/extensions.json
vendored
@ -1,10 +0,0 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"golang.go",
|
||||
"dorzey.vscode-sqlfluff",
|
||||
"bufbuild.vscode-buf",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"svelte.svelte-vscode",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
49
.vscode/settings.json
vendored
49
.vscode/settings.json
vendored
@ -1,46 +1,7 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
|
||||
// Go
|
||||
"go.lintTool": "revive",
|
||||
"go.formatTool": "goimports",
|
||||
"go.buildTags": "dev",
|
||||
"go.lintFlags": ["--config=server/revive.toml"],
|
||||
"gopls": { "ui.semanticTokens": true },
|
||||
"[go]": {
|
||||
"editor.defaultFormatter": "golang.go"
|
||||
},
|
||||
|
||||
// SQLFluff
|
||||
"sqlfluff.config": "server/db/.sqlfluff",
|
||||
"[sql]": {
|
||||
"editor.defaultFormatter": "dorzey.vscode-sqlfluff"
|
||||
},
|
||||
|
||||
// Proto
|
||||
"[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"
|
||||
}
|
||||
"go.lintTool": "revive",
|
||||
"go.lintFlags": [
|
||||
"--config=server/revive.toml"
|
||||
],
|
||||
"sqlfluff.config": "server/db/.sqlfluff",
|
||||
}
|
29
Dockerfile
Normal file
29
Dockerfile
Normal file
@ -0,0 +1,29 @@
|
||||
# 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
21
LICENSE
@ -1,21 +0,0 @@
|
||||
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
125
README.md
@ -1,125 +0,0 @@
|
||||
## 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,8 +1,5 @@
|
||||
version: v2
|
||||
clean: true
|
||||
inputs:
|
||||
- directory: proto
|
||||
|
||||
managed:
|
||||
enabled: true
|
||||
override:
|
||||
@ -30,5 +27,5 @@ plugins:
|
||||
out: client/static/openapi
|
||||
strategy: all
|
||||
opt:
|
||||
- base=openapi.yaml
|
||||
- base=openapi.base.yaml
|
||||
- path=openapi.yaml
|
||||
|
@ -1,6 +1,6 @@
|
||||
# For details on buf.yaml configuration, visit https://buf.build/docs/configuration/v2/buf-yaml
|
||||
version: v2
|
||||
modules:
|
||||
- path: .
|
||||
- path: proto
|
||||
deps:
|
||||
- buf.build/bufbuild/protovalidate
|
@ -3,21 +3,8 @@
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": [
|
||||
"prettier-plugin-svelte",
|
||||
"prettier-plugin-tailwindcss",
|
||||
"@ianvs/prettier-plugin-sort-imports"
|
||||
],
|
||||
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
||||
"tailwindFunctions": ["tv", "cn", "clsx"],
|
||||
"importOrder": [
|
||||
"<TYPES>^(node:)",
|
||||
"<TYPES>",
|
||||
"<TYPES>^[.]",
|
||||
"<BUILTIN_MODULES>",
|
||||
"^(\\$lib/ui)(/.*)$",
|
||||
"<THIRD_PARTY_MODULES>",
|
||||
"^[.]"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.svelte",
|
||||
|
@ -1,12 +1,11 @@
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { includeIgnoreFile } from '@eslint/compat';
|
||||
import js from '@eslint/js';
|
||||
import prettier from 'eslint-config-prettier';
|
||||
import js from '@eslint/js';
|
||||
import { includeIgnoreFile } from '@eslint/compat';
|
||||
import svelte from 'eslint-plugin-svelte';
|
||||
import globals from 'globals';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import ts from 'typescript-eslint';
|
||||
import svelteConfig from './svelte.config.js';
|
||||
|
||||
const gitignorePath = fileURLToPath(new URL('./.prettierignore', import.meta.url));
|
||||
|
||||
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",
|
||||
"private": true,
|
||||
"version": "0.0.47",
|
||||
"version": "0.0.22",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
@ -19,33 +19,33 @@
|
||||
"@connectrpc/connect-web": "^2.0.2",
|
||||
"@eslint/compat": "^1.2.9",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
|
||||
"@lucide/svelte": "^0.479.0",
|
||||
"@scalar/api-reference": "^1.28.34",
|
||||
"@scalar/api-reference": "^1.28.32",
|
||||
"@simplewebauthn/browser": "^13.1.0",
|
||||
"@sveltejs/adapter-static": "^3.0.8",
|
||||
"@sveltejs/kit": "^2.21.1",
|
||||
"@sveltejs/kit": "^2.20.8",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||
"@tailwindcss/vite": "^4.1.7",
|
||||
"bits-ui": "^1.5.3",
|
||||
"@tailwindcss/vite": "^4.1.6",
|
||||
"bits-ui": "^1.4.8",
|
||||
"clsx": "^2.1.1",
|
||||
"eslint": "^9.27.0",
|
||||
"eslint": "^9.26.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-svelte": "^3.8.1",
|
||||
"eslint-plugin-svelte": "^3.5.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"globals": "^16.1.0",
|
||||
"mode-watcher": "^1.0.7",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-svelte": "^3.4.0",
|
||||
"prettier-plugin-svelte": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"svelte": "^5.31.1",
|
||||
"svelte-check": "^4.2.1",
|
||||
"svelte": "^5.28.2",
|
||||
"svelte-check": "^4.1.7",
|
||||
"svelte-sonner": "^0.3.28",
|
||||
"tailwind-merge": "^3.3.0",
|
||||
"tailwind-variants": "^1.0.0",
|
||||
"tailwindcss": "^4.0.13",
|
||||
"tw-animate-css": "^1.3.0",
|
||||
"tw-animate-css": "^1.2.9",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.32.1",
|
||||
"typescript-eslint": "^8.32.0",
|
||||
"vite": "^6.3.5"
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
<title>TrevStack</title>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="tap" class="bg-crust text-text min-h-dvh">
|
||||
<body data-sveltekit-preload-data="tap" class="bg-crust text-text min-h-screen">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,11 +1,14 @@
|
||||
import type { DescMessage, DescService, MessageInitShape, MessageShape } from '@bufbuild/protobuf';
|
||||
import type { Violation } from '@bufbuild/protovalidate';
|
||||
import type { Client } from '@connectrpc/connect';
|
||||
import type { Action } from 'svelte/action';
|
||||
import { create } from '@bufbuild/protobuf';
|
||||
import { ValidationError } from '@bufbuild/protovalidate';
|
||||
import { ConnectError } from '@connectrpc/connect';
|
||||
import {
|
||||
create,
|
||||
type DescMessage,
|
||||
type DescService,
|
||||
type MessageShape,
|
||||
type MessageInitShape
|
||||
} from '@bufbuild/protobuf';
|
||||
import { ValidationError, type Violation } from '@bufbuild/protovalidate';
|
||||
import { Validator } from '../transport';
|
||||
import { ConnectError, type Client } from '@connectrpc/connect';
|
||||
import type { Action } from 'svelte/action';
|
||||
|
||||
type Options<Input extends DescMessage, Output extends DescMessage> = {
|
||||
init?: MessageInitShape<Input>;
|
||||
@ -27,7 +30,9 @@ export function coolForm<Service extends DescService, Method extends Service['me
|
||||
) {
|
||||
const input = $state(create(method.input as Method['input'], options?.init));
|
||||
const output = $state(create(method.output as Method['output']));
|
||||
const errors: Violations<Method['input']['field']> & { form?: ConnectError } = $state({});
|
||||
const errors: Violations<Method['input']['field']> & {
|
||||
form?: ConnectError;
|
||||
} = $state({});
|
||||
let loading = $state(false);
|
||||
|
||||
const validate = () => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { newState } from './conststate.svelte';
|
||||
import { coolForm } from './coolforms.svelte';
|
||||
import { newState } from './conststate.svelte';
|
||||
|
||||
export { coolForm, newState };
|
||||
|
@ -1,12 +1,11 @@
|
||||
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 { goto } from '$app/navigation';
|
||||
import { page } from '$app/state';
|
||||
import { ItemService } from '$lib/connect/item/v1/item_pb';
|
||||
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 { page } from '$app/state';
|
||||
|
||||
const redirector: Interceptor = (next) => async (req) => {
|
||||
try {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Avatar as AvatarPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
@ -13,7 +13,7 @@
|
||||
bind:ref
|
||||
data-slot="avatar-fallback"
|
||||
class={cn(
|
||||
'bg-surface flex size-full items-center justify-center rounded-full text-sm transition-all select-none',
|
||||
'bg-surface outline-surface-2 flex size-full items-center justify-center rounded-full text-sm transition-all select-none',
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Avatar as AvatarPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Avatar as AvatarPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
@ -13,8 +13,7 @@
|
||||
bind:ref
|
||||
data-slot="avatar"
|
||||
class={cn(
|
||||
'outline-surface-1 relative flex size-9 shrink-0 overflow-hidden rounded-full shadow-xs outline outline-offset-2',
|
||||
|
||||
'outline-surface-1 relative flex size-9 shrink-0 overflow-hidden rounded-full outline outline-offset-2',
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Fallback from './avatar-fallback.svelte';
|
||||
import Image from './avatar-image.svelte';
|
||||
import Root from './avatar.svelte';
|
||||
import Image from './avatar-image.svelte';
|
||||
import Fallback from './avatar-fallback.svelte';
|
||||
|
||||
export {
|
||||
Root,
|
||||
|
@ -1,14 +1,13 @@
|
||||
<script lang="ts" module>
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
||||
import type { VariantProps } from 'tailwind-variants';
|
||||
import { LoaderCircle } from '@lucide/svelte';
|
||||
import { type VariantProps, tv } from 'tailwind-variants';
|
||||
import { cn } from '$lib/utils';
|
||||
import { tv } from 'tailwind-variants';
|
||||
import { LoaderCircle } from '@lucide/svelte';
|
||||
|
||||
export const buttonVariants = tv({
|
||||
base: cn(
|
||||
'inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all',
|
||||
'inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap shadow-xs transition-all',
|
||||
|
||||
// Focus
|
||||
'focus-visible:outline-accent focus-visible:outline-2 focus-visible:outline-offset-2',
|
||||
@ -25,7 +24,7 @@
|
||||
red: 'text-crust bg-red hover:bg-red/90 shadow-xs',
|
||||
outline: 'text-text border-surface-1 hover:bg-surface border bg-transparent shadow-xs',
|
||||
input: 'text-text border-surface-1 hover:border-overlay border bg-transparent shadow-xs',
|
||||
ghost: 'text-text hover:bg-surface'
|
||||
ghost: 'text-text hover:bg-surface shadow-xs'
|
||||
},
|
||||
size: {
|
||||
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
|
||||
|
@ -1,5 +1,9 @@
|
||||
import type { ButtonProps, ButtonSize, ButtonVariant } from './button.svelte';
|
||||
import Root, { buttonVariants } from './button.svelte';
|
||||
import Root, {
|
||||
type ButtonProps,
|
||||
type ButtonSize,
|
||||
type ButtonVariant,
|
||||
buttonVariants
|
||||
} from './button.svelte';
|
||||
|
||||
export {
|
||||
Root,
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { cn } from '$lib/utils';
|
||||
|
||||
type Props = WithElementRef<HTMLAttributes<HTMLDivElement>>;
|
||||
|
||||
|
@ -1,12 +1,16 @@
|
||||
<script lang="ts">
|
||||
import type { DateValue } from '@internationalized/date';
|
||||
import type { DateRange } from 'bits-ui';
|
||||
import { buttonVariants } from '$lib/ui/button';
|
||||
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 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 { RangeCalendar } from '$lib/ui/range-calendar';
|
||||
import * as Popover from '$lib/ui/popover';
|
||||
|
||||
let {
|
||||
className,
|
||||
@ -37,11 +41,7 @@
|
||||
<div class={cn('grid gap-2', className)}>
|
||||
<Popover.Root>
|
||||
<Popover.Trigger
|
||||
class={cn(
|
||||
buttonVariants({ variant: 'input' }),
|
||||
'bg-based text-md md:text-sm',
|
||||
!value && 'text-subtext'
|
||||
)}
|
||||
class={cn(buttonVariants({ variant: 'input' }), 'bg-based', !value && 'text-subtext')}
|
||||
>
|
||||
<CalendarIcon class="mr-2 size-4" />
|
||||
{#if value && value.start}
|
||||
|
@ -1,10 +1,9 @@
|
||||
<script lang="ts">
|
||||
import type { WithoutChildrenOrChild } from 'bits-ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { Dialog as DialogPrimitive, type WithoutChildrenOrChild } from 'bits-ui';
|
||||
import X from '@lucide/svelte/icons/x';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Dialog as DialogPrimitive } from 'bits-ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
import * as Dialog from './index.js';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Dialog as DialogPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Dialog as DialogPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Dialog as DialogPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,13 +1,14 @@
|
||||
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 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 Title from './dialog-title.svelte';
|
||||
import Content from './dialog-content.svelte';
|
||||
import Description from './dialog-description.svelte';
|
||||
import Trigger from './dialog-trigger.svelte';
|
||||
import Root from './dialog.svelte';
|
||||
import Close from './dialog-close.svelte';
|
||||
|
||||
const Portal = DialogPrimitive.Portal;
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
<script lang="ts">
|
||||
import type { WithoutChildrenOrChild } from 'bits-ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { DropdownMenu as DropdownMenuPrimitive, type WithoutChildrenOrChild } from 'bits-ui';
|
||||
import Check from '@lucide/svelte/icons/check';
|
||||
import Minus from '@lucide/svelte/icons/minus';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { type WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,8 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { WithoutChild } from 'bits-ui';
|
||||
import { DropdownMenu as DropdownMenuPrimitive, type WithoutChild } from 'bits-ui';
|
||||
import Circle from '@lucide/svelte/icons/circle';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { type WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
import ChevronRight from '@lucide/svelte/icons/chevron-right';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -3,15 +3,15 @@ import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
|
||||
import Content from './dropdown-menu-content.svelte';
|
||||
import Group from './dropdown-menu-group.svelte';
|
||||
import Item from './dropdown-menu-item.svelte';
|
||||
import Label from './dropdown-menu-label.svelte';
|
||||
import Link from './dropdown-menu-link.svelte';
|
||||
import Label from './dropdown-menu-label.svelte';
|
||||
import RadioGroup from './dropdown-menu-radio-group.svelte';
|
||||
import RadioItem from './dropdown-menu-radio-item.svelte';
|
||||
import Separator from './dropdown-menu-separator.svelte';
|
||||
import Shortcut from './dropdown-menu-shortcut.svelte';
|
||||
import Trigger from './dropdown-menu-trigger.svelte';
|
||||
import SubContent from './dropdown-menu-sub-content.svelte';
|
||||
import SubTrigger from './dropdown-menu-sub-trigger.svelte';
|
||||
import Trigger from './dropdown-menu-trigger.svelte';
|
||||
|
||||
const Sub = DropdownMenuPrimitive.Sub;
|
||||
const Root = DropdownMenuPrimitive.Root;
|
||||
|
@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import type { Violation } from '@bufbuild/protovalidate';
|
||||
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';
|
||||
import type { WithElementRef, WithoutChildren } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import type { Violation } from '@bufbuild/protovalidate';
|
||||
import type { ConnectError } from '@connectrpc/connect';
|
||||
|
||||
type Props = WithoutChildren<WithElementRef<HTMLAttributes<HTMLDivElement>>> & {
|
||||
errors?: Violation[] | ConnectError;
|
||||
|
@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { cn } from '$lib/utils';
|
||||
import { setFormContext } from './context.svelte';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
|
||||
type Props = WithElementRef<HTMLAttributes<HTMLDivElement>> & {
|
||||
name?: string;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import Errors from './errors.svelte';
|
||||
import Field from './field.svelte';
|
||||
import Errors from './errors.svelte';
|
||||
import Label from './label.svelte';
|
||||
|
||||
export { Field, Errors, Label };
|
||||
|
@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { cn } from '$lib/utils';
|
||||
import { getFormContext } from './context.svelte';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
|
||||
type Props = WithElementRef<HTMLAttributes<HTMLLabelElement>>;
|
||||
let { ref = $bindable(null), class: className, children, ...restProps }: Props = $props();
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLInputAttributes, HTMLInputTypeAttribute } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { getFormContext } from '../form/context.svelte';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Label as LabelPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,10 +1,10 @@
|
||||
import Root from './pagination.svelte';
|
||||
import Content from './pagination-content.svelte';
|
||||
import Ellipsis from './pagination-ellipsis.svelte';
|
||||
import Item from './pagination-item.svelte';
|
||||
import Link from './pagination-link.svelte';
|
||||
import NextButton from './pagination-next-button.svelte';
|
||||
import PrevButton from './pagination-prev-button.svelte';
|
||||
import Root from './pagination.svelte';
|
||||
import NextButton from './pagination-next-button.svelte';
|
||||
import Ellipsis from './pagination-ellipsis.svelte';
|
||||
|
||||
export {
|
||||
Root,
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import Ellipsis from '@lucide/svelte/icons/ellipsis';
|
||||
import type { WithElementRef, WithoutChildren } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import Ellipsis from '@lucide/svelte/icons/ellipsis';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLLiAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,8 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { Props } from '$lib/ui/button';
|
||||
import { buttonVariants } from '$lib/ui/button';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Pagination as PaginationPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { type Props, buttonVariants } from '$lib/ui/button';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
@ -34,7 +33,7 @@
|
||||
size
|
||||
}),
|
||||
'text-text',
|
||||
isActive && 'bg-surface',
|
||||
isActive && 'bg-surface-1',
|
||||
className
|
||||
)}
|
||||
children={children || Fallback}
|
||||
|
@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||
import ChevronRight from '@lucide/svelte/icons/chevron-right';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Pagination as PaginationPrimitive } from 'bits-ui';
|
||||
import ChevronRight from '@lucide/svelte/icons/chevron-right';
|
||||
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Pagination as PaginationPrimitive } from 'bits-ui';
|
||||
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
|
||||
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,8 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { pushState } from '$app/navigation';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Pagination as PaginationPrimitive } from 'bits-ui';
|
||||
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { pushState } from '$app/navigation';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Popover as PopoverPrimitive } from 'bits-ui';
|
||||
import Content from './popover-content.svelte';
|
||||
import Trigger from './popover-trigger.svelte';
|
||||
|
||||
const Root = PopoverPrimitive.Root;
|
||||
const Close = PopoverPrimitive.Close;
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
import Root from './range-calendar.svelte';
|
||||
import Cell from './range-calendar-cell.svelte';
|
||||
import Day from './range-calendar-day.svelte';
|
||||
import GridRow from './range-calendar-grid-row.svelte';
|
||||
import Grid from './range-calendar-grid.svelte';
|
||||
import HeadCell from './range-calendar-head-cell.svelte';
|
||||
import Header from './range-calendar-header.svelte';
|
||||
import Heading from './range-calendar-heading.svelte';
|
||||
import Months from './range-calendar-months.svelte';
|
||||
import GridRow from './range-calendar-grid-row.svelte';
|
||||
import Heading from './range-calendar-heading.svelte';
|
||||
import HeadCell from './range-calendar-head-cell.svelte';
|
||||
import NextButton from './range-calendar-next-button.svelte';
|
||||
import PrevButton from './range-calendar-prev-button.svelte';
|
||||
import Root from './range-calendar.svelte';
|
||||
|
||||
const GridHead = RangeCalendarPrimitive.GridHead;
|
||||
const GridBody = RangeCalendarPrimitive.GridBody;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
@ -17,7 +17,7 @@
|
||||
class={cn(
|
||||
buttonVariants({ variant: 'ghost' }),
|
||||
'size-9 p-0 font-normal',
|
||||
'[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-crust [&[data-today]:not([data-selected])]:rounded-md',
|
||||
'[&[data-today]:not([data-selected])]:bg-blue [&[data-today]:not([data-selected])]:text-crust [&[data-today]:not([data-selected])]:rounded-md',
|
||||
// Selected
|
||||
'data-[selected]:bg-surface data-[selected]:hover:bg-surface-1 data-[selected]:rounded-none data-[selected]:opacity-100',
|
||||
// Selection Start
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||
import ChevronRight from '@lucide/svelte/icons/chevron-right';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
import ChevronRight from '@lucide/svelte/icons/chevron-right';
|
||||
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
|
||||
import { buttonVariants } from '$lib/ui/button/index.js';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,8 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { WithoutChildrenOrChild } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { RangeCalendar as RangeCalendarPrimitive } from 'bits-ui';
|
||||
import { RangeCalendar as RangeCalendarPrimitive, type WithoutChildrenOrChild } from 'bits-ui';
|
||||
import * as RangeCalendar from './index.js';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { Select as SelectPrimitive } from 'bits-ui';
|
||||
import Content from './select-content.svelte';
|
||||
|
||||
import Group from './select-group.svelte';
|
||||
import Item from './select-item.svelte';
|
||||
import Label from './select-label.svelte';
|
||||
import Separator from './select-separator.svelte';
|
||||
import Item from './select-item.svelte';
|
||||
import Content from './select-content.svelte';
|
||||
import Trigger from './select-trigger.svelte';
|
||||
import Separator from './select-separator.svelte';
|
||||
|
||||
const Root = SelectPrimitive.Root;
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithoutChild } from 'bits-ui';
|
||||
import { Select as SelectPrimitive, type WithoutChild } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Select as SelectPrimitive } from 'bits-ui';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,8 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { WithoutChild } from 'bits-ui';
|
||||
import Check from '@lucide/svelte/icons/check';
|
||||
import { Select as SelectPrimitive, type WithoutChild } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Select as SelectPrimitive } from 'bits-ui';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { type WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,8 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { WithoutChild } from 'bits-ui';
|
||||
import { Select as SelectPrimitive, type WithoutChild } from 'bits-ui';
|
||||
import ChevronDown from '@lucide/svelte/icons/chevron-down';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Select as SelectPrimitive } from 'bits-ui';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Separator as SeparatorPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { Dialog as SheetPrimitive } from 'bits-ui';
|
||||
import Close from './sheet-close.svelte';
|
||||
import Content from './sheet-content.svelte';
|
||||
import Description from './sheet-description.svelte';
|
||||
import Footer from './sheet-footer.svelte';
|
||||
import Header from './sheet-header.svelte';
|
||||
import Overlay from './sheet-overlay.svelte';
|
||||
import Title from './sheet-title.svelte';
|
||||
import Trigger from './sheet-trigger.svelte';
|
||||
import Root from './sheet.svelte';
|
||||
import Trigger from './sheet-trigger.svelte';
|
||||
import Close from './sheet-close.svelte';
|
||||
import Overlay from './sheet-overlay.svelte';
|
||||
import Content from './sheet-content.svelte';
|
||||
import Header from './sheet-header.svelte';
|
||||
import Footer from './sheet-footer.svelte';
|
||||
import Title from './sheet-title.svelte';
|
||||
import Description from './sheet-description.svelte';
|
||||
|
||||
const Portal = SheetPrimitive.Portal;
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
<script lang="ts" module>
|
||||
import type { VariantProps } from 'tailwind-variants';
|
||||
import { tv } from 'tailwind-variants';
|
||||
|
||||
import { tv, type VariantProps } from 'tailwind-variants';
|
||||
export const sheetVariants = tv({
|
||||
base: 'bg-mantle border-surface data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 gap-4 p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
|
||||
variants: {
|
||||
@ -23,12 +21,11 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import type { WithoutChildrenOrChild } from 'bits-ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { Dialog as SheetPrimitive, type WithoutChildrenOrChild } from 'bits-ui';
|
||||
import X from '@lucide/svelte/icons/x';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Dialog as SheetPrimitive } from 'bits-ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
import SheetOverlay from './sheet-overlay.svelte';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Dialog as SheetPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Dialog as SheetPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Dialog as SheetPrimitive } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
|
@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import type { ToasterProps as SonnerProps } from 'svelte-sonner';
|
||||
import { Toaster as Sonner } from 'svelte-sonner';
|
||||
import { Toaster as Sonner, type ToasterProps as SonnerProps } from 'svelte-sonner';
|
||||
|
||||
let { ...restProps }: SonnerProps = $props();
|
||||
</script>
|
||||
@ -13,7 +12,7 @@
|
||||
'bg-based text-sm flex gap-2 px-4 border border-surface-1 p-2 rounded-md items-center text-text w-full min-h-12',
|
||||
title: 'text-text',
|
||||
description: 'text-subtext text-xs',
|
||||
actionButton: 'bg-accent',
|
||||
actionButton: 'bg-blue',
|
||||
cancelButton: 'bg-red',
|
||||
closeButton: 'bg-green'
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import Root from './table.svelte';
|
||||
import Body from './table-body.svelte';
|
||||
import Caption from './table-caption.svelte';
|
||||
import Cell from './table-cell.svelte';
|
||||
@ -5,7 +6,6 @@ import Footer from './table-footer.svelte';
|
||||
import Head from './table-head.svelte';
|
||||
import Header from './table-header.svelte';
|
||||
import Row from './table-row.svelte';
|
||||
import Root from './table.svelte';
|
||||
|
||||
export {
|
||||
Root,
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLTdAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLThAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import type { HTMLTableAttributes } from 'svelte/elements';
|
||||
import type { WithElementRef } from 'bits-ui';
|
||||
import { cn } from '$lib/utils.js';
|
||||
|
||||
let {
|
||||
|
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