aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.vscode/extensions.json2
-rw-r--r--README.CN.md52
-rw-r--r--README.md60
-rw-r--r--packages/ui/CHANGELOG.md16
-rw-r--r--packages/ui/package.json2
-rw-r--r--packages/ui/src/components/bottom-bar.tsx19
-rw-r--r--packages/ui/src/components/sidebar.tsx27
-rw-r--r--packages/ui/src/components/ui/radio-group.tsx36
-rw-r--r--packages/ui/src/main.tsx2
-rw-r--r--packages/ui/src/models/instance.ts10
-rw-r--r--packages/ui/src/models/java.ts25
-rw-r--r--packages/ui/src/pages/instances-view.tsx214
-rw-r--r--packages/ui/src/pages/settings.tsx90
-rw-r--r--packages/ui/vite.config.ts2
-rw-r--r--src-tauri/CHANGELOG.md22
-rw-r--r--src-tauri/Cargo.toml2
-rw-r--r--src-tauri/icons/128x128.pngbin6188 -> 3488 bytes
-rw-r--r--src-tauri/icons/128x128@2x.pngbin15146 -> 7652 bytes
-rw-r--r--src-tauri/icons/32x32.pngbin1338 -> 1016 bytes
-rw-r--r--src-tauri/icons/64x64.pngbin2953 -> 1707 bytes
-rw-r--r--src-tauri/icons/Square107x107Logo.pngbin7025 -> 3559 bytes
-rw-r--r--src-tauri/icons/Square142x142Logo.pngbin9641 -> 4398 bytes
-rw-r--r--src-tauri/icons/Square150x150Logo.pngbin10549 -> 4866 bytes
-rw-r--r--src-tauri/icons/Square284x284Logo.pngbin21937 -> 9097 bytes
-rw-r--r--src-tauri/icons/Square30x30Logo.pngbin1375 -> 730 bytes
-rw-r--r--src-tauri/icons/Square310x310Logo.pngbin24443 -> 10267 bytes
-rw-r--r--src-tauri/icons/Square44x44Logo.pngbin2202 -> 1304 bytes
-rw-r--r--src-tauri/icons/Square71x71Logo.pngbin4059 -> 2397 bytes
-rw-r--r--src-tauri/icons/Square89x89Logo.pngbin5279 -> 2930 bytes
-rw-r--r--src-tauri/icons/StoreLogo.pngbin2679 -> 1528 bytes
-rw-r--r--src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml5
-rw-r--r--src-tauri/icons/android/mipmap-hdpi/ic_launcher.pngbin0 -> 2769 bytes
-rw-r--r--src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.pngbin0 -> 5185 bytes
-rw-r--r--src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.pngbin0 -> 2943 bytes
-rw-r--r--src-tauri/icons/android/mipmap-mdpi/ic_launcher.pngbin0 -> 1891 bytes
-rw-r--r--src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.pngbin0 -> 2901 bytes
-rw-r--r--src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.pngbin0 -> 2236 bytes
-rw-r--r--src-tauri/icons/android/mipmap-xhdpi/ic_launcher.pngbin0 -> 4038 bytes
-rw-r--r--src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.pngbin0 -> 7106 bytes
-rw-r--r--src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 5031 bytes
-rw-r--r--src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.pngbin0 -> 8346 bytes
-rw-r--r--src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.pngbin0 -> 10894 bytes
-rw-r--r--src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 9870 bytes
-rw-r--r--src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 9868 bytes
-rw-r--r--src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.pngbin0 -> 15489 bytes
-rw-r--r--src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 12716 bytes
-rw-r--r--src-tauri/icons/android/values/ic_launcher_background.xml4
-rw-r--r--src-tauri/icons/icon.icnsbin208048 -> 96515 bytes
-rw-r--r--src-tauri/icons/icon.icobin27104 -> 17164 bytes
-rw-r--r--src-tauri/icons/icon.pngbin22699 -> 16666 bytes
-rw-r--r--src-tauri/icons/icon.svg50
-rw-r--r--src-tauri/icons/ios/AppIcon-20x20@1x.pngbin0 -> 437 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-20x20@2x-1.pngbin0 -> 1105 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-20x20@2x.pngbin0 -> 1105 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-20x20@3x.pngbin0 -> 1539 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-29x29@1x.pngbin0 -> 786 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-29x29@2x-1.pngbin0 -> 1794 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-29x29@2x.pngbin0 -> 1794 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-29x29@3x.pngbin0 -> 2810 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-40x40@1x.pngbin0 -> 1105 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-40x40@2x-1.pngbin0 -> 2259 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-40x40@2x.pngbin0 -> 2259 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-40x40@3x.pngbin0 -> 3431 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-512@2x.pngbin0 -> 36729 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-60x60@2x.pngbin0 -> 3431 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-60x60@3x.pngbin0 -> 5328 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-76x76@1x.pngbin0 -> 2321 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-76x76@2x.pngbin0 -> 4530 bytes
-rw-r--r--src-tauri/icons/ios/AppIcon-83.5x83.5@2x.pngbin0 -> 5384 bytes
-rw-r--r--src-tauri/tauri.conf.json2
70 files changed, 394 insertions, 248 deletions
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index bdef820..c2d945b 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,3 +1,3 @@
{
- "recommendations": ["svelte.svelte-vscode"]
+ "recommendations": [""]
}
diff --git a/README.CN.md b/README.CN.md
index 5017b66..c6f64a0 100644
--- a/README.CN.md
+++ b/README.CN.md
@@ -14,7 +14,7 @@
DropOut 是一个现代的、可复现的、开发者级别的 Minecraft 启动器。
它不仅仅是为了启动 Minecraft 而设计的,而是将 Minecraft 环境作为确定性的、版本化的工作空间进行管理。
-DropOut 使用 Tauri v2 构建,DropOut 提供原生性能和最小资源使用,并配有现代响应式 Web UI(目前使用 Svelte 5,正在迁移到 React)。
+DropOut 使用 Tauri v2 构建,DropOut 提供原生性能和最小资源使用,并配有现代响应式 Web UI(基于 React 19、shadcn/ui 和 Tailwind CSS 4 构建)。
> Minecraft 环境是一个复杂的系统。
> DropOut 将它们视为软件项目。
@@ -29,20 +29,20 @@ DropOut 使用 Tauri v2 构建,DropOut 提供原生性能和最小资源使用
DropOut 专注于保持你的游戏稳定、可调试和可重现。
- 整合包昨天还能游玩,今天却坏了?
-→ DropOut 让它可追溯。
+ → DropOut 让它可追溯。
- 分享模组包意味着压缩数 GB 的文件?
-→ DropOut 分享精确的依赖清单。
+ → DropOut 分享精确的依赖清单。
- Java、加载器、模组、配置不同步?
-→ DropOut 将它们锁定在一起。
+ → DropOut 将它们锁定在一起。
这个启动器是为重视控制、透明度和长期稳定性的玩家构建的。
## 功能特性
- **高性能**:使用 Rust 和 Tauri 构建,实现最小资源使用和快速启动时间。
-- **现代工业 UI**:使用 **Svelte 5** 和 **Tailwind CSS 4** 设计的干净、无干扰界面。
+- **现代工业 UI**:使用 **React 19**、**shadcn/ui** 和 **Tailwind CSS 4** 设计的干净、无干扰界面。
- **Microsoft 认证**:通过官方 Xbox Live 和 Microsoft OAuth 流程(设备代码流程)提供安全登录支持。
- **模组加载器支持**:
- **Fabric**:内置安装程序和版本管理。
@@ -58,14 +58,14 @@ DropOut 专注于保持你的游戏稳定、可调试和可重现。
## 路线图
-- [X] **账户持久化** — 在会话之间保存登录状态
-- [X] **令牌刷新** — 自动刷新过期的 Microsoft 令牌
-- [X] **JVM 参数解析** — 完全支持 `arguments.jvm` 和 `arguments.game` 解析
-- [X] **Java 自动检测和下载** — 扫描系统并下载 Java 运行时
-- [X] **Fabric 加载器支持** — 使用 Fabric 安装和启动
-- [X] **Forge 加载器支持** — 使用 Forge 安装和启动
-- [X] **GitHub 发布集成** — 在应用内查看变更日志
-- [ ] **实例/配置文件系统** — 多个隔离的游戏目录,具有不同的版本/模组
+- [x] **账户持久化** — 在会话之间保存登录状态
+- [x] **令牌刷新** — 自动刷新过期的 Microsoft 令牌
+- [x] **JVM 参数解析** — 完全支持 `arguments.jvm` 和 `arguments.game` 解析
+- [x] **Java 自动检测和下载** — 扫描系统并下载 Java 运行时
+- [x] **Fabric 加载器支持** — 使用 Fabric 安装和启动
+- [x] **Forge 加载器支持** — 使用 Forge 安装和启动
+- [x] **GitHub 发布集成** — 在应用内查看变更日志
+- [ ] **[WIP]实例/配置文件系统** — 多个隔离的游戏目录,具有不同的版本/模组
- [ ] **多账户支持** — 在多个账户之间无缝切换
- [ ] **自定义游戏目录** — 允许用户选择游戏文件位置
- [ ] **启动器自动更新** — 通过 Tauri 更新插件的自更新机制
@@ -76,21 +76,21 @@ DropOut 专注于保持你的游戏稳定、可调试和可重现。
从 [Releases](https://github.com/HsiangNianian/DropOut/releases) 页面下载适用于您平台的最新版本。
-| 平台 | 文件 |
-| -------------- | ----------------------- |
-| Linux x86_64 | `.deb`, `.AppImage` |
-| Linux ARM64 | `.deb`, `.AppImage` |
-| macOS ARM64 | `.dmg` |
-| Windows x86_64 | `.msi`, `.exe` |
-| Windows ARM64 | `.msi`, `.exe` |
+| 平台 | 文件 |
+| -------------- | ------------------- |
+| Linux x86_64 | `.deb`, `.AppImage` |
+| Linux ARM64 | `.deb`, `.AppImage` |
+| macOS ARM64 | `.dmg` |
+| Windows x86_64 | `.msi`, `.exe` |
+| Windows ARM64 | `.msi`, `.exe` |
## 从源码构建
### 先决条件
1. **Rust**:从 [rustup.rs](https://rustup.rs/) 安装。
-2. **Node.js** 和 **pnpm**:用于前端依赖。
-3. **系统依赖**:按照您的操作系统遵循 [Tauri 先决条件](https://v2.tauri.app/start/prerequisites/)。
+1. **Node.js** 和 **pnpm**:用于前端依赖。
+1. **系统依赖**:按照您的操作系统遵循 [Tauri 先决条件](https://v2.tauri.app/start/prerequisites/)。
### 步骤
@@ -101,22 +101,20 @@ DropOut 专注于保持你的游戏稳定、可调试和可重现。
cd DropOut
```
-2. **安装前端依赖**
+2. **安装依赖**
```bash
- cd ui
pnpm install
- cd ..
```
-3. **运行开发模式**
+1. **运行开发模式**
```bash
# 这将启动前端服务器和 Tauri 应用窗口
cargo tauri dev
```
-4. **构建发布版本**
+1. **构建发布版本**
```bash
cargo tauri build
diff --git a/README.md b/README.md
index 6d0eac0..bd37c53 100644
--- a/README.md
+++ b/README.md
@@ -11,10 +11,12 @@ English | [中文](README.CN.md)
[![Semifold CI](https://github.com/HydroRoll-Team/DropOut/actions/workflows/semifold-ci.yaml/badge.svg)](https://github.com/HydroRoll-Team/DropOut/actions/workflows/release.yml)
[![Test & Build](https://github.com/HydroRoll-Team/DropOut/actions/workflows/test.yml/badge.svg)](https://github.com/HydroRoll-Team/DropOut/actions/workflows/test.yml)
+<img align="right" src="https://repology.org/badge/vertical-allrepos/dropout.svg?columns=2" alt="DropOut package status on Repology" />
+
DropOut is a modern, reproducible, and developer-grade Minecraft launcher.
It is designed not just to launch Minecraft, but to manage Minecraft environments as deterministic, versioned workspaces.
-Built with Tauri v2 and Rust, DropOut delivers native performance and minimal resource usage, paired with a modern reactive web UI (currently Svelte 5, migrating to React).
+Built with Tauri v2, DropOut delivers native performance and minimal resource usage, paired with a modern reactive web UI built with React 19, shadcn/ui, and Tailwind CSS 4.
> Minecraft environments are complex systems.
> DropOut treats them like software projects.
@@ -28,21 +30,21 @@ Built with Tauri v2 and Rust, DropOut delivers native performance and minimal re
Most Minecraft launchers focus on getting you into the game.
DropOut focuses on keeping your game stable, debuggable, and reproducible.
-- Your instance worked yesterday but broke today?
-→ DropOut makes it traceable.
+- Your instance worked yesterday but broke today?\
+ → DropOut makes it traceable.
-- Sharing a modpack means zipping gigabytes?
-→ DropOut shares exact dependency manifests.
+- Sharing a modpack means zipping gigabytes?\
+ → DropOut shares exact dependency manifests.
-- Java, loader, mods, configs drift out of sync?
-→ DropOut locks them together.
+- Java, loader, mods, configs drift out of sync?\
+ → DropOut locks them together.
This launcher is built for players who value control, transparency, and long-term stability.
## Features
- **High Performance**: Built with Rust and Tauri for minimal resource usage and fast startup times.
-- **Modern Industrial UI**: A clean, distraction-free interface designed with **Svelte 5** and **Tailwind CSS 4**.
+- **Modern Industrial UI**: A clean, distraction-free interface designed with **React 19**, **shadcn/ui**, and **Tailwind CSS 4**.
- **Microsoft Authentication**: Secure login support via official Xbox Live & Microsoft OAuth flows (Device Code Flow).
- **Mod Loader Support**:
- **Fabric**: Built-in installer and version management.
@@ -60,14 +62,14 @@ This launcher is built for players who value control, transparency, and long-ter
Check our full roadmap at: <https://roadmap.sh/r/minecraft-launcher-dev>
-- [X] **Account Persistence** — Save login state between sessions
-- [X] **Token Refresh** — Auto-refresh expired Microsoft tokens
-- [X] **JVM Arguments Parsing** — Full support for `arguments.jvm` and `arguments.game` parsing
-- [X] **Java Auto-detection & Download** — Scan system and download Java runtimes
-- [X] **Fabric Loader Support** — Install and launch with Fabric
-- [X] **Forge Loader Support** — Install and launch with Forge
-- [X] **GitHub Releases Integration** — View changelogs in-app
-- [ ] **Instance/Profile System** — Multiple isolated game directories with different versions/mods
+- [x] **Account Persistence** — Save login state between sessions
+- [x] **Token Refresh** — Auto-refresh expired Microsoft tokens
+- [x] **JVM Arguments Parsing** — Full support for `arguments.jvm` and `arguments.game` parsing
+- [x] **Java Auto-detection & Download** — Scan system and download Java runtimes
+- [x] **Fabric Loader Support** — Install and launch with Fabric
+- [x] **Forge Loader Support** — Install and launch with Forge
+- [x] **GitHub Releases Integration** — View changelogs in-app
+- [ ] **[WIP]Instance/Profile System** — Multiple isolated game directories with different versions/mods
- [ ] **Multi-account Support** — Switch between multiple accounts seamlessly
- [ ] **Custom Game Directory** — Allow users to choose game files location
- [ ] **Launcher Auto-updater** — Self-update mechanism via Tauri updater plugin
@@ -78,21 +80,21 @@ Check our full roadmap at: <https://roadmap.sh/r/minecraft-launcher-dev>
Download the latest release for your platform from the [Releases](https://github.com/HsiangNianian/DropOut/releases) page.
-| Platform | Files |
-| -------------- | ----------------------- |
-| Linux x86_64 | `.deb`, `.AppImage` |
-| Linux ARM64 | `.deb`, `.AppImage` |
-| macOS ARM64 | `.dmg` |
-| Windows x86_64 | `.msi`, `.exe` |
-| Windows ARM64 | `.msi`, `.exe` |
+| Platform | Files |
+| -------------- | ------------------- |
+| Linux x86_64 | `.deb`, `.AppImage` |
+| Linux ARM64 | `.deb`, `.AppImage` |
+| macOS ARM64 | `.dmg` |
+| Windows x86_64 | `.msi`, `.exe` |
+| Windows ARM64 | `.msi`, `.exe` |
## Building from Source
### Prerequisites
1. **Rust**: Install from [rustup.rs](https://rustup.rs/).
-2. **Node.js** & **pnpm**: Used for the frontend dependencies.
-3. **System Dependencies**: Follow the [Tauri Prerequisites](https://v2.tauri.app/start/prerequisites/) for your OS.
+1. **Node.js** & **pnpm**: Used for the frontend dependencies.
+1. **System Dependencies**: Follow the [Tauri Prerequisites](https://v2.tauri.app/start/prerequisites/) for your OS.
### Steps
@@ -103,22 +105,20 @@ Download the latest release for your platform from the [Releases](https://github
cd DropOut
```
-2. **Install Frontend Dependencies**
+2. **Install Dependencies**
```bash
- cd ui
pnpm install
- cd ..
```
-3. **Run in Development Mode**
+1. **Run in Development Mode**
```bash
# This will start the frontend server and the Tauri app window
cargo tauri dev
```
-4. **Build Release Version**
+1. **Build Release Version**
```bash
cargo tauri build
diff --git a/packages/ui/CHANGELOG.md b/packages/ui/CHANGELOG.md
index bc780fb..d9e5b4d 100644
--- a/packages/ui/CHANGELOG.md
+++ b/packages/ui/CHANGELOG.md
@@ -1,5 +1,21 @@
# Changelog
+## v0.1.0-alpha.3
+
+### Refactors
+
+- [`24a229e`](https://github.com/HydroRoll-Team/DropOut/commit/24a229ede321e8296ea99b332ccfa61213791d10): Partial rewrite layout of instances page.
+
+### Bug Fixes
+
+- [`9e40b5b`](https://github.com/HydroRoll-Team/DropOut/commit/9e40b5b7bea60e6802a4b448ef315b14fba4de7f): Auto select game version if version is unique.
+
+### New Features
+
+- [`0ac743f`](https://github.com/HydroRoll-Team/DropOut/commit/0ac743f6d126d047352e6b247ea1ee513361d240): Improve sidebar avatar on large and small screens.
+- [`9e40b5b`](https://github.com/HydroRoll-Team/DropOut/commit/9e40b5b7bea60e6802a4b448ef315b14fba4de7f): Support detect and select java path.
+- [`47aeabf`](https://github.com/HydroRoll-Team/DropOut/commit/47aeabf5d44d7483101d30d289cb4c56761e3faa): Improve position and colors of the UI toast.
+
## v0.1.0-alpha.2
### Chores
diff --git a/packages/ui/package.json b/packages/ui/package.json
index b85f887..42705f8 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -1,7 +1,7 @@
{
"name": "@dropout/ui",
"private": true,
- "version": "0.1.0-alpha.2",
+ "version": "0.1.0-alpha.3",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/packages/ui/src/components/bottom-bar.tsx b/packages/ui/src/components/bottom-bar.tsx
index 5489675..0710c3a 100644
--- a/packages/ui/src/components/bottom-bar.tsx
+++ b/packages/ui/src/components/bottom-bar.tsx
@@ -6,7 +6,6 @@ import { listInstalledVersions, startGame } from "@/client";
import { cn } from "@/lib/utils";
import { useAuthStore } from "@/models/auth";
import { useInstanceStore } from "@/models/instance";
-import { useGameStore } from "@/stores/game-store";
import { LoginModal } from "./login-modal";
import { Button } from "./ui/button";
import {
@@ -26,7 +25,6 @@ interface InstalledVersion {
export function BottomBar() {
const authStore = useAuthStore();
- const gameStore = useGameStore();
const instancesStore = useInstanceStore();
const [isLaunched, setIsLaunched] = useState<boolean>(false);
@@ -51,24 +49,18 @@ export function BottomBar() {
const versions = await listInstalledVersions(
instancesStore.activeInstance.id,
);
-
- const installed = versions || [];
- setInstalledVersions(installed);
+ setInstalledVersions(versions);
// If no version is selected but we have installed versions, select the first one
- if (!gameStore.selectedVersion && installed.length > 0) {
- gameStore.setSelectedVersion(installed[0].id);
+ if (!selectedVersion && versions.length > 0) {
+ setSelectedVersion(versions[0].id);
}
} catch (error) {
console.error("Failed to load installed versions:", error);
} finally {
setIsLoadingVersions(false);
}
- }, [
- instancesStore.activeInstance,
- gameStore.selectedVersion,
- gameStore.setSelectedVersion,
- ]);
+ }, [instancesStore.activeInstance, selectedVersion]);
useEffect(() => {
loadInstalledVersions();
@@ -225,6 +217,7 @@ export function BottomBar() {
</div>
<Select
+ value={selectedVersion}
items={versionOptions}
onValueChange={setSelectedVersion}
disabled={isLoadingVersions}
@@ -238,7 +231,7 @@ export function BottomBar() {
}
/>
</SelectTrigger>
- <SelectContent>
+ <SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{versionOptions.map((item) => (
<SelectItem
diff --git a/packages/ui/src/components/sidebar.tsx b/packages/ui/src/components/sidebar.tsx
index 0147b0a..d81156f 100644
--- a/packages/ui/src/components/sidebar.tsx
+++ b/packages/ui/src/components/sidebar.tsx
@@ -49,12 +49,33 @@ function NavItem({ Icon, label, to }: NavItemProps) {
export function Sidebar() {
const authStore = useAuthStore();
+ const renderUserAvatar = () => {
+ return (
+ <div className="w-full flex flex-col items-center hover:bg-accent/90 transition-colors cursor-pointer">
+ <div className="lg:hidden">
+ <UserAvatar />
+ </div>
+ <div className="w-full hidden lg:flex bg-accent/90 p-3 flex-row space-x-3">
+ <UserAvatar />
+ <div className="">
+ <p className="text-sm font-medium text-white">
+ {authStore.account?.username}
+ </p>
+ <p className="text-xs text-zinc-400">
+ {authStore.account?.type === "microsoft" ? "Online" : "Offline"}
+ </p>
+ </div>
+ </div>
+ </div>
+ );
+ };
+
return (
<aside
className={cn(
"flex flex-col items-center lg:items-start",
"bg-sidebar transition-all duration-300",
- "w-20 lg:w-64 shrink-0 py-6 h-full",
+ "w-20 lg:w-64 shrink-0 pt-6 pb-6 lg:pb-3 h-full",
)}
>
{/* Logo Area */}
@@ -162,9 +183,9 @@ export function Sidebar() {
<NavItem Icon={Settings} label="Settings" to="/settings" />
</nav>
- <div className="flex-1 flex flex-col justify-end">
+ <div className="w-full lg:px-3 flex-1 flex flex-col justify-end">
<DropdownMenu>
- <DropdownMenuTrigger render={<UserAvatar />}>
+ <DropdownMenuTrigger render={renderUserAvatar()} className="w-full">
Open
</DropdownMenuTrigger>
<DropdownMenuContent align="end" side="right" sideOffset={20}>
diff --git a/packages/ui/src/components/ui/radio-group.tsx b/packages/ui/src/components/ui/radio-group.tsx
new file mode 100644
index 0000000..d8b39dd
--- /dev/null
+++ b/packages/ui/src/components/ui/radio-group.tsx
@@ -0,0 +1,36 @@
+import { Radio as RadioPrimitive } from "@base-ui/react/radio"
+import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group"
+
+import { cn } from "@/lib/utils"
+
+function RadioGroup({ className, ...props }: RadioGroupPrimitive.Props) {
+ return (
+ <RadioGroupPrimitive
+ data-slot="radio-group"
+ className={cn("grid w-full gap-2", className)}
+ {...props}
+ />
+ )
+}
+
+function RadioGroupItem({ className, ...props }: RadioPrimitive.Root.Props) {
+ return (
+ <RadioPrimitive.Root
+ data-slot="radio-group-item"
+ className={cn(
+ "border-input dark:bg-input/30 data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary data-checked:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 dark:aria-invalid:border-destructive/50 group/radio-group-item peer relative flex aspect-square size-4 shrink-0 rounded-full border outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3",
+ className
+ )}
+ {...props}
+ >
+ <RadioPrimitive.Indicator
+ data-slot="radio-group-indicator"
+ className="flex size-4 items-center justify-center"
+ >
+ <span className="bg-primary-foreground absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full" />
+ </RadioPrimitive.Indicator>
+ </RadioPrimitive.Root>
+ )
+}
+
+export { RadioGroup, RadioGroupItem }
diff --git a/packages/ui/src/main.tsx b/packages/ui/src/main.tsx
index a3157bd..c5cbfc8 100644
--- a/packages/ui/src/main.tsx
+++ b/packages/ui/src/main.tsx
@@ -33,6 +33,6 @@ const root = createRoot(document.getElementById("root") as HTMLElement);
root.render(
<StrictMode>
<RouterProvider router={router} />
- <Toaster />
+ <Toaster position="top-right" richColors />
</StrictMode>,
);
diff --git a/packages/ui/src/models/instance.ts b/packages/ui/src/models/instance.ts
index a3fda3d..b1b463e 100644
--- a/packages/ui/src/models/instance.ts
+++ b/packages/ui/src/models/instance.ts
@@ -96,14 +96,8 @@ export const useInstanceStore = create<InstanceState>((set, get) => ({
},
setActiveInstance: async (instance) => {
- try {
- await setActiveInstance(instance.id);
- set({ activeInstance: instance });
- toast.success("Active instance changed");
- } catch (e) {
- console.error("Failed to set active instance:", e);
- toast.error("Error setting active instance");
- }
+ await setActiveInstance(instance.id);
+ set({ activeInstance: instance });
},
duplicate: async (id, newName) => {
diff --git a/packages/ui/src/models/java.ts b/packages/ui/src/models/java.ts
new file mode 100644
index 0000000..3e5d2d0
--- /dev/null
+++ b/packages/ui/src/models/java.ts
@@ -0,0 +1,25 @@
+import { create } from "zustand/react";
+import { detectJava, refreshJavaCatalog } from "@/client";
+import type { JavaCatalog, JavaInstallation } from "@/types";
+
+export interface JavaState {
+ catalog: JavaCatalog | null;
+ installations: JavaInstallation[] | null;
+
+ refresh: () => Promise<void>;
+ refreshInstallations: () => Promise<void>;
+}
+
+export const useJavaStore = create<JavaState>((set) => ({
+ catalog: null,
+ installations: null,
+
+ refresh: async () => {
+ const catalog = await refreshJavaCatalog();
+ set({ catalog });
+ },
+ refreshInstallations: async () => {
+ const installations = await detectJava();
+ set({ installations });
+ },
+}));
diff --git a/packages/ui/src/pages/instances-view.tsx b/packages/ui/src/pages/instances-view.tsx
index 1634905..e99004c 100644
--- a/packages/ui/src/pages/instances-view.tsx
+++ b/packages/ui/src/pages/instances-view.tsx
@@ -1,5 +1,7 @@
-import { Copy, Edit2, Plus, Trash2 } from "lucide-react";
+import { CopyIcon, EditIcon, Plus, RocketIcon, Trash2Icon } from "lucide-react";
import { useEffect, useState } from "react";
+import { toast } from "sonner";
+import { startGame } from "@/client";
import InstanceCreationModal from "@/components/instance-creation-modal";
import InstanceEditorModal from "@/components/instance-editor-modal";
import { Button } from "@/components/ui/button";
@@ -12,9 +14,9 @@ import {
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
-import { toNumber } from "@/lib/tsrs-utils";
+import { cn } from "@/lib/utils";
import { useInstanceStore } from "@/models/instance";
-import type { Instance } from "../types/bindings/instance";
+import type { Instance } from "@/types";
export function InstancesView() {
const instancesStore = useInstanceStore();
@@ -76,21 +78,6 @@ export function InstancesView() {
setShowDuplicateModal(false);
};
- const formatDate = (timestamp: number): string =>
- new Date(timestamp * 1000).toLocaleDateString();
-
- const formatLastPlayed = (timestamp: number): string => {
- const date = new Date(timestamp * 1000);
- const now = new Date();
- const diff = now.getTime() - date.getTime();
- const days = Math.floor(diff / (1000 * 60 * 60 * 24));
-
- if (days === 0) return "Today";
- if (days === 1) return "Yesterday";
- if (days < 7) return `${days} days ago`;
- return date.toLocaleDateString();
- };
-
return (
<div className="h-full flex flex-col gap-4 p-6 overflow-y-auto">
<div className="flex items-center justify-between">
@@ -115,7 +102,7 @@ export function InstancesView() {
</div>
</div>
) : (
- <ul className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
+ <ul className="flex flex-col space-y-3">
{instancesStore.instances.map((instance) => {
const isActive = instancesStore.activeInstance?.id === instance.id;
@@ -123,98 +110,109 @@ export function InstancesView() {
<li
key={instance.id}
onClick={() => instancesStore.setActiveInstance(instance)}
- onKeyDown={(e) =>
- e.key === "Enter" &&
- instancesStore.setActiveInstance(instance)
- }
- className={`relative p-4 text-left border-2 transition-all cursor-pointer hover:border-blue-500 ${
- isActive ? "border-blue-500" : "border-transparent"
- } bg-gray-100 dark:bg-gray-800`}
+ onKeyDown={async (e) => {
+ if (e.key === "Enter") {
+ try {
+ await instancesStore.setActiveInstance(instance);
+ } catch (e) {
+ console.error("Failed to set active instance:", e);
+ toast.error("Error setting active instance");
+ }
+ }
+ }}
+ className="cursor-pointer"
>
- {/* Instance Icon */}
- {instance.iconPath ? (
- <div className="w-12 h-12 mb-3 rounded overflow-hidden">
- <img
- src={instance.iconPath}
- alt={instance.name}
- className="w-full h-full object-cover"
- />
- </div>
- ) : (
- <div className="w-12 h-12 mb-3 rounded bg-linear-to-br from-blue-500 to-purple-600 flex items-center justify-center">
- <span className="text-white font-bold text-lg">
- {instance.name.charAt(0).toUpperCase()}
- </span>
- </div>
- )}
-
- <h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-1">
- {instance.name}
- </h3>
-
- <div className="space-y-1 text-sm text-gray-600 dark:text-gray-400">
- {instance.versionId ? (
- <p className="truncate">Version: {instance.versionId}</p>
- ) : (
- <p className="text-gray-400">No version selected</p>
- )}
-
- {instance.modLoader && (
- <p className="truncate">
- Mod Loader:{" "}
- <span className="capitalize">{instance.modLoader}</span>
- </p>
+ <div
+ className={cn(
+ "flex flex-row space-x-3 p-3 justify-between",
+ "border bg-card/5 backdrop-blur-xl",
+ "hover:bg-accent/50 transition-colors",
+ isActive && "border-primary",
)}
+ >
+ <div className="flex flex-row space-x-4">
+ {instance.iconPath ? (
+ <div className="w-12 h-12 rounded overflow-hidden">
+ <img
+ src={instance.iconPath}
+ alt={instance.name}
+ className="w-full h-full object-cover"
+ />
+ </div>
+ ) : (
+ <div className="w-12 h-12 rounded bg-linear-to-br from-blue-500 to-purple-600 flex items-center justify-center">
+ <span className="text-white font-bold text-lg">
+ {instance.name.charAt(0).toUpperCase()}
+ </span>
+ </div>
+ )}
+
+ <div className="flex flex-col">
+ <h3 className="text-lg font-semibold">{instance.name}</h3>
+ {instance.versionId ? (
+ <p className="text-sm text-muted-foreground">
+ {instance.versionId}
+ </p>
+ ) : (
+ <p className="text-sm text-muted-foreground">
+ No version selected
+ </p>
+ )}
+ </div>
+ </div>
- <p className="truncate">
- Created: {formatDate(toNumber(instance.createdAt))}
- </p>
-
- {instance.lastPlayed && (
- <p className="truncate">
- Last played:{" "}
- {formatLastPlayed(toNumber(instance.lastPlayed))}
- </p>
- )}
- </div>
-
- {/* Action Buttons */}
- <div className="mt-4 flex gap-2">
- <button
- type="button"
- onClick={(e) => {
- e.stopPropagation();
- openEdit(instance);
- }}
- className="flex-1 flex items-center justify-center gap-1 px-3 py-1.5 bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 rounded text-sm transition-colors"
- >
- <Edit2 size={14} />
- Edit
- </button>
-
- <button
- type="button"
- onClick={(e) => {
- e.stopPropagation();
- openDuplicate(instance);
- }}
- className="flex-1 flex items-center justify-center gap-1 px-3 py-1.5 bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 rounded text-sm transition-colors"
- >
- <Copy size={14} />
- Duplicate
- </button>
-
- <button
- type="button"
- onClick={(e) => {
- e.stopPropagation();
- openDelete(instance);
- }}
- className="flex-1 flex items-center justify-center gap-1 px-3 py-1.5 bg-red-500 hover:bg-red-600 text-white rounded text-sm transition-colors"
- >
- <Trash2 size={14} />
- Delete
- </button>
+ <div className="flex items-center">
+ <div className="flex flex-row space-x-2">
+ <Button
+ variant="ghost"
+ size="icon"
+ onClick={async () => {
+ if (!instance.versionId) {
+ toast.error("No version selected or installed");
+ return;
+ }
+ try {
+ await startGame(instance.id, instance.versionId);
+ } catch (e) {
+ console.error("Failed to start game:", e);
+ toast.error("Error starting game");
+ }
+ }}
+ >
+ <RocketIcon />
+ </Button>
+ <Button
+ variant="ghost"
+ size="icon"
+ onClick={(e) => {
+ e.stopPropagation();
+ openDuplicate(instance);
+ }}
+ >
+ <CopyIcon />
+ </Button>
+ <Button
+ variant="ghost"
+ size="icon"
+ onClick={(e) => {
+ e.stopPropagation();
+ openEdit(instance);
+ }}
+ >
+ <EditIcon />
+ </Button>
+ <Button
+ variant="destructive"
+ size="icon"
+ onClick={(e) => {
+ e.stopPropagation();
+ openDelete(instance);
+ }}
+ >
+ <Trash2Icon />
+ </Button>
+ </div>
+ </div>
</div>
</li>
);
diff --git a/packages/ui/src/pages/settings.tsx b/packages/ui/src/pages/settings.tsx
index 440a5dc..9387e23 100644
--- a/packages/ui/src/pages/settings.tsx
+++ b/packages/ui/src/pages/settings.tsx
@@ -1,6 +1,7 @@
import { toNumber } from "es-toolkit/compat";
import { FileJsonIcon } from "lucide-react";
import { useEffect, useState } from "react";
+import { toast } from "sonner";
import { migrateSharedCaches } from "@/client";
import { ConfigEditor } from "@/components/config-editor";
import { Button } from "@/components/ui/button";
@@ -13,9 +14,11 @@ import {
FieldLabel,
FieldLegend,
FieldSet,
+ FieldTitle,
} from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
+import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
Select,
@@ -28,18 +31,40 @@ import {
import { Spinner } from "@/components/ui/spinner";
import { Switch } from "@/components/ui/switch";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
+import { useJavaStore } from "@/models/java";
import { useSettingsStore } from "@/models/settings";
export type SettingsTab = "general" | "appearance" | "advanced";
export function SettingsPage() {
const { config, ...settings } = useSettingsStore();
+ const javaStore = useJavaStore();
const [showConfigEditor, setShowConfigEditor] = useState<boolean>(false);
const [activeTab, setActiveTab] = useState<SettingsTab>("general");
useEffect(() => {
- if (!config) settings.refresh();
- }, [config, settings.refresh]);
+ const refresh = async () => {
+ try {
+ await settings.refresh();
+ } catch (error) {
+ console.error(error);
+ toast.error(`Failed to refresh settings: ${error}`);
+ }
+ try {
+ await javaStore.refreshInstallations();
+ if (!javaStore.catalog) await javaStore.refresh();
+ } catch (error) {
+ console.error(error);
+ toast.error(`Failed to refresh java catalogs: ${error}`);
+ }
+ };
+ refresh();
+ }, [
+ settings.refresh,
+ javaStore.refresh,
+ javaStore.refreshInstallations,
+ javaStore.catalog,
+ ]);
const renderScrollArea = () => {
if (!config) {
@@ -158,7 +183,66 @@ export function SettingsPage() {
<CardTitle className="font-bold text-xl">
Java Installations
</CardTitle>
- <CardContent></CardContent>
+ <CardContent>
+ <FieldGroup>
+ <Field>
+ <FieldLabel htmlFor="java-path">Java Path</FieldLabel>
+ <Input
+ type="text"
+ name="java-path"
+ value={config?.javaPath}
+ onChange={(e) => {
+ settings.merge({
+ javaPath: e.target.value,
+ });
+ }}
+ onBlur={() => {
+ settings.save();
+ }}
+ />
+ </Field>
+ <FieldSet>
+ <FieldLegend>Java Installations</FieldLegend>
+ {javaStore.installations ? (
+ <RadioGroup
+ value={config.javaPath}
+ onValueChange={(value) => {
+ settings.merge({
+ javaPath: value,
+ });
+ settings.save();
+ }}
+ >
+ {javaStore.installations?.map((installation) => (
+ <FieldLabel
+ key={installation.path}
+ htmlFor={installation.path}
+ >
+ <Field orientation="horizontal">
+ <FieldContent>
+ <FieldTitle>
+ {installation.vendor} ({installation.version})
+ </FieldTitle>
+ <FieldDescription>
+ {installation.path}
+ </FieldDescription>
+ </FieldContent>
+ <RadioGroupItem
+ value={installation.path}
+ id={installation.path}
+ />
+ </Field>
+ </FieldLabel>
+ ))}
+ </RadioGroup>
+ ) : (
+ <div className="flex justify-center items-center h-30">
+ <Spinner />
+ </div>
+ )}
+ </FieldSet>
+ </FieldGroup>
+ </CardContent>
</CardHeader>
</Card>
</TabsContent>
diff --git a/packages/ui/vite.config.ts b/packages/ui/vite.config.ts
index 27ce1ff..8c90267 100644
--- a/packages/ui/vite.config.ts
+++ b/packages/ui/vite.config.ts
@@ -1,6 +1,6 @@
+import path from "node:path";
import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";
-import path from "path";
import { defineConfig } from "vite";
// https://vite.dev/config/
diff --git a/src-tauri/CHANGELOG.md b/src-tauri/CHANGELOG.md
index f0f3123..3778d95 100644
--- a/src-tauri/CHANGELOG.md
+++ b/src-tauri/CHANGELOG.md
@@ -1,5 +1,27 @@
# Changelog
+## v0.2.0-alpha.5
+
+### New Features
+
+- [`0ac743f`](https://github.com/HydroRoll-Team/DropOut/commit/0ac743f6d126d047352e6b247ea1ee513361d240): Improve sidebar avatar on large and small screens.
+- [`9e40b5b`](https://github.com/HydroRoll-Team/DropOut/commit/9e40b5b7bea60e6802a4b448ef315b14fba4de7f): Support detect and select java path.
+- [`47aeabf`](https://github.com/HydroRoll-Team/DropOut/commit/47aeabf5d44d7483101d30d289cb4c56761e3faa): Improve position and colors of the UI toast.
+
+### Chores
+
+- [`8a4133c`](https://github.com/HydroRoll-Team/DropOut/commit/8a4133c9c517556cd16c2bbc1cd20bf4ee8f52f0): Update README file
+- [`0ffa00e`](https://github.com/HydroRoll-Team/DropOut/commit/0ffa00eb79f06d877c74925b3da4abb0e25370ec): Remove unnecessary vsc extension svelte
+
+### Refactors
+
+- [`24a229e`](https://github.com/HydroRoll-Team/DropOut/commit/24a229ede321e8296ea99b332ccfa61213791d10): Partial rewrite layout of instances page.
+
+### Bug Fixes
+
+- [`47aeabf`](https://github.com/HydroRoll-Team/DropOut/commit/47aeabf5d44d7483101d30d289cb4c56761e3faa): Fix logo on Linux and MacOS.
+- [`9e40b5b`](https://github.com/HydroRoll-Team/DropOut/commit/9e40b5b7bea60e6802a4b448ef315b14fba4de7f): Auto select game version if version is unique.
+
## v0.2.0-alpha.4
### Chores
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 1cce2cc..b375c6e 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "dropout"
-version = "0.2.0-alpha.4"
+version = "0.2.0-alpha.5"
edition = "2024"
authors = ["HsiangNianian"]
description = "The DropOut Minecraft Game Launcher"
diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png
index ff83086..0355e6c 100644
--- a/src-tauri/icons/128x128.png
+++ b/src-tauri/icons/128x128.png
Binary files differ
diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png
index d2945bc..072f818 100644
--- a/src-tauri/icons/128x128@2x.png
+++ b/src-tauri/icons/128x128@2x.png
Binary files differ
diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png
index 0450dbc..9ac999c 100644
--- a/src-tauri/icons/32x32.png
+++ b/src-tauri/icons/32x32.png
Binary files differ
diff --git a/src-tauri/icons/64x64.png b/src-tauri/icons/64x64.png
index dd57cf5..d846039 100644
--- a/src-tauri/icons/64x64.png
+++ b/src-tauri/icons/64x64.png
Binary files differ
diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png
index 3d69d32..667383f 100644
--- a/src-tauri/icons/Square107x107Logo.png
+++ b/src-tauri/icons/Square107x107Logo.png
Binary files differ
diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png
index 1fe00e0..c113bc2 100644
--- a/src-tauri/icons/Square142x142Logo.png
+++ b/src-tauri/icons/Square142x142Logo.png
Binary files differ
diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png
index 42c10c2..491dbac 100644
--- a/src-tauri/icons/Square150x150Logo.png
+++ b/src-tauri/icons/Square150x150Logo.png
Binary files differ
diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png
index 6acb9fa..75f7ada 100644
--- a/src-tauri/icons/Square284x284Logo.png
+++ b/src-tauri/icons/Square284x284Logo.png
Binary files differ
diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png
index 7ca72b4..e6510c4 100644
--- a/src-tauri/icons/Square30x30Logo.png
+++ b/src-tauri/icons/Square30x30Logo.png
Binary files differ
diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png
index 2733c71..c280413 100644
--- a/src-tauri/icons/Square310x310Logo.png
+++ b/src-tauri/icons/Square310x310Logo.png
Binary files differ
diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png
index fe734cc..887afd1 100644
--- a/src-tauri/icons/Square44x44Logo.png
+++ b/src-tauri/icons/Square44x44Logo.png
Binary files differ
diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png
index c1e42ae..ca3d7cf 100644
--- a/src-tauri/icons/Square71x71Logo.png
+++ b/src-tauri/icons/Square71x71Logo.png
Binary files differ
diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png
index 7803afd..93cffc9 100644
--- a/src-tauri/icons/Square89x89Logo.png
+++ b/src-tauri/icons/Square89x89Logo.png
Binary files differ
diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png
index 1032810..72bd926 100644
--- a/src-tauri/icons/StoreLogo.png
+++ b/src-tauri/icons/StoreLogo.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml b/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..03f0660
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
+ <background android:drawable="@color/ic_launcher_background"/>
+</adaptive-icon>
diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..55295ee
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..36af393
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9838f21
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..d266d84
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..588180b
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..5bb8398
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..aa3d140
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..c95d18e
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..4b35f34
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d916842
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..107d4e0
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dd535ef
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..9c46477
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..0697dcc
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..2e1e41f
--- /dev/null
+++ b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/src-tauri/icons/android/values/ic_launcher_background.xml b/src-tauri/icons/android/values/ic_launcher_background.xml
new file mode 100644
index 0000000..3024847
--- /dev/null
+++ b/src-tauri/icons/android/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="ic_launcher_background">#fff</color>
+</resources>
diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns
index c2324db..c3c7971 100644
--- a/src-tauri/icons/icon.icns
+++ b/src-tauri/icons/icon.icns
Binary files differ
diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico
index be3c285..3a276d9 100644
--- a/src-tauri/icons/icon.ico
+++ b/src-tauri/icons/icon.ico
Binary files differ
diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png
index 2466203..620bf79 100644
--- a/src-tauri/icons/icon.png
+++ b/src-tauri/icons/icon.png
Binary files differ
diff --git a/src-tauri/icons/icon.svg b/src-tauri/icons/icon.svg
deleted file mode 100644
index 0baf00f..0000000
--- a/src-tauri/icons/icon.svg
+++ /dev/null
@@ -1,50 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
- <!-- Background -->
- <rect width="100%" height="100%" fill="#23272a"/>
-
- <!-- Grid Pattern -->
- <defs>
- <pattern id="smallGrid" width="40" height="40" patternUnits="userSpaceOnUse">
- <path d="M 40 0 L 0 0 0 40" fill="none" stroke="#2c2f33" stroke-width="2"/>
- </pattern>
- <!-- Glow filter for active connections -->
- <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
- <feGaussianBlur stdDeviation="3" result="blur" />
- <feComposite in="SourceGraphic" in2="blur" operator="over" />
- </filter>
- </defs>
- <rect width="100%" height="100%" fill="url(#smallGrid)" />
-
- <!-- Neural Network Connections (Lines) -->
- <!-- Only lines between ACTIVE nodes are drawn normally -->
-
- <!-- Input (Left) to Hidden (Middle Active) -->
- <path d="M 100 128 L 256 256" stroke="#43b581" stroke-width="8" stroke-linecap="round" opacity="0.8"/> <!-- Top to Center -->
- <path d="M 100 256 L 256 256" stroke="#43b581" stroke-width="8" stroke-linecap="round" opacity="1.0" filter="url(#glow)"/> <!-- Mid to Center (Strongest) -->
- <path d="M 100 384 L 256 256" stroke="#43b581" stroke-width="8" stroke-linecap="round" opacity="0.8"/> <!-- Bot to Center -->
-
- <!-- Hidden (Middle Active) to Output (Right) -->
- <path d="M 256 256 L 412 256" stroke="#43b581" stroke-width="8" stroke-linecap="round" opacity="1.0" filter="url(#glow)"/>
-
- <!-- Disconnected "Ghost" Lines (Optional: faint traces, or just omit to emphasize dropout) -->
- <!-- Let's omit them to keep it clean and high-contrast, representing true dropout -->
-
- <!-- Nodes -->
-
- <!-- Layer 1: Input (All Active) - x=100 -->
- <circle cx="100" cy="128" r="30" fill="#7289da" stroke="#ffffff" stroke-width="4"/>
- <circle cx="100" cy="256" r="30" fill="#7289da" stroke="#ffffff" stroke-width="4"/>
- <circle cx="100" cy="384" r="30" fill="#7289da" stroke="#ffffff" stroke-width="4"/>
-
- <!-- Layer 2: Hidden (Dropout Layer) - x=256 -->
- <!-- Node 1: DROPPED (Ghost) -->
- <circle cx="256" cy="128" r="28" fill="none" stroke="#4f545c" stroke-width="4" stroke-dasharray="8,6"/>
- <!-- Node 2: ACTIVE -->
- <circle cx="256" cy="256" r="32" fill="#43b581" stroke="#ffffff" stroke-width="4"/>
- <!-- Node 3: DROPPED (Ghost) -->
- <circle cx="256" cy="384" r="28" fill="none" stroke="#4f545c" stroke-width="4" stroke-dasharray="8,6"/>
-
- <!-- Layer 3: Output - x=412 -->
- <circle cx="412" cy="256" r="30" fill="#7289da" stroke="#ffffff" stroke-width="4"/>
-
-</svg>
diff --git a/src-tauri/icons/ios/AppIcon-20x20@1x.png b/src-tauri/icons/ios/AppIcon-20x20@1x.png
new file mode 100644
index 0000000..413fb23
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-20x20@1x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/src-tauri/icons/ios/AppIcon-20x20@2x-1.png
new file mode 100644
index 0000000..1303e1f
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-20x20@2x-1.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-20x20@2x.png b/src-tauri/icons/ios/AppIcon-20x20@2x.png
new file mode 100644
index 0000000..1303e1f
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-20x20@2x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-20x20@3x.png b/src-tauri/icons/ios/AppIcon-20x20@3x.png
new file mode 100644
index 0000000..db36923
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-20x20@3x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-29x29@1x.png b/src-tauri/icons/ios/AppIcon-29x29@1x.png
new file mode 100644
index 0000000..7867663
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-29x29@1x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/src-tauri/icons/ios/AppIcon-29x29@2x-1.png
new file mode 100644
index 0000000..e4ea45e
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-29x29@2x-1.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-29x29@2x.png b/src-tauri/icons/ios/AppIcon-29x29@2x.png
new file mode 100644
index 0000000..e4ea45e
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-29x29@2x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-29x29@3x.png b/src-tauri/icons/ios/AppIcon-29x29@3x.png
new file mode 100644
index 0000000..9c4b0e1
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-29x29@3x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-40x40@1x.png b/src-tauri/icons/ios/AppIcon-40x40@1x.png
new file mode 100644
index 0000000..1303e1f
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-40x40@1x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/src-tauri/icons/ios/AppIcon-40x40@2x-1.png
new file mode 100644
index 0000000..b690f0e
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-40x40@2x-1.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-40x40@2x.png b/src-tauri/icons/ios/AppIcon-40x40@2x.png
new file mode 100644
index 0000000..b690f0e
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-40x40@2x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-40x40@3x.png b/src-tauri/icons/ios/AppIcon-40x40@3x.png
new file mode 100644
index 0000000..7180dc4
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-40x40@3x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-512@2x.png b/src-tauri/icons/ios/AppIcon-512@2x.png
new file mode 100644
index 0000000..95d749a
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-512@2x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-60x60@2x.png b/src-tauri/icons/ios/AppIcon-60x60@2x.png
new file mode 100644
index 0000000..7180dc4
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-60x60@2x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-60x60@3x.png b/src-tauri/icons/ios/AppIcon-60x60@3x.png
new file mode 100644
index 0000000..097bddd
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-60x60@3x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-76x76@1x.png b/src-tauri/icons/ios/AppIcon-76x76@1x.png
new file mode 100644
index 0000000..8836adf
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-76x76@1x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-76x76@2x.png b/src-tauri/icons/ios/AppIcon-76x76@2x.png
new file mode 100644
index 0000000..d0b4089
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-76x76@2x.png
Binary files differ
diff --git a/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png
new file mode 100644
index 0000000..b3fe311
--- /dev/null
+++ b/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png
Binary files differ
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 08e2fc9..1c31a09 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -1,6 +1,6 @@
{
"productName": "Dropout",
- "version": "0.2.0-alpha.4",
+ "version": "0.2.0-alpha.5",
"identifier": "com.dropout.launcher",
"build": {
"beforeDevCommand": "pnpm --filter @dropout/ui dev",