fix: subdomain routing fixed, favicon bundles
This commit is contained in:
@@ -60,10 +60,10 @@ describe("resolvePageHeadMeta — canonical URL derivation", () => {
|
||||
expect(meta.canonical).toBe("https://nessa.freno.me/contact");
|
||||
});
|
||||
|
||||
// The in-app subdomain middleware (src/middleware.ts) rewrites the internal
|
||||
// request path to the prefix form (/nessa/contact) before the SolidStart
|
||||
// router matches it. useLocation() therefore reports the prefixed path, and
|
||||
// resolvePageHeadMeta must strip the prefix so the canonical stays public.
|
||||
// Subdomain routing is host-aware (root routes dispatch by useSite()), so
|
||||
// useLocation() normally reports the public path. resolvePageHeadMeta also
|
||||
// defensively strips a subdomain prefix from a prefixed pathname, so the
|
||||
// canonical stays public even if the prefixed form ever appears.
|
||||
it("nessa prefixed /nessa/contact → https://nessa.freno.me/contact", () => {
|
||||
const meta = resolvePageHeadMeta(
|
||||
BASE_PROPS,
|
||||
|
||||
@@ -12,13 +12,13 @@ import { For, Show } from "solid-js";
|
||||
import { A, useLocation } from "@solidjs/router";
|
||||
import { useSite } from "~/context/SiteContext";
|
||||
import { useDarkMode } from "~/context/darkMode";
|
||||
import { NAV_CONFIG, BACK_TO_FRENO } from "~/lib/nav-config";
|
||||
import { NAV_CONFIG } from "~/lib/nav-config";
|
||||
import { DarkModeToggle } from "~/components/DarkModeToggle";
|
||||
|
||||
export default function SubdomainHeader() {
|
||||
const site = useSite();
|
||||
const location = useLocation();
|
||||
const { isDark, toggleDarkMode } = useDarkMode();
|
||||
const { isDark } = useDarkMode();
|
||||
|
||||
const brandName = () => site().displayName;
|
||||
const brandColor = () =>
|
||||
@@ -32,10 +32,7 @@ export default function SubdomainHeader() {
|
||||
};
|
||||
|
||||
return (
|
||||
<header
|
||||
class="sticky top-0 z-50 w-full border-b backdrop-blur-md"
|
||||
classList={{ "bg-base/80 border-surface0": site().headerOpaque }}
|
||||
>
|
||||
<header class="bg-base/80 border-surface0 sticky top-0 z-50 w-full border-b backdrop-blur-md">
|
||||
<div class="mx-auto flex h-14 max-w-7xl items-center justify-between px-4">
|
||||
<A
|
||||
href="/"
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
* - `title` → `props.title + site.titleSuffix`
|
||||
* - `canonical` → explicit `props.canonical` override wins; otherwise
|
||||
* `https://${site.domain}${pathname}` where `pathname` is the *public*
|
||||
* browser path. Because the subdomain prefix (`/lineage`, `/nessa`, …) is
|
||||
* an internal-only rewrite (applied by `vercel.json` host rewrites or, in
|
||||
* their absence, by `src/middleware.ts`), `useLocation()` reports the
|
||||
* prefixed path (`/lineage/privacy`) and we strip the prefix back off so
|
||||
* the canonical reflects the public URL (`https://lineage.freno.me/privacy`).
|
||||
* browser path. Subdomain routing is host-aware (root routes dispatch by
|
||||
* `useSite()`, see `src/routes/index.tsx`/`privacy.tsx`/`deletion.tsx`),
|
||||
* so `useLocation()` already reports the public path. The defensive
|
||||
* prefix-strip below also handles any legacy prefixed form, so the canonical
|
||||
* is always the public URL.
|
||||
* - `ogImage` → explicit `props.ogImage` wins; otherwise `site.ogDefaultImage`.
|
||||
* - `ogTitle` / `ogDescription` → explicit override wins; otherwise fall
|
||||
* back to the base title (no suffix) / description (existing behavior).
|
||||
@@ -56,13 +56,11 @@ export function resolvePageHeadMeta(
|
||||
): ResolvedPageHeadMeta {
|
||||
const title = `${props.title}${site.titleSuffix}`;
|
||||
/**
|
||||
* The canonical URL is the *public* browser URL, never the internal route
|
||||
* prefix. SolidStart's file router is host-blind, so subdomain routes live
|
||||
* under `src/routes/<prefix>/*` and are served either by `vercel.json` host
|
||||
* rewrites OR by `src/middleware.ts` (the in-app host rewrite). Both append
|
||||
* the prefix to the internal request path (`/privacy` → `/lineage/privacy`),
|
||||
* so `useLocation()` reports the prefixed path — which we strip back off so
|
||||
* the canonical stays `https://lineage.freno.me/privacy`.
|
||||
* The canonical URL is the *public* browser URL, never any internal route
|
||||
* prefix. Subdomain routing is host-aware (root routes dispatch by
|
||||
* `useSite()`), so `useLocation()` returns the public path. The strip below
|
||||
* is a defensive no-op for the public path and still yields the canonical
|
||||
* `https://lineage.freno.me/privacy` if a prefixed form ever appears.
|
||||
*/
|
||||
const publicPath =
|
||||
site.baseRoutePrefix &&
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { JSX, splitProps, Show, createSignal, createEffect } from "solid-js";
|
||||
import {
|
||||
type JSX,
|
||||
splitProps,
|
||||
Show,
|
||||
createSignal,
|
||||
createEffect
|
||||
} from "solid-js";
|
||||
import { Spinner } from "~/components/Spinner";
|
||||
|
||||
export interface ButtonProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
@@ -6,6 +12,11 @@ export interface ButtonProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement>
|
||||
size?: "sm" | "md" | "lg";
|
||||
loading?: boolean;
|
||||
fullWidth?: boolean;
|
||||
/**
|
||||
* Override the variant's background color with an explicit CSS color.
|
||||
* Used by download pages to theme the button with the product brand color.
|
||||
*/
|
||||
color?: string;
|
||||
}
|
||||
|
||||
export default function Button(props: ButtonProps) {
|
||||
@@ -16,7 +27,8 @@ export default function Button(props: ButtonProps) {
|
||||
"fullWidth",
|
||||
"class",
|
||||
"children",
|
||||
"disabled"
|
||||
"disabled",
|
||||
"color"
|
||||
]);
|
||||
|
||||
let contentRef: HTMLSpanElement | undefined;
|
||||
@@ -53,8 +65,8 @@ export default function Button(props: ButtonProps) {
|
||||
: "bg-surface0 hover:brightness-125 active:scale-90";
|
||||
case "download":
|
||||
return isDisabledOrLoading
|
||||
? "bg-green text-base cursor-not-allowed brightness-75"
|
||||
: "bg-green text-base hover:brightness-125 active:scale-90";
|
||||
? "text-base cursor-not-allowed brightness-75"
|
||||
: "text-base hover:brightness-125 active:scale-90";
|
||||
case "danger":
|
||||
return isDisabledOrLoading
|
||||
? "bg-red cursor-not-allowed brightness-75"
|
||||
@@ -83,11 +95,19 @@ export default function Button(props: ButtonProps) {
|
||||
|
||||
const widthClass = () => (local.fullWidth ? "w-full" : "");
|
||||
|
||||
const buttonStyle = (): JSX.CSSProperties => {
|
||||
if (local.color) {
|
||||
return { background: local.color };
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
{...others}
|
||||
disabled={local.disabled || local.loading}
|
||||
class={`${baseClasses} ${variantClasses()} ${sizeClasses()} ${widthClass()} ${local.class || ""}`}
|
||||
style={buttonStyle()}
|
||||
>
|
||||
<Show
|
||||
when={local.loading}
|
||||
|
||||
Reference in New Issue
Block a user