68 lines
2.0 KiB
TypeScript
68 lines
2.0 KiB
TypeScript
|
|
import React, { createContext, useContext, useMemo } from 'react';
|
||
|
|
import { resolveTheme, type ShadeTheme, type ThemeMode } from './theme.js';
|
||
|
|
|
||
|
|
export interface ShadeContextValue {
|
||
|
|
observerUrl: string;
|
||
|
|
token: string;
|
||
|
|
theme: ShadeTheme;
|
||
|
|
pollIntervalMs: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
const ShadeContext = createContext<ShadeContextValue | null>(null);
|
||
|
|
|
||
|
|
export interface ShadeProviderProps {
|
||
|
|
/** Base URL of the Shade observer endpoint, e.g. "https://shade.example.com/shade-observer" */
|
||
|
|
observerUrl: string;
|
||
|
|
/** Bearer token for the observer (matches SHADE_OBSERVER_TOKEN on the server) */
|
||
|
|
token: string;
|
||
|
|
/** Theme mode: dark, light, or auto (matches system preference). Default: dark. */
|
||
|
|
themeMode?: ThemeMode;
|
||
|
|
/** How often to poll /api/state in milliseconds. Default: 5000. */
|
||
|
|
pollIntervalMs?: number;
|
||
|
|
children: React.ReactNode;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ShadeProvider — root context provider that all Shade widgets need.
|
||
|
|
*
|
||
|
|
* Wrap your dashboard or specific widget container with this and pass
|
||
|
|
* the observer URL + token. All child widgets will share the connection.
|
||
|
|
*
|
||
|
|
* ```tsx
|
||
|
|
* <ShadeProvider observerUrl="https://x.com/shade-observer" token={process.env.TOKEN!}>
|
||
|
|
* <SessionList />
|
||
|
|
* <PrekeyStock />
|
||
|
|
* </ShadeProvider>
|
||
|
|
* ```
|
||
|
|
*/
|
||
|
|
export function ShadeProvider({
|
||
|
|
observerUrl,
|
||
|
|
token,
|
||
|
|
themeMode = 'dark',
|
||
|
|
pollIntervalMs = 5000,
|
||
|
|
children,
|
||
|
|
}: ShadeProviderProps): React.ReactElement {
|
||
|
|
const value = useMemo<ShadeContextValue>(
|
||
|
|
() => ({
|
||
|
|
observerUrl: observerUrl.replace(/\/$/, ''),
|
||
|
|
token,
|
||
|
|
theme: resolveTheme(themeMode),
|
||
|
|
pollIntervalMs,
|
||
|
|
}),
|
||
|
|
[observerUrl, token, themeMode, pollIntervalMs],
|
||
|
|
);
|
||
|
|
|
||
|
|
return <ShadeContext.Provider value={value}>{children}</ShadeContext.Provider>;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Internal hook used by widgets to access the context. Throws if no provider. */
|
||
|
|
export function useShadeContext(): ShadeContextValue {
|
||
|
|
const ctx = useContext(ShadeContext);
|
||
|
|
if (!ctx) {
|
||
|
|
throw new Error(
|
||
|
|
'Shade widgets must be wrapped in <ShadeProvider observerUrl="..." token="..." />',
|
||
|
|
);
|
||
|
|
}
|
||
|
|
return ctx;
|
||
|
|
}
|