Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.skyvexsoftware.com/llms.txt

Use this file to discover all available pages before exploring further.

If your plugin needs more than one page, you implement routing inside your root component. The shell doesn’t impose a router — you match the current path and render the appropriate page.

How Routing Works

When your plugin is active, the shell’s URL path looks like:
/plugins/{your-plugin-id}/overview
/plugins/{your-plugin-id}/roster
/plugins/{your-plugin-id}/roster/pilot-123
Your root component reads the current path, strips the plugin prefix, and renders the matching page.

Basic Router Pattern

import { usePluginContext } from "@skyvexsoftware/stratos-sdk";
import OverviewPage from "./pages/OverviewPage";
import RosterPage from "./pages/RosterPage";
import PilotDetailPage from "./pages/PilotDetailPage";

function useSubPath(): string {
  const ctx = usePluginContext();
  const fullPath = ctx.navigation.getCurrentPath();
  const prefix = `/plugins/${ctx.pluginId}/`;
  return fullPath.startsWith(prefix) ? fullPath.slice(prefix.length) : "";
}

function Router() {
  const subPath = useSubPath() || "overview";

  // Dynamic routes — match before static routes
  const pilotMatch = subPath.match(/^roster\/(.+)$/);
  if (pilotMatch) return <PilotDetailPage pilotId={pilotMatch[1]} />;

  // Static routes
  if (subPath === "roster") return <RosterPage />;
  return <OverviewPage />;
}

export default function MyPlugin() {
  return <Router />;
}
Use useShellNavigation() to navigate between sub-pages:
import { useShellNavigation } from "@skyvexsoftware/stratos-sdk";

function OverviewPage() {
  const nav = useShellNavigation();

  return (
    <button onClick={() => nav.navigateTo("roster")}>
      View Roster
    </button>
  );
}
const nav = useShellNavigation();

// Navigate within your plugin (relative path)
nav.navigateTo("roster");
nav.navigateTo("roster/pilot-123");

// Navigate to another plugin
nav.navigateToPlugin("flight-tracking", "history");

// Navigate to a shell page
nav.navigateToShell("settings");

// Read the current full path
const path = nav.getCurrentPath();

Reading Route Params

For dynamic segments, extract params yourself from the sub-path:
function useSubPath(): string {
  const ctx = usePluginContext();
  const fullPath = ctx.navigation.getCurrentPath();
  const prefix = `/plugins/${ctx.pluginId}/`;
  return fullPath.startsWith(prefix) ? fullPath.slice(prefix.length) : "";
}

function PilotDetailPage() {
  const subPath = useSubPath();
  // subPath === "roster/pilot-abc-123"
  const pilotId = subPath.split("/")[1];

  // fetch pilot by pilotId...
}
Or parse it at the router level and pass as props:
function Router() {
  const subPath = useSubPath() || "overview";

  const pilotMatch = subPath.match(/^roster\/(.+)$/);
  if (pilotMatch) {
    return <PilotDetailPage pilotId={pilotMatch[1]} />;
  }

  if (subPath === "roster") return <RosterPage />;
  return <OverviewPage />;
}

Full Example

A plugin with three pages: Overview, Roster, and Pilot Detail.
src/
├── ui/
│   └── index.tsx          ← root component with router
├── pages/
│   ├── OverviewPage.tsx
│   ├── RosterPage.tsx
│   └── PilotDetailPage.tsx
src/ui/index.tsx:
import { usePluginContext } from "@skyvexsoftware/stratos-sdk";
import OverviewPage from "../pages/OverviewPage";
import RosterPage from "../pages/RosterPage";
import PilotDetailPage from "../pages/PilotDetailPage";

function useSubPath(): string {
  const ctx = usePluginContext();
  const fullPath = ctx.navigation.getCurrentPath();
  const prefix = `/plugins/${ctx.pluginId}/`;
  return fullPath.startsWith(prefix) ? fullPath.slice(prefix.length) : "";
}

function Router() {
  const subPath = useSubPath() || "overview";

  const pilotMatch = subPath.match(/^roster\/(.+)$/);
  if (pilotMatch) return <PilotDetailPage pilotId={pilotMatch[1]} />;

  if (subPath === "roster") return <RosterPage />;
  return <OverviewPage />;
}

export default function MyPlugin() {
  return (
    <div className="flex h-full flex-col overflow-y-auto">
      <Router />
    </div>
  );
}
src/pages/OverviewPage.tsx:
import { useShellNavigation, Button } from "@skyvexsoftware/stratos-sdk";

export default function OverviewPage() {
  const nav = useShellNavigation();

  return (
    <div className="p-6">
      <h1 className="text-2xl font-bold">Overview</h1>
      <Button className="mt-4" onClick={() => nav.navigateTo("roster")}>
        View Roster
      </Button>
    </div>
  );
}
src/pages/RosterPage.tsx:
import { useShellNavigation } from "@skyvexsoftware/stratos-sdk";

type Pilot = { id: string; name: string };

export default function RosterPage({ pilots }: { pilots: Pilot[] }) {
  const nav = useShellNavigation();

  return (
    <div className="p-6">
      <h1 className="text-2xl font-bold">Roster</h1>
      <ul className="mt-4 space-y-2">
        {pilots.map((pilot) => (
          <li
            key={pilot.id}
            className="cursor-pointer rounded border p-3 hover:bg-muted"
            onClick={() => nav.navigateTo(`roster/${pilot.id}`)}
          >
            {pilot.name}
          </li>
        ))}
      </ul>
    </div>
  );
}