105 lines
3.3 KiB
TypeScript
105 lines
3.3 KiB
TypeScript
import { invoke } from "@tauri-apps/api/core";
|
|
import { useEffect, useState } from "react";
|
|
import { Toaster } from "sonner";
|
|
import "./App.css";
|
|
import AccessibilityPermissions from "./components/AccessibilityPermissions";
|
|
import Footer from "./components/footer";
|
|
import HandyTextLogo from "./components/icons/HandyTextLogo";
|
|
import Onboarding from "./components/onboarding";
|
|
import { Sidebar, SidebarSection, SECTIONS_CONFIG } from "./components/Sidebar";
|
|
import { useSettings } from "./hooks/useSettings";
|
|
|
|
const renderSettingsContent = (section: SidebarSection) => {
|
|
const ActiveComponent =
|
|
SECTIONS_CONFIG[section]?.component || SECTIONS_CONFIG.general.component;
|
|
return <ActiveComponent />;
|
|
};
|
|
|
|
function App() {
|
|
const [showOnboarding, setShowOnboarding] = useState<boolean | null>(null);
|
|
const [currentSection, setCurrentSection] =
|
|
useState<SidebarSection>("general");
|
|
const { settings, updateSetting } = useSettings();
|
|
|
|
useEffect(() => {
|
|
checkOnboardingStatus();
|
|
}, []);
|
|
|
|
// Handle keyboard shortcuts for debug mode toggle
|
|
useEffect(() => {
|
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
// Check for Ctrl+Shift+D (Windows/Linux) or Cmd+Shift+D (macOS)
|
|
const isDebugShortcut =
|
|
event.shiftKey &&
|
|
event.key.toLowerCase() === "d" &&
|
|
(event.ctrlKey || event.metaKey);
|
|
|
|
if (isDebugShortcut) {
|
|
event.preventDefault();
|
|
const currentDebugMode = settings?.debug_mode ?? false;
|
|
updateSetting("debug_mode", !currentDebugMode);
|
|
}
|
|
};
|
|
|
|
// Add event listener when component mounts
|
|
document.addEventListener("keydown", handleKeyDown);
|
|
|
|
// Cleanup event listener when component unmounts
|
|
return () => {
|
|
document.removeEventListener("keydown", handleKeyDown);
|
|
};
|
|
}, [settings?.debug_mode, updateSetting]);
|
|
|
|
const checkOnboardingStatus = async () => {
|
|
try {
|
|
// Always check if they have any models available
|
|
const modelsAvailable: boolean = await invoke("has_any_models_available");
|
|
setShowOnboarding(!modelsAvailable);
|
|
} catch (error) {
|
|
console.error("Failed to check onboarding status:", error);
|
|
setShowOnboarding(true);
|
|
}
|
|
};
|
|
|
|
const handleModelSelected = () => {
|
|
// Transition to main app - user has started a download
|
|
setShowOnboarding(false);
|
|
};
|
|
|
|
if (showOnboarding) {
|
|
return (
|
|
<div className="h-screen flex flex-col">
|
|
<div className="flex-1 flex flex-col items-center justify-center p-4 gap-4">
|
|
<HandyTextLogo width={200} />
|
|
<Onboarding onModelSelected={handleModelSelected} />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="h-screen flex flex-col">
|
|
<Toaster />
|
|
{/* Main content area that takes remaining space */}
|
|
<div className="flex-1 flex overflow-hidden">
|
|
<Sidebar
|
|
activeSection={currentSection}
|
|
onSectionChange={setCurrentSection}
|
|
/>
|
|
{/* Scrollable content area */}
|
|
<div className="flex-1 flex flex-col overflow-hidden">
|
|
<div className="flex-1 overflow-y-auto">
|
|
<div className="flex flex-col items-center p-4 gap-4">
|
|
<AccessibilityPermissions />
|
|
{renderSettingsContent(currentSection)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/* Fixed footer at bottom */}
|
|
<Footer />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default App;
|