Session 14: Africa checkout, Tank01 NBA/MLB wiring, WNBA+MLB odds proxies, OAuth icons, loading skeletons (1330 tests)
This commit is contained in:
@@ -26,6 +26,20 @@ import { useAuth } from '@/contexts/AuthContext';
|
||||
* key, one error-by-key map. The Slate component is the only writer.
|
||||
*/
|
||||
|
||||
// Session 14 — shimmer skeleton style. Width is a percentage string
|
||||
// so cards remain responsive at small viewports. The keyframe rule
|
||||
// lives in globals.css.
|
||||
function skeletonStyle({ widthPct, height }: { widthPct: number; height: number }): React.CSSProperties {
|
||||
return {
|
||||
width: `${widthPct}%`,
|
||||
height,
|
||||
borderRadius: 4,
|
||||
background: 'linear-gradient(90deg, #12121A 0%, #1A1A24 50%, #12121A 100%)',
|
||||
backgroundSize: '200% 100%',
|
||||
animation: 'vyndr-shimmer 1.5s ease-in-out infinite',
|
||||
};
|
||||
}
|
||||
|
||||
type SlateTab = 'all' | 'nba' | 'wnba' | 'mlb' | 'soccer';
|
||||
|
||||
const TABS: Array<{ id: SlateTab; label: string }> = [
|
||||
@@ -38,11 +52,11 @@ const TABS: Array<{ id: SlateTab; label: string }> = [
|
||||
|
||||
// Per-tab → list of fetch URLs. `null` indicates "no endpoint yet";
|
||||
// the Slate renders a soft "coming soon" badge for that sport rather
|
||||
// than 404-spamming the backend.
|
||||
// than 404-spamming the backend. Session 14 brought WNBA + MLB online.
|
||||
const FETCH_URLS: Record<Exclude<SlateTab, 'all'>, string[] | null> = {
|
||||
nba: ['/api/odds/nba'],
|
||||
wnba: null, // No /api/odds/wnba proxy yet.
|
||||
mlb: null, // No /api/odds/mlb proxy yet.
|
||||
wnba: ['/api/odds/wnba'],
|
||||
mlb: ['/api/odds/mlb'],
|
||||
soccer: ['/api/odds/soccer/wc'],
|
||||
};
|
||||
|
||||
@@ -339,8 +353,33 @@ export default function Slate({ initialTab = 'all', tier = 'free' }: SlateProps)
|
||||
|
||||
{/* Body */}
|
||||
{loading && (
|
||||
<div style={{ padding: 40, textAlign: 'center', color: 'var(--text-tertiary, #6B6B7B)' }}>
|
||||
Loading the slate…
|
||||
// Session 14 — shimmer skeletons replace the bare "Loading…" text.
|
||||
// Three placeholder cards approximating GameCard dimensions; the
|
||||
// shimmer animation lives in globals.css (`@keyframes
|
||||
// vyndr-shimmer`) so multiple loading surfaces stay in sync.
|
||||
<div style={{ display: 'grid', gap: 16 }} role="status" aria-label="Loading the slate">
|
||||
{[0, 1, 2].map((i) => (
|
||||
<div
|
||||
key={i}
|
||||
style={{
|
||||
background: 'var(--bg-2, #12121A)',
|
||||
border: '1px solid var(--border, #1A1A24)',
|
||||
borderRadius: 8,
|
||||
padding: 16,
|
||||
display: 'grid',
|
||||
gap: 10,
|
||||
}}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div style={skeletonStyle({ widthPct: 60, height: 18 })} />
|
||||
<div style={skeletonStyle({ widthPct: 40, height: 10 })} />
|
||||
<div style={{ display: 'grid', gap: 8, marginTop: 8 }}>
|
||||
<div style={skeletonStyle({ widthPct: 88, height: 14 })} />
|
||||
<div style={skeletonStyle({ widthPct: 70, height: 14 })} />
|
||||
<div style={skeletonStyle({ widthPct: 80, height: 14 })} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user