diff --git a/aha-ui/.vscode/extensions.json b/aha-ui/.vscode/extensions.json
new file mode 100644
index 0000000..24d7cc6
--- /dev/null
+++ b/aha-ui/.vscode/extensions.json
@@ -0,0 +1,3 @@
+{
+ "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
+}
diff --git a/aha-ui/README.md b/aha-ui/README.md
new file mode 100644
index 0000000..102e366
--- /dev/null
+++ b/aha-ui/README.md
@@ -0,0 +1,7 @@
+# Tauri + React + Typescript
+
+This template should help get you started developing with Tauri, React and Typescript in Vite.
+
+## Recommended IDE Setup
+
+- [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
diff --git a/aha-ui/index.html b/aha-ui/index.html
new file mode 100644
index 0000000..ff93803
--- /dev/null
+++ b/aha-ui/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ Tauri + React + Typescript
+
+
+
+
+
+
+
diff --git a/aha-ui/package.json b/aha-ui/package.json
new file mode 100644
index 0000000..eabf183
--- /dev/null
+++ b/aha-ui/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "aha-ui",
+ "private": true,
+ "version": "0.1.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview",
+ "tauri": "tauri"
+ },
+ "dependencies": {
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "@tauri-apps/api": "^2",
+ "@tauri-apps/plugin-opener": "^2"
+ },
+ "devDependencies": {
+ "@types/react": "^19.1.8",
+ "@types/react-dom": "^19.1.6",
+ "@vitejs/plugin-react": "^4.6.0",
+ "typescript": "~5.8.3",
+ "vite": "^7.0.4",
+ "@tauri-apps/cli": "^2"
+ }
+}
diff --git a/aha-ui/public/tauri.svg b/aha-ui/public/tauri.svg
new file mode 100644
index 0000000..31b62c9
--- /dev/null
+++ b/aha-ui/public/tauri.svg
@@ -0,0 +1,6 @@
+
diff --git a/aha-ui/public/vite.svg b/aha-ui/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/aha-ui/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/aha-ui/src-tauri/Cargo.toml b/aha-ui/src-tauri/Cargo.toml
new file mode 100644
index 0000000..bc34802
--- /dev/null
+++ b/aha-ui/src-tauri/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+name = "aha-ui"
+version = "0.1.0"
+description = "A Tauri App"
+authors = ["you"]
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[lib]
+# The `_lib` suffix may seem redundant but it is necessary
+# to make the lib name unique and wouldn't conflict with the bin name.
+# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
+name = "aha_ui_lib"
+crate-type = ["staticlib", "cdylib", "rlib"]
+
+[build-dependencies]
+tauri-build = { version = "2", features = [] }
+
+[dependencies]
+tauri = { version = "2", features = [] }
+tauri-plugin-opener = "2"
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+
diff --git a/aha-ui/src-tauri/build.rs b/aha-ui/src-tauri/build.rs
new file mode 100644
index 0000000..d860e1e
--- /dev/null
+++ b/aha-ui/src-tauri/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+ tauri_build::build()
+}
diff --git a/aha-ui/src-tauri/capabilities/default.json b/aha-ui/src-tauri/capabilities/default.json
new file mode 100644
index 0000000..4cdbf49
--- /dev/null
+++ b/aha-ui/src-tauri/capabilities/default.json
@@ -0,0 +1,10 @@
+{
+ "$schema": "../gen/schemas/desktop-schema.json",
+ "identifier": "default",
+ "description": "Capability for the main window",
+ "windows": ["main"],
+ "permissions": [
+ "core:default",
+ "opener:default"
+ ]
+}
diff --git a/aha-ui/src-tauri/icons/128x128.png b/aha-ui/src-tauri/icons/128x128.png
new file mode 100644
index 0000000..6be5e50
Binary files /dev/null and b/aha-ui/src-tauri/icons/128x128.png differ
diff --git a/aha-ui/src-tauri/icons/128x128@2x.png b/aha-ui/src-tauri/icons/128x128@2x.png
new file mode 100644
index 0000000..e81bece
Binary files /dev/null and b/aha-ui/src-tauri/icons/128x128@2x.png differ
diff --git a/aha-ui/src-tauri/icons/32x32.png b/aha-ui/src-tauri/icons/32x32.png
new file mode 100644
index 0000000..a437dd5
Binary files /dev/null and b/aha-ui/src-tauri/icons/32x32.png differ
diff --git a/aha-ui/src-tauri/icons/Square107x107Logo.png b/aha-ui/src-tauri/icons/Square107x107Logo.png
new file mode 100644
index 0000000..0ca4f27
Binary files /dev/null and b/aha-ui/src-tauri/icons/Square107x107Logo.png differ
diff --git a/aha-ui/src-tauri/icons/Square142x142Logo.png b/aha-ui/src-tauri/icons/Square142x142Logo.png
new file mode 100644
index 0000000..b81f820
Binary files /dev/null and b/aha-ui/src-tauri/icons/Square142x142Logo.png differ
diff --git a/aha-ui/src-tauri/icons/Square150x150Logo.png b/aha-ui/src-tauri/icons/Square150x150Logo.png
new file mode 100644
index 0000000..624c7bf
Binary files /dev/null and b/aha-ui/src-tauri/icons/Square150x150Logo.png differ
diff --git a/aha-ui/src-tauri/icons/Square284x284Logo.png b/aha-ui/src-tauri/icons/Square284x284Logo.png
new file mode 100644
index 0000000..c021d2b
Binary files /dev/null and b/aha-ui/src-tauri/icons/Square284x284Logo.png differ
diff --git a/aha-ui/src-tauri/icons/Square30x30Logo.png b/aha-ui/src-tauri/icons/Square30x30Logo.png
new file mode 100644
index 0000000..6219700
Binary files /dev/null and b/aha-ui/src-tauri/icons/Square30x30Logo.png differ
diff --git a/aha-ui/src-tauri/icons/Square310x310Logo.png b/aha-ui/src-tauri/icons/Square310x310Logo.png
new file mode 100644
index 0000000..f9bc048
Binary files /dev/null and b/aha-ui/src-tauri/icons/Square310x310Logo.png differ
diff --git a/aha-ui/src-tauri/icons/Square44x44Logo.png b/aha-ui/src-tauri/icons/Square44x44Logo.png
new file mode 100644
index 0000000..d5fbfb2
Binary files /dev/null and b/aha-ui/src-tauri/icons/Square44x44Logo.png differ
diff --git a/aha-ui/src-tauri/icons/Square71x71Logo.png b/aha-ui/src-tauri/icons/Square71x71Logo.png
new file mode 100644
index 0000000..63440d7
Binary files /dev/null and b/aha-ui/src-tauri/icons/Square71x71Logo.png differ
diff --git a/aha-ui/src-tauri/icons/Square89x89Logo.png b/aha-ui/src-tauri/icons/Square89x89Logo.png
new file mode 100644
index 0000000..f3f705a
Binary files /dev/null and b/aha-ui/src-tauri/icons/Square89x89Logo.png differ
diff --git a/aha-ui/src-tauri/icons/StoreLogo.png b/aha-ui/src-tauri/icons/StoreLogo.png
new file mode 100644
index 0000000..4556388
Binary files /dev/null and b/aha-ui/src-tauri/icons/StoreLogo.png differ
diff --git a/aha-ui/src-tauri/icons/icon.icns b/aha-ui/src-tauri/icons/icon.icns
new file mode 100644
index 0000000..12a5bce
Binary files /dev/null and b/aha-ui/src-tauri/icons/icon.icns differ
diff --git a/aha-ui/src-tauri/icons/icon.ico b/aha-ui/src-tauri/icons/icon.ico
new file mode 100644
index 0000000..b3636e4
Binary files /dev/null and b/aha-ui/src-tauri/icons/icon.ico differ
diff --git a/aha-ui/src-tauri/icons/icon.png b/aha-ui/src-tauri/icons/icon.png
new file mode 100644
index 0000000..e1cd261
Binary files /dev/null and b/aha-ui/src-tauri/icons/icon.png differ
diff --git a/aha-ui/src-tauri/src/lib.rs b/aha-ui/src-tauri/src/lib.rs
new file mode 100644
index 0000000..4a277ef
--- /dev/null
+++ b/aha-ui/src-tauri/src/lib.rs
@@ -0,0 +1,14 @@
+// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
+#[tauri::command]
+fn greet(name: &str) -> String {
+ format!("Hello, {}! You've been greeted from Rust!", name)
+}
+
+#[cfg_attr(mobile, tauri::mobile_entry_point)]
+pub fn run() {
+ tauri::Builder::default()
+ .plugin(tauri_plugin_opener::init())
+ .invoke_handler(tauri::generate_handler![greet])
+ .run(tauri::generate_context!())
+ .expect("error while running tauri application");
+}
diff --git a/aha-ui/src-tauri/src/main.rs b/aha-ui/src-tauri/src/main.rs
new file mode 100644
index 0000000..414cd84
--- /dev/null
+++ b/aha-ui/src-tauri/src/main.rs
@@ -0,0 +1,6 @@
+// Prevents additional console window on Windows in release, DO NOT REMOVE!!
+#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
+
+fn main() {
+ aha_ui_lib::run()
+}
diff --git a/aha-ui/src-tauri/tauri.conf.json b/aha-ui/src-tauri/tauri.conf.json
new file mode 100644
index 0000000..f4299d5
--- /dev/null
+++ b/aha-ui/src-tauri/tauri.conf.json
@@ -0,0 +1,35 @@
+{
+ "$schema": "https://schema.tauri.app/config/2",
+ "productName": "aha-ui",
+ "version": "0.1.0",
+ "identifier": "com.boer.aha-ui",
+ "build": {
+ "beforeDevCommand": "pnpm dev",
+ "devUrl": "http://localhost:1420",
+ "beforeBuildCommand": "pnpm build",
+ "frontendDist": "../dist"
+ },
+ "app": {
+ "windows": [
+ {
+ "title": "aha-ui",
+ "width": 800,
+ "height": 600
+ }
+ ],
+ "security": {
+ "csp": null
+ }
+ },
+ "bundle": {
+ "active": true,
+ "targets": "all",
+ "icon": [
+ "icons/32x32.png",
+ "icons/128x128.png",
+ "icons/128x128@2x.png",
+ "icons/icon.icns",
+ "icons/icon.ico"
+ ]
+ }
+}
diff --git a/aha-ui/src/App.css b/aha-ui/src/App.css
new file mode 100644
index 0000000..85f7a4a
--- /dev/null
+++ b/aha-ui/src/App.css
@@ -0,0 +1,116 @@
+.logo.vite:hover {
+ filter: drop-shadow(0 0 2em #747bff);
+}
+
+.logo.react:hover {
+ filter: drop-shadow(0 0 2em #61dafb);
+}
+:root {
+ font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
+ font-size: 16px;
+ line-height: 24px;
+ font-weight: 400;
+
+ color: #0f0f0f;
+ background-color: #f6f6f6;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-text-size-adjust: 100%;
+}
+
+.container {
+ margin: 0;
+ padding-top: 10vh;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+ transition: 0.75s;
+}
+
+.logo.tauri:hover {
+ filter: drop-shadow(0 0 2em #24c8db);
+}
+
+.row {
+ display: flex;
+ justify-content: center;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+
+a:hover {
+ color: #535bf2;
+}
+
+h1 {
+ text-align: center;
+}
+
+input,
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ color: #0f0f0f;
+ background-color: #ffffff;
+ transition: border-color 0.25s;
+ box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
+}
+
+button {
+ cursor: pointer;
+}
+
+button:hover {
+ border-color: #396cd8;
+}
+button:active {
+ border-color: #396cd8;
+ background-color: #e8e8e8;
+}
+
+input,
+button {
+ outline: none;
+}
+
+#greet-input {
+ margin-right: 5px;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ color: #f6f6f6;
+ background-color: #2f2f2f;
+ }
+
+ a:hover {
+ color: #24c8db;
+ }
+
+ input,
+ button {
+ color: #ffffff;
+ background-color: #0f0f0f98;
+ }
+ button:active {
+ background-color: #0f0f0f69;
+ }
+}
diff --git a/aha-ui/src/App.tsx b/aha-ui/src/App.tsx
new file mode 100644
index 0000000..8286a76
--- /dev/null
+++ b/aha-ui/src/App.tsx
@@ -0,0 +1,51 @@
+import { useState } from "react";
+import reactLogo from "./assets/react.svg";
+import { invoke } from "@tauri-apps/api/core";
+import "./App.css";
+
+function App() {
+ const [greetMsg, setGreetMsg] = useState("");
+ const [name, setName] = useState("");
+
+ async function greet() {
+ // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
+ setGreetMsg(await invoke("greet", { name }));
+ }
+
+ return (
+
+ Welcome to Tauri + React
+
+
+ Click on the Tauri, Vite, and React logos to learn more.
+
+
+ {greetMsg}
+
+ );
+}
+
+export default App;
diff --git a/aha-ui/src/assets/react.svg b/aha-ui/src/assets/react.svg
new file mode 100644
index 0000000..6c87de9
--- /dev/null
+++ b/aha-ui/src/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/aha-ui/src/main.tsx b/aha-ui/src/main.tsx
new file mode 100644
index 0000000..2be325e
--- /dev/null
+++ b/aha-ui/src/main.tsx
@@ -0,0 +1,9 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App";
+
+ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
+
+
+ ,
+);
diff --git a/aha-ui/src/vite-env.d.ts b/aha-ui/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/aha-ui/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/aha-ui/tsconfig.json b/aha-ui/tsconfig.json
new file mode 100644
index 0000000..a7fc6fb
--- /dev/null
+++ b/aha-ui/tsconfig.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/aha-ui/tsconfig.node.json b/aha-ui/tsconfig.node.json
new file mode 100644
index 0000000..42872c5
--- /dev/null
+++ b/aha-ui/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/aha-ui/vite.config.ts b/aha-ui/vite.config.ts
new file mode 100644
index 0000000..ddad22a
--- /dev/null
+++ b/aha-ui/vite.config.ts
@@ -0,0 +1,32 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+
+// @ts-expect-error process is a nodejs global
+const host = process.env.TAURI_DEV_HOST;
+
+// https://vite.dev/config/
+export default defineConfig(async () => ({
+ plugins: [react()],
+
+ // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
+ //
+ // 1. prevent Vite from obscuring rust errors
+ clearScreen: false,
+ // 2. tauri expects a fixed port, fail if that port is not available
+ server: {
+ port: 1420,
+ strictPort: true,
+ host: host || false,
+ hmr: host
+ ? {
+ protocol: "ws",
+ host,
+ port: 1421,
+ }
+ : undefined,
+ watch: {
+ // 3. tell Vite to ignore watching `src-tauri`
+ ignored: ["**/src-tauri/**"],
+ },
+ },
+}));