File size: 3,378 Bytes
00a4363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { NavLink, Outlet, Navigate } from "react-router-dom";
import { useAuth } from "../hooks/useAuth";
import Logo from "./Logo";
import SkyCanvas from "./SkyCanvas";
import {
  AsteroidIcon,
  CometIcon,
  ConstellationIcon,
  HelmetIcon,
  LaunchpadIcon,
  LaunchWindowIcon,
  OrbitIcon,
  PlanetIcon,
  RadarIcon,
  RocketIcon,
  SatelliteDishIcon,
} from "./icons/Icons";

// Theme in the icon, clarity in the label: the plain label always shows.
const NAV = [
  { to: "/app", label: "Mission Control", icon: RadarIcon, end: true },
  { to: "/app/notebooks", label: "Notebooks", icon: PlanetIcon },
  { to: "/app/sources", label: "Sources", icon: SatelliteDishIcon },
  { to: "/app/map", label: "Topic map", icon: ConstellationIcon },
  { to: "/app/voice", label: "Voice profile", icon: HelmetIcon },
  { to: "/app/studio", label: "Video and audio", icon: LaunchWindowIcon },
  { to: "/app/launch-kit", label: "Launch Kit", icon: RocketIcon },
  { to: "/app/launchpad", label: "Launchpad", icon: LaunchpadIcon },
  { to: "/app/archive", label: "Archive", icon: AsteroidIcon },
  { to: "/app/resurface", label: "Resurfacing", icon: CometIcon },
  { to: "/app/settings", label: "Settings", icon: OrbitIcon },
];

export default function AppShell() {
  const { user, loading, logout } = useAuth();
  if (loading) return <div className="boot"><div className="orbit-loader"><span /></div></div>;
  if (!user) return <Navigate to="/auth" replace />;

  return (
    <div className="shell">
      <SkyCanvas intensity={0.35} />
      <aside className="sidebar">
        <NavLink to="/" className="sidebar-brand">
          <Logo size={28} />
        </NavLink>
        <nav aria-label="App">
          {NAV.map(({ to, label, icon: Icon, end }) => (
            <NavLink key={to} to={to} end={end} className={({ isActive }) => `side-link${isActive ? " active" : ""}`}>
              <Icon />
              <span>{label}</span>
            </NavLink>
          ))}
        </nav>
        <div className="sidebar-user">
          <span className="mono muted">{user.email}</span>
          <button className="link-btn" onClick={logout}>
            Sign out
          </button>
        </div>
      </aside>
      <main className="shell-main">
        <Outlet />
      </main>
    </div>
  );
}

export function ComingSoon({ title, phase }: { title: string; phase: string }) {
  return (
    <div className="empty-state">
      <svg width="120" height="90" viewBox="0 0 120 90" fill="none" aria-hidden="true" className="empty-art">
        <circle cx="84" cy="30" r="16" stroke="currentColor" strokeWidth="1.5" />
        <circle cx="78" cy="26" r="3" stroke="currentColor" strokeWidth="1.5" opacity="0.5" />
        <circle cx="90" cy="36" r="2" stroke="currentColor" strokeWidth="1.5" opacity="0.5" />
        <path d="M20 70l14-8 6 10-14 8z" stroke="currentColor" strokeWidth="1.5" />
        <path d="M34 62l10-6M26 80l-6 6" stroke="currentColor" strokeWidth="1.5" />
        <circle cx="12" cy="20" r="1" fill="currentColor" />
        <circle cx="50" cy="12" r="1" fill="currentColor" />
        <circle cx="108" cy="72" r="1" fill="currentColor" />
      </svg>
      <h1>{title}</h1>
      <p className="muted">This part of the station comes online in {phase}.</p>
      <NavLink to="/app" className="btn">
        Back to Mission Control
      </NavLink>
    </div>
  );
}