// Root app: hash-based router + tweaks panel + accent color binding.
const { useState, useEffect, useMemo } = React;
const DEFAULT_TWEAKS = /*EDITMODE-BEGIN*/{
"accent": "#7c7cff",
"heroDensity": 1.6,
"glassOpacity": 5,
"metagraphEnabled": false
}/*EDITMODE-END*/;
function useHashRoute() {
const [route, setRoute] = useState(() => (window.location.hash || '#/').slice(1) || '/');
useEffect(() => {
const onHash = () => setRoute((window.location.hash || '#/').slice(1) || '/');
window.addEventListener('hashchange', onHash);
return () => window.removeEventListener('hashchange', onHash);
}, []);
const navigate = (path) => {
if (!path.startsWith('/')) path = '/' + path;
window.location.hash = '#' + path;
window.scrollTo({ top: 0, behavior: 'instant' });
};
return [route, navigate];
}
function App() {
const [route, navigate] = useHashRoute();
const [tweaks, setTweak] = useTweaks(DEFAULT_TWEAKS);
// Sync env flag with tweak so toggling the tweak hides the route too.
useEffect(() => {
window.__ENV.METAGRAPH_ENABLED = !!tweaks.metagraphEnabled;
}, [tweaks.metagraphEnabled]);
// Push accent to CSS vars
useEffect(() => {
const root = document.documentElement;
root.style.setProperty('--accent', tweaks.accent);
// derive a near-accent for the gradient end
root.style.setProperty('--accent-2', mix(tweaks.accent, '#ffffff', 0.35));
root.style.setProperty('--accent-glow', hexToRgba(tweaks.accent, 0.35));
}, [tweaks.accent]);
// Push glass tint to CSS vars. Slider goes 0–100; we map to a tint alpha
// that goes from "barely there" (0.01) to "clearly visible glass" (0.20).
useEffect(() => {
const root = document.documentElement;
const t = Math.max(0, Math.min(100, tweaks.glassOpacity ?? 30)) / 100;
const tint = 0.01 + t * 0.19; // 0.01 .. 0.20
const tintLow = tint * 0.3; // gradient endpoint
root.style.setProperty('--lg-tint', tint.toFixed(3));
root.style.setProperty('--lg-tint-low', tintLow.toFixed(3));
}, [tweaks.glassOpacity]);
// Document title per route
useEffect(() => {
const titles = {
'/': 'graphite · structured world knowledge',
'/graphs': 'Knowledge Graphs · graphite',
'/graphs/financial': 'Financial Knowledge Graph · graphite',
'/metagraph': 'Metagraph · graphite',
'/portal': 'API Portal · graphite',
'/pricing': 'Pricing · graphite',
'/admin': 'Admin · graphite',
};
document.title = titles[route] || 'graphite';
}, [route]);
// /admin renders full-screen (no global Nav, its own header) so we
// branch on it before the rest of the routing.
if (route === '/admin') {
return METAGRAPH_ENABLED in env.js. Off → tab disappears and the route stops resolving.
{reason || "We couldn't find that page."}
{e.preventDefault();navigate('/');}}>Back to home