Compare commits

...
Author SHA1 Message Date
b1e8af7ec3 (tmp): trigger workflow
All checks were successful
/ build-web (push) Successful in 4m26s
/ build-desktop (linux) (push) Successful in 5m32s
/ build-mobile (push) Successful in 19m43s
/ release (push) Successful in 1m52s
2026-06-28 20:27:08 +02:00
05a94c58f9 (fix): make the flake more robust 2026-06-28 20:26:43 +02:00
eef6c68426 (fix): workflows
Some checks failed
/ build-web (push) Successful in 3m23s
/ build-desktop (linux) (push) Successful in 4m12s
/ build-mobile (push) Failing after 18m40s
/ release (push) Has been skipped
2026-06-28 20:01:55 +02:00
b704e266d6 (fix): workflows
Some checks failed
/ build-web (push) Successful in 4m1s
/ build-desktop (linux) (push) Successful in 5m0s
/ build-mobile (push) Failing after 8m9s
/ release (push) Has been skipped
2026-06-28 19:50:51 +02:00
018571c950 (fix): workflows
Some checks failed
/ build-web (push) Failing after 3s
/ build-desktop (linux) (push) Failing after 3s
/ build-mobile (push) Failing after 3s
/ release (push) Has been skipped
2026-06-28 19:48:40 +02:00
1dd8a979ee (fix): workflows
Some checks failed
/ build-web (push) Failing after 1s
/ build-mobile (push) Failing after 1s
/ build-desktop (linux) (push) Failing after 2s
/ release (push) Has been skipped
2026-06-28 19:47:12 +02:00
70740e31e6 (fix): try workflow fix
Some checks failed
/ build-mobile (push) Failing after 1s
/ build-web (push) Failing after 1s
/ build-desktop (linux) (push) Failing after 1s
/ release (push) Has been skipped
2026-06-28 19:21:21 +02:00
4980ca8f9f (tmp): dubious change to trigger workflow
Some checks failed
/ build-desktop (linux) (push) Failing after 1m55s
/ build-web (push) Failing after 1m58s
/ build-mobile (push) Failing after 5m24s
/ release (push) Has been skipped
2026-06-28 19:14:01 +02:00
692e1da4b0 (feat): add coreutils to dev shell 2026-06-28 19:12:40 +02:00
3c7a28ceb2 Reapply "(fix): now run builds in nix shell"
Some checks failed
/ build-web (push) Failing after 2m19s
/ build-desktop (linux) (push) Failing after 2m7s
/ release (push) Has been cancelled
/ build-mobile (push) Has been cancelled
This reverts commit 10da530e9e.
2026-06-28 19:10:23 +02:00
10da530e9e Revert "(fix): now run builds in nix shell"
Some checks failed
/ build-desktop (linux) (push) Has been cancelled
/ release (push) Has been cancelled
/ build-web (push) Has been cancelled
/ build-mobile (push) Has been cancelled
This reverts commit f81235c68d.
2026-06-28 19:09:50 +02:00
f81235c68d (fix): now run builds in nix shell
Some checks failed
/ build-web (push) Failing after 1m53s
/ build-desktop (linux) (push) Failing after 1m56s
/ release (push) Has been cancelled
/ build-mobile (push) Has been cancelled
2026-06-28 19:05:22 +02:00
d7aedad9b4 (fix): build issues
Some checks failed
/ build-web (push) Failing after 1m57s
/ build-desktop (linux) (push) Failing after 2m0s
/ build-mobile (push) Failing after 6m2s
/ release (push) Has been skipped
2026-06-28 18:58:55 +02:00
d176de6cb1 (qol): run format
Some checks failed
/ build-desktop (linux) (push) Failing after 1m35s
/ build-web (push) Failing after 1m46s
/ build-mobile (push) Failing after 5m39s
/ release (push) Has been skipped
2026-06-28 18:47:14 +02:00
63abd5697f (fix): nix dev shell 2026-06-28 18:45:58 +02:00
3f2275179b (qol): update readme
Some checks failed
/ build-desktop (linux) (push) Failing after 36s
/ build-web (push) Failing after 36s
/ release (push) Has been cancelled
/ build-mobile (push) Has been cancelled
2026-06-28 18:38:13 +02:00
de3150b74b (fix): dep 2026-06-28 18:36:18 +02:00
6df912f428 (feat): merge nix flakes
Some checks failed
/ build-desktop (linux) (push) Failing after 26s
/ release (push) Has been cancelled
/ build-mobile (push) Has been cancelled
/ build-web (push) Has been cancelled
(fix): workflows
2026-06-28 18:35:11 +02:00
74b152969b (fix): workflows
Some checks failed
/ build-web (push) Failing after 6s
/ build-mobile (push) Failing after 6s
/ build-desktop (linux) (push) Failing after 6s
/ release (push) Has been skipped
2026-06-28 18:03:19 +02:00
e3e90d4779 (feat): update workflows to use nixos runners
Some checks failed
/ build-mobile (push) Failing after 5s
/ build-web (push) Failing after 5s
/ release (push) Has been cancelled
/ build-desktop (linux) (push) Has been cancelled
(wip): add mini hover context menu
(qol): update todo
2026-06-28 18:00:21 +02:00
1828191317 (feat): improve dev releases cleanup
All checks were successful
/ build-web (push) Successful in 1m18s
/ build-desktop (linux) (push) Successful in 6m42s
/ build-mobile (push) Successful in 18m3s
/ release (push) Successful in 30s
2026-06-27 02:20:02 +02:00
de09cf4ebd (feat): make workflows fail early
All checks were successful
/ build-web (push) Successful in 1m20s
/ build-desktop (linux) (push) Successful in 6m49s
/ build-mobile (push) Successful in 17m57s
/ release (push) Successful in 31s
2026-06-27 01:48:21 +02:00
14518978d2 (fix): workflows
Some checks failed
/ release (push) Has been cancelled
/ build-desktop (linux) (push) Has been cancelled
/ build-mobile (push) Has been cancelled
/ build-web (push) Has been cancelled
2026-06-27 01:45:19 +02:00
29f1ff2d54 Revert "(fix): workflow"
Some checks failed
/ build-web (push) Successful in 1m26s
/ build-desktop (linux) (push) Successful in 7m32s
/ release (push) Has been cancelled
/ build-mobile (push) Has been cancelled
This reverts commit cc2f790c62.
2026-06-27 01:33:20 +02:00
cc2f790c62 (fix): workflow
Some checks failed
/ build-web (push) Successful in 1m28s
/ build-desktop (linux) (push) Successful in 7m1s
/ build-mobile (push) Failing after 14m37s
/ release (push) Has been skipped
2026-06-27 01:11:26 +02:00
0e6b235c1b (feat): minor ui changes
Some checks failed
/ build-web (push) Successful in 1m23s
/ build-desktop (linux) (push) Successful in 6m49s
/ build-mobile (push) Failing after 13m32s
/ release (push) Has been skipped
(qol): update todo
2026-06-27 00:47:26 +02:00
b09ef8a997 (feat): update message state icons
Some checks failed
/ build-web (push) Successful in 1m42s
/ build-desktop (linux) (push) Successful in 7m46s
/ release (push) Has been cancelled
/ build-mobile (push) Has been cancelled
(feat): log ttpUrl
2026-06-27 00:13:47 +02:00
c484a3c303 (feat): add message states
Some checks failed
/ build-web (push) Successful in 1m20s
/ build-desktop (linux) (push) Successful in 7m6s
/ build-mobile (push) Failing after 13m56s
/ release (push) Has been skipped
(qol): prep for mtp migration
2026-06-26 10:54:25 +02:00
b100967fda (fix): dumb issue
Some checks failed
/ build-web (push) Successful in 1m20s
/ build-desktop (linux) (push) Successful in 6m54s
/ release (push) Has been cancelled
/ build-mobile (push) Has been cancelled
2026-06-21 14:24:06 +02:00
6ed9ee1109 (feat): add custom css
Some checks failed
/ build-desktop (linux) (push) Failing after 52s
/ build-web (push) Failing after 57s
/ build-mobile (push) Failing after 59s
/ release (push) Has been skipped
2026-06-18 22:58:29 +02:00
31e36b2abc (fix): incorrect dep link
Some checks failed
/ build-web (push) Successful in 1m27s
/ build-desktop (linux) (push) Successful in 8m39s
/ build-mobile (push) Failing after 22m35s
/ release (push) Has been cancelled
2026-06-18 15:15:09 +02:00
94e9a67f6e (feat): add border radius option
Some checks failed
/ build-desktop (linux) (push) Failing after 28s
/ build-web (push) Failing after 33s
/ build-mobile (push) Failing after 55s
/ release (push) Has been skipped
2026-06-18 15:14:06 +02:00
d3ab472531 (feat): update logo
Some checks failed
/ build-web (push) Failing after 1m20s
/ build-desktop (linux) (push) Successful in 6m27s
/ build-mobile (push) Failing after 13m20s
/ release (push) Has been skipped
2026-06-16 15:04:30 +02:00
forgejo-actions
f02536ca49 (qol): update release flake hash 2026-06-16 10:07:08 +00:00
91 changed files with 865 additions and 619 deletions

View file

