This commit is contained in:
2025-12-17 13:33:31 -05:00
parent e18aa3f42c
commit c49bfe5a3d
38 changed files with 2436 additions and 436 deletions

View File

@@ -6,7 +6,7 @@ interface Props {
hideFooter?: boolean;
}
import Themes from "astro-themes";
import { ClientRouter } from "astro:transitions";
import BaseHead from "../components/BaseHead.astro";
import { metaData } from "../config";
@@ -67,11 +67,16 @@ if (import.meta.env.DEV) {
<html lang="en" class="scrollbar-hide lenis lenis-smooth" data-subsite={isSubsite ? 'true' : 'false'}>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="googlebot"
content="index, follow, max-video-preview:-1, max-image-preview:large, max-snippet:-1"
/>
<Themes />
<meta name="color-scheme" content="dark light" />
<style is:inline>
html { visibility: hidden; }
html.ready { visibility: visible; }
html { background: #fff; }
html.dark { background: #121212; }
</style>
<script src="/scripts/theme-init.js" is:inline></script>
<ClientRouter />
<BaseHead title={whitelabel?.siteTitle ?? title} description={description} image={image ?? metaData.ogImage} isWhitelabel={!!whitelabel} whitelabel={whitelabel} subsite={detectedSubsite} />
<script>
import "@scripts/lenisSmoothScroll.js";
@@ -83,13 +88,13 @@ if (import.meta.env.DEV) {
scrollbar-hide"
style={`--brand-color: ${whitelabel?.brandColor ?? '#111827'}`}>
<!-- Nav is outside main to allow full-width -->
<div class="w-full">
<!-- Nav is outside main to allow full-width, sticky wrapper -->
<div class="w-full sticky top-0 z-50">
{whitelabel ? <SubNav whitelabel={whitelabel} subsite={detectedSubsite} /> : <Nav />}
</div>
<main
class="page-enter flex-auto min-w-0 mt-6 md:mt-8 flex flex-col px-4 sm:px-6 md:px-0 max-w-3xl w-full pb-8">
class="flex-auto min-w-0 mt-6 md:mt-8 flex flex-col px-4 sm:px-6 md:px-0 max-w-3xl w-full pb-8">
<noscript>
<div style="background: #f44336; color: white; padding: 1em; text-align: center;">
This site requires JavaScript to function. Please enable JavaScript in your browser.
@@ -99,9 +104,6 @@ if (import.meta.env.DEV) {
{!hideFooter && <Footer />}
</main>
<style>
/* Minimal page transition to replace deprecated ViewTransitions */
.page-enter { opacity: 0; transform: translateY(6px); transition: opacity 220ms ease, transform 240ms ease; }
html.page-ready .page-enter { opacity: 1; transform: none; }
/* CSS rules for the page scrollbar */
.scrollbar-hide::-webkit-scrollbar {
display: none;
@@ -112,20 +114,5 @@ if (import.meta.env.DEV) {
scrollbar-width: none;
}
</style>
<script>
// Mark the page ready so CSS transitions run (replaces ViewTransitions).
// We don't rely on any Astro-specific API here — just a small client-side toggle.
(function () {
try {
// Add page-ready on the next animation frame so the transition always runs.
if (typeof window !== 'undefined') {
requestAnimationFrame(() => document.documentElement.classList.add('page-ready'));
}
} catch (e) {
// no-op
}
})();
</script>
</body>
</html>

View File

@@ -46,7 +46,7 @@ const currentPath = Astro.url.pathname;
<script src="/scripts/nav-controls.js" defer data-api-url={API_URL}></script>
<nav class="w-full px-4 sm:px-6 py-3 sticky top-0 z-50 backdrop-blur-xl bg-white/75 dark:bg-[#0a0a0a]/75 border-b border-neutral-200/40 dark:border-neutral-800/40 shadow-sm shadow-neutral-900/5 dark:shadow-black/20">
<nav class="w-full px-4 sm:px-6 py-3 backdrop-blur-xl bg-white/75 dark:bg-[#0a0a0a]/75 border-b border-neutral-200/40 dark:border-neutral-800/40 shadow-sm shadow-neutral-900/5 dark:shadow-black/20">
<div class="max-w-7xl mx-auto">
<div class="nav-bar-row flex items-center gap-4 justify-between">
<!-- Logo/Brand -->
@@ -62,6 +62,7 @@ const currentPath = Astro.url.pathname;
{visibleNavItems.map((item) => {
const isExternal = item.href?.startsWith("http");
const isAuthedPath = item.auth ?? false;
const isTRipLink = item.href?.startsWith("/TRip");
const normalize = (url) => (url || '/').replace(/\/+$/, '') || '/';
const normalizedCurrent = normalize(currentPath);
const normalizedHref = normalize(item.href);
@@ -82,6 +83,7 @@ const currentPath = Astro.url.pathname;
target={isExternal ? "_blank" : undefined}
rel={(isExternal || isAuthedPath) ? "external" : undefined}
onclick={item.onclick}
data-astro-reload={isTRipLink ? true : undefined}
>
{item.label}
{item.icon === "external" && (
@@ -166,6 +168,7 @@ const currentPath = Astro.url.pathname;
{visibleNavItems.map((item) => {
const isExternal = item.href?.startsWith("http");
const isAuthedPath = item.auth ?? false;
const isTRipLink = item.href?.startsWith("/TRip");
const normalize = (url) => (url || '/').replace(/\/+$/, '') || '/';
const normalizedCurrent = normalize(currentPath);
const normalizedHref = normalize(item.href);
@@ -179,16 +182,17 @@ const currentPath = Astro.url.pathname;
<li>
<a
href={item.href}
class={isActive
class={isActive
? "flex items-center gap-0 px-4 py-3 rounded-lg text-base font-medium transition-all duration-200 text-white"
: "flex items-center gap-0 px-4 py-3 rounded-lg text-base font-medium transition-all duration-200 text-neutral-700 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-800"
: "flex items-center gap-0 px-4 py-3 rounded-lg text-base font-medium transition-all duration-200 text-neutral-700 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-800"
}
style={isActive ? `background: #111827` : undefined}
target={isExternal ? "_blank" : undefined}
rel={(isExternal || isAuthedPath) ? "external" : undefined}
onclick={item.onclick}
data-astro-reload={isTRipLink ? true : undefined}
>
<span>{item.label}</span>
<span style="color:inherit;">{item.label}</span>
{item.icon === "external" && (
<span class="inline-flex ml-0.5" aria-hidden="true" set:html={externalLinkIconSvg}></span>
)}

View File

@@ -0,0 +1,107 @@
---
/**
* SubsiteBase.astro - Lightweight base layout for subsites
*
* This layout excludes heavy CSS/JS from the main site to reduce payload.
* It does NOT import AppLayout or its dependencies.
*/
interface Props {
title?: string;
description?: string;
image?: string;
hideFooter?: boolean;
}
import { ClientRouter } from "astro:transitions";
import BaseHead from "../components/BaseHead.astro";
import { metaData } from "../config";
import Footer from "../components/Footer.astro";
// Minimal font imports for subsites
import "@fontsource/ibm-plex-sans/500.css";
import "@fontsource/geist-sans/400.css";
import "@styles/global.css";
const { title, description, image, hideFooter = false } = Astro.props;
const hostHeader = Astro.request?.headers?.get('host') || '';
const host = hostHeader.split(':')[0];
import { getSubsiteByHost, getSubsiteFromSignal, getSubsiteByPath } from '../utils/subsites.js';
import { WHITELABELS } from "../config";
const detectedSubsite = getSubsiteByHost(host) ?? getSubsiteByPath(Astro.url.pathname) ?? null;
const isReq = detectedSubsite?.short === 'req';
// Accept forced whitelabel via query param, headers or request locals
const forcedParam = Astro.url.searchParams.get('whitelabel') || Astro.request?.headers?.get('x-whitelabel') || (Astro.request as any)?.locals?.whitelabel || null;
let whitelabel: any = null;
if (forcedParam) {
const forced = getSubsiteFromSignal(forcedParam);
if (forced) whitelabel = WHITELABELS[forced.host] ?? null;
}
if (!whitelabel) {
whitelabel = WHITELABELS[host] ?? (isReq ? WHITELABELS[detectedSubsite.host] : null);
}
---
<html lang="en" class="scrollbar-hide" data-subsite="true">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="color-scheme" content="dark light" />
<style is:inline>
html { visibility: hidden; }
html.ready { visibility: visible; }
html { background: #fff; }
html.dark { background: #121212; }
</style>
<script src="/scripts/theme-init.js" is:inline></script>
<ClientRouter />
<BaseHead title={whitelabel?.siteTitle ?? title} description={description} image={image ?? metaData.ogImage} isWhitelabel={!!whitelabel} whitelabel={whitelabel} subsite={detectedSubsite} />
</head>
<body
class="antialiased flex flex-col items-center mx-auto min-h-screen scrollbar-hide"
style={`--brand-color: ${whitelabel?.brandColor ?? '#111827'}`}>
<!-- Lightweight nav for subsites -->
<div class="w-full sticky top-0 z-50">
<script src="/scripts/nav-controls.js" defer></script>
<nav class="w-full px-4 sm:px-6 py-3 backdrop-blur-xl bg-white/75 dark:bg-[#0a0a0a]/75 border-b border-neutral-200/40 dark:border-neutral-800/40 shadow-sm">
<div class="max-w-7xl mx-auto">
<div class="flex items-center justify-between">
<a href="/" class="text-xl font-bold tracking-tight bg-gradient-to-r from-neutral-900 to-neutral-600 dark:from-white dark:to-neutral-400 bg-clip-text text-transparent hover:opacity-80 transition-opacity">
{whitelabel?.logoText ?? detectedSubsite?.short?.toUpperCase() ?? 'Subsite'}
</a>
<button
aria-label="Toggle theme"
type="button"
class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-neutral-100 dark:hover:bg-neutral-800 transition-colors"
onclick="toggleTheme()"
>
<svg class="h-4 w-4 text-neutral-700 dark:text-neutral-300" viewBox="0 0 512 512" fill="currentColor">
<path d="M448 256c0-106-86-192-192-192v384c106 0 192-86 192-192M0 256a256 256 0 1 1 512 0a256 256 0 1 1-512 0"/>
</svg>
</button>
</div>
</div>
</nav>
</div>
<main class="flex-auto min-w-0 mt-6 md:mt-8 flex flex-col px-4 sm:px-6 md:px-0 max-w-3xl w-full pb-8">
<noscript>
<div style="background: #f44336; color: white; padding: 1em; text-align: center;">
This site requires JavaScript to function. Please enable JavaScript in your browser.
</div>
</noscript>
<slot />
{!hideFooter && <Footer />}
</main>
<style is:global>
.scrollbar-hide::-webkit-scrollbar { display: none; }
.scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; }
</style>
</body>
</html>