feat: add Reduced motion setting and polish chrome, files, and stack-detail (#1501)

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).
This commit is contained in:
Anso
2026-06-28 06:18:02 -04:00
committed by GitHub
parent 083442d5ea
commit b5810a9b55
27 changed files with 489 additions and 119 deletions
@@ -9,7 +9,7 @@ import { useLicense } from '@/context/LicenseContext';
import { useNodes } from '@/context/NodeContext';
import { SENCHO_NAVIGATE_EVENT } from '@/components/NodeManager';
import type { SenchoNavigateDetail } from '@/components/NodeManager';
import type { SecurityTab } from '@/lib/events';
import type { SecurityTab, FleetTab } from '@/lib/events';
import type { SectionId } from '@/components/settings/types';
import type { ScheduleTaskPrefill } from '@/components/ScheduledOperationsView';
@@ -61,6 +61,7 @@ export function useViewNavigationState(options?: UseViewNavigationStateOptions)
const [activeView, setActiveView] = useState<ActiveView>('dashboard');
const [settingsSection, setSettingsSection] = useState<SectionId>('appearance');
const [securityTab, setSecurityTab] = useState<SecurityTab>('overview');
const [fleetTab, setFleetTab] = useState<FleetTab | null>(null);
const [filterNodeId, setFilterNodeId] = useState<number | null>(null);
const [schedulePrefill, setSchedulePrefill] = useState<ScheduleTaskPrefill | null>(null);
const [mobileNavOpen, setMobileNavOpen] = useState(false);
@@ -96,6 +97,14 @@ export function useViewNavigationState(options?: UseViewNavigationStateOptions)
setFilterNodeId(detail.nodeId ?? null);
return;
}
if (detail.view === 'fleet') {
// Set the target sub-tab before switching so the controlled FleetView
// lands on it (e.g. Snapshots from the stack storage warning).
if (detail.fleetTab) setFleetTab(detail.fleetTab);
setActiveView('fleet');
setFilterNodeId(detail.nodeId ?? null);
return;
}
setActiveView(detail.view as ActiveView);
setFilterNodeId(detail.nodeId ?? null);
};
@@ -146,6 +155,7 @@ export function useViewNavigationState(options?: UseViewNavigationStateOptions)
activeView, setActiveView,
settingsSection, setSettingsSection,
securityTab, setSecurityTab,
fleetTab, setFleetTab,
filterNodeId, setFilterNodeId,
schedulePrefill, setSchedulePrefill,
mobileNavOpen, setMobileNavOpen,