@ -5,74 +5,110 @@ on:
paths-ignore:
- flake.nix
env:
NIX_CONFIG: experimental-features = nix-command flakes
jobs:
build-web:
runs-on: docker
runs-on: nixos
steps:
- name: Install node
run: nix profile add nixpkgs#nodejs_24
- name: Check out repo
uses: https://data.forgejo.org/actions/checkout@v4
- name: Install Packages
run: apt-get update && apt-get install -y sudo curl jq fakeroot dpkg rpm
- name: Install Nix
uses: https://github.com/cachix/install-nix-action@v30
- name: Install Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile
run: nix develop .#electron --command bun install --frozen-lockfile
- name: Copy licenses
run: bun run copy-licenses
run: nix develop .#electron --command bun --bun run copy-licenses
- name: Build packages
run: bun run build:packages
run: nix develop .#electron --command bun --bun run build:packages
- name: Build web
run: bun run build:web
- name: Install rsync
run: apt-get update && apt-get install -y rsync
run: nix develop .#electron --command bun --bun run build:web
- name: Deploy
run: rsync -a --delete apps/web/dist/ /var/lib/www/tensamin-web-dev/
run: nix develop .#electron --command rsync -a --delete apps/web/dist/ /var/lib/www/tensamin-web-dev/
build-mobile:
runs-on: docker
runs-on: nixos
steps:
- name: Install node
run: nix profile add nixpkgs#nodejs_24
- name: Check out repo
uses: https://data.forgejo.org/actions/checkout@v4
- name: Install Packages
run: apt-get update && apt-get install -y sudo curl jq fakeroot dpkg rpm
- name: Install Nix
uses: https://github.com/cachix/install-nix-action@v30
- name: Install Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile
run: nix develop .#tauri --command bun install --frozen-lockfile
- name: Copy licenses
run: bun run copy-licenses
run: nix develop .#tauri --command bun --bun run copy-licenses
- name: Build packages
run: bun run build:packages
run: nix develop .#tauri --command bun --bun run build:packages
- name: Setup Android Keystore
env:
KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
KEYSTORE_PROPERTIES: ${{ secrets.ANDROID_KEYSTORE_PROPERTIES }}
run: |
bun -e "require('fs').writeFileSync('keystore.jks', Buffer.from(process.env.KEYSTORE_BASE64.replace(/\s+/g, ''), 'base64'))"
bun -e "const content = process.env.KEYSTORE_PROPERTIES.replace(/\\n/g, '\n').replace(/\r/g, '').split('\n').map(l => l.trim()).filter(l => l).join('\n'); require('fs').writeFileSync('keystore.properties', content)"
nix profile add nixpkgs#gnused
set -euo pipefail
if [ -z "$KEYSTORE_BASE64" ]; then
echo "ANDROID_KEYSTORE_BASE64 secret is missing or empty"
exit 1
fi
if [ -z "$KEYSTORE_PROPERTIES" ]; then
echo "ANDROID_KEYSTORE_PROPERTIES secret is missing or empty"
exit 1
fi
printf '%s' "$KEYSTORE_BASE64" \
| tr -d '[:space:]' \
| base64 -d > keystore.jks
printf '%s' "$KEYSTORE_PROPERTIES" \
| sed 's/\\n/\n/g' \
| tr -d '\r' \
| sed 's|^[[:space:]]*storeFile[[:space:]]*=.*|storeFile=keystore.jks|' \
> keystore.properties
grep -q '^[[:space:]]*storeFile[[:space:]]*=' keystore.properties || printf '\nstoreFile=keystore.jks\n' >> keystore.properties
if [ ! -s keystore.jks ]; then
echo "Decoded keystore.jks is missing or empty"
exit 1
fi
if [ ! -s keystore.properties ]; then
echo "Generated keystore.properties is missing or empty"
exit 1
fi
if ! grep -q '^[[:space:]]*keyAlias[[:space:]]*=' keystore.properties; then
echo "keystore.properties is missing keyAlias"
exit 1
fi
if ! grep -Eq '^[[:space:]]*(keyPassword|password)[[:space:]]*=' keystore.properties; then
echo "keystore.properties is missing keyPassword or password"
exit 1
fi
if ! grep -Eq '^[[:space:]]*(storePassword|password)[[:space:]]*=' keystore.properties; then
echo "keystore.properties is missing storePassword or password"
exit 1
fi
- name: Build mobile
run: bun run build:mobile
run: nix develop .#tauri --command bun --bun run build:mobile
- name: Upload mobile artifact
uses: https://data.forgejo.org/actions/upload-artifact@v3
@ -81,31 +117,30 @@ jobs:
path: apps/tauri/src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release.apk
build-desktop:
runs-on: docker
runs-on: nixos
strategy:
matrix:
target: [linux]
steps:
- name: Install node
run: nix profile add nixpkgs#nodejs_24
- name: Check out repo
uses: https://data.forgejo.org/actions/checkout@v4
- name: Install Packages
run: apt-get update && apt-get install -y sudo curl jq fakeroot dpkg rpm xz-utils
- name: Install Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile
run: nix develop .#electron --command bun install --frozen-lockfile
- name: Copy licenses
run: bun run copy-licenses
run: nix develop .#electron --command bun --bun run copy-licenses
- name: Build packages
run: bun run build:packages
run: nix develop .#electron --command bun --bun run build:packages
- name: Set Electron dev version
run: |
nix develop .#electron --command bash <<'EOF'
set -euo pipefail
VERSION="$(node -p "require('./package.json').version")"
SHORT_SHA="$(git rev-parse --short HEAD)"
DEV_VERSION="$VERSION-dev-$SHORT_SHA"
@ -117,9 +152,10 @@ jobs:
pkg.version = process.env.DEV_VERSION;
fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + "\n");
'
EOF
- name: Build Electron desktop
run: bun run build:desktop
run: nix develop .#electron --command bun --bun run build:desktop
- name: Upload desktop artifacts
uses: https://data.forgejo.org/actions/upload-artifact@v3
@ -128,22 +164,19 @@ jobs:
path: apps/electron/release/
release:
runs-on: docker
runs-on: nixos
needs: [build-web, build-mobile, build-desktop]
steps:
- name: Install node
run: nix profile add nixpkgs#nodejs_24
- name: Check out repo
uses: https://data.forgejo.org/actions/checkout@v4
with:
fetch-depth: 0
- name: Install Packages
run: apt-get update && apt-get install -y sudo curl jq
- name: Install Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile
run: nix develop .#electron --command bun install --frozen-lockfile
- name: Download mobile artifact
uses: https://data.forgejo.org/actions/download-artifact@v3
@ -160,21 +193,27 @@ jobs:
- name: Read version and hash
id: version
run: |
nix develop .#electron --command bash <<'EOF'
set -euo pipefail
VERSION="$(node -p "require('./package.json').version")"
SHORT_SHA="$(git rev-parse --short HEAD)"
echo "version=$VERSION" >> "$FORGEJO_OUTPUT"
echo "short_sha=$SHORT_SHA" >> "$FORGEJO_OUTPUT"
echo "tag=${VERSION}-dev-${SHORT_SHA}" >> "$FORGEJO_OUTPUT"
echo "title=${VERSION}-dev-${SHORT_SHA}" >> "$FORGEJO_OUTPUT"
EOF
- name: Copy releases
env:
TENSAMIN_RELEASE_VERSION: ${{ steps.version.outputs.tag }}
TENSAMIN_RELEASE_TAG: ${{ steps.version.outputs.tag }}
run: |
nix develop .#electron --command bash <<'EOF'
set -euo pipefail
ASSET_BASE_URL="${{ forgejo.api_url }}"
ASSET_BASE_URL="${ASSET_BASE_URL%/api/v1}/${{ forgejo.repository }}/releases/download/${{ steps.version.outputs.tag }}"
FORGEJO_RELEASE_ASSET_BASE_URL="$ASSET_BASE_URL" bun --bun run copy-releases
EOF
- name: Create pre-release and upload files
env:
@ -185,6 +224,7 @@ jobs:
TAG: ${{ steps.version.outputs.tag }}
TITLE: ${{ steps.version.outputs.title }}
run: |
nix develop .#electron --command bash <<'EOF'
set -eu
test -d releases
@ -273,3 +313,4 @@ jobs:
-H "Authorization: token $TOKEN" \
-F "attachment=@$file"
done
EOF

View file

@ -6,74 +6,110 @@ on:
paths-ignore:
- flake.nix
env:
NIX_CONFIG: experimental-features = nix-command flakes
jobs:
build-web:
runs-on: docker
runs-on: nixos
steps:
- name: Install node
run: nix profile add nixpkgs#nodejs_24
- name: Check out repo
uses: https://data.forgejo.org/actions/checkout@v4
- name: Install Packages
run: apt-get update && apt-get install -y sudo curl jq fakeroot dpkg rpm
- name: Install Nix
uses: https://github.com/cachix/install-nix-action@v30
- name: Install Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile
run: nix develop .#electron --command bun install --frozen-lockfile
- name: Copy licenses
run: bun run copy-licenses
run: nix develop .#electron --command bun --bun run copy-licenses
- name: Build packages
run: bun run build:packages
run: nix develop .#electron --command bun --bun run build:packages
- name: Build web
run: bun run build:web
- name: Install rsync
run: apt-get update && apt-get install -y rsync
run: nix develop .#electron --command bun --bun run build:web
- name: Deploy
run: rsync -a --delete apps/web/dist/ /var/lib/www/tensamin-web-prod/
run: nix develop .#electron --command rsync -a --delete apps/web/dist/ /var/lib/www/tensamin-web-prod/
build-mobile:
runs-on: docker
runs-on: nixos
steps:
- name: Install node
run: nix profile add nixpkgs#nodejs_24
- name: Check out repo
uses: https://data.forgejo.org/actions/checkout@v4
- name: Install Packages
run: apt-get update && apt-get install -y sudo curl jq fakeroot dpkg rpm
- name: Install Nix
uses: https://github.com/cachix/install-nix-action@v30
- name: Install Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile
run: nix develop .#tauri --command bun install --frozen-lockfile
- name: Copy licenses
run: bun run copy-licenses
run: nix develop .#tauri --command bun --bun run copy-licenses
- name: Build packages
run: bun run build:packages
run: nix develop .#tauri --command bun --bun run build:packages
- name: Setup Android Keystore
env:
KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
KEYSTORE_PROPERTIES: ${{ secrets.ANDROID_KEYSTORE_PROPERTIES }}
run: |
bun -e "require('fs').writeFileSync('keystore.jks', Buffer.from(process.env.KEYSTORE_BASE64.replace(/\s+/g, ''), 'base64'))"
bun -e "const content = process.env.KEYSTORE_PROPERTIES.replace(/\\n/g, '\n').replace(/\r/g, '').split('\n').map(l => l.trim()).filter(l => l).join('\n'); require('fs').writeFileSync('keystore.properties', content)"
nix profile add nixpkgs#gnused
set -euo pipefail
if [ -z "$KEYSTORE_BASE64" ]; then
echo "ANDROID_KEYSTORE_BASE64 secret is missing or empty"
exit 1
fi
if [ -z "$KEYSTORE_PROPERTIES" ]; then
echo "ANDROID_KEYSTORE_PROPERTIES secret is missing or empty"
exit 1
fi
printf '%s' "$KEYSTORE_BASE64" \
| tr -d '[:space:]' \
| base64 -d > keystore.jks
printf '%s' "$KEYSTORE_PROPERTIES" \
| sed 's/\\n/\n/g' \
| tr -d '\r' \
| sed 's|^[[:space:]]*storeFile[[:space:]]*=.*|storeFile=keystore.jks|' \
> keystore.properties
grep -q '^[[:space:]]*storeFile[[:space:]]*=' keystore.properties || printf '\nstoreFile=keystore.jks\n' >> keystore.properties
if [ ! -s keystore.jks ]; then
echo "Decoded keystore.jks is missing or empty"
exit 1
fi
if [ ! -s keystore.properties ]; then
echo "Generated keystore.properties is missing or empty"
exit 1
fi
if ! grep -q '^[[:space:]]*keyAlias[[:space:]]*=' keystore.properties; then
echo "keystore.properties is missing keyAlias"
exit 1
fi
if ! grep -Eq '^[[:space:]]*(keyPassword|password)[[:space:]]*=' keystore.properties; then
echo "keystore.properties is missing keyPassword or password"
exit 1
fi
if ! grep -Eq '^[[:space:]]*(storePassword|password)[[:space:]]*=' keystore.properties; then
echo "keystore.properties is missing storePassword or password"
exit 1
fi
- name: Build mobile
run: bun run build:mobile
run: nix develop .#tauri --command bun --bun run build:mobile
- name: Upload mobile artifact
uses: https://data.forgejo.org/actions/upload-artifact@v3
@ -82,31 +118,30 @@ jobs:
path: apps/tauri/src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release.apk
build-desktop:
runs-on: docker
runs-on: nixos
strategy:
matrix:
target: [linux]
steps:
- name: Install node
run: nix profile add nixpkgs#nodejs_24
- name: Check out repo
uses: https://data.forgejo.org/actions/checkout@v4
- name: Install Packages
run: apt-get update && apt-get install -y sudo curl jq fakeroot dpkg rpm xz-utils
- name: Install Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile
run: nix develop .#electron --command bun install --frozen-lockfile
- name: Copy licenses
run: bun run copy-licenses
run: nix develop .#electron --command bun --bun run copy-licenses
- name: Build packages
run: bun run build:packages
run: nix develop .#electron --command bun --bun run build:packages
- name: Set Electron prod version
run: |
nix develop .#electron --command bash <<'EOF'
set -euo pipefail
VERSION="$(node -p "require('./package.json').version")"
export VERSION
node -e '
@ -116,9 +151,10 @@ jobs:
pkg.version = process.env.VERSION;
fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + "\n");
'
EOF
- name: Build Electron desktop
run: bun run build:desktop
run: nix develop .#electron --command bun --bun run build:desktop
- name: Upload desktop artifacts
uses: https://data.forgejo.org/actions/upload-artifact@v3
@ -127,20 +163,17 @@ jobs:
path: apps/electron/release/
release:
runs-on: docker
runs-on: nixos
needs: [build-web, build-mobile, build-desktop]
steps:
- name: Install node
run: nix profile add nixpkgs#nodejs_24
- name: Check out repo
uses: https://data.forgejo.org/actions/checkout@v4
- name: Install Packages
run: apt-get update && apt-get install -y sudo curl jq
- name: Install Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile
run: nix develop .#electron --command bun install --frozen-lockfile
- name: Download mobile artifact
uses: https://data.forgejo.org/actions/download-artifact@v3
@ -157,18 +190,24 @@ jobs:
- name: Read version
id: version
run: |
nix develop .#electron --command bash <<'EOF'
set -euo pipefail
VERSION="$(node -p "require('./package.json').version")"
echo "version=$VERSION" >> "$FORGEJO_OUTPUT"
echo "tag=$VERSION" >> "$FORGEJO_OUTPUT"
EOF
- name: Copy releases
env:
TENSAMIN_RELEASE_VERSION: ${{ steps.version.outputs.tag }}
TENSAMIN_RELEASE_TAG: ${{ steps.version.outputs.tag }}
run: |
nix develop .#electron --command bash <<'EOF'
set -euo pipefail
ASSET_BASE_URL="${{ forgejo.api_url }}"
ASSET_BASE_URL="${ASSET_BASE_URL%/api/v1}/${{ forgejo.repository }}/releases/download/${{ steps.version.outputs.tag }}"
FORGEJO_RELEASE_ASSET_BASE_URL="$ASSET_BASE_URL" bun --bun run copy-releases
EOF
- name: Create release and upload files
env:
@ -178,6 +217,7 @@ jobs:
SHA: ${{ forgejo.sha }}
TAG: ${{ steps.version.outputs.tag }}
run: |
nix develop .#electron --command bash <<'EOF'
set -eu
test -d releases
@ -231,18 +271,18 @@ jobs:
-H "Authorization: token $TOKEN" \
-F "attachment=@$file"
done
EOF
- name: Delete dev releases for prod version
- name: Delete dev releases
env:
TOKEN: ${{ forgejo.token }}
API: ${{ forgejo.api_url }}
REPO: ${{ forgejo.repository }}
TAG: ${{ steps.version.outputs.tag }}
run: |
nix develop .#electron --command bash <<'EOF'
set -eu
PAGE=1
PREFIX="$TAG-dev-"
DELETE_RELEASES=delete-dev-releases.tsv
: > "$DELETE_RELEASES"
@ -257,8 +297,7 @@ jobs:
test "$COUNT" -gt 0 || break
jq -r \
--arg prefix "$PREFIX" \
'.[] | select(.prerelease == true) | select(.tag_name | startswith($prefix)) | [.id, .tag_name] | @tsv' releases.json \
'.[] | select(.prerelease == true) | select(.tag_name | contains("-dev-")) | [.id, .tag_name] | @tsv' releases.json \
>> "$DELETE_RELEASES"
PAGE="$((PAGE + 1))"
@ -271,11 +310,13 @@ jobs:
-H "Authorization: token $TOKEN" \
"$API/repos/$REPO/releases/$release_id"
done < "$DELETE_RELEASES"
EOF
- name: Update root flake release hash
env:
TAG: ${{ steps.version.outputs.tag }}
run: |
nix develop .#electron --command bash <<'EOF'
set -eu
DEB="$(find releases -maxdepth 1 -type f -name 'Tensamin-*-linux-amd64.deb' -print -quit)"
@ -324,3 +365,4 @@ jobs:
git add flake.nix
git -c user.name="forgejo-actions" -c user.email="forgejo-actions@localhost" commit -m "(qol): update release flake hash"
git push origin HEAD:dev
EOF

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Before After
Before After

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Before After
Before After

View file

@ -1,61 +0,0 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1779508470,
"narHash": "sha256-Ap9KJX+5xHIn3bPIpfNgT6MEXdAECECwo4/rmlQD74M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "29916453413845e54a65b8a1cf996842300cd299",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View file

@ -1,88 +0,0 @@
{
description = "Electron Development Environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = {nixpkgs, flake-utils, ...}:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs {inherit system; config.allowUnfree = true;};
electronRuntimeLibs = with pkgs; [
alsa-lib
at-spi2-atk
at-spi2-core
atk
cairo
cups
dbus
expat
fontconfig
freetype
gdk-pixbuf
glib
gtk3
libdrm
libgbm
libglvnd
libnotify
libpulseaudio
libuuid
libxkbcommon
mesa
nspr
nss
pango
pipewire
systemd
wayland
# xorg
libX11
libXScrnSaver
libXcomposite
libXcursor
libXdamage
libXext
libXfixes
libXi
libXrandr
libXtst
libxcb
];
in {
devShells.default = pkgs.mkShell {
packages = with pkgs; [
nodejs_22
corepack_22
bun
electron
pkg-config
python3
gcc
gnumake
git
jq
patchelf
dpkg
rpm
fpm
] ++ electronRuntimeLibs;
shellHook = ''
export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath electronRuntimeLibs}:$LD_LIBRARY_PATH"
export ELECTRON_ENABLE_LOGGING=1
export ELECTRON_OZONE_PLATFORM_HINT="''${ELECTRON_OZONE_PLATFORM_HINT:-auto}"
export NPM_CONFIG_TARGET_ARCH="''${NPM_CONFIG_TARGET_ARCH:-x64}"
export npm_config_build_from_source=true
export USE_SYSTEM_FPM=true
alias electron-install='cd ../.. && bun install'
alias electron-build-web='cd ../.. && bun run build:web'
alias electron-dev='bun run dev'
alias electron-package='bun run package:linux'
alias electron-validate='bun run validate'
'';
};
});
}

View file

@ -13,19 +13,19 @@
"build:web": "cd ../.. && bun run build:web",
"build": "tsc -p tsconfig.json && esbuild src/preload/preload.ts --bundle --platform=node --format=cjs --external:electron --outfile=dist/preload/preload.cjs",
"dev:raw": "cd ../.. && bun run build:web && cd apps/electron && bun run build && electron . --verbose",
"dev": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop --command bun run dev:raw; else bun run dev:raw; fi",
"dev": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop ../..#electron --command bun run dev:raw; else bun run dev:raw; fi",
"start:raw": "bun run build && electron .",
"start": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop --command bun run start:raw; else bun run start:raw; fi",
"start": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop ../..#electron --command bun run start:raw; else bun run start:raw; fi",
"package:raw": "cd ../.. && bun run build:web && cd apps/electron && bun run build && electron-builder --publish never",
"package": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop --command bun run package:raw; else bun run package:raw; fi",
"package": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop ../..#electron --command bun run package:raw; else bun run package:raw; fi",
"package:linux:raw": "cd ../.. && bun run build:web && cd apps/electron && bun run build && electron-builder --linux --publish never",
"package:linux": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop --command bun run package:linux:raw; else bun run package:linux:raw; fi",
"package:linux": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop ../..#electron --command bun run package:linux:raw; else bun run package:linux:raw; fi",
"package:windows:raw": "cd ../.. && bun run build:web && cd apps/electron && bun run build && electron-builder --win --publish never",
"package:windows": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop --command bun run package:windows:raw; else bun run package:windows:raw; fi",
"package:windows": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop ../..#electron --command bun run package:windows:raw; else bun run package:windows:raw; fi",
"checksum": "bun scripts/generate-release-metadata.ts",
"generate-signing-key": "bun scripts/generate-signing-key.ts",
"validate:raw": "bun run build && bun run package:linux:raw",
"validate": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop --command bun run validate:raw; else bun run validate:raw; fi"
"validate": "if command -v nix >/dev/null 2>&1 && [ -z \"$IN_NIX_SHELL\" ]; then nix develop ../..#electron --command bun run validate:raw; else bun run validate:raw; fi"
},
"dependencies": {},
"devDependencies": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Before After
Before After

96
apps/tauri/flake.lock generated
View file

@ -1,96 +0,0 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1775036866,
"narHash": "sha256-ZojAnPuCdy657PbTq5V0Y+AHKhZAIwSIT2cb8UgAz/U=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6201e203d09599479a3b3450ed24fa81537ebc4e",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1744536153,
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1775272153,
"narHash": "sha256-FwYb64ysv8J2TxaqsYYcDyHAHBUEaQlriPMWPMi1K7M=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "740fb0203b2852917b909a72b948d34d0b171ec0",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View file

@ -1,108 +0,0 @@
{
description = "Tauri mobile development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rust-overlay.url = "github:oxalica/rust-overlay";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = {
self,
nixpkgs,
rust-overlay,
flake-utils,
}:
flake-utils.lib.eachDefaultSystem (
system: let
overlays = [(import rust-overlay)];
pkgs = import nixpkgs {
inherit system overlays;
config = {
allowUnfree = true;
android_sdk.accept_license = true;
};
};
projectRoot = ".";
androidHome = "${projectRoot}/.android";
sdkRoot = "${androidHome}/sdk";
ndkVersion = "29.0.14206865";
android = pkgs.androidenv.composeAndroidPackages {
cmdLineToolsVersion = "8.0";
toolsVersion = "26.1.1";
platformToolsVersion = "35.0.2";
buildToolsVersions = ["35.0.0"];
platformVersions = ["35" "36"];
includeSources = false;
includeSystemImages = false;
includeNDK = true;
ndkVersions = [ndkVersion];
useGoogleAPIs = false;
};
rustToolchain = pkgs.rust-bin.stable.latest.default.override {
extensions = ["rust-src" "rust-analyzer"];
targets = [
"aarch64-linux-android"
"armv7-linux-androideabi"
"i686-linux-android"
"x86_64-linux-android"
"wasm32-unknown-unknown"
];
};
in {
devShells.default = pkgs.mkShell {
buildInputs = with pkgs;
[
jdk17
rustToolchain
gradle
nodejs
pkg-config
]
++ [
android.androidsdk
pkgs.android-studio-tools
];
shellHook = ''
sdkSource="${android.androidsdk}/libexec/android-sdk"
mkdir -p "${androidHome}"
if [ -L "${sdkRoot}" ]; then
rm -f "${sdkRoot}"
fi
mkdir -p "${sdkRoot}"
ln -sfn "$sdkSource/build-tools" "${sdkRoot}/build-tools"
ln -sfn "$sdkSource/cmake" "${sdkRoot}/cmake"
ln -sfn "$sdkSource/licenses" "${sdkRoot}/licenses"
ln -sfn "$sdkSource/ndk" "${sdkRoot}/ndk"
ln -sfn "$sdkSource/ndk-bundle" "${sdkRoot}/ndk-bundle"
ln -sfn "$sdkSource/platforms" "${sdkRoot}/platforms"
ln -sfn "$sdkSource/platform-tools" "${sdkRoot}/platform-tools"
ln -sfn "$sdkSource/tools" "${sdkRoot}/tools"
mkdir -p "${sdkRoot}/cmdline-tools"
ln -sfn "$sdkSource/cmdline-tools/8.0" "${sdkRoot}/cmdline-tools/8.0"
ln -sfn "8.0" "${sdkRoot}/cmdline-tools/latest"
sdkRootAbs="$(realpath "${sdkRoot}")"
ndkRootAbs="''${sdkRootAbs}/ndk/${ndkVersion}"
export PATH="''${sdkRootAbs}/cmdline-tools/latest/bin:''${sdkRootAbs}/platform-tools:''${ndkRootAbs}:${pkgs.android-studio-tools}/bin:$PATH"
export ANDROID_HOME="''${sdkRootAbs}"
export ANDROID_SDK_ROOT="''${sdkRootAbs}"
export ANDROID_NDK_ROOT="''${ndkRootAbs}"
export ANDROID_NDK_HOME="$ANDROID_NDK_ROOT"
export NDK_HOME="$ANDROID_NDK_ROOT"
export NDK_PATH="$ANDROID_NDK_ROOT"
export JAVA_HOME="${pkgs.jdk17}"
'';
};
}
);
}

View file

