From 92da9b9e3982f49888e322bf06a21805036006fb Mon Sep 17 00:00:00 2001 From: functionstackx <47992694+functionstackx@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:01:59 -0400 Subject: [PATCH 1/3] Move GPU Reliability link to footer --- .../components/footer/footer-links.test.ts | 14 ++++++++++ .../app/src/components/footer/footer-links.ts | 8 ++++++ .../footer/footer-reliability-link.tsx | 24 +++++++++++++++++ packages/app/src/components/footer/footer.tsx | 2 ++ .../app/src/components/tab-nav-links.test.ts | 27 +++++++++++++++++++ packages/app/src/components/tab-nav-links.ts | 20 ++++++++++++++ packages/app/src/components/tab-nav.tsx | 17 +++--------- 7 files changed, 99 insertions(+), 13 deletions(-) create mode 100644 packages/app/src/components/footer/footer-links.test.ts create mode 100644 packages/app/src/components/footer/footer-links.ts create mode 100644 packages/app/src/components/footer/footer-reliability-link.tsx create mode 100644 packages/app/src/components/tab-nav-links.test.ts create mode 100644 packages/app/src/components/tab-nav-links.ts diff --git a/packages/app/src/components/footer/footer-links.test.ts b/packages/app/src/components/footer/footer-links.test.ts new file mode 100644 index 0000000..9e8d193 --- /dev/null +++ b/packages/app/src/components/footer/footer-links.test.ts @@ -0,0 +1,14 @@ +import { describe, expect, it } from 'vitest'; + +import { FOOTER_RELIABILITY_LINK } from '@/components/footer/footer-links'; + +describe('FOOTER_RELIABILITY_LINK', () => { + it('points to the GPU Reliability page from the footer', () => { + expect(FOOTER_RELIABILITY_LINK).toEqual({ + href: '/reliability', + label: 'GPU Reliability', + testId: 'footer-link-reliability', + event: 'footer_reliability_clicked', + }); + }); +}); diff --git a/packages/app/src/components/footer/footer-links.ts b/packages/app/src/components/footer/footer-links.ts new file mode 100644 index 0000000..3eacf98 --- /dev/null +++ b/packages/app/src/components/footer/footer-links.ts @@ -0,0 +1,8 @@ +const FOOTER_RELIABILITY_LINK = { + href: '/reliability', + label: 'GPU Reliability', + testId: 'footer-link-reliability', + event: 'footer_reliability_clicked', +} as const; + +export { FOOTER_RELIABILITY_LINK }; diff --git a/packages/app/src/components/footer/footer-reliability-link.tsx b/packages/app/src/components/footer/footer-reliability-link.tsx new file mode 100644 index 0000000..420678c --- /dev/null +++ b/packages/app/src/components/footer/footer-reliability-link.tsx @@ -0,0 +1,24 @@ +'use client'; + +import Link from 'next/link'; + +import { track } from '@/lib/analytics'; + +import { FOOTER_RELIABILITY_LINK } from './footer-links'; + +const linkClassName = 'text-sm text-muted-foreground hover:text-foreground transition-colors'; + +function FooterReliabilityLink() { + return ( + track(FOOTER_RELIABILITY_LINK.event)} + > + {FOOTER_RELIABILITY_LINK.label} + + ); +} + +export { FooterReliabilityLink }; diff --git a/packages/app/src/components/footer/footer.tsx b/packages/app/src/components/footer/footer.tsx index 48babcc..151121e 100644 --- a/packages/app/src/components/footer/footer.tsx +++ b/packages/app/src/components/footer/footer.tsx @@ -3,6 +3,7 @@ import Link from 'next/link'; import { ShareTwitterButton, ShareLinkedInButton } from '@/components/share-buttons'; +import { FooterReliabilityLink } from './footer-reliability-link'; import { StarButton } from './footer-star-cta'; export const Footer = ({ starCount }: { starCount?: number | null }) => { @@ -71,6 +72,7 @@ export const Footer = ({ starCount }: { starCount?: number | null }) => { > About +
Legal diff --git a/packages/app/src/components/tab-nav-links.test.ts b/packages/app/src/components/tab-nav-links.test.ts new file mode 100644 index 0000000..a6a7225 --- /dev/null +++ b/packages/app/src/components/tab-nav-links.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from 'vitest'; + +import { TAB_LINKS, isTabLinkValue } from '@/components/tab-nav-links'; + +describe('TAB_LINKS', () => { + it('omits GPU Reliability from the visible tab navigation', () => { + expect(TAB_LINKS.map((tab) => tab.href)).toEqual([ + '/inference', + '/evaluation', + '/historical', + '/calculator', + '/gpu-specs', + '/gpu-metrics', + '/submissions', + ]); + }); +}); + +describe('isTabLinkValue', () => { + it('returns false for the footer-only reliability route', () => { + expect(isTabLinkValue('reliability')).toBe(false); + }); + + it('returns true for routes still shown in the nav', () => { + expect(isTabLinkValue('gpu-specs')).toBe(true); + }); +}); diff --git a/packages/app/src/components/tab-nav-links.ts b/packages/app/src/components/tab-nav-links.ts new file mode 100644 index 0000000..4096afd --- /dev/null +++ b/packages/app/src/components/tab-nav-links.ts @@ -0,0 +1,20 @@ +const TAB_LINKS = [ + { href: '/inference', label: 'Inference Performance', testId: 'tab-trigger-inference' }, + { href: '/evaluation', label: 'Accuracy Evals', testId: 'tab-trigger-evaluation' }, + { href: '/historical', label: 'Historical Trends', testId: 'tab-trigger-historical' }, + { href: '/calculator', label: 'TCO Calculator', testId: 'tab-trigger-calculator' }, + { href: '/gpu-specs', label: 'GPU Specs', testId: 'tab-trigger-gpu-specs' }, + { href: '/gpu-metrics', label: 'PowerX', testId: 'tab-trigger-gpu-metrics', gated: true }, + { href: '/submissions', label: 'Submissions', testId: 'tab-trigger-submissions', gated: true }, +] as const; + +type TabLinkValue = (typeof TAB_LINKS)[number]['href'] extends `/${infer Value}` ? Value : never; + +const TAB_LINK_VALUES = new Set(TAB_LINKS.map((tab) => tab.href.slice(1))); + +function isTabLinkValue(value: string): value is TabLinkValue { + return TAB_LINK_VALUES.has(value); +} + +export { TAB_LINKS, isTabLinkValue }; +export type { TabLinkValue }; diff --git a/packages/app/src/components/tab-nav.tsx b/packages/app/src/components/tab-nav.tsx index a25c6f6..6584370 100644 --- a/packages/app/src/components/tab-nav.tsx +++ b/packages/app/src/components/tab-nav.tsx @@ -6,6 +6,7 @@ import { useEffect, useRef, useState } from 'react'; import { track } from '@/lib/analytics'; import { Card } from '@/components/ui/card'; +import { TAB_LINKS, isTabLinkValue } from '@/components/tab-nav-links'; import { Label } from '@/components/ui/label'; import { Select, @@ -64,17 +65,6 @@ function useFeatureGate(): boolean { return unlocked; } -const TAB_LINKS = [ - { href: '/inference', label: 'Inference Performance', testId: 'tab-trigger-inference' }, - { href: '/evaluation', label: 'Accuracy Evals', testId: 'tab-trigger-evaluation' }, - { href: '/historical', label: 'Historical Trends', testId: 'tab-trigger-historical' }, - { href: '/calculator', label: 'TCO Calculator', testId: 'tab-trigger-calculator' }, - { href: '/reliability', label: 'GPU Reliability', testId: 'tab-trigger-reliability' }, - { href: '/gpu-specs', label: 'GPU Specs', testId: 'tab-trigger-gpu-specs' }, - { href: '/gpu-metrics', label: 'PowerX', testId: 'tab-trigger-gpu-metrics', gated: true }, - { href: '/submissions', label: 'Submissions', testId: 'tab-trigger-submissions', gated: true }, -] as const; - function activeTab(pathname: string): string { const seg = pathname.split('/').filter(Boolean)[0] || 'inference'; return seg; @@ -85,6 +75,7 @@ export function TabNav() { const router = useRouter(); const featureGateUnlocked = useFeatureGate(); const current = activeTab(pathname); + const selectedTab = isTabLinkValue(current) ? current : ''; const handleMobileChange = (value: string) => { window.dispatchEvent(new CustomEvent('inferencex:tab-change')); @@ -105,9 +96,9 @@ export function TabNav() {
- - + {TAB_LINKS.map((tab) => { From e0dc7a9e76e6300f1aee285bfa443868939755a6 Mon Sep 17 00:00:00 2001 From: functionstackx <47992694+functionstackx@users.noreply.github.com> Date: Fri, 3 Apr 2026 19:30:48 -0400 Subject: [PATCH 2/3] Update Cypress specs for footer reliability link --- packages/app/cypress/e2e/csv-export.cy.ts | 2 +- packages/app/cypress/e2e/tabs.cy.ts | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/app/cypress/e2e/csv-export.cy.ts b/packages/app/cypress/e2e/csv-export.cy.ts index e13ad20..edd9210 100644 --- a/packages/app/cypress/e2e/csv-export.cy.ts +++ b/packages/app/cypress/e2e/csv-export.cy.ts @@ -27,7 +27,7 @@ describe('CSV Export', () => { }); it('reliability chart has CSV export option', () => { - cy.get('[data-testid="tab-trigger-reliability"]').click(); + cy.visit('/reliability'); cy.get('[data-testid="reliability-chart-display"]').should('exist'); cy.get('[data-testid="export-button"]').first().click(); diff --git a/packages/app/cypress/e2e/tabs.cy.ts b/packages/app/cypress/e2e/tabs.cy.ts index dbc0d15..292e3f8 100644 --- a/packages/app/cypress/e2e/tabs.cy.ts +++ b/packages/app/cypress/e2e/tabs.cy.ts @@ -16,9 +16,6 @@ describe('Chart Section Tabs — E2E', () => { cy.get('[data-testid="tab-trigger-calculator"]').click(); cy.url().should('include', '/calculator'); - cy.get('[data-testid="tab-trigger-reliability"]').click(); - cy.url().should('include', '/reliability'); - cy.get('[data-testid="tab-trigger-gpu-specs"]').click(); cy.url().should('include', '/gpu-specs'); @@ -26,6 +23,14 @@ describe('Chart Section Tabs — E2E', () => { cy.url().should('include', '/inference'); }); + it('opens GPU Reliability from the footer link', () => { + cy.get('[data-testid="tab-trigger-reliability"]').should('not.exist'); + + cy.get('[data-testid="footer-link-reliability"]').scrollIntoView().click(); + cy.url().should('include', '/reliability'); + cy.get('[data-testid="reliability-chart-display"]').should('exist'); + }); + it('shows mobile chart select dropdown on small viewport', () => { cy.viewport(375, 812); cy.visit('/inference'); From 6b8bd021b5926fbd1d3ec38afa323eedbd423a3c Mon Sep 17 00:00:00 2001 From: adibarra <93070681+adibarra@users.noreply.github.com> Date: Fri, 3 Apr 2026 20:50:20 -0500 Subject: [PATCH 3/3] simplify: inline footer link, move TAB_LINKS back into tab-nav --- .../components/footer/footer-links.test.ts | 14 ---------- .../app/src/components/footer/footer-links.ts | 8 ------ .../footer/footer-reliability-link.tsx | 24 ----------------- packages/app/src/components/footer/footer.tsx | 14 +++++++--- .../app/src/components/tab-nav-links.test.ts | 27 ------------------- packages/app/src/components/tab-nav-links.ts | 20 -------------- packages/app/src/components/tab-nav.tsx | 15 +++++++++-- 7 files changed, 24 insertions(+), 98 deletions(-) delete mode 100644 packages/app/src/components/footer/footer-links.test.ts delete mode 100644 packages/app/src/components/footer/footer-links.ts delete mode 100644 packages/app/src/components/footer/footer-reliability-link.tsx delete mode 100644 packages/app/src/components/tab-nav-links.test.ts delete mode 100644 packages/app/src/components/tab-nav-links.ts diff --git a/packages/app/src/components/footer/footer-links.test.ts b/packages/app/src/components/footer/footer-links.test.ts deleted file mode 100644 index 9e8d193..0000000 --- a/packages/app/src/components/footer/footer-links.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { FOOTER_RELIABILITY_LINK } from '@/components/footer/footer-links'; - -describe('FOOTER_RELIABILITY_LINK', () => { - it('points to the GPU Reliability page from the footer', () => { - expect(FOOTER_RELIABILITY_LINK).toEqual({ - href: '/reliability', - label: 'GPU Reliability', - testId: 'footer-link-reliability', - event: 'footer_reliability_clicked', - }); - }); -}); diff --git a/packages/app/src/components/footer/footer-links.ts b/packages/app/src/components/footer/footer-links.ts deleted file mode 100644 index 3eacf98..0000000 --- a/packages/app/src/components/footer/footer-links.ts +++ /dev/null @@ -1,8 +0,0 @@ -const FOOTER_RELIABILITY_LINK = { - href: '/reliability', - label: 'GPU Reliability', - testId: 'footer-link-reliability', - event: 'footer_reliability_clicked', -} as const; - -export { FOOTER_RELIABILITY_LINK }; diff --git a/packages/app/src/components/footer/footer-reliability-link.tsx b/packages/app/src/components/footer/footer-reliability-link.tsx deleted file mode 100644 index 420678c..0000000 --- a/packages/app/src/components/footer/footer-reliability-link.tsx +++ /dev/null @@ -1,24 +0,0 @@ -'use client'; - -import Link from 'next/link'; - -import { track } from '@/lib/analytics'; - -import { FOOTER_RELIABILITY_LINK } from './footer-links'; - -const linkClassName = 'text-sm text-muted-foreground hover:text-foreground transition-colors'; - -function FooterReliabilityLink() { - return ( - track(FOOTER_RELIABILITY_LINK.event)} - > - {FOOTER_RELIABILITY_LINK.label} - - ); -} - -export { FooterReliabilityLink }; diff --git a/packages/app/src/components/footer/footer.tsx b/packages/app/src/components/footer/footer.tsx index 151121e..c2e9cca 100644 --- a/packages/app/src/components/footer/footer.tsx +++ b/packages/app/src/components/footer/footer.tsx @@ -3,7 +3,6 @@ import Link from 'next/link'; import { ShareTwitterButton, ShareLinkedInButton } from '@/components/share-buttons'; -import { FooterReliabilityLink } from './footer-reliability-link'; import { StarButton } from './footer-star-cta'; export const Footer = ({ starCount }: { starCount?: number | null }) => { @@ -42,7 +41,7 @@ export const Footer = ({ starCount }: { starCount?: number | null }) => {
{/* Center — Links */} -
+
SemiAnalysis { > About -
Legal @@ -116,6 +114,16 @@ export const Footer = ({ starCount }: { starCount?: number | null }) => { Frontend
+
+ More + + GPU Reliability + +
{/* Right — CTA + Social */} diff --git a/packages/app/src/components/tab-nav-links.test.ts b/packages/app/src/components/tab-nav-links.test.ts deleted file mode 100644 index a6a7225..0000000 --- a/packages/app/src/components/tab-nav-links.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { TAB_LINKS, isTabLinkValue } from '@/components/tab-nav-links'; - -describe('TAB_LINKS', () => { - it('omits GPU Reliability from the visible tab navigation', () => { - expect(TAB_LINKS.map((tab) => tab.href)).toEqual([ - '/inference', - '/evaluation', - '/historical', - '/calculator', - '/gpu-specs', - '/gpu-metrics', - '/submissions', - ]); - }); -}); - -describe('isTabLinkValue', () => { - it('returns false for the footer-only reliability route', () => { - expect(isTabLinkValue('reliability')).toBe(false); - }); - - it('returns true for routes still shown in the nav', () => { - expect(isTabLinkValue('gpu-specs')).toBe(true); - }); -}); diff --git a/packages/app/src/components/tab-nav-links.ts b/packages/app/src/components/tab-nav-links.ts deleted file mode 100644 index 4096afd..0000000 --- a/packages/app/src/components/tab-nav-links.ts +++ /dev/null @@ -1,20 +0,0 @@ -const TAB_LINKS = [ - { href: '/inference', label: 'Inference Performance', testId: 'tab-trigger-inference' }, - { href: '/evaluation', label: 'Accuracy Evals', testId: 'tab-trigger-evaluation' }, - { href: '/historical', label: 'Historical Trends', testId: 'tab-trigger-historical' }, - { href: '/calculator', label: 'TCO Calculator', testId: 'tab-trigger-calculator' }, - { href: '/gpu-specs', label: 'GPU Specs', testId: 'tab-trigger-gpu-specs' }, - { href: '/gpu-metrics', label: 'PowerX', testId: 'tab-trigger-gpu-metrics', gated: true }, - { href: '/submissions', label: 'Submissions', testId: 'tab-trigger-submissions', gated: true }, -] as const; - -type TabLinkValue = (typeof TAB_LINKS)[number]['href'] extends `/${infer Value}` ? Value : never; - -const TAB_LINK_VALUES = new Set(TAB_LINKS.map((tab) => tab.href.slice(1))); - -function isTabLinkValue(value: string): value is TabLinkValue { - return TAB_LINK_VALUES.has(value); -} - -export { TAB_LINKS, isTabLinkValue }; -export type { TabLinkValue }; diff --git a/packages/app/src/components/tab-nav.tsx b/packages/app/src/components/tab-nav.tsx index 6584370..2fc9774 100644 --- a/packages/app/src/components/tab-nav.tsx +++ b/packages/app/src/components/tab-nav.tsx @@ -6,7 +6,6 @@ import { useEffect, useRef, useState } from 'react'; import { track } from '@/lib/analytics'; import { Card } from '@/components/ui/card'; -import { TAB_LINKS, isTabLinkValue } from '@/components/tab-nav-links'; import { Label } from '@/components/ui/label'; import { Select, @@ -65,6 +64,18 @@ function useFeatureGate(): boolean { return unlocked; } +const TAB_LINKS = [ + { href: '/inference', label: 'Inference Performance', testId: 'tab-trigger-inference' }, + { href: '/evaluation', label: 'Accuracy Evals', testId: 'tab-trigger-evaluation' }, + { href: '/historical', label: 'Historical Trends', testId: 'tab-trigger-historical' }, + { href: '/calculator', label: 'TCO Calculator', testId: 'tab-trigger-calculator' }, + { href: '/gpu-specs', label: 'GPU Specs', testId: 'tab-trigger-gpu-specs' }, + { href: '/gpu-metrics', label: 'PowerX', testId: 'tab-trigger-gpu-metrics', gated: true }, + { href: '/submissions', label: 'Submissions', testId: 'tab-trigger-submissions', gated: true }, +] as const; + +const TAB_VALUES = new Set(TAB_LINKS.map((t) => t.href.slice(1))); + function activeTab(pathname: string): string { const seg = pathname.split('/').filter(Boolean)[0] || 'inference'; return seg; @@ -75,7 +86,7 @@ export function TabNav() { const router = useRouter(); const featureGateUnlocked = useFeatureGate(); const current = activeTab(pathname); - const selectedTab = isTabLinkValue(current) ? current : ''; + const selectedTab = TAB_VALUES.has(current) ? current : ''; const handleMobileChange = (value: string) => { window.dispatchEvent(new CustomEvent('inferencex:tab-change'));