mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-17 14:08:19 +00:00
b5810a9b55
A batch of UI/UX polish: - New independent "Reduced motion" appearance setting (separate from Reduced effects). Drives framer-motion via MotionConfig and clamps CSS transitions via data-motion on <html>; toasts are unaffected. Defaults off (OS preference still honored). - Stack-detail Files tab: rename "Files & Volumes" to "Files", add a persisted word-wrap toggle to the file viewer (default on), and add a fullscreen toggle that collapses the Command Center + Logs column so the editor fills the width. - Create Stack > From Git: remove the nested scroll clamp so the deploy toggle and footer are reachable. - Fleet: full-width tab band with icon-only Refresh / Export Dossier, icon-only Check-for-updates / Add-node on the Overview toolbar, theme-aware empty-state headings (calm drops the italic), and fix the Actions card body overlapping the action-row divider. - Snapshots: restyle Restore and Restore all to the ghost button design used by View / Preview / Download, and right-align the per-stack Restore. - Settings sidebar: App Store gradient active style and standard font size. - Compose Doctor: dismiss the high-risk banner (and clear the tab dot) until the findings change, via a shared fingerprint-keyed hook. - Stack-detail Storage: link the "no recent fleet snapshot" warning to the Fleet Snapshots tab (FleetView tabs are now controlled to support the deep link).
79 lines
2.4 KiB
TypeScript
79 lines
2.4 KiB
TypeScript
import type { ReactNode } from 'react';
|
|
import { MotionConfig } from 'motion/react';
|
|
import { AuthProvider, useAuth } from './context/AuthContext';
|
|
import { useReducedMotion } from './hooks/use-theme';
|
|
import { NodeProvider } from './context/NodeContext';
|
|
import { LicenseProvider } from './context/LicenseContext';
|
|
import { Login } from './components/Login';
|
|
import { Setup } from './components/Setup';
|
|
import EditorLayout from './components/EditorLayout';
|
|
import { MfaChallenge } from './components/MfaChallenge';
|
|
import { DeployFeedbackProvider } from './context/DeployFeedbackContext';
|
|
import { DeployFeedbackPortal } from './components/DeployFeedbackPortal';
|
|
import { ToastContainer } from './components/ui/toast';
|
|
|
|
/** Gates framer-motion animations on the "Reduced motion" appearance setting.
|
|
* 'always' suppresses transform/layout motion app-wide; 'user' defers to the OS
|
|
* prefers-reduced-motion. Sonner toasts do not use framer-motion, so they are
|
|
* unaffected. Subscribes only to the motion flag to avoid re-rendering the app
|
|
* tree on unrelated theme changes. */
|
|
function MotionProvider({ children }: { children: ReactNode }) {
|
|
const reducedMotion = useReducedMotion();
|
|
return (
|
|
<MotionConfig reducedMotion={reducedMotion ? 'always' : 'user'}>
|
|
{children}
|
|
</MotionConfig>
|
|
);
|
|
}
|
|
|
|
function AppContent() {
|
|
const { appStatus, isAuthenticated, needsSetup, completeSetup } = useAuth();
|
|
|
|
if (appStatus === 'loading') {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center app-canvas">
|
|
<div className="text-muted-foreground">Loading...</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (needsSetup) {
|
|
return <Setup onComplete={completeSetup} />;
|
|
}
|
|
|
|
if (appStatus === 'mfaChallenge') {
|
|
return <MfaChallenge />;
|
|
}
|
|
|
|
if (!isAuthenticated) {
|
|
return <Login />;
|
|
}
|
|
|
|
return (
|
|
<MotionProvider>
|
|
<NodeProvider>
|
|
<LicenseProvider>
|
|
<EditorLayout />
|
|
{/* Portal lives inside LicenseProvider so the editor surface and its
|
|
portalled overlays can read license state via useLicense().
|
|
Outer DeployFeedbackProvider is still an ancestor through App. */}
|
|
<DeployFeedbackPortal />
|
|
</LicenseProvider>
|
|
</NodeProvider>
|
|
</MotionProvider>
|
|
);
|
|
}
|
|
|
|
function App() {
|
|
return (
|
|
<AuthProvider>
|
|
<DeployFeedbackProvider>
|
|
<AppContent />
|
|
</DeployFeedbackProvider>
|
|
<ToastContainer />
|
|
</AuthProvider>
|
|
);
|
|
}
|
|
|
|
export default App;
|