Layout & Sidebar
The Layout component is the full app shell — sidebar navigation, session context, mobile drawer, and user dropdown. Every page in an SM product app is a child of Layout.
Usage
import { Layout } from '@nomadahq/sm-ui'
import '@nomadahq/sm-ui/css'
import '@nomadahq/sm-ui/css/shell'
import '@nomadahq/sm-ui/css/components'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
// Define nav for your product
const NAV = {
'mode': {
label: 'Mode',
items: [
{ to: '/discovery', label: 'Discovery', step: 1 },
{ to: '/scan', label: 'Scan', step: 2 },
{ to: '/results', label: 'Results', step: 3 },
{ to: '/billing', label: 'Billing', icon: 'bill' },
]
}
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout navConfig={NAV} />}>
<Route path="discovery" element={<Discovery />} />
<Route path="scan" element={<Scan />} />
</Route>
</Routes>
</BrowserRouter>
)
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
navConfig | object | {} | Product nav sections. Merged with SM defaults. |
logoSrc | string | SM logo | Override logo in sidebar header |
logoAlt | string | "Sprint Mode" | Logo alt text |
onLogout | function | clears cookie → /auth/login | Custom logout handler |
profilePath | string | "/profile" | Where profile dropdown links go |
Nav Config Format
const NAV = {
// Key must match the product name in the user's JWT `products[]`
'your-product': {
label: 'Your Product',
items: [
// Icon-based nav item
{ to: '/dashboard', label: 'Dashboard', icon: 'grid', exact: true },
{ to: '/clients', label: 'Clients', icon: 'users' },
// Step-based nav item (shows numbered step badge instead of icon)
{ to: '/step-one', label: 'Step One', step: 1 },
{ to: '/step-two', label: 'Step Two', step: 2 },
]
}
}Available icon names: grid, users, bill, code, trend, portfolio, file, msg, gear, dollar
Default Nav Sections
Layout ships with pre-built nav for SM products. These show automatically when the logged-in user's products[] contains that key:
| Key | Section |
|---|---|
sprint-mode | Sprint Mode (Dashboard, Team) — always shown if user has any product |
studios | Studios (Dashboard, Billing) |
mode | Mode (7 workflow steps + Billing) |
investor | Investor (Overview, Portfolio, Documents, Updates) |
Products pass navConfig to add or override sections.
Session Context
Layout fetches the user session from SM API on mount and provides it via React context. If no session exists, the user is redirected to /auth/login.
import { useSession } from '@nomadahq/sm-ui'
function Dashboard() {
const session = useSession()
// session: { id, email, name, avatar, products[], iat, exp }
return <h1>Welcome, {session.name}</h1>
}useSession() returns null only if called outside of Layout. Since Layout redirects on missing session, any page rendered inside Layout will always have a valid session.
Auth Redirect Flow
Layoutmounts → callsfetchSession()(GET/auth/me)- If 401 →
navigate('/auth/login?redirect=' + currentPath) - Login page → Google SSO or magic link → SM API sets
sm_clientcookie - SM API redirects back to
redirectparam →Layoutloads, session exists - Pages render normally
The login page must be at /auth/login in your router and must render the Login component. See Login Component.
