Add desktop app downloads page and release workflow

- Add GitHub Actions workflow for building desktop apps (Windows/macOS/Linux)
- Create /downloads page with GitHub releases integration
- Update README with download links
- Automated release creation on desktop-v* tags

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
MrPiglr 2026-01-29 23:32:02 -07:00
parent bad838c659
commit b8d5062f3e
5 changed files with 394 additions and 0 deletions

View file

@ -0,0 +1,7 @@
{
"permissions": {
"allow": [
"Bash(git add:*)"
]
}
}

143
.github/workflows/release-desktop.yml vendored Normal file
View file

@ -0,0 +1,143 @@
name: Release Desktop Apps
on:
push:
tags:
- 'desktop-v*' # Trigger on tags like desktop-v1.0.0
workflow_dispatch:
inputs:
version:
description: 'Version number (e.g., 1.0.0)'
required: true
jobs:
create-release:
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
version: ${{ steps.get_version.outputs.version }}
steps:
- name: Get version
id: get_version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
else
echo "version=${GITHUB_REF#refs/tags/desktop-v}" >> $GITHUB_OUTPUT
fi
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: desktop-v${{ steps.get_version.outputs.version }}
release_name: AeThex OS Desktop v${{ steps.get_version.outputs.version }}
draft: false
prerelease: false
body: |
# AeThex OS Desktop v${{ steps.get_version.outputs.version }}
## Downloads
- **Windows**: Download the `.msi` installer
- **macOS**: Download the `.dmg` file
- **Linux**: Download the `.AppImage`, `.deb`, or `.rpm` file
## What's New
- Desktop application release
- Cross-platform support (Windows, macOS, Linux)
- Native performance with Tauri
## Installation
- **Windows**: Run the MSI installer
- **macOS**: Open the DMG and drag to Applications
- **Linux**: Make AppImage executable with `chmod +x` and run, or install DEB/RPM
build-desktop:
needs: create-release
strategy:
fail-fast: false
matrix:
include:
- platform: 'macos-latest'
args: '--target universal-apple-darwin'
- platform: 'ubuntu-22.04'
args: ''
- platform: 'windows-latest'
args: ''
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Install dependencies (Ubuntu only)
if: matrix.platform == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev \
libappindicator3-dev librsvg2-dev patchelf
- name: Install frontend dependencies
run: npm install
- name: Install Tauri dependencies
working-directory: shell/aethex-shell
run: npm install
- name: Build Tauri app
working-directory: shell/aethex-shell
run: npm run tauri build -- ${{ matrix.args }}
- name: Upload Windows MSI
if: matrix.platform == 'windows-latest'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./shell/aethex-shell/src-tauri/target/release/bundle/msi/aethex-os_${{ needs.create-release.outputs.version }}_x64_en-US.msi
asset_name: AeThex-OS-${{ needs.create-release.outputs.version }}-Windows-x64.msi
asset_content_type: application/x-msi
- name: Upload macOS DMG
if: matrix.platform == 'macos-latest'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./shell/aethex-shell/src-tauri/target/universal-apple-darwin/release/bundle/dmg/AeThex OS_${{ needs.create-release.outputs.version }}_universal.dmg
asset_name: AeThex-OS-${{ needs.create-release.outputs.version }}-macOS-universal.dmg
asset_content_type: application/x-apple-diskimage
- name: Upload Linux AppImage
if: matrix.platform == 'ubuntu-22.04'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./shell/aethex-shell/src-tauri/target/release/bundle/appimage/aethex-os_${{ needs.create-release.outputs.version }}_amd64.AppImage
asset_name: AeThex-OS-${{ needs.create-release.outputs.version }}-Linux-x86_64.AppImage
asset_content_type: application/x-executable
- name: Upload Linux DEB
if: matrix.platform == 'ubuntu-22.04'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./shell/aethex-shell/src-tauri/target/release/bundle/deb/aethex-os_${{ needs.create-release.outputs.version }}_amd64.deb
asset_name: AeThex-OS-${{ needs.create-release.outputs.version }}-Linux-amd64.deb
asset_content_type: application/vnd.debian.binary-package

View file

