diff --git a/.forgejo/workflows/deploy-dev.yml b/.forgejo/workflows/deploy-dev.yml
index ab7edf1..26053ff 100644
--- a/.forgejo/workflows/deploy-dev.yml
+++ b/.forgejo/workflows/deploy-dev.yml
@@ -4,31 +4,20 @@ on:
- dev
jobs:
- build-web:
+ deploy:
runs-on: docker
+
steps:
- 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 Nix
- uses: https://github.com/cachix/install-nix-action@v30
-
- - name: Install Bun
+ - name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile
- - name: Copy licenses
- run: bun run copy-licenses
-
- - name: Build packages
- run: bun run build:packages
-
- - name: Build web
+ - name: Build
run: bun run build:web
- name: Install rsync
@@ -36,204 +25,3 @@ jobs:
- name: Deploy
run: rsync -a --delete apps/web/dist/ /var/lib/www/tensamin-web-dev/
-
- build-mobile:
- runs-on: docker
- steps:
- - 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 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
-
- - name: Copy licenses
- run: bun run copy-licenses
-
- - name: Build packages
- run: 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)"
-
- - name: Build mobile
- run: bun run build:mobile
-
- - name: Upload mobile artifact
- uses: https://data.forgejo.org/actions/upload-artifact@v3
- with:
- name: mobile-apk
- path: apps/tauri/src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release.apk
-
- build-desktop:
- runs-on: docker
- steps:
- - 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 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
-
- - name: Copy licenses
- run: bun run copy-licenses
-
- - name: Build packages
- run: bun run build:packages
-
- - name: Build desktop
- run: bun run build:desktop
-
- - name: Upload desktop artifacts
- uses: https://data.forgejo.org/actions/upload-artifact@v3
- with:
- name: desktop-bundles
- path: apps/tauri/src-tauri/target/release/bundle/
-
- release:
- runs-on: docker
- needs: [build-web, build-mobile, build-desktop]
- steps:
- - 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
-
- - name: Download mobile artifact
- uses: https://data.forgejo.org/actions/download-artifact@v3
- with:
- name: mobile-apk
- path: apps/tauri/src-tauri/gen/android/app/build/outputs/apk/universal/release/
-
- - name: Download desktop artifacts
- uses: https://data.forgejo.org/actions/download-artifact@v3
- with:
- name: desktop-bundles
- path: apps/tauri/src-tauri/target/release/bundle/
-
- - name: Copy releases
- run: bun --bun run copy-releases
-
- - name: Read version and hash
- id: version
- run: |
- 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"
-
- - name: Create pre-release and upload files
- env:
- TOKEN: ${{ forgejo.token }}
- API: ${{ forgejo.api_url }}
- REPO: ${{ forgejo.repository }}
- SHA: ${{ forgejo.sha }}
- TAG: ${{ steps.version.outputs.tag }}
- TITLE: ${{ steps.version.outputs.title }}
- run: |
- set -eu
-
- test -d releases
- find releases -type f | grep -q .
-
- LATEST_PROD_TAG="$(git tag --list '*-prod' --sort=-v:refname | head -n 1 || true)"
-
- if [ -n "$LATEST_PROD_TAG" ]; then
- RAW_LOG="$(git log "$LATEST_PROD_TAG"..HEAD --pretty=format:'- %s')"
- else
- RAW_LOG="$(git log --pretty=format:'- %s')"
- fi
-
- export RAW_LOG LATEST_PROD_TAG API REPO TAG
- BODY="$(node -e '
- const raw = process.env.RAW_LOG;
- const lines = raw.split("\n");
- const commits = [];
- for (const line of lines) {
- const msg = line.replace(/^- /, "");
- const parts = msg.split(/(?=\([^)]+\):)/).filter(Boolean).map(s => s.trim()).filter(s => s);
- for (const part of parts) {
- commits.push(part);
- }
- }
- const priority = { "(feat):": 1, "(fix):": 2, "(qol):": 3 };
- commits.sort((a, b) => {
- const tagA = a.match(/^(\([^)]+\):)/)?.[1] || "";
- const tagB = b.match(/^(\([^)]+\):)/)?.[1] || "";
- return (priority[tagA] || 99) - (priority[tagB] || 99);
- });
- const log = commits.map(c => "- " + c).join("\n");
- const latestTag = process.env.LATEST_PROD_TAG;
- if (latestTag) {
- const serverUrl = process.env.API.replace(/\/api\/v1.*/, "");
- const compareUrl = serverUrl + "/" + process.env.REPO + "/compare/" + latestTag + "..." + process.env.TAG;
- console.log(log + "\n\n[View changes](" + compareUrl + ")");
- } else {
- console.log(log);
- }
- ')"
-
- HTTP_STATUS=$(curl -s -w "%{http_code}" -o release_out.json -H "Authorization: token $TOKEN" "$API/repos/$REPO/releases/tags/$TAG")
-
- if [ "$HTTP_STATUS" = "200" ]; then
- echo "Release $TAG already exists."
- RELEASE_ID="$(jq -r .id release_out.json)"
- else
- echo "Creating new pre-release for $TAG"
- RELEASE_JSON="$(curl -f -sS -X POST "$API/repos/$REPO/releases" \
- -H "Authorization: token $TOKEN" \
- -H "Content-Type: application/json" \
- -d "$(jq -n \
- --arg tag "$TAG" \
- --arg name "$TITLE" \
- --arg body "$BODY" \
- --arg target "$SHA" \
- '{
- tag_name: $tag,
- name: $name,
- body: $body,
- target_commitish: $target,
- draft: false,
- prerelease: true
- }')")"
- RELEASE_ID="$(echo "$RELEASE_JSON" | jq -r .id)"
- fi
-
- find releases -type f -print0 | while IFS= read -r -d '' file; do
- name="$(basename "$file")"
- curl -fsS -X POST "$API/repos/$REPO/releases/$RELEASE_ID/assets?name=$name" \
- -H "Authorization: token $TOKEN" \
- -F "attachment=@$file"
- done
diff --git a/.forgejo/workflows/deploy-prod.yml b/.forgejo/workflows/deploy-prod.yml
index 7cd9016..1df5b60 100644
--- a/.forgejo/workflows/deploy-prod.yml
+++ b/.forgejo/workflows/deploy-prod.yml
@@ -4,8 +4,9 @@ on:
- main
jobs:
- build-web:
+ deploy:
runs-on: docker
+
steps:
- name: Check out repo
uses: https://data.forgejo.org/actions/checkout@v4
@@ -22,132 +23,29 @@ jobs:
- name: Install dependencies
run: bun install --frozen-lockfile
- - name: Copy licenses
- run: bun run copy-licenses
-
- - name: Build packages
- run: bun run build:packages
-
- - name: Build web
- run: bun run build:web
-
- - name: Install rsync
- run: apt-get update && apt-get install -y rsync
-
- - name: Deploy
- run: rsync -a --delete apps/web/dist/ /var/lib/www/tensamin-web-prod/
-
- build-mobile:
- runs-on: docker
- steps:
- - 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 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
-
- - name: Copy licenses
- run: bun run copy-licenses
-
- - name: Build packages
- run: 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)"
+ 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)"
- - name: Build mobile
- run: bun run build:mobile
+ - name: Build
+ run: bun run build:apps
- - name: Upload mobile artifact
- uses: https://data.forgejo.org/actions/upload-artifact@v3
- with:
- name: mobile-apk
- path: apps/tauri/src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release.apk
+ - name: Install rsync
+ run: apt-get update && apt-get install -y rsync
- build-desktop:
- runs-on: docker
- steps:
- - 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 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
-
- - name: Copy licenses
- run: bun run copy-licenses
-
- - name: Build packages
- run: bun run build:packages
-
- - name: Build desktop
- run: bun run build:desktop
-
- - name: Upload desktop artifacts
- uses: https://data.forgejo.org/actions/upload-artifact@v3
- with:
- name: desktop-bundles
- path: apps/tauri/src-tauri/target/release/bundle/
-
- release:
- runs-on: docker
- needs: [build-web, build-mobile, build-desktop]
- steps:
- - 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
-
- - name: Download mobile artifact
- uses: https://data.forgejo.org/actions/download-artifact@v3
- with:
- name: mobile-apk
- path: apps/tauri/src-tauri/gen/android/app/build/outputs/apk/universal/release/
-
- - name: Download desktop artifacts
- uses: https://data.forgejo.org/actions/download-artifact@v3
- with:
- name: desktop-bundles
- path: apps/tauri/src-tauri/target/release/bundle/
-
- - name: Copy releases
- run: bun --bun run copy-releases
+ - name: Deploy
+ run: rsync -a --delete apps/web/dist/ /var/lib/www/tensamin-web-prod/
- name: Read version
id: version
run: |
VERSION="$(node -p "require('./package.json').version")"
echo "version=$VERSION" >> "$FORGEJO_OUTPUT"
- echo "tag=${VERSION}-prod" >> "$FORGEJO_OUTPUT"
+ echo "tag=v$VERSION" >> "$FORGEJO_OUTPUT"
- name: Create release and upload files
env:
@@ -156,40 +54,39 @@ jobs:
REPO: ${{ forgejo.repository }}
SHA: ${{ forgejo.sha }}
TAG: ${{ steps.version.outputs.tag }}
+ VERSION: ${{ steps.version.outputs.version }}
run: |
set -eu
test -d releases
find releases -type f | grep -q .
- COMMIT_MSG="$(git log -1 --pretty=%B | sed 's/$/ /')"
-
HTTP_STATUS=$(curl -s -w "%{http_code}" -o release_out.json -H "Authorization: token $TOKEN" "$API/repos/$REPO/releases/tags/$TAG")
if [ "$HTTP_STATUS" = "200" ]; then
echo "Release $TAG already exists."
- exit 0
+ RELEASE_ID="$(jq -r .id release_out.json)"
+ else
+ echo "Creating new release for $TAG"
+ RELEASE_JSON="$(curl -f -sS -X POST "$API/repos/$REPO/releases" \
+ -H "Authorization: token $TOKEN" \
+ -H "Content-Type: application/json" \
+ -d "$(jq -n \
+ --arg tag "$TAG" \
+ --arg name "$TAG" \
+ --arg body "Release $VERSION" \
+ --arg target "$SHA" \
+ '{
+ tag_name: $tag,
+ name: $name,
+ body: $body,
+ target_commitish: $target,
+ draft: false,
+ prerelease: false
+ }')")"
+ RELEASE_ID="$(echo "$RELEASE_JSON" | jq -r .id)"
fi
- echo "Creating new release for $TAG"
- RELEASE_JSON="$(curl -f -sS -X POST "$API/repos/$REPO/releases" \
- -H "Authorization: token $TOKEN" \
- -H "Content-Type: application/json" \
- -d "$(jq -n \
- --arg tag "$TAG" \
- --arg name "$TAG" \
- --arg body "$COMMIT_MSG" \
- --arg target "$SHA" \
- '{
- tag_name: $tag,
- name: $name,
- body: $body,
- target_commitish: $target,
- draft: false,
- prerelease: false
- }')")"
- RELEASE_ID="$(echo "$RELEASE_JSON" | jq -r .id)"
-
find releases -type f -print0 | while IFS= read -r -d '' file; do
name="$(basename "$file")"
curl -fsS -X POST "$API/repos/$REPO/releases/$RELEASE_ID/assets?name=$name" \
diff --git a/apps/web/src/components/sidebar.tsx b/apps/web/src/components/sidebar.tsx
index 6b4b6cd..ce9bb6b 100644
--- a/apps/web/src/components/sidebar.tsx
+++ b/apps/web/src/components/sidebar.tsx
@@ -6,7 +6,6 @@ import {
Sidebar as SidebarRoot,
SidebarContent,
SidebarFooter,
- useSidebar,
} from "@tensamin/ui";
import { isTauri } from "@tauri-apps/api/core";
import { useIsMobile } from "@tensamin/ui";
@@ -14,21 +13,17 @@ import { MobileNavbar } from "./navbar";
import SidebarBox from "@tensamin/call/sidebarBox";
import { useShowMobileNavbar } from "@/routes/app/layout";
+
/**
* Renders the conversation sidebar with account summary and conversation list.
- * On mobile the sidebar is always kept in the DOM and hidden via CSS
- * (opacity + translateX) instead of being unmounted. This keeps the DOM and
- * React state alive while the drawer is closed, allowing the sidebar to open
- * instantly on subsequent toggles.
* @returns Sidebar JSX.
*/
export default function Sidebar() {
const isMobile = useIsMobile();
const showMobileNavbar = useShowMobileNavbar();
- const { openMobile, setOpenMobile } = useSidebar();
- const content = (
- <>
+ return (
+