fix(stats): correct breadcrumb behavior
This commit is contained in:
@@ -39,6 +39,7 @@ import {
|
|||||||
uniqueComparisonPairs,
|
uniqueComparisonPairs,
|
||||||
type ComparisonModelRef,
|
type ComparisonModelRef,
|
||||||
} from "../compare-cards"
|
} from "../compare-cards"
|
||||||
|
import { createBreadcrumbMenuRoot } from "../breadcrumb-menu"
|
||||||
import {
|
import {
|
||||||
applyThemePreference,
|
applyThemePreference,
|
||||||
Footer,
|
Footer,
|
||||||
@@ -284,9 +285,10 @@ function ModelHero(props: {
|
|||||||
const labModels = () =>
|
const labModels = () =>
|
||||||
props.catalogData?.labs.find((lab) => lab.id === providerSlug(labId()))?.models ??
|
props.catalogData?.labs.find((lab) => lab.id === providerSlug(labId()))?.models ??
|
||||||
(props.catalog ? [props.catalog] : [])
|
(props.catalog ? [props.catalog] : [])
|
||||||
|
const menuRoot = createBreadcrumbMenuRoot()
|
||||||
return (
|
return (
|
||||||
<section id="overview" data-section="model-hero">
|
<section id="overview" data-section="model-hero">
|
||||||
<nav data-component="model-hero-breadcrumb" aria-label="Data breadcrumb">
|
<nav ref={menuRoot} data-component="model-hero-breadcrumb" aria-label="Data breadcrumb">
|
||||||
<a data-slot="model-hero-crumb" href={language.route(import.meta.env.BASE_URL)}>
|
<a data-slot="model-hero-crumb" href={language.route(import.meta.env.BASE_URL)}>
|
||||||
Data
|
Data
|
||||||
</a>
|
</a>
|
||||||
@@ -294,14 +296,14 @@ function ModelHero(props: {
|
|||||||
<Show
|
<Show
|
||||||
when={labs().length > 0}
|
when={labs().length > 0}
|
||||||
fallback={
|
fallback={
|
||||||
<span data-slot="model-hero-crumb" data-current="true">
|
<span data-slot="model-hero-crumb" data-menu="true">
|
||||||
<span>{props.labName}</span>
|
<span>{props.labName}</span>
|
||||||
<ChevronDownIcon />
|
<ChevronDownIcon />
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<details data-component="model-hero-menu">
|
<details data-component="model-hero-menu">
|
||||||
<summary data-slot="model-hero-crumb" data-current="true">
|
<summary data-slot="model-hero-crumb" data-menu="true">
|
||||||
<span>{props.labName}</span>
|
<span>{props.labName}</span>
|
||||||
<ChevronDownIcon />
|
<ChevronDownIcon />
|
||||||
</summary>
|
</summary>
|
||||||
@@ -324,14 +326,19 @@ function ModelHero(props: {
|
|||||||
<Show
|
<Show
|
||||||
when={labModels().length > 0}
|
when={labModels().length > 0}
|
||||||
fallback={
|
fallback={
|
||||||
<span data-slot="model-hero-crumb" data-current="true" aria-current="page">
|
<span data-slot="model-hero-crumb" data-menu="true" data-current="true" aria-current="page">
|
||||||
<span>{modelName()}</span>
|
<span>{modelName()}</span>
|
||||||
<ChevronDownIcon />
|
<ChevronDownIcon />
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<details data-component="model-hero-menu">
|
<details data-component="model-hero-menu">
|
||||||
<summary data-slot="model-hero-crumb" data-current="true" aria-current="page">
|
<summary
|
||||||
|
data-slot="model-hero-crumb"
|
||||||
|
data-menu="true"
|
||||||
|
data-current="true"
|
||||||
|
aria-current="page"
|
||||||
|
>
|
||||||
<span>{modelName()}</span>
|
<span>{modelName()}</span>
|
||||||
<ChevronDownIcon />
|
<ChevronDownIcon />
|
||||||
</summary>
|
</summary>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { SectionHeading } from "../section-heading"
|
|||||||
import { runStatsEffect } from "../../stats-runtime"
|
import { runStatsEffect } from "../../stats-runtime"
|
||||||
import { setStatsPageCacheHeaders } from "../stats-cache"
|
import { setStatsPageCacheHeaders } from "../stats-cache"
|
||||||
import { ComparisonCardsSection, modelRefFromCatalog, uniqueComparisonPairs } from "../compare-cards"
|
import { ComparisonCardsSection, modelRefFromCatalog, uniqueComparisonPairs } from "../compare-cards"
|
||||||
|
import { createBreadcrumbMenuRoot } from "../breadcrumb-menu"
|
||||||
import {
|
import {
|
||||||
applyThemePreference,
|
applyThemePreference,
|
||||||
Footer,
|
Footer,
|
||||||
@@ -205,8 +206,9 @@ function LabHero(props: { lab: ModelCatalogLab; labs: ModelCatalogLab[] }) {
|
|||||||
function LabHeroBreadcrumb(props: { label: string; labs?: ModelCatalogLab[] }) {
|
function LabHeroBreadcrumb(props: { label: string; labs?: ModelCatalogLab[] }) {
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const labs = () => props.labs ?? []
|
const labs = () => props.labs ?? []
|
||||||
|
const menuRoot = createBreadcrumbMenuRoot()
|
||||||
return (
|
return (
|
||||||
<nav data-component="lab-hero-breadcrumb" aria-label="Data breadcrumb">
|
<nav ref={menuRoot} data-component="lab-hero-breadcrumb" aria-label="Data breadcrumb">
|
||||||
<a data-slot="lab-hero-crumb" href={language.route(import.meta.env.BASE_URL)}>
|
<a data-slot="lab-hero-crumb" href={language.route(import.meta.env.BASE_URL)}>
|
||||||
Data
|
Data
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { onCleanup, onMount } from "solid-js"
|
||||||
|
|
||||||
|
export function createBreadcrumbMenuRoot() {
|
||||||
|
let root: HTMLElement | undefined
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
const closeMenus = (except?: HTMLDetailsElement) => {
|
||||||
|
root?.querySelectorAll<HTMLDetailsElement>("details[open]").forEach((menu) => {
|
||||||
|
if (menu !== except) menu.open = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const onPointerDown = (event: PointerEvent) => {
|
||||||
|
const path = event.composedPath()
|
||||||
|
root?.querySelectorAll<HTMLDetailsElement>("details[open]").forEach((menu) => {
|
||||||
|
if (!path.includes(menu)) menu.open = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
|
if (event.key !== "Escape") return
|
||||||
|
const menu = root?.querySelector<HTMLDetailsElement>("details[open]")
|
||||||
|
if (!menu) return
|
||||||
|
event.preventDefault()
|
||||||
|
menu.open = false
|
||||||
|
menu.querySelector<HTMLElement>("summary")?.focus()
|
||||||
|
}
|
||||||
|
const onToggle = (event: Event) => {
|
||||||
|
if (!(event.target instanceof HTMLDetailsElement) || !event.target.open) return
|
||||||
|
closeMenus(event.target)
|
||||||
|
}
|
||||||
|
const onFocusOut = () => {
|
||||||
|
queueMicrotask(() => {
|
||||||
|
if (root?.contains(document.activeElement)) return
|
||||||
|
closeMenus()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("pointerdown", onPointerDown)
|
||||||
|
document.addEventListener("keydown", onKeyDown)
|
||||||
|
root?.addEventListener("toggle", onToggle, true)
|
||||||
|
root?.addEventListener("focusout", onFocusOut)
|
||||||
|
onCleanup(() => {
|
||||||
|
document.removeEventListener("pointerdown", onPointerDown)
|
||||||
|
document.removeEventListener("keydown", onKeyDown)
|
||||||
|
root?.removeEventListener("toggle", onToggle, true)
|
||||||
|
root?.removeEventListener("focusout", onFocusOut)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return (element: HTMLElement) => {
|
||||||
|
root = element
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3113,10 +3113,18 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-page="stats"] [data-slot="model-hero-crumb"][data-current="true"] {
|
[data-page="stats"] a[data-slot="model-hero-crumb"] {
|
||||||
|
color: var(--stats-hero-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-page="stats"] [data-slot="model-hero-crumb"][data-menu="true"] {
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-page="stats"] [data-slot="model-hero-crumb"][data-current="true"] {
|
||||||
|
color: var(--stats-text);
|
||||||
|
}
|
||||||
|
|
||||||
[data-page="stats"] [data-component="model-hero-menu"] {
|
[data-page="stats"] [data-component="model-hero-menu"] {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -3151,7 +3159,7 @@
|
|||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
color: var(--stats-faint);
|
color: currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-page="stats"] [data-component="model-hero-menu"][open] [data-slot="model-hero-crumb"] svg {
|
[data-page="stats"] [data-component="model-hero-menu"][open] [data-slot="model-hero-crumb"] svg {
|
||||||
@@ -5533,6 +5541,14 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-page="stats"] a[data-slot="compare-home-crumb"] {
|
||||||
|
color: var(--stats-hero-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-page="stats"] [data-slot="compare-home-crumb"][data-current="true"] {
|
||||||
|
color: var(--stats-text);
|
||||||
|
}
|
||||||
|
|
||||||
[data-page="stats"] a[data-slot="compare-home-crumb"]:hover,
|
[data-page="stats"] a[data-slot="compare-home-crumb"]:hover,
|
||||||
[data-page="stats"] a[data-slot="compare-home-crumb"]:focus-visible {
|
[data-page="stats"] a[data-slot="compare-home-crumb"]:focus-visible {
|
||||||
color: var(--stats-text);
|
color: var(--stats-text);
|
||||||
|
|||||||
Reference in New Issue
Block a user