feat: restructure as pnpm monorepo with Tauri desktop shell
- Migrate to packages/web + packages/desktop workspace layout via git mv - Add Tauri v2 desktop shell with @tauri-apps/plugin-http for CORS bypass - Configure Turborepo with package-level dependsOn build graph - Add semantic-release with exec plugin for GHA output and disabled PR comments - Fix http:default capability scope to allow all HTTP/HTTPS origins - Add Vite Tauri integration (clearScreen, TAURI_DEV_HOST, target, envPrefix) - Add semantic-release.yml and release.yml GitHub Actions workflows - Fix all Biome lint errors (noArrayIndexKey, noNonNullAssertion, button types)
This commit is contained in:
43
packages/web/src/routes/__root.tsx
Normal file
43
packages/web/src/routes/__root.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Sidebar } from "@/components/layout/Sidebar";
|
||||
import { loadConfig } from "@/lib/config";
|
||||
import { applyTheme, getStoredTheme } from "@/lib/theme";
|
||||
import { Outlet, createRootRoute, useRouter } from "@tanstack/react-router";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function RootLayout() {
|
||||
const config = loadConfig();
|
||||
const router = useRouter();
|
||||
const isSettings = router.state.location.pathname === "/settings";
|
||||
|
||||
useEffect(() => {
|
||||
applyTheme(getStoredTheme());
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!config && !isSettings) {
|
||||
router.navigate({ to: "/settings" as never });
|
||||
}
|
||||
}, [config, isSettings, router]);
|
||||
|
||||
if (isSettings) {
|
||||
return <Outlet />;
|
||||
}
|
||||
|
||||
if (!config) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex h-screen w-full overflow-hidden"
|
||||
style={{ background: "var(--bg)", position: "relative", zIndex: 1 }}
|
||||
>
|
||||
<Sidebar />
|
||||
<main className="flex-1 overflow-auto" style={{ position: "relative", zIndex: 1 }}>
|
||||
<Outlet />
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const Route = createRootRoute({
|
||||
component: RootLayout,
|
||||
});
|
||||
6
packages/web/src/routes/index.tsx
Normal file
6
packages/web/src/routes/index.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { Dashboard } from "@/components/dashboard/Dashboard";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
component: Dashboard,
|
||||
});
|
||||
48
packages/web/src/routes/settings.tsx
Normal file
48
packages/web/src/routes/settings.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { SettingsForm } from "@/components/settings/SettingsForm";
|
||||
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||
import { motion } from "framer-motion";
|
||||
import { Brain } from "lucide-react";
|
||||
|
||||
export const Route = createFileRoute("/settings")({
|
||||
component: SettingsPage,
|
||||
});
|
||||
|
||||
function SettingsPage() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex-1 flex items-center justify-center p-4 overflow-auto"
|
||||
style={{ background: "var(--bg)" }}
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 16 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ type: "spring", stiffness: 260, damping: 24 }}
|
||||
className="w-full max-w-md"
|
||||
>
|
||||
<div className="mb-8 text-center">
|
||||
<div
|
||||
className="w-14 h-14 rounded-2xl flex items-center justify-center mx-auto mb-4"
|
||||
style={{
|
||||
background: "linear-gradient(135deg, #4f46e5, #7c3aed)",
|
||||
boxShadow: "0 0 32px rgba(99,102,241,0.35)",
|
||||
}}
|
||||
>
|
||||
<Brain className="w-7 h-7 text-white" strokeWidth={2} />
|
||||
</div>
|
||||
<h1 className="text-2xl font-semibold tracking-tight" style={{ color: "var(--text-1)" }}>
|
||||
Honcho UI
|
||||
</h1>
|
||||
<p className="text-sm mt-1" style={{ color: "var(--text-3)" }}>
|
||||
Connect to your self-hosted Honcho instance
|
||||
</p>
|
||||
</div>
|
||||
<SettingsForm onSaved={() => navigate({ to: "/" as never })} />
|
||||
<p className="text-xs text-center mt-4" style={{ color: "var(--text-4)" }}>
|
||||
Connection details are stored locally on this device only
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
6
packages/web/src/routes/workspaces.tsx
Normal file
6
packages/web/src/routes/workspaces.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { WorkspaceList } from "@/components/workspaces/WorkspaceList";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/workspaces")({
|
||||
component: WorkspaceList,
|
||||
});
|
||||
6
packages/web/src/routes/workspaces_.$workspaceId.tsx
Normal file
6
packages/web/src/routes/workspaces_.$workspaceId.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { WorkspaceDetail } from "@/components/workspaces/WorkspaceDetail";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/workspaces_/$workspaceId")({
|
||||
component: WorkspaceDetail,
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
import { ConclusionBrowser } from "@/components/conclusions/ConclusionBrowser";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/workspaces_/$workspaceId_/conclusions")({
|
||||
component: ConclusionBrowser,
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
import { PeerList } from "@/components/peers/PeerList";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/workspaces_/$workspaceId_/peers")({
|
||||
component: PeerList,
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
import { PeerDetail } from "@/components/peers/PeerDetail";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/workspaces_/$workspaceId_/peers_/$peerId")({
|
||||
component: PeerDetail,
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
import { ChatPage } from "@/components/chat/ChatPage";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/workspaces_/$workspaceId_/peers_/$peerId_/chat")({
|
||||
component: ChatPage,
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
import { SessionList } from "@/components/sessions/SessionList";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/workspaces_/$workspaceId_/sessions")({
|
||||
component: SessionList,
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
import { SessionDetail } from "@/components/sessions/SessionDetail";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/workspaces_/$workspaceId_/sessions_/$sessionId")({
|
||||
component: SessionDetail,
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { WebhookManager } from "@/components/workspaces/WebhookManager";
|
||||
import { createFileRoute, useParams } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/workspaces_/$workspaceId_/webhooks")({
|
||||
component: WebhookManagerPage,
|
||||
});
|
||||
|
||||
function WebhookManagerPage() {
|
||||
const { workspaceId } = useParams({ strict: false }) as { workspaceId: string };
|
||||
return <WebhookManager workspaceId={workspaceId} />;
|
||||
}
|
||||
Reference in New Issue
Block a user