refactor: convert to bun-workspaces monorepo (desktop/ + www/)

- Move the Tauri app (React frontend + Rust backend) into desktop/ via
  git mv — configs unchanged (relative paths: tauri.conf.json, vite.config.ts)
- Root package.json becomes a private bun workspace container with
  orchestration scripts; desktop package renamed gridline-desktop
- Scaffold www/ with Astro 7 + Tailwind v4 (hand-wired vite plugin,
  static output, ready for Dokploy)
- Update release.yml for the new layout: projectPath: desktop,
  desktop/src-tauri resource paths, rust-cache workspace path
- Update README + AGENTS.md structure trees and dev commands
- Verified: vitest (1074), cargo test (354), desktop build, tauri dev
  (window launches), tauri build (dmg + app bundles), Astro build
This commit is contained in:
2026-08-16 19:31:53 +08:00
parent d752642b4d
commit 6854d889c5
400 changed files with 857 additions and 149 deletions
+133
View File
@@ -0,0 +1,133 @@
import { useEffect } from "react";
import { useConnectionStore } from "./stores/connectionStore";
import { useSettingsStore } from "./stores/settingsStore";
import { useUiStore } from "./stores/uiStore";
import { useBackupStore } from "./stores/backupStore";
import { HomeScreen } from "./components/layout/HomeScreen";
import { SettingsPage } from "./components/settings/SettingsPage";
import { NewConnectionScreen } from "./components/connections/NewConnectionScreen";
import { ErrorBanner } from "./components/ui/ErrorBanner";
import { ToastContainer } from "./components/ui/Toast";
import { DbViewerScreen } from "./components/db-viewer/DbViewerScreen";
import { useAppearance } from "./hooks/useAppearance";
import { isMacOS } from "./lib/platform";
import { getCurrentWindow } from "@tauri-apps/api/window";
const VIEW_TITLES: Record<string, string> = {
home: "Gridline",
settings: "Settings",
"new-connection": "New Connection",
"db-viewer": "",
};
export default function App() {
const activeView = useUiStore((s) => s.activeView);
const setActiveView = useUiStore((s) => s.setActiveView);
const settingsReturnView = useUiStore((s) => s.settingsReturnView);
const openSettings = useUiStore((s) => s.openSettings);
const loadConnections = useConnectionStore((s) => s.loadAll);
const loadSettings = useSettingsStore((s) => s.load);
const settings = useSettingsStore((s) => s.settings);
const connectionError = useConnectionStore((s) => s.error);
const activeFolderId = useUiStore((s) => s.activeFolderId);
const folders = useConnectionStore((s) => s.folders);
const tags = useConnectionStore((s) => s.tags);
const prefilledConnectionString = useUiStore((s) => s.prefilledConnectionString);
const clearPrefilledConnectionString = useUiStore((s) => s.clearPrefilledConnectionString);
useAppearance(settings?.theme ?? "system", settings?.font_size ?? "medium", settings?.accent_color ?? "#2563EB");
useEffect(() => {
loadConnections();
loadSettings();
// Init backup event listener (noop outside Tauri)
useBackupStore.getState().initListener().catch(() => {});
}, [loadConnections, loadSettings]);
// If the user hasn't navigated anywhere yet, start in the configured default folder
const setActiveFolderId = useUiStore((s) => s.setActiveFolderId);
const defaultFolderId = settings?.default_folder_id;
useEffect(() => {
if (defaultFolderId && useUiStore.getState().activeFolderId === null) {
setActiveFolderId(defaultFolderId);
}
}, [defaultFolderId, setActiveFolderId]);
useEffect(() => {
let title = VIEW_TITLES[activeView] ?? "Gridline";
if (activeView === "db-viewer") {
const conn = useConnectionStore.getState().connections.find(
(c) => c.id === useUiStore.getState().activeConnectionId
);
if (conn) title = conn.name;
}
document.title = title;
try {
getCurrentWindow().setTitle(title).catch(() => {
// Ignore environments where the Tauri API is unavailable (tests, browser)
});
} catch {
// getCurrentWindow can throw outside of a Tauri runtime
}
}, [activeView]);
const keepDbViewerMounted =
activeView === "db-viewer" ||
(activeView === "settings" && settingsReturnView === "db-viewer");
const dbViewerVisible = activeView === "db-viewer";
return (
<div className="h-svh bg-canvas select-none flex flex-col overflow-hidden">
{typeof window !== "undefined" &&
"__TAURI_INTERNALS__" in window &&
isMacOS() && (
// macOS "Overlay" title bar: in-flow strip the window can be
// dragged by; traffic lights float over it. Only in Tauri.
<div
data-tauri-drag-region
aria-hidden
className="h-7 shrink-0 bg-canvas select-none"
/>
)}
<div className="flex-1 min-h-0">
{connectionError && (
<div className="px-6 pt-4">
<ErrorBanner
error={connectionError}
onRetry={loadConnections}
/>
</div>
)}
{activeView === "settings" && <SettingsPage />}
{activeView === "new-connection" && (
<NewConnectionScreen
defaultFolderId={activeFolderId}
prefilledConnectionString={prefilledConnectionString ?? ""}
folders={folders}
tags={tags}
onSaved={() => {
clearPrefilledConnectionString();
setActiveView("home");
}}
onCancel={() => {
clearPrefilledConnectionString();
setActiveView("home");
}}
/>
)}
{activeView === "home" && <HomeScreen />}
{keepDbViewerMounted && (
<div className={dbViewerVisible ? "contents" : "hidden"}>
<DbViewerScreen
connectionId={useUiStore.getState().activeConnectionId ?? ""}
onHome={() => setActiveView("home")}
onSettings={openSettings}
/>
</div>
)}
</div>
<ToastContainer />
</div>
);
}