@ -2,14 +2,14 @@
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="90mm"
height="90mm"
viewBox="0 0 90 90"
width="90.476906mm"
height="90.476906mm"
viewBox="0 0 90.476906 90.476906"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
sodipodi:docname="logo_raw.svg"
sodipodi:docname="logo_square_outline_gen.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
@ -24,16 +24,32 @@
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:document-units="mm"
inkscape:zoom="0.99999999"
inkscape:cx="450"
inkscape:cy="291.5"
inkscape:window-width="1223"
inkscape:window-height="1369"
inkscape:window-x="26"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:zoom="2"
inkscape:cx="191.5"
inkscape:cy="117.25"
inkscape:window-width="2500"
inkscape:window-height="1403"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" /><defs
id="defs1"><linearGradient
id="defs1"><inkscape:path-effect
effect="fillet_chamfer"
id="path-effect1"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0.26458333,0,1 @ F,0,0,1,0,0.26458333,0,1 @ F,0,0,1,0,0.26458333,0,1 @ F,0,0,1,0,0.26458333,0,1 @ F,0,0,1,0,0.26458333,0,1 @ F,0,0,1,0,0.26458333,0,1 @ F,0,0,1,0,0.26458333,0,1"
radius="1"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" /><linearGradient
id="swatch15"
inkscape:swatch="solid"><stop
style="stop-color:#000000;stop-opacity:1;"
@ -51,7 +67,7 @@
id="stop3" /></linearGradient><linearGradient
id="swatch2"
inkscape:swatch="solid"><stop
style="stop-color:#000000;stop-opacity:1;"
style="stop-color:#b8f8ff;stop-opacity:1;"
offset="0"
id="stop2" /></linearGradient><linearGradient
id="swatch1"
@ -184,13 +200,23 @@
x1="63.191292"
y1="148.5"
x2="146.82355"
y2="148.5" /></defs><g
y2="148.5" /><linearGradient
inkscape:collect="always"
xlink:href="#swatch2"
id="linearGradient1"
gradientUnits="userSpaceOnUse"
x1="63.191292"
y1="148.5"
x2="146.82355"
y2="148.5"
gradientTransform="matrix(1.0144629,0,0,1.0151924,217.46226,13.830072)" /></defs><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-62.941767,-104.13688)"><g
transform="translate(-281.06837,-119.33314)"
><g
id="g2"
transform="matrix(0.78671048,0,0,0.83608014,-116.36038,-50.640745)"
transform="matrix(0.77770172,0,0,0.82714179,104.17421,-33.291714)"
inkscape:label="background"
style="display:inline;stroke:url(#linearGradient15);stroke-width:0.616508;stroke-dasharray:none"
clip-path="url(#clipPath1)"><path
@ -213,11 +239,19 @@
id="rect1-1-3-6-2"
style="fill:#12a89e;stroke:url(#linearGradient21);stroke-width:0.616508;stroke-dasharray:none"
transform="rotate(-75)"
d="m -227.83395,371.18179 h 146.303341 v 24.39636 H -227.83395 Z" /></g><g
d="m -227.83395,371.18179 h 146.303341 v 24.39636 H -227.83395 Z" /></g><path
id="path1-5"
style="fill:none;stroke:url(#linearGradient1);stroke-width:2;stroke-dasharray:none"
inkscape:label="glow_outline"
d="m 323.73413,119.91784 -40.80246,15.9513 c -0.13609,0.0532 -0.26542,0.21326 -0.28843,0.35757 -2.90631,18.22859 -0.19736,34.27444 8.28042,47.36302 0.0794,0.12264 0.10916,0.33484 0.0657,0.47436 l -7.08112,22.75509 a 0.11130973,0.11130973 40.101955 0 0 0.15695,0.13218 l 18.7652,-9.59506 c 0.13011,-0.0665 0.32608,-0.044 0.43816,0.0497 5.75202,4.81168 12.45464,8.67546 20.46583,11.84762 0.13586,0.0538 0.3564,0.0538 0.49225,-3e-5 32.16862,-12.74646 46.41741,-39.59704 41.09168,-73.02692 -0.023,-0.14431 -0.15232,-0.30436 -0.28841,-0.35757 l -40.80297,-15.9513 a 0.67679193,0.67679193 179.99988 0 0 -0.49284,0 z"
sodipodi:nodetypes="cccccccc"
inkscape:original-d="m 323.98055,119.8215 -41.2953,16.14398 c -2.99079,18.43973 -0.24934,34.65473 8.38277,47.84598 l -7.23836,23.26035 19.23635,-9.83596 c 5.85568,4.9403 12.69983,8.88741 20.91454,12.11489 32.42602,-12.73985 46.75142,-39.74883 41.29581,-73.38526 z"
inkscape:path-effect="#path-effect1"
transform="matrix(0.98854883,0,0,0.98930922,6.03231,1.7325084)" /><g
id="g3"
inkscape:label="foreground"
style="stroke:url(#linearGradient16);stroke-width:0.5;stroke-dasharray:none"
transform="translate(3.3653788,0.84760028)"><g
transform="matrix(0.98854883,0,0,0.98930922,222.52896,17.64618)"><g
id="g1"
inkscape:label="outline"
style="stroke:url(#linearGradient23);stroke-width:0.5;stroke-dasharray:none"><path

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before After
Before After

View file

@ -21,9 +21,9 @@
"dev:mobile:raw": "tauri android dev --host ${TAURI_DEV_HOST:-127.0.0.1}",
"start-adb:mobile:raw": "adb devices",
"build:mobile:raw": "tauri android build",
"dev:mobile": "if command -v nix >/dev/null 2>&1; then nix develop --command bun dev:mobile:raw; else bun dev:mobile:raw; fi",
"start-adb:mobile": "if command -v nix >/dev/null 2>&1; then nix develop --command bun start-adb:mobile:raw; else bun start-adb:mobile:raw; fi",
"build:mobile": "bun run render-version.ts && if command -v nix >/dev/null 2>&1; then nix develop --command bun build:mobile:raw; else bun build:mobile:raw; fi && bun run render-version.ts --unrender",
"dev:mobile": "if command -v nix >/dev/null 2>&1; then nix develop ../..#tauri --command bun dev:mobile:raw; else bun dev:mobile:raw; fi",
"start-adb:mobile": "if command -v nix >/dev/null 2>&1; then nix develop ../..#tauri --command bun start-adb:mobile:raw; else bun start-adb:mobile:raw; fi",
"build:mobile": "bun run render-version.ts && if command -v nix >/dev/null 2>&1; then nix develop ../..#tauri --command bun build:mobile:raw; else bun build:mobile:raw; fi && bun run render-version.ts --unrender",
"gen-icons": "tauri icon ./logo.json && bun scripts/sync-electron-icons.ts",
"format": "bunx prettier --write .",
"lint": "eslint src"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Before After
Before After

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before After
Before After

View file

