Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added dashboard/app/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dashboard/app/favicon.ico
Binary file not shown.
Binary file added dashboard/app/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 11 additions & 26 deletions dashboard/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ import { Nav } from '../components/nav';
import { Footer } from '../components/footer';
import './globals.css';

// Self-hosted Geist (no network fetch) for UI + tabular numbers; Space Grotesk
// (display) only for large headings, to give the site a real type pairing
// instead of a single-font, system-ui look.
const display = Space_Grotesk({
subsets: ['latin'],
weight: ['500', '600', '700'],
Expand All @@ -24,38 +21,30 @@ export const metadata: Metadata = {
},
description:
'Continuous, on-chain-derived safety scores for Stellar/Soroban DeFi protocols. Audits are a snapshot; Stenion tracks risk as it moves.',
icons: {
icon: '/icon.png',
shortcut: '/favicon.ico',
apple: '/apple-touch-icon.png',
},
twitter: {
card: 'summary_large_image',
title: 'Stenion — live risk intelligence for Stellar DeFi',
description:
'Continuous, on-chain-derived safety scores for Stellar/Soroban DeFi protocols. Audits are a snapshot; Stenion tracks risk as it moves.',
},
};

// Resolve the theme BEFORE first paint. This is a blocking inline script in
// <head>, deliberately not a useEffect — an effect runs after hydration, which
// is precisely when the wrong-theme flash happens.
//
// It only writes `data-theme` for an EXPLICIT light/dark choice. "System" is
// the absence of the attribute, which lets the `prefers-color-scheme` block in
// globals.css apply on its own — so system mode needs no JS at all, keeps
// following the OS live, and still paints correctly if this script fails.
const THEME_INIT = `(function(){try{var c=localStorage.getItem('stenion-theme');var d=document.documentElement;if(c==='light'||c==='dark'){d.setAttribute('data-theme',c)}else{d.removeAttribute('data-theme')}}catch(e){}})()`;

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
// suppressHydrationWarning: the script above mutates `data-theme` before
// React hydrates, so the server HTML and the live DOM differ by design.
<html
lang="en"
suppressHydrationWarning
data-scroll-behavior="smooth"
className={`${GeistSans.variable} ${GeistMono.variable} ${display.variable}`}
>
<body className="min-h-screen bg-bg text-ink antialiased">
{/* FIRST child of <body>, and deliberately NOT inside a <head> element.
Inside <head> this is part of the React tree Next may stream: on a
route that calls notFound() the head is already flushed, so the tag
arrived only in the RSC payload as serialised JSON and never
executed — /protocol/<unknown-id> rendered in the wrong theme while
every other route was fine. At the top of <body> it is always in the
initial shell. It still runs before first paint: the stylesheet is
already in <head>, and a synchronous inline script blocks parsing,
so the attribute is set before any body content is laid out. */}
<script dangerouslySetInnerHTML={{ __html: THEME_INIT }} />
<a
href="#main-content"
Expand All @@ -66,10 +55,6 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<Nav />
<main id="main-content">{children}</main>
<Footer />
{/* Vercel Analytics — client component that injects the pageview script.
Renders no markup, so it sits last and can't affect layout. Pageviews
only: no props, no custom events, and nothing protocol- or score-related
is ever passed to it. */}
<Analytics />
</body>
</html>
Expand Down
Loading