@ -16,6 +16,15 @@
- 📱 **Mobile Application** - Capacitor-based app (Android/iOS)
- 🐧 **Linux Distribution** - Bootable OS replacing traditional operating systems
## 📥 Downloads
### Desktop Application
- **[Download for Windows, macOS, or Linux](https://github.com/AeThex-Corporation/AeThex-OS/releases/latest)** - Latest desktop releases
- **[All Releases](https://github.com/AeThex-Corporation/AeThex-OS/releases)** - View all versions
### Web Application
- **[Use Online](https://aethex.app)** - No installation required
## 🚀 Quick Start
Choose your deployment mode:

View file

@ -18,6 +18,7 @@ import Login from "@/pages/login";
import Admin from "@/pages/admin";
import Pitch from "@/pages/pitch";
import Builds from "@/pages/builds";
import Downloads from "@/pages/downloads";
import AdminArchitects from "@/pages/admin-architects";
import AdminProjects from "@/pages/admin-projects";
import AdminCredentials from "@/pages/admin-credentials";
@ -90,6 +91,7 @@ function Router() {
<Route path="/admin/notifications">{() => <ProtectedRoute><AdminNotifications /></ProtectedRoute>}</Route>
<Route path="/pitch" component={Pitch} />
<Route path="/builds" component={Builds} />
<Route path="/downloads" component={Downloads} />
<Route path="/os" component={AeThexOS} />
<Route path="/os/link">{() => <ProtectedRoute><OsLink /></ProtectedRoute>}</Route>
<Route path="/network" component={Network} />

View file

@ -0,0 +1,233 @@
import { Download, Monitor, Apple, Code, Package } from "lucide-react";
import { useEffect, useState } from "react";
interface Release {
tag_name: string;
name: string;
published_at: string;
assets: Array<{
name: string;
browser_download_url: string;
size: number;
}>;
}
export default function Downloads() {
const [latestRelease, setLatestRelease] = useState<Release | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://api.github.com/repos/AeThex-Corporation/AeThex-OS/releases')
.then(res => res.json())
.then(releases => {
// Find the latest desktop release (tagged with desktop-v*)
const desktopRelease = releases.find((r: Release) =>
r.tag_name.startsWith('desktop-v')
);
setLatestRelease(desktopRelease || null);
setLoading(false);
})
.catch(err => {
console.error('Failed to fetch releases:', err);
setLoading(false);
});
}, []);
const getAssetByPlatform = (platform: string) => {
if (!latestRelease) return null;
return latestRelease.assets.find(asset =>
asset.name.toLowerCase().includes(platform.toLowerCase())
);
};
const formatBytes = (bytes: number) => {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
};
return (
<div className="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 text-white p-8">
<div className="max-w-6xl mx-auto">
{/* Header */}
<div className="text-center mb-12">
<h1 className="text-5xl font-bold bg-gradient-to-r from-cyan-400 to-emerald-400 bg-clip-text text-transparent mb-4">
Download AeThex OS
</h1>
<p className="text-slate-400 text-lg">
Get the desktop application for Windows, macOS, or Linux
</p>
{latestRelease && (
<div className="mt-4 text-sm text-slate-500">
Latest Version: {latestRelease.tag_name.replace('desktop-v', '')}
Released {new Date(latestRelease.published_at).toLocaleDateString()}
</div>
)}
</div>
{loading ? (
<div className="text-center py-12">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-cyan-400 mx-auto"></div>
<p className="mt-4 text-slate-400">Loading releases...</p>
</div>
) : !latestRelease ? (
<div className="bg-slate-800/50 rounded-lg p-8 text-center border border-slate-700">
<Package className="w-16 h-16 text-slate-600 mx-auto mb-4" />
<h2 className="text-2xl font-bold mb-2">No Desktop Releases Yet</h2>
<p className="text-slate-400 mb-6">
Desktop releases are coming soon. In the meantime, you can:
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<a
href="https://aethex.app"
className="px-6 py-3 bg-gradient-to-r from-cyan-600 to-emerald-600 rounded-lg font-semibold hover:from-cyan-500 hover:to-emerald-500 transition-all"
>
Use Web Version
</a>
<a
href="https://github.com/AeThex-Corporation/AeThex-OS"
className="px-6 py-3 bg-slate-700 rounded-lg font-semibold hover:bg-slate-600 transition-all flex items-center gap-2"
>
<Code className="w-5 h-5" />
Build from Source
</a>
</div>
</div>
) : (
<div className="grid md:grid-cols-3 gap-6">
{/* Windows */}
<DownloadCard
icon={<Monitor className="w-12 h-12" />}
platform="Windows"
description="MSI Installer for Windows 10/11"
asset={getAssetByPlatform('windows')}
formatBytes={formatBytes}
color="from-blue-600 to-blue-400"
/>
{/* macOS */}
<DownloadCard
icon={<Apple className="w-12 h-12" />}
platform="macOS"
description="Universal DMG for Intel & Apple Silicon"
asset={getAssetByPlatform('macos')}
formatBytes={formatBytes}
color="from-slate-600 to-slate-400"
/>
{/* Linux */}
<DownloadCard
icon={<Code className="w-12 h-12" />}
platform="Linux"
description="AppImage & DEB packages"
asset={getAssetByPlatform('linux')}
formatBytes={formatBytes}
color="from-orange-600 to-orange-400"
/>
</div>
)}
{/* Additional Info */}
<div className="mt-12 grid md:grid-cols-2 gap-6">
<div className="bg-slate-800/30 rounded-lg p-6 border border-slate-700">
<h3 className="text-xl font-bold mb-4 flex items-center gap-2">
<Package className="w-6 h-6 text-cyan-400" />
Installation Instructions
</h3>
<div className="space-y-3 text-slate-300 text-sm">
<div>
<strong className="text-white">Windows:</strong> Run the MSI installer and follow the prompts
</div>
<div>
<strong className="text-white">macOS:</strong> Open the DMG file and drag AeThex OS to Applications
</div>
<div>
<strong className="text-white">Linux (AppImage):</strong> Make executable with <code className="bg-slate-900 px-2 py-1 rounded">chmod +x</code> and run
</div>
<div>
<strong className="text-white">Linux (DEB):</strong> Install with <code className="bg-slate-900 px-2 py-1 rounded">sudo dpkg -i filename.deb</code>
</div>
</div>
</div>
<div className="bg-slate-800/30 rounded-lg p-6 border border-slate-700">
<h3 className="text-xl font-bold mb-4 flex items-center gap-2">
<Download className="w-6 h-6 text-emerald-400" />
Other Options
</h3>
<div className="space-y-3">
<a
href="https://aethex.app"
className="block p-3 bg-slate-700/50 rounded hover:bg-slate-700 transition-all"
>
<div className="font-semibold text-cyan-400">Web Application</div>
<div className="text-sm text-slate-400">Use AeThex OS directly in your browser</div>
</a>
<a
href="https://github.com/AeThex-Corporation/AeThex-OS/releases"
className="block p-3 bg-slate-700/50 rounded hover:bg-slate-700 transition-all"
>
<div className="font-semibold text-emerald-400">All Releases</div>
<div className="text-sm text-slate-400">View all versions and changelogs</div>
</a>
<a
href="https://github.com/AeThex-Corporation/AeThex-OS"
className="block p-3 bg-slate-700/50 rounded hover:bg-slate-700 transition-all"
>
<div className="font-semibold text-orange-400">Build from Source</div>
<div className="text-sm text-slate-400">Clone the repository and build locally</div>
</a>
</div>
</div>
</div>
</div>
</div>
);
}
function DownloadCard({
icon,
platform,
description,
asset,
formatBytes,
color
}: {
icon: React.ReactNode;
platform: string;
description: string;
asset: any;
formatBytes: (bytes: number) => string;
color: string;
}) {
return (
<div className="bg-slate-800/50 rounded-lg p-6 border border-slate-700 hover:border-slate-600 transition-all">
<div className={`w-16 h-16 rounded-lg bg-gradient-to-br ${color} flex items-center justify-center mb-4`}>
{icon}
</div>
<h3 className="text-2xl font-bold mb-2">{platform}</h3>
<p className="text-slate-400 text-sm mb-4">{description}</p>
{asset ? (
<>
<div className="text-xs text-slate-500 mb-3">
{formatBytes(asset.size)}
</div>
<a
href={asset.browser_download_url}
className="block w-full px-4 py-3 bg-gradient-to-r from-cyan-600 to-emerald-600 rounded-lg font-semibold text-center hover:from-cyan-500 hover:to-emerald-500 transition-all flex items-center justify-center gap-2"
>
<Download className="w-5 h-5" />
Download
</a>
</>
) : (
<div className="text-sm text-slate-500 text-center py-3">
Not available yet
</div>
)}
</div>
);
}