@ -19,7 +19,7 @@ export function Basic({
extra?: React.ReactNode;
}) {
return (
<Card className="animate-in fade-in duration-300 rounded-2xl py-0 m-px">
<Card className="animate-in fade-in duration-300 rounded-xl py-0 m-px">
<CardHeader className="flex flex-row gap-2.5 items-center justify-start p-2">
<div className="relative shrink-0 overflow-visible">
<Avatar>

View file

@ -12,7 +12,6 @@ import {
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuGroup,
DropdownMenuLabel,
Dialog,
DialogContent,
DialogFooter,
@ -228,7 +227,6 @@ export default function Sidebar() {
/>
<DropdownMenuContent>
<DropdownMenuGroup>
<DropdownMenuLabel>Profile</DropdownMenuLabel>
<DropdownMenuItem
onClick={() => {
setDraftStatus(user.status ?? "");

View file

@ -23,10 +23,10 @@ export default function Switch(props: {
return (
<div
role="tablist"
className="border relative grid grid-cols-2 rounded-full bg-card p-1 select-none"
className="border relative grid grid-cols-2 rounded-4xl bg-card p-1 select-none"
>
<div
className="absolute top-1 bottom-1 rounded-full bg-input shadow-sm transition-all duration-300 ease-in-out"
className="absolute top-1 bottom-1 rounded-4xl bg-input shadow-sm transition-all duration-300 ease-in-out"
style={{
left: props.category === "conversations" ? "0.25rem" : "50%",
width: "calc(50% - 0.25rem)",
@ -35,7 +35,7 @@ export default function Switch(props: {
<button
role="tab"
aria-selected={props.category === "conversations"}
className={`relative z-10 w-full cursor-pointer rounded-full px-2.5 py-1.5 text-center text-sm font-medium transition-colors duration-300 ${
className={`relative z-10 w-full cursor-pointer rounded-4xl px-2.5 py-1.5 text-center text-sm font-medium transition-colors duration-300 ${
props.category === "conversations"
? "text-foreground"
: "text-ring/50 hover:text-ring"
@ -47,7 +47,7 @@ export default function Switch(props: {
<button
role="tab"
aria-selected={props.category === "communities"}
className={`relative z-10 w-full cursor-pointer rounded-full px-2.5 py-1.5 text-center text-sm font-medium transition-colors duration-300 ${
className={`relative z-10 w-full cursor-pointer rounded-4xl px-2.5 py-1.5 text-center text-sm font-medium transition-colors duration-300 ${
props.category === "communities"
? "text-foreground"
: "text-ring/50 hover:text-ring"

View file

@ -22,6 +22,17 @@
}
}
@theme inline {
--radius-sm: calc(var(--radius) * 0.6);
--radius-md: calc(var(--radius) * 0.8);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) * 1.4);
--radius-2xl: calc(var(--radius) * 1.8);
--radius-3xl: calc(var(--radius) * 2.2);
--radius-4xl: calc(var(--radius) * 2.6);
--radius-full: calc(var(--radius) * 9999);
}
html,
body,
#root {

View file

@ -119,6 +119,10 @@ function ThemeStorageBridge() {
setThemePolarity,
themeTint,
setThemeTint,
themeBorderRadius,
setThemeBorderRadius,
themeCustomCss,
setThemeCustomCss,
} = useTheme();
const loadedRef = useRef(false);
@ -131,7 +135,18 @@ function ThemeStorageBridge() {
load("theme_primary_color"),
load("theme_polarity"),
load("theme_tint"),
]).then(([color, palette, primaryColor, polarity, tint]) => {
load("theme_border_radius"),
load("theme_custom_css"),
]).then(
([
color,
palette,
primaryColor,
polarity,
tint,
borderRadius,
customCss,
]) => {
if (!active) {
return;
}
@ -141,15 +156,20 @@ function ThemeStorageBridge() {
setThemePrimaryColor(primaryColor);
setThemePolarity(polarity);
setThemeTint(tint);
setThemeBorderRadius(borderRadius);
setThemeCustomCss(customCss);
loadedRef.current = true;
});
},
);
return () => {
active = false;
};
}, [
load,
setThemeBorderRadius,
setThemeColor,
setThemeCustomCss,
setThemePalette,
setThemePolarity,
setThemePrimaryColor,
@ -196,6 +216,22 @@ function ThemeStorageBridge() {
save("theme_tint", themeTint);
}, [save, themeTint]);
useEffect(() => {
if (!loadedRef.current) {
return;
}
save("theme_border_radius", themeBorderRadius);
}, [save, themeBorderRadius]);
useEffect(() => {
if (!loadedRef.current) {
return;
}
save("theme_custom_css", themeCustomCss);
}, [save, themeCustomCss]);
return null;
}
@ -210,6 +246,8 @@ function RootShell() {
paletteStorageKey={null}
primaryColorStorageKey={null}
tintStorageKey={null}
borderRadiusStorageKey={null}
customCssStorageKey={null}
>
<div className="w-screen h-dvh overflow-hidden">
<Toaster

View file

@ -1,5 +1,20 @@
import { StylePicker } from "@tensamin/ui";
export default function Page() {
return <StylePicker />;
return (
<div className="overflow-y-auto">
<StylePicker />
<div className="absolute bottom-0 right-0 mb-3 mr-2">
<a
className="block w-60 text-xs whitespace-pre-wrap"
href="https://git.methanium.net/tensamin/client/issues/new"
target="_blank"
rel="noreferrer"
>
Please open a Git issue to help us improve this feature. We want to
get it right.
</a>
</div>
</div>
);
}

112
bun.lock
View file

@ -258,7 +258,7 @@
},
"overrides": {
"@tensamin/ttp-core": "https://git.methanium.net/tensamin/ttp/archive/0.0.24.tar.gz",
"@tensamin/ui": "https://git.methanium.net/tensamin/ui/archive/0.0.37.tar.gz",
"@tensamin/ui": "https://git.methanium.net/tensamin/ui/archive/0.0.39.tar.gz",
},
"packages": {
"@antfu/ni": ["@antfu/ni@25.0.0", "", { "dependencies": { "ansis": "^4.0.0", "fzf": "^0.5.2", "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" }, "bin": { "na": "bin/na.mjs", "ni": "bin/ni.mjs", "nr": "bin/nr.mjs", "nci": "bin/nci.mjs", "nlx": "bin/nlx.mjs", "nun": "bin/nun.mjs", "nup": "bin/nup.mjs" } }, "sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA=="],
@ -321,9 +321,9 @@
"@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="],
"@base-ui/react": ["@base-ui/react@1.5.0", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@base-ui/utils": "0.2.9", "@floating-ui/react-dom": "^2.1.8", "@floating-ui/utils": "^0.2.11", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@date-fns/tz": "^1.2.0", "@types/react": "^17 || ^18 || ^19", "date-fns": "^4.0.0", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@date-fns/tz", "@types/react", "date-fns"] }, "sha512-z1gSAlced1yY+iM+mHDEtIkD8UI3Ebs52MuBPxvV6f5hRutk+xvCH/wuB7hDqDzK9JG5FoMz5nhrqtSs1wjt1A=="],
"@base-ui/react": ["@base-ui/react@1.6.0", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@base-ui/utils": "0.3.1", "@floating-ui/react-dom": "^2.1.8", "@floating-ui/utils": "^0.2.11", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@date-fns/tz": "^1.2.0", "@types/react": "^17 || ^18 || ^19", "date-fns": "^4.0.0", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@date-fns/tz", "@types/react", "date-fns"] }, "sha512-/jzjTWJYXhRFO45Bev9lc3cHbmjzCMpUqbMZ2AgKy/z25mY9B6shGSNcXcjQar9n5doM0KYW1W8fcFv2jZBuMw=="],
"@base-ui/utils": ["@base-ui/utils@0.2.9", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@floating-ui/utils": "^0.2.11", "reselect": "^5.1.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-x/PDDCYzoqPpjrdyb3VcyylTI2IjUXEtYDGi5foh7KsnmNJIIaVwA2GLgDH1dps1GgXiJbA60hM+AyuTfQzIvw=="],
"@base-ui/utils": ["@base-ui/utils@0.3.1", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@floating-ui/utils": "^0.2.11", "reselect": "^5.2.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-gFFiltORVmW/N6IILTGxizP3PBpVpysqML1ALY5Vk0mH+7faVkCknOU31goYHN5Aoek2dkjxva1XOD2Ce9WuIg=="],
"@bufbuild/protobuf": ["@bufbuild/protobuf@1.10.1", "", {}, "sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ=="],
@ -349,7 +349,7 @@
"@date-fns/tz": ["@date-fns/tz@1.5.0", "", {}, "sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg=="],
"@dotenvx/dotenvx": ["@dotenvx/dotenvx@1.71.3", "", { "dependencies": { "commander": "^11.1.0", "dotenv": "^17.2.1", "eciesjs": "^0.4.10", "enquirer": "^2.4.1", "execa": "^5.1.1", "fdir": "^6.2.0", "ignore": "^5.3.0", "object-treeify": "1.1.33", "picomatch": "^4.0.4", "which": "^4.0.0", "yocto-spinner": "^1.1.0" }, "bin": { "dotenvx": "src/cli/dotenvx.js" } }, "sha512-WSmox5aD+XxJEUEOTk7gKLpd5+Iz9Nik89Zpbu5DijMln6LsFiv3xpNKBMc/b9sSkUlKvAblzrhik2TqKFE7NA=="],
"@dotenvx/dotenvx": ["@dotenvx/dotenvx@1.73.1", "", { "dependencies": { "commander": "^11.1.0", "conf": "^10.2.0", "dotenv": "^17.2.1", "eciesjs": "^0.4.10", "enquirer": "^2.4.1", "env-paths": "^2.2.1", "execa": "^5.1.1", "fdir": "^6.2.0", "ignore": "^5.3.0", "object-treeify": "1.1.33", "open": "^8.4.2", "picomatch": "^4.0.4", "systeminformation": "^5.22.11", "undici": "^7.11.0", "which": "^4.0.0", "yocto-spinner": "^1.1.0" }, "bin": { "dotenvx": "src/cli/dotenvx.js" } }, "sha512-AWf8edAsSpINqJbtaZsaiV3PO+vw5pS4wJFl6ahYNdnp3gfFYeMxRCdsA9042bKP4UPCs8yr5FikSFlvkmFVag=="],
"@ecies/ciphers": ["@ecies/ciphers@0.2.6", "", { "peerDependencies": { "@noble/ciphers": "^1.0.0" } }, "sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g=="],
@ -443,21 +443,21 @@
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.7.2", "", { "dependencies": { "@eslint/core": "^1.2.1", "levn": "^0.4.1" } }, "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A=="],
"@fallow-cli/darwin-arm64": ["@fallow-cli/darwin-arm64@2.96.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-y5zqGloIyeDnLXtrmCDSaANK+jrEXIR9an3UokkIhtCvztq2/Oi4ha2kWgBuNDQhrT8dk9tXTYX/+lBV9a7Yhg=="],
"@fallow-cli/darwin-arm64": ["@fallow-cli/darwin-arm64@2.99.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-aVrW4PSIyAP2lG9yWI+Ub6OJSSwEpkxwv7ZFy24wOODgAsUvjRtGW3LUMn43I7zKu7DbrTzadlupPzWYQrF1mg=="],
"@fallow-cli/darwin-x64": ["@fallow-cli/darwin-x64@2.96.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ofN1Y4MoGV2bO19j0p7REZBdflZJ7oSAAel8DOQkrcoAqa5rEu2iJAFO0u9I0gSDxQG/g++GawojPK2jWsGz7Q=="],
"@fallow-cli/darwin-x64": ["@fallow-cli/darwin-x64@2.99.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-lJ+TsjZeu9aD2egHfl7Hhr/P4ExhagNtVwpDfk5tx15tSzsS/P+lAzVZ9Avr6ENV4jyQ3f1l771as2nsnp80wQ=="],
"@fallow-cli/linux-arm64-gnu": ["@fallow-cli/linux-arm64-gnu@2.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-GlHpuXQhrK/BpDLV2GahGHSL+LawzufDLGfFujdrLCsOsCHggqWr0T3NR6fuzHgapel/nhtjBRzWJSYAMz0PLg=="],
"@fallow-cli/linux-arm64-gnu": ["@fallow-cli/linux-arm64-gnu@2.99.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-VSfnBt/MpnJxlkuY24kpH2pPjGDMS524eqIQRswCnqmMeLttYRLNrHd9zca7lXR9qLoEcEjGb34VpEpKJl2WOw=="],
"@fallow-cli/linux-arm64-musl": ["@fallow-cli/linux-arm64-musl@2.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EAKnmAxvALNiSomznrT/UwGOSI3B/V2ISFoJFaIOcd+K2tVr9rbxNyv40gPWgzECWukiDn+u+vWMO+ul7fpd4A=="],
"@fallow-cli/linux-arm64-musl": ["@fallow-cli/linux-arm64-musl@2.99.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-OlK6rzCRbv8L5/JlQOrGUZR/5dFWU8Wn95qzOFUoSYj/4e+ABoqaFw4hbYkbelsEhdVb40L57bxt78FO5u6POw=="],
"@fallow-cli/linux-x64-gnu": ["@fallow-cli/linux-x64-gnu@2.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-gobVZ9J1rhPanZyPkVHT0T9SmPHgC+C46IPPcjdjC0C655X7pAGV6CysVjvIBAo+pAIcUWVvkD5DiDa1OFYwgw=="],
"@fallow-cli/linux-x64-gnu": ["@fallow-cli/linux-x64-gnu@2.99.0", "", { "os": "linux", "cpu": "x64" }, "sha512-uOxJj3FahMT9Lgws5mtEF5eRUdjlt232DbwfxI/5VknqrcvqqWjqsdkE1JrW6aPoy8Ex4KBc93DBcEHxyrSYMA=="],
"@fallow-cli/linux-x64-musl": ["@fallow-cli/linux-x64-musl@2.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-SjeU14V5SYUhXzYjKOVo2oijpxYSbMxKoiKzeiKNK+hmMGC7SoCPruP9jD8IdsTr1NmgR+MdkKafxuGmWBvWKw=="],
"@fallow-cli/linux-x64-musl": ["@fallow-cli/linux-x64-musl@2.99.0", "", { "os": "linux", "cpu": "x64" }, "sha512-VBLvXobdtap1L73UjSPOoC2m5jXpBR5k8qB91XjyNAOreqwreVz5d2UlM3UVy39/VyiP6FM+MxctGneHJlmiJg=="],
"@fallow-cli/win32-arm64-msvc": ["@fallow-cli/win32-arm64-msvc@2.96.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-KL6Xf/J/XPOhK0VfIURFYCyJ11tfa4pn6+HzKc8hKa4DucwJlvpO+Pk4937hEQgCkLC/HmCzZWPn3rE7WiIvNQ=="],
"@fallow-cli/win32-arm64-msvc": ["@fallow-cli/win32-arm64-msvc@2.99.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-TSQmWZDmNNjppWTlbZX+L808pwSuXh40RXqwA0D8gm4kBk1zwr9dVITcj5s2NLuIVzhnU4+A5U9AO28BRThcSQ=="],
"@fallow-cli/win32-x64-msvc": ["@fallow-cli/win32-x64-msvc@2.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-WXrNyYxqW4A1jMAZuMLInGuzL4E35kQlaDfLtGqkbC3vbbq36eMPmdoXuK8trtllqg0NA8Cd+KYQwN8xA8zzNA=="],
"@fallow-cli/win32-x64-msvc": ["@fallow-cli/win32-x64-msvc@2.99.0", "", { "os": "win32", "cpu": "x64" }, "sha512-BUfixVqZiaTQG30LXZ5srGD9k1CSBLICsIBBWhl7b+P8P+wd/ZjFDlLnC6/EqBCb1tzU84Qev3r84CEmx4HHlw=="],
"@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="],
@ -689,19 +689,19 @@
"@tanstack/react-query": ["@tanstack/react-query@5.101.0", "", { "dependencies": { "@tanstack/query-core": "5.101.0" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-rLlJXSpkqfizLWgkR5+eLeIk0MvTx/meEIR7LRjxic+qxiQP8zVjq7BqQkiCMNLQBlLfuOLqqr6KO5GtrDlmSg=="],
"@tanstack/react-router": ["@tanstack/react-router@1.170.15", "", { "dependencies": { "@tanstack/history": "1.162.0", "@tanstack/react-store": "^0.9.3", "@tanstack/router-core": "1.171.13", "isbot": "^5.1.22" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-GawYz7HEjj8rTUUDoT/SemDEVm63pZUO+2mOcXHY9Jl3EwMS5gFBnPu/2UvcrwRm1jN1k79fokc0d4aFmrLatg=="],
"@tanstack/react-router": ["@tanstack/react-router@1.170.16", "", { "dependencies": { "@tanstack/history": "1.162.0", "@tanstack/react-store": "^0.9.3", "@tanstack/router-core": "1.171.13", "isbot": "^5.1.22" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-w6eq1IJklujs1tESazaK/FxH0+H2l8vm/QPuu1cD3oRW/ubgKneQpd7b64ti/8gUyEimzimJQZDmJr6YHfP5+g=="],
"@tanstack/react-store": ["@tanstack/react-store@0.9.3", "", { "dependencies": { "@tanstack/store": "0.9.3", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg=="],
"@tanstack/react-virtual": ["@tanstack/react-virtual@3.14.2", "", { "dependencies": { "@tanstack/virtual-core": "3.17.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-IpWnmCLvuymRfeeLNVXIzNEYBFLpd3drVIS91sqV78VTZFyldlChkOocZRCPp1B+Wnk09bcLNme8WaMU/9/9bQ=="],
"@tanstack/react-virtual": ["@tanstack/react-virtual@3.14.3", "", { "dependencies": { "@tanstack/virtual-core": "3.17.1" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-k/cnHPVaOfn46hSbiY6n4Dzf4QjCGWSF40zR5QIIYUqPAjpA6TN7InfYmcMiDVQGP2iUn9xsRbAl8u1v3UmeVQ=="],
"@tanstack/router-core": ["@tanstack/router-core@1.171.13", "", { "dependencies": { "@tanstack/history": "1.162.0", "cookie-es": "^3.0.0", "seroval": "^1.5.4", "seroval-plugins": "^1.5.4" } }, "sha512-+NOwEj1kO/6IGmpHRIZHasYxYWpyBQGNIZAST9aNrk9Q3YlU9SgqVnl1pbLa9qAKfeNdXQIRve0RQb/0kyDeDA=="],
"@tanstack/store": ["@tanstack/store@0.11.0", "", {}, "sha512-WlzzCt3xi0G6pCAJu1U+2jiECwabETDpQDi3hfkFZvJii9AuZqEKbOiVarX1/bWhTNjU486yQtJCCasi/0q+Cw=="],
"@tanstack/virtual-core": ["@tanstack/virtual-core@3.17.0", "", {}, "sha512-gOxY/hFkPh/XQYhnThBHzkbkX3Ed+z/iushyz+R+JAr213aXxUDgQoTgTdrDpBSRsjFM73P/KfUyWmaF9WHMkQ=="],
"@tanstack/virtual-core": ["@tanstack/virtual-core@3.17.1", "", {}, "sha512-VZyW2Uiml5tmBZwPGrSD3Sz73OxzljQMCmzYHsUTPEuTsERf5xwa+uWb01xEzkz3ZSYTjj8NEb/mKHvgKxyZdA=="],
"@tauri-apps/api": ["@tauri-apps/api@2.11.0", "", {}, "sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA=="],
"@tauri-apps/api": ["@tauri-apps/api@2.11.1", "", {}, "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA=="],
"@tauri-apps/cli": ["@tauri-apps/cli@2.11.2", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.11.2", "@tauri-apps/cli-darwin-x64": "2.11.2", "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.2", "@tauri-apps/cli-linux-arm64-gnu": "2.11.2", "@tauri-apps/cli-linux-arm64-musl": "2.11.2", "@tauri-apps/cli-linux-riscv64-gnu": "2.11.2", "@tauri-apps/cli-linux-x64-gnu": "2.11.2", "@tauri-apps/cli-linux-x64-musl": "2.11.2", "@tauri-apps/cli-win32-arm64-msvc": "2.11.2", "@tauri-apps/cli-win32-ia32-msvc": "2.11.2", "@tauri-apps/cli-win32-x64-msvc": "2.11.2" }, "bin": { "tauri": "tauri.js" } }, "sha512-bk3HemqvGRoy+5D/dVMUQHKMYLglD0jVnMm/0iGMH6ufZ+p8r14m6BpIixwij3PBvZdvORUp1YifTD8QxVZ1Nw=="],
@ -759,7 +759,7 @@
"@tensamin/ttp-core": ["@tensamin/ttp-core@https://git.methanium.net/tensamin/ttp/archive/0.0.24.tar.gz", { "dependencies": { "@eslint/js": "^10.0.1", "@tauri-apps/api": "^2.9.0", "@typescript-eslint/parser": "^8.59.1", "@webtransport-bun/webtransport": "^0.3.0", "globals": "^17.5.0", "typescript": "^6.0.3", "typescript-eslint": "^8.59.1", "zod": "^4.4.1" } }, "sha512-Db94CDOTYvzJSQDZGDgziUXRvXx9PiEfYDQt6sYe8Nyg+KD/aiKnyQx7NeEiG03TfYE3ogNxXOsrcsip4di8+g=="],
"@tensamin/ui": ["@tensamin/ui@https://git.methanium.net/tensamin/ui/archive/0.0.37.tar.gz", { "dependencies": { "@base-ui/react": "^1.3.0", "@fontsource-variable/inter": "^5.2.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", "lucide-react": "^1.8.0", "next-themes": "^0.4.6", "react-day-picker": "^9.14.0", "react-resizable-panels": "^4.10.0", "recharts": "3.8.0", "shadcn": "^3.5.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tw-animate-css": "^1.3.0", "vaul": "^1.1.2" }, "peerDependencies": { "react": "^19.2.0", "react-dom": "^19.2.0" } }, "sha512-yxZjHxzagey2+r5UqXi2+Z2GYVSuj2QKVtitHLAuXzdidobGDdtV8tHkTJP7WKLdFASJ/g4ULSWvGJ12PHPoaw=="],
"@tensamin/ui": ["@tensamin/ui@https://git.methanium.net/tensamin/ui/archive/0.0.39.tar.gz", { "dependencies": { "@base-ui/react": "^1.3.0", "@fontsource-variable/inter": "^5.2.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", "lucide-react": "^1.8.0", "next-themes": "^0.4.6", "react-day-picker": "^9.14.0", "react-resizable-panels": "^4.10.0", "recharts": "3.8.0", "shadcn": "^3.5.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tw-animate-css": "^1.3.0", "vaul": "^1.1.2" }, "peerDependencies": { "react": "^19.2.0", "react-dom": "^19.2.0" } }, "sha512-7GtOjH6H+8Go8tPJmnlbmmo9Chn2wbZ/pZdUydEc8fS5XPh8qdPTI3PhUpBuyuay60pRsfoUHpCVK5DqdQUACA=="],
"@tensamin/user": ["@tensamin/user@workspace:packages/user"],
@ -893,13 +893,15 @@
"at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="],
"atomically": ["atomically@1.7.0", "", {}, "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w=="],
"aws4": ["aws4@1.13.2", "", {}, "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="],
"balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.37", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.38", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw=="],
"bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="],
@ -981,6 +983,8 @@
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"conf": ["conf@10.2.0", "", { "dependencies": { "ajv": "^8.6.3", "ajv-formats": "^2.1.1", "atomically": "^1.7.0", "debounce-fn": "^4.0.0", "dot-prop": "^6.0.1", "env-paths": "^2.2.1", "json-schema-typed": "^7.0.3", "onetime": "^5.1.2", "pkg-up": "^3.1.0", "semver": "^7.3.5" } }, "sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg=="],
"content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="],
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
@ -1037,6 +1041,8 @@
"date-fns-jalali": ["date-fns-jalali@4.1.0-0", "", {}, "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg=="],
"debounce-fn": ["debounce-fn@4.0.0", "", { "dependencies": { "mimic-fn": "^3.0.0" } }, "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="],
@ -1083,6 +1089,8 @@
"dmg-builder": ["dmg-builder@26.15.3", "", { "dependencies": { "app-builder-lib": "26.15.3", "builder-util": "26.15.3", "fs-extra": "^10.1.0", "js-yaml": "^4.1.0" } }, "sha512-O3zJUFUYHJKgzPqioHxfxzBzlSC1eXCSr79gMSBKBP5AgjjpmrydMsMLotEg9fAJF36vdUncb+4ndRNxoPdlSQ=="],
"dot-prop": ["dot-prop@6.0.1", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA=="],
"dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
"dotenv-expand": ["dotenv-expand@11.0.7", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA=="],
@ -1105,7 +1113,7 @@
"electron-publish": ["electron-publish@26.15.3", "", { "dependencies": { "@types/fs-extra": "^9.0.11", "aws4": "^1.13.2", "builder-util": "26.15.3", "builder-util-runtime": "9.7.0", "chalk": "^4.1.2", "form-data": "^4.0.5", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" } }, "sha512-g/2bn8YTavY4cuS5F+jOS7zmZbXXBV8KZ8yHKfJjFPoKtzBqrpCdNPxBd3tqdBwP7BVd0lGzf7Bk2s0KesWZ4Q=="],
"electron-to-chromium": ["electron-to-chromium@1.5.372", "", {}, "sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA=="],
"electron-to-chromium": ["electron-to-chromium@1.5.375", "", {}, "sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q=="],
"electron-winstaller": ["electron-winstaller@5.4.0", "", { "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", "fs-extra": "^7.0.1", "lodash": "^4.17.21", "temp": "^0.9.0" }, "optionalDependencies": { "@electron/windows-sign": "^1.1.2" } }, "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg=="],
@ -1191,7 +1199,7 @@
"extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="],
"fallow": ["fallow@2.96.0", "", { "dependencies": { "detect-libc": "2.1.2" }, "optionalDependencies": { "@fallow-cli/darwin-arm64": "2.96.0", "@fallow-cli/darwin-x64": "2.96.0", "@fallow-cli/linux-arm64-gnu": "2.96.0", "@fallow-cli/linux-arm64-musl": "2.96.0", "@fallow-cli/linux-x64-gnu": "2.96.0", "@fallow-cli/linux-x64-musl": "2.96.0", "@fallow-cli/win32-arm64-msvc": "2.96.0", "@fallow-cli/win32-x64-msvc": "2.96.0" }, "bin": { "fallow": "bin/fallow", "fallow-lsp": "bin/fallow-lsp", "fallow-mcp": "bin/fallow-mcp" } }, "sha512-fNEj+b/LUVXwfyxZPnr+SJjdQHCKjUbWgluW/wC7Q5kcJENHNEJtmFDgpHEqKY6gY257xRCgyg1AlSC8YQgROA=="],
"fallow": ["fallow@2.99.0", "", { "dependencies": { "detect-libc": "2.1.2" }, "optionalDependencies": { "@fallow-cli/darwin-arm64": "2.99.0", "@fallow-cli/darwin-x64": "2.99.0", "@fallow-cli/linux-arm64-gnu": "2.99.0", "@fallow-cli/linux-arm64-musl": "2.99.0", "@fallow-cli/linux-x64-gnu": "2.99.0", "@fallow-cli/linux-x64-musl": "2.99.0", "@fallow-cli/win32-arm64-msvc": "2.99.0", "@fallow-cli/win32-x64-msvc": "2.99.0" }, "bin": { "fallow": "bin/fallow", "fallow-lsp": "bin/fallow-lsp", "fallow-mcp": "bin/fallow-mcp" } }, "sha512-p+JRuyx8chpTI/zJ3rF1F0b0baMpG1WYdJcJZn1fYPRSyio/uheF1o24TWz/eDZNIFrQQDsy9n5nznnW6Lmcqw=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
@ -1303,7 +1311,7 @@
"hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="],
"hono": ["hono@4.12.25", "", {}, "sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ=="],
"hono": ["hono@4.12.26", "", {}, "sha512-uyZtpnYxM9CmQ7QsQknM4zN8EftNqhON1qYeIKM0Se67CCEe2c44xyGURwB0axX2fBDu1dqHrHAc1hmNT8ITkw=="],
"hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="],
@ -1343,7 +1351,7 @@
"is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
"is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
"is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
@ -1373,7 +1381,7 @@
"is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
"is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="],
"is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
"isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
@ -1463,7 +1471,7 @@
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"lucide-react": ["lucide-react@1.18.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-LZDb7H/0YfM+RJncD0hDQRCAu+vSGODqpe35TuVI8EuXaRjkczbsx7p8dY4J87F/MUSj6bpYqeI8nw8qXaAdmA=="],
"lucide-react": ["lucide-react@1.21.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-reEZMXq8Qdd5jg5XYkQ5TR1fB/GiQ7ih4vcrthYDtgjSDwh0i6/YLiGjsWsIwgN49gpAnd4J2elSNzncMEEUUQ=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
@ -1487,7 +1495,7 @@
"mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
"mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
"mimic-fn": ["mimic-fn@3.1.0", "", {}, "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ=="],
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
@ -1509,7 +1517,7 @@
"mute-stream": ["mute-stream@3.0.0", "", {}, "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw=="],
"nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="],
"nanoid": ["nanoid@3.3.13", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-sPdqC6ByMVVGvF1ynvvMo0/o+oD1VX7DaHhijt1bFgjvBkHBib4t49GoNDhf2NDta4oeUNlaGbSt5K7qjZ955Q=="],
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
@ -1529,7 +1537,7 @@
"node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="],
"node-releases": ["node-releases@2.0.47", "", {}, "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og=="],
"node-releases": ["node-releases@2.0.48", "", {}, "sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA=="],
"nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="],
@ -1597,6 +1605,8 @@
"pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],
"pkg-up": ["pkg-up@3.1.0", "", { "dependencies": { "find-up": "^3.0.0" } }, "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA=="],
"pkijs": ["pkijs@3.4.0", "", { "dependencies": { "@noble/hashes": "1.4.0", "asn1js": "^3.0.6", "bytestreamjs": "^2.0.1", "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw=="],
"plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="],
@ -1733,7 +1743,7 @@
"sdp-transform": ["sdp-transform@2.15.0", "", { "bin": { "sdp-verify": "checker.js" } }, "sha512-KrOH82c/W+GYQ0LHqtr3caRpM3ITglq3ljGUIb8LTki7ByacJZ9z+piSGiwZDsRyhQbYBOBJgr2k6X4BZXi3Kw=="],
"semver": ["semver@7.8.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA=="],
"semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="],
@ -1809,6 +1819,8 @@
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"systeminformation": ["systeminformation@5.31.7", "", { "os": "!aix", "bin": { "systeminformation": "lib/cli.js" } }, "sha512-/8NC53e5nP9nmhn42/ncdOkyJnOoue/Vy+tJOyUGd1Yv66G069wK4rrziwhrqDETgk78CudTQupw5z19S5uoZw=="],
"tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="],
"tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="],
@ -1873,7 +1885,7 @@
"typescript-eslint": ["typescript-eslint@8.61.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.61.1", "@typescript-eslint/parser": "8.61.1", "@typescript-eslint/typescript-estree": "8.61.1", "@typescript-eslint/utils": "8.61.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-V7PayAfJokV3pEHgN7/v03D1SpujhRfQtYLbLIiBfDDncdg4PAiRBfoS4cnCANK4jmAPncczi59QO3afiXUlNw=="],
"undici": ["undici@6.27.0", "", {}, "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg=="],
"undici": ["undici@7.28.0", "", {}, "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA=="],
"undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
@ -1965,12 +1977,16 @@
"@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@base-ui/utils/reselect": ["reselect@5.2.0", "", {}, "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw=="],
"@dotenvx/dotenvx/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="],
"@dotenvx/dotenvx/dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="],
"@dotenvx/dotenvx/execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
"@dotenvx/dotenvx/open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="],
"@dotenvx/dotenvx/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
"@electron/asar/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="],
@ -2007,11 +2023,13 @@
"@reduxjs/toolkit/immer": ["immer@11.1.8", "", {}, "sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA=="],
"@reduxjs/toolkit/reselect": ["reselect@5.2.0", "", {}, "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.2" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q=="],
@ -2033,8 +2051,6 @@
"app-builder-lib/ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="],
"app-builder-lib/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"app-builder-lib/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="],
"body-parser/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
@ -2043,8 +2059,16 @@
"clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="],
"conf/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
"conf/ajv-formats": ["ajv-formats@2.1.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="],
"conf/json-schema-typed": ["json-schema-typed@7.0.3", "", {}, "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A=="],
"dir-compare/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
"dot-prop/is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="],
"eciesjs/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="],
"eciesjs/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
@ -2069,6 +2093,8 @@
"hosted-git-info/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
"is-inside-container/is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
"log-symbols/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
"log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],
@ -2077,14 +2103,20 @@
"micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
"node-gyp/undici": ["undici@6.27.0", "", {}, "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg=="],
"node-gyp/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="],
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
"onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
"ora/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
"ora/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"pkg-up/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="],
"pkijs/@noble/hashes": ["@noble/hashes@1.4.0", "", {}, "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg=="],
"postject/commander": ["commander@9.5.0", "", {}, "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="],
@ -2115,6 +2147,8 @@
"wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"wsl-utils/is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="],
"@dotenvx/dotenvx/execa/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
"@dotenvx/dotenvx/execa/human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
@ -2127,6 +2161,8 @@
"@dotenvx/dotenvx/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
"@dotenvx/dotenvx/open/define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="],
"@dotenvx/dotenvx/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="],
"@electron/asar/minimatch/brace-expansion": ["brace-expansion@1.1.15", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg=="],
@ -2139,8 +2175,6 @@
"@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
"ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"app-builder-lib/@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="],
@ -2153,6 +2187,8 @@
"cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"conf/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"dir-compare/minimatch/brace-expansion": ["brace-expansion@1.1.15", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg=="],
"electron-winstaller/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
@ -2175,6 +2211,8 @@
"ora/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"pkg-up/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="],
"qrcode/yargs/cliui": ["cliui@6.0.0", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="],
"qrcode/yargs/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="],
@ -2201,12 +2239,18 @@
"glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"pkg-up/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="],
"pkg-up/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="],
"qrcode/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"qrcode/yargs/cliui/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
"qrcode/yargs/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="],
"pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
"qrcode/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"qrcode/yargs/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],

48
flake.lock generated
View file

@ -2,22 +2,58 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1779508470,
"narHash": "sha256-Ap9KJX+5xHIn3bPIpfNgT6MEXdAECECwo4/rmlQD74M=",
"lastModified": 1782467914,
"narHash": "sha256-pGvFkM8N0xEkIIXDe5YYfbEAvHrk4IxBrjB/x8OomhE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "29916453413845e54a65b8a1cf996842300cd299",
"rev": "e73de5be04e0eff4190a1432b946d469c794e7b4",
"type": "github"
},
"original": {
"id": "nixpkgs",
"owner": "NixOS",
"ref": "nixos-unstable",
"type": "indirect"
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1744536153,
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1782616745,
"narHash": "sha256-NN5B1cKBXF6h1Ec681gMGZ2o/99d7vKXAAfFNEvyOKA=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "b916d014dc57eb555f84e51172a82f7f6fb560d7",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
}
},

241
flake.nix
View file

@ -1,23 +1,39 @@
{
description = "Tensamin desktop client";
description = "Tensamin Client";
inputs.nixpkgs.url = "nixpkgs/nixos-unstable";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rust-overlay.url = "github:oxalica/rust-overlay";
};
outputs = {nixpkgs, ...}: let
outputs = {
self,
nixpkgs,
rust-overlay,
...
}: let
systems = ["x86_64-linux"];
forAllSystems = nixpkgs.lib.genAttrs systems;
version = "0.0.9";
x86_64DebHash = "sha256-8rVb12SGGSac6l1NVPGyRLsAKAGDAOJVUwG8l+hoRCU=";
version = "0.0.10";
x86_64DebHash = "sha256-VVKkZ9yQ7BoLnYnCf5OSHcrakoBNfUx/uWxBmm3gBZE=";
forgejoBaseUrl = "https://git.methanium.net/tensamin/client/releases/download/${version}";
in {
packages = forAllSystems (system: let
pkgs = import nixpkgs {inherit system;};
pkgs = import nixpkgs {
inherit system;
overlays = [(import rust-overlay)];
config = {
allowUnfree = true;
android_sdk.accept_license = true;
};
};
debArtifact = "Tensamin-${version}-linux-amd64.deb";
electronRuntimeLibs = with pkgs; [
alsa-lib
at-spi2-atk
at-spi2-core
atk
cairo
cups
dbus
@ -29,6 +45,7 @@
gtk3
libdrm
libgbm
libglvnd
libnotify
libpulseaudio
libuuid
@ -37,6 +54,7 @@
nspr
nss
pango
pipewire
systemd
wayland
libX11
@ -92,8 +110,219 @@
url = "${forgejoBaseUrl}/${debArtifact}";
hash = x86_64DebHash;
});
localDebPath = builtins.getEnv "TENSAMIN_DEB";
localPathPackage =
if localDebPath == ""
then
pkgs.writeShellScriptBin "tensamin" ''
echo "Set TENSAMIN_DEB to a local .deb path and run with --impure." >&2
exit 1
''
else
packageDeb (builtins.path {
path = localDebPath;
name = debArtifact;
});
in {
default = defaultPackage;
tensamin = defaultPackage;
electron = defaultPackage;
localPathForDev = localPathPackage;
});
devShells = forAllSystems (system: let
pkgs = import nixpkgs {
inherit system;
overlays = [(import rust-overlay)];
config = {
allowUnfree = true;
android_sdk.accept_license = true;
};
};
electronRuntimeLibs = with pkgs; [
alsa-lib
at-spi2-atk
at-spi2-core
atk
cairo
cups
dbus
expat
fontconfig
freetype
gdk-pixbuf
glib
gtk3
libdrm
libgbm
libglvnd
libnotify
libpulseaudio
libuuid
libxkbcommon
mesa
nspr
nss
pango
pipewire
systemd
wayland
libX11
libXScrnSaver
libXcomposite
libXcursor
libXdamage
libXext
libXfixes
libXi
libXrandr
libXtst
libxcb
];
buildToolsVersion = "35.0.0";
ndkVersion = "29.0.14206865";
android = pkgs.androidenv.composeAndroidPackages {
cmdLineToolsVersion = "8.0";
toolsVersion = "26.1.1";
platformToolsVersion = "35.0.2";
buildToolsVersions = [buildToolsVersion];
platformVersions = ["35" "36"];
includeSources = false;
includeSystemImages = false;
includeNDK = true;
ndkVersions = [ndkVersion];
useGoogleAPIs = false;
};
rustToolchain = pkgs.rust-bin.stable.latest.default.override {
extensions = ["rust-src" "rust-analyzer"];
targets = [
"aarch64-linux-android"
"armv7-linux-androideabi"
"i686-linux-android"
"x86_64-linux-android"
"wasm32-unknown-unknown"
];
};
in rec {
default = electron;
electron = pkgs.mkShell {
packages = with pkgs;
[
nodejs_22
corepack_22
coreutils
bun
pkgs.electron
pkg-config
python3
gcc
gnumake
git
jq
patchelf
dpkg
rpm
fpm
sudo
curl
fakeroot
rsync
xz
]
++ electronRuntimeLibs;
shellHook = ''
export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath electronRuntimeLibs}:$LD_LIBRARY_PATH"
export ELECTRON_ENABLE_LOGGING=1
export ELECTRON_OZONE_PLATFORM_HINT="''${ELECTRON_OZONE_PLATFORM_HINT:-auto}"
export NPM_CONFIG_TARGET_ARCH="''${NPM_CONFIG_TARGET_ARCH:-x64}"
export npm_config_build_from_source=true
export USE_SYSTEM_FPM=true
alias electron-install='cd "$(git rev-parse --show-toplevel 2>/dev/null || pwd)" && bun install'
alias electron-build-web='cd "$(git rev-parse --show-toplevel 2>/dev/null || pwd)" && bun run build:web'
alias electron-dev='bun run dev'
alias electron-package='bun run package:linux'
alias electron-validate='bun run validate'
'';
};
tauri = pkgs.mkShell {
buildInputs = with pkgs;
[
jdk17
rustToolchain
gradle
bun
nodejs
coreutils
pkg-config
git
jq
curl
]
++ [
android.androidsdk
android-studio-tools
];
shellHook = ''
sdkSource="${android.androidsdk}/libexec/android-sdk"
if [ -d apps/tauri/src-tauri ]; then
projectRoot="$PWD/apps/tauri"
else
projectRoot="$PWD"
fi
androidHome="$projectRoot/.android"
sdkRoot="$androidHome/sdk"
mkdir -p "$androidHome"
if [ -L "$sdkRoot" ]; then
rm -f "$sdkRoot"
fi
mkdir -p "$sdkRoot"
ln -sfn "$sdkSource/build-tools" "$sdkRoot/build-tools"
ln -sfn "$sdkSource/cmake" "$sdkRoot/cmake"
ln -sfn "$sdkSource/licenses" "$sdkRoot/licenses"
ln -sfn "$sdkSource/ndk" "$sdkRoot/ndk"
ln -sfn "$sdkSource/ndk-bundle" "$sdkRoot/ndk-bundle"
ln -sfn "$sdkSource/platforms" "$sdkRoot/platforms"
ln -sfn "$sdkSource/platform-tools" "$sdkRoot/platform-tools"
ln -sfn "$sdkSource/tools" "$sdkRoot/tools"
mkdir -p "$sdkRoot/cmdline-tools"
ln -sfn "$sdkSource/cmdline-tools/8.0" "$sdkRoot/cmdline-tools/8.0"
ln -sfn "8.0" "$sdkRoot/cmdline-tools/latest"
sdkRootAbs="$(realpath "$sdkRoot")"
ndkRootAbs="''${sdkRootAbs}/ndk/${ndkVersion}"
export PATH="''${sdkRootAbs}/cmdline-tools/latest/bin:''${sdkRootAbs}/platform-tools:''${ndkRootAbs}:${pkgs.android-studio-tools}/bin:$PATH"
export ANDROID_HOME="''${sdkRootAbs}"
export ANDROID_SDK_ROOT="''${sdkRootAbs}"
export ANDROID_NDK_ROOT="''${ndkRootAbs}"
export ANDROID_NDK_HOME="$ANDROID_NDK_ROOT"
export NDK_HOME="$ANDROID_NDK_ROOT"
export NDK_PATH="$ANDROID_NDK_ROOT"
export JAVA_HOME="${pkgs.jdk17}"
aapt2Path="''${sdkRootAbs}/build-tools/${buildToolsVersion}/aapt2"
if [ -x "$aapt2Path" ]; then
mkdir -p "$HOME/.gradle"
gradleProperties="$HOME/.gradle/gradle.properties"
touch "$gradleProperties"
if grep -q '^android\.aapt2FromMavenOverride=' "$gradleProperties"; then
sed -i "s|^android\.aapt2FromMavenOverride=.*|android.aapt2FromMavenOverride=$aapt2Path|" "$gradleProperties"
else
printf '\nandroid.aapt2FromMavenOverride=%s\n' "$aapt2Path" >> "$gradleProperties"
fi
fi
'';
};
});
};
}

View file

@ -26,7 +26,7 @@
"dev:desktop": "cd apps/electron && bun run dev",
"build:desktop": "cd apps/electron && bun run package",
"run:desktop": "TENSAMIN_DEB=\"$PWD/apps/electron/release/Tensamin-$(node -p \\\"require('./package.json').version\\\")-linux-amd64.deb\" nix run .#localPathForDev --impure",
"delete:mobile": "cd apps/tauri && nix develop --command adb uninstall net.tensamin.client"
"delete:mobile": "cd apps/tauri && nix develop ../..#tauri --command adb uninstall net.tensamin.client"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
@ -44,7 +44,7 @@
"typescript-eslint": "^8.59.1"
},
"overrides": {
"@tensamin/ui": "https://git.methanium.net/tensamin/ui/archive/0.0.37.tar.gz",
"@tensamin/ui": "https://git.methanium.net/tensamin/ui/archive/0.0.39.tar.gz",
"@tensamin/ttp-core": "https://git.methanium.net/tensamin/ttp/archive/0.0.24.tar.gz"
},
"dependencies": {

View file

@ -7,3 +7,4 @@
- Implement context menu features
- Add quality selection
- Good preview page
- Settings page

View file

@ -69,6 +69,8 @@ export default function InputComponent({
return;
}
log(3, "chat", "purple", "Message send init, adding live message ...");
const reference = addLiveMessage({
height: 0,
not_encrypted: true,
@ -78,7 +80,19 @@ export default function InputComponent({
message_state: "awaiting",
});
const encryptedContext = await encryptText(sharedSecret, currentValue);
log(3, "chat", "purple", "Live message added, encrypting...");
const encryptedContext = await encryptText(
sharedSecret,
currentValue,
).catch((err) => {
toast("error", "Failed to encrypt message", String(err));
reference.setFailed(true);
});
if (!encryptedContext) return;
log(3, "chat", "purple", "Content encrypted, sending message...");
send("message_send", {
height: 0,
@ -96,6 +110,8 @@ export default function InputComponent({
toast("error", "Failed to send message");
});
log(3, "chat", "purple", "Message sent");
moveUserIdToTop(userId);
if (!preserveContent) {

View file

@ -39,17 +39,13 @@ export default function MediaSaveButton({
}
return (
<div
className={cn(
"absolute right-1 top-1 z-10 h-9 w-9 -translate-y-2 rounded-sm bg-black opacity-0 transition-all group-hover:translate-y-0 group-hover:opacity-100",
className,
)}
>
<Button
aria-label={ariaLabel ?? (isSaved ? "Unsave media" : "Save media")}
className="h-full w-full rounded-sm border-0! p-0"
className={cn(
"rounded-sm border-0! p-0 absolute right-1 top-1 z-10 h-9 w-9 -translate-y-2 opacity-0 transition-all group-hover:translate-y-0 group-hover:opacity-100 bg-card",
className,
)}
onClick={handleClick}
variant="secondary"
>
<Save
className={cn(
@ -58,6 +54,5 @@ export default function MediaSaveButton({
)}
/>
</Button>
</div>
);
}

View file

@ -1,21 +1,34 @@
import * as React from "react";
import type { RawMessage } from "../values";
import Text from "@tensamin/markdown/text";
import { AlertTriangle } from "lucide-react";
import { useEffect, useState } from "react";
import {
AlertTriangle,
Check,
Ellipse,
Forward,
Laugh,
RefreshCw,
Reply,
} from "lucide-react";
import { useCallback, useEffect, useState } from "react";
import type { User } from "@tensamin/user/context";
import {
Avatar,
AvatarFallback,
AvatarImage,
Button,
Card,
cn,
Separator,
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@tensamin/ui";
import MessageContextMenu from "./messageContextMenu";
import Media from "./media";
import { useStorage } from "@tensamin/storage/context";
import { useTTP } from "@tensamin/ttp";
function MessageComponent({
grouped,
@ -29,14 +42,14 @@ function MessageComponent({
user: User | null;
}) {
const actuallyFailed = message.failed && message.message_state === "awaiting";
// Fade-in
const [hasFadedIn, setHasFadedIn] = useState(false);
const opacityClass = !hasFadedIn
? "opacity-0"
: actuallyFailed || message.message_state === "awaiting"
? "opacity-50"
: "opacity-100";
const [isValidURL, setIsValidURL] = useState(false);
useEffect(() => {
const timeout = window.setTimeout(() => {
setHasFadedIn(true);
@ -47,6 +60,8 @@ function MessageComponent({
};
}, []);
// Check if message is a url
const [isValidURL, setIsValidURL] = useState(false);
useEffect(() => {
try {
if (message.content.split(" ").length > 1) throw new Error();
@ -58,6 +73,58 @@ function MessageComponent({
}
}, [message.content]);
// Message states
const { load } = useStorage();
const { send } = useTTP();
const messageStateReadUpdate = useCallback(async () => {
const readConfirmations = await load("settings.read_confirmations");
if (readConfirmations) {
if (!user?.user_id) return;
await send("message_state", {
chat_partner_id: user?.user_id,
send_time: message.send_time,
message_state: "read",
});
} else {
await send("message_state", {
chat_partner_id: user?.user_id,
send_time: message.send_time,
message_state: "received",
});
}
}, [load, message.send_time, user?.user_id, send]);
useEffect(() => {
let cancelled = false;
async function run() {
const receiveConfirmations = await load("settings.receive_confirmations");
if (cancelled) return;
switch (message.message_state) {
case "sent":
if (receiveConfirmations) {
messageStateReadUpdate();
}
break;
case "received":
messageStateReadUpdate();
break;
default:
break;
}
}
run();
return () => {
cancelled = true;
};
}, [message.message_state, load, messageStateReadUpdate]);
return (
<div
// pt-3 is to get a gap between messages
@ -69,7 +136,7 @@ function MessageComponent({
>
<div
className={cn(
"group hover:bg-muted/50 select-text! justify-start flex gap-1 items-center w-full px-2 whitespace-pre-wrap break-all",
"group hover:bg-muted/50 select-text! relative justify-start flex gap-1 items-center w-full px-2 whitespace-pre-wrap break-all",
{
"bg-(--destructive)/15 text-destructive-foreground":
actuallyFailed,
@ -101,7 +168,26 @@ function MessageComponent({
<TooltipTrigger render={<AlertTriangle size={17} />} />
</Tooltip>
)}
<div className="flex flex-col">
<div className="flex flex-col group">
<Card className="absolute right-4 -top-3 opacity-0 group-hover:opacity-100 flex flex-row justify-end gap-0! z-10 p-0! shadow-lg rounded-lg!">
{[0, 1, 2].map((item) => (
<Button key={item} variant="ghost" className="h-8 w-8">
{item === 0 && "👍"}
{item === 1 && "🔥"}
{item === 2 && "✅"}
</Button>
))}
<Separator orientation="vertical" className="my-1" />
<Button variant="ghost" className="h-8 w-8">
<Laugh />
</Button>
<Button variant="ghost" className="h-8 w-8">
<Reply />
</Button>
<Button variant="ghost" className="h-8 w-8">
<Forward />
</Button>
</Card>
{!grouped && (
<div className="flex items-center gap-1">
<p className="font-medium">{user.display}</p>
@ -111,6 +197,20 @@ function MessageComponent({
minute: "2-digit",
})}
</p>
<div>
{message.message_state === "read" ? (
<Check
size={12}
color="var(--primary-foreground-alt)"
/>
) : message.message_state === "received" ? (
<Check size={12} color="var(--muted-foreground)" />
) : message.message_state === "sent" ? (
<RefreshCw size={12} color="var(--muted-foreground)" />
) : message.message_state === "sending" ? (
<Ellipse size={12} color="var(--muted-foreground)" />
) : null}
</div>
</div>
)}
{isValidURL ? (

View file

@ -132,11 +132,7 @@ export default function Screen() {
fetchNextPageRef.current = () => {
void fetchMessagesNextPage();
};
}, [
fetchMessagesNextPage,
hasMessagesNextPage,
isFetchingMessagesNextPage,
]);
}, [fetchMessagesNextPage, hasMessagesNextPage, isFetchingMessagesNextPage]);
React.useEffect(() => {
clearLiveMessages();

View file

@ -1,2 +1,3 @@
- Implement context menu features
- Add default-emoji-hotkey in settings
- Add default-emoji-hotkey
- Placeholder image if media fails to load

View file

@ -52,20 +52,20 @@ export default function Provider(props: { children: React.ReactNode }) {
);
// Update message state
if (
(await load("settings.read_confirmations")) &&
userId === sender_id
) {
void send(
"message_state",
{
message_state: "read",
},
{
id: ttpMessage.id,
},
);
} else {
if (userId === sender_id) {
addLiveMessage({
...message,
content: decryptedContent,
sent_by_self: false,
});
return;
}
// todo: add notification symbol to conversation cards (incl. message start)
moveUserIdToTop(sender_id);
if (await load("settings.receive_confirmations")) {
void send(
"message_state",
{
@ -77,20 +77,6 @@ export default function Provider(props: { children: React.ReactNode }) {
);
}
if (userId === sender_id) {
addLiveMessage({
...message,
content: decryptedContent,
sent_by_self: false,
});
return;
}
// todo: add notification symbol to conversation cards (incl. message start)
moveUserIdToTop(sender_id);
if (isTauri()) {
console.log("weewoo");
} else {

View file

@ -23,8 +23,8 @@ export const message = z.object({
avatar: z.boolean().optional(),
display: z.boolean().optional(),
message_state: z
.enum(["read", "received", "sent", "sending", "awaiting"])
.default("received"), // awaiting for 'internal' use
.enum(["read", "received", "sent", "sending", "awaiting"]) // awaiting for 'internal' use
.default("received"),
});
export const failedUser = {
@ -285,6 +285,8 @@ export interface Storage extends SettingsStorageDefaults {
theme_primary_color: string;
theme_polarity: "dark" | "light" | "system";
theme_tint: "soft" | "hard" | "extreme";
theme_border_radius: number;
theme_custom_css: string;
chat_trusted_domains: string[];
chat_picker_saved_media: string[];
chat_picker_last_tab: "gif" | "meme" | "saved";
@ -333,6 +335,8 @@ export const storageDefaults: Storage = {
theme_primary_color: "",
theme_polarity: "system",
theme_tint: "soft",
theme_border_radius: 0.55,
theme_custom_css: "",
chat_trusted_domains: [
// Other platforms
"cdn.discordapp.com",

View file

@ -67,26 +67,31 @@ const size = 20;
export function toast(
type: "error" | "info" | "warn" | "success",
message: string,
description?: string,
) {
switch (type) {
case "error":
sonnerToast(message, {
icon: <Ban size={size} />,
description,
});
break;
case "info":
sonnerToast(message, {
icon: <Info size={size} />,
description,
});
break;
case "warn":
sonnerToast(message, {
icon: <TriangleAlert size={size} />,
description,
});
break;
case "success":
sonnerToast(message, {
icon: <Check size={size} />,
description,
});
break;
}

View file

@ -378,6 +378,10 @@ export function Provider(props: {
url: ttpUrl,
serverCert: ttpServerCert || undefined,
onReadyStateChange: (state) => {
if (state === READY_STATE.CONNECTING) {
log(2, "ttp", "blue", ttpUrl);
}
setReadyState(state);
if (state === READY_STATE.OPEN) {

3
packages/ttp/todo.md Normal file
View file

@ -0,0 +1,3 @@
- Replace with MTP
- Remove queue
- Use Date.now() for message id

View file

@ -1,3 +1,3 @@
# Information
All dev releases between two prod version get deleted upon creation of the latest prod release.
All dev releases get deleted upon creation of the latest prod release.

0
temp Normal file
View file