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
34 changes: 18 additions & 16 deletions src/app/benchmarks/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -481,22 +481,6 @@ export default async function BenchmarkPage({
<ArrowLeft size={14} strokeWidth={2} />
All benchmarks
</Link>
{!isDraft && (
<div className="ml-auto flex flex-wrap items-center gap-2">
<ShareSection
slug={benchmark.slug}
title={benchmark.title}
benchmark={benchmark}
chain={chain}
/>
<ExportVideoSection
slug={benchmark.slug}
title={benchmark.title}
benchmark={benchmark}
/>
<ReportSection slug={benchmark.slug} />
</div>
)}
</div>

{/* Bench identifier - minimal mono line, no SaaS-style pills. */}
Expand Down Expand Up @@ -743,6 +727,24 @@ export default async function BenchmarkPage({
initialKind={kind ?? null}
initialVenue={venue ?? null}
hasLongHistory={benchmark.slug === "hyperliquid-frontends"}
pageActions={
!isDraft ? (
<>
<ShareSection
slug={benchmark.slug}
title={benchmark.title}
benchmark={benchmark}
chain={chain}
/>
<ExportVideoSection
slug={benchmark.slug}
title={benchmark.title}
benchmark={benchmark}
/>
<ReportSection slug={benchmark.slug} />
</>
) : undefined
}
/>
</Suspense>
)}
Expand Down
16 changes: 11 additions & 5 deletions src/components/benchmark-body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
initialKind = null,
initialVenue = null,
hasLongHistory = false,
pageActions,
}: {
variants: Record<string, Benchmark>;
chainOptions: ChainOption[];
Expand All @@ -165,6 +166,11 @@
* below the main ledger. Only set on benches whose harness ships a
* long-window archive blob (currently: hyperliquid-frontends). */
hasLongHistory?: boolean;
/** Page-level toolbar (Image / Video / Report). Rendered inline in the
* chart's header row on the left of the ViewSwitcher so the sharing
* affordances sit visually next to the per-chart Copy / Download
* button instead of floating alone at the top of the page. */
pageActions?: import("react").ReactNode;
}) {
// Read ?chain= / ?region= / ?kind= client-side. The server can't read these any
// more (doing so would force /benchmarks/<slug> to render dynamic on
Expand Down Expand Up @@ -559,7 +565,7 @@
// not only on the timeseries view. Providers the panel has no value
// for (book could not fill the tier) drop out of the ranking, which
// is the skipped-not-extrapolated rule made visible.
const panelViewBenchmark = useMemo(() => {

Check failure on line 568 in src/components/benchmark-body.tsx

View workflow job for this annotation

GitHub Actions / check

React Hook "useMemo" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return?
if (!activePanel) return viewBenchmark;
const vals = activePanel.values ?? {};
return {
Expand Down Expand Up @@ -727,7 +733,7 @@
{view === "countLeaderboard" && (
<CountLeaderboard
benchmark={viewBenchmark}
headerActions={<ViewSwitcher allowed={allowedViews} value={view} onChange={setView} />}
headerActions={<>{pageActions}<ViewSwitcher allowed={allowedViews} value={view} onChange={setView} /></>}
/>
)}
{view === "rankedBar" && (
Expand All @@ -752,7 +758,7 @@
onResetExcluded={resetExcluded}
disableTopN={hasLayerSplit}
topNControl={topNControl}
headerActions={<ViewSwitcher allowed={allowedViews} value={view} onChange={setView} />}
headerActions={<>{pageActions}<ViewSwitcher allowed={allowedViews} value={view} onChange={setView} /></>}
/>
</>
)}
Expand All @@ -764,7 +770,7 @@
onResetExcluded={resetExcluded}
disableTopN={hasLayerSplit}
topNControl={topNControl}
headerActions={<ViewSwitcher allowed={allowedViews} value={view} onChange={setView} />}
headerActions={<>{pageActions}<ViewSwitcher allowed={allowedViews} value={view} onChange={setView} /></>}
/>
)}
{view === "donut" && (
Expand All @@ -774,7 +780,7 @@
onToggleExclude={toggleExclude}
disableTopN={hasLayerSplit}
topNControl={topNControl}
headerActions={<ViewSwitcher allowed={allowedViews} value={view} onChange={setView} />}
headerActions={<>{pageActions}<ViewSwitcher allowed={allowedViews} value={view} onChange={setView} /></>}
/>
)}
{view === "timeseries" && (
Expand Down Expand Up @@ -807,7 +813,7 @@
onResetExcluded={resetExcluded}
disableTopN={hasLayerSplit}
topNControl={topNControl}
headerActions={<ViewSwitcher allowed={allowedViews} value={view} onChange={setView} />}
headerActions={<>{pageActions}<ViewSwitcher allowed={allowedViews} value={view} onChange={setView} /></>}
seriesOverride={activePanel?.seriesByProvider}
seriesOverride7d={activePanel?.seriesByProvider7d}
seriesOverride30d={activePanel?.seriesByProvider30d}
Expand Down
5 changes: 2 additions & 3 deletions src/components/export-video-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,9 @@ function ExportVideoModal({ slug, title, benchmark }: Props) {
onClick={() => setOpen(true)}
aria-label="Export video"
title="Export video"
className="inline-flex items-center gap-1.5 rounded-md border border-ink/15 bg-paper px-2.5 py-1 text-[11px] font-sans font-medium uppercase tracking-[0.1em] text-ink shadow-sm transition-colors hover:bg-paper-soft"
className="inline-flex items-center justify-center rounded-md border border-ink/15 bg-paper p-1.5 text-ink shadow-sm transition-colors hover:bg-paper-soft"
>
<Video size={11} strokeWidth={2} />
<span className="hidden sm:inline">Video</span>
<Video size={13} strokeWidth={2} />
</button>

{open && (
Expand Down
7 changes: 4 additions & 3 deletions src/components/report-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,11 @@ export function ReportSection({ slug }: Props) {
<button
type="button"
onClick={() => setOpen(true)}
className="inline-flex items-center gap-2 rounded-md border border-ink bg-paper px-3.5 py-2 text-[11px] font-medium uppercase tracking-[0.18em] text-ink hover:bg-ink hover:text-paper transition-colors"
aria-label="Report an issue"
title="Report an issue"
className="inline-flex items-center justify-center rounded-md border border-ink/15 bg-paper p-1.5 text-ink shadow-sm transition-colors hover:bg-paper-soft"
>
<AlertTriangle size={14} strokeWidth={2} />
Report
<AlertTriangle size={13} strokeWidth={2} />
</button>

{open && (
Expand Down
5 changes: 2 additions & 3 deletions src/components/share-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,9 @@ export function ShareSection({ slug, title, benchmark, chain }: Props) {
onClick={() => setOpen(true)}
aria-label="Export image"
title="Export image"
className="inline-flex items-center gap-1.5 rounded-md border border-ink/15 bg-paper px-2.5 py-1 text-[11px] font-sans font-medium uppercase tracking-[0.1em] text-ink shadow-sm transition-colors hover:bg-paper-soft"
className="inline-flex items-center justify-center rounded-md border border-ink/15 bg-paper p-1.5 text-ink shadow-sm transition-colors hover:bg-paper-soft"
>
<ImageIcon size={11} strokeWidth={2} />
<span className="hidden sm:inline">Image</span>
<ImageIcon size={13} strokeWidth={2} />
</button>

{open && (
Expand Down
Loading