Merge pull request '(feat): various workflow improvements, mobile sidebar improvements' (#2) from dev into main
Reviewed-on: #2
This commit is contained in:
commit
8b1b34db6a
3 changed files with 386 additions and 38 deletions
|
|
@ -4,20 +4,31 @@ on:
|
|||
- dev
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
build-web:
|
||||
runs-on: docker
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: https://data.forgejo.org/actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
- 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: Build
|
||||
- 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
|
||||
|
|
@ -25,3 +36,204 @@ 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
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ on:
|
|||
- main
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
build-web:
|
||||
runs-on: docker
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: https://data.forgejo.org/actions/checkout@v4
|
||||
|
|
@ -23,16 +22,14 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- 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: Copy licenses
|
||||
run: bun run copy-licenses
|
||||
|
||||
- name: Build
|
||||
run: bun run build:apps
|
||||
- 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
|
||||
|
|
@ -40,12 +37,117 @@ jobs:
|
|||
- 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)"
|
||||
|
||||
- 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
|
||||
|
||||
- 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
|
||||
id: version
|
||||
run: |
|
||||
VERSION="$(node -p "require('./package.json').version")"
|
||||
echo "version=$VERSION" >> "$FORGEJO_OUTPUT"
|
||||
echo "tag=v$VERSION" >> "$FORGEJO_OUTPUT"
|
||||
echo "tag=${VERSION}-prod" >> "$FORGEJO_OUTPUT"
|
||||
|
||||
- name: Create release and upload files
|
||||
env:
|
||||
|
|
@ -54,39 +156,40 @@ 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."
|
||||
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)"
|
||||
exit 0
|
||||
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" \
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
Sidebar as SidebarRoot,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
useSidebar,
|
||||
} from "@tensamin/ui";
|
||||
import { isTauri } from "@tauri-apps/api/core";
|
||||
import { useIsMobile } from "@tensamin/ui";
|
||||
|
|
@ -13,17 +14,21 @@ 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();
|
||||
|
||||
return (
|
||||
<SidebarRoot className="border-0!">
|
||||
const content = (
|
||||
<>
|
||||
<SidebarContent
|
||||
className={
|
||||
isTauri() && isMobile ? "pt-[env(safe-area-inset-top)]" : "pt-2"
|
||||
|
|
@ -52,6 +57,34 @@ export default function Sidebar() {
|
|||
<SidebarBox />
|
||||
</SidebarFooter>
|
||||
)}
|
||||
</SidebarRoot>
|
||||
</>
|
||||
);
|
||||
|
||||
if (isMobile) {
|
||||
return (
|
||||
<>
|
||||
{openMobile && (
|
||||
<div
|
||||
className="fixed inset-0 z-40 bg-black/10"
|
||||
onClick={() => setOpenMobile(false)}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
data-sidebar="sidebar"
|
||||
data-slot="sidebar"
|
||||
data-mobile="true"
|
||||
className="fixed inset-y-0 left-0 z-50 w-screen bg-sidebar p-0 text-sidebar-foreground transition-[transform,opacity] duration-150 ease-linear"
|
||||
style={{
|
||||
transform: openMobile ? "translateX(0)" : "translateX(-100%)",
|
||||
opacity: openMobile ? 1 : 0,
|
||||
pointerEvents: openMobile ? "auto" : "none",
|
||||
}}
|
||||
>
|
||||
<div className="flex h-full w-full flex-col">{content}</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return <SidebarRoot className="border-0!">{content}</SidebarRoot>;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue