feat(picker): add the speedrun mood and the speedrun.com link
Build, Test & Push Frontend / quality-check (push) Successful in 15s
Build, Test & Push Frontend / docker (push) Successful in 23s

"What to play next" gets a Speedrun mood. The game detail links the
game's speedrun.com page when Core found one with verified runs; only
https://www.speedrun.com/ links are shown.
This commit is contained in:
lobo committed 2026-09-26 10:39:10 +02:00
1 parent b0c78d8dca
commit 23ab5a91e7
7 files changed
+82 -12

No files matched your search

+13 -1
View File
@@ -1,7 +1,7 @@
import {useEffect, useMemo, useState} from 'react';
import {Link, useNavigate, useParams} from 'react-router-dom';
import {useTranslation} from 'react-i18next';
import {ArrowLeft, Clock, ExternalLink, Gamepad2, Image as ImageIcon, ImageOff, PanelTop, RotateCcw, ShieldOff, Trophy} from 'lucide-react';
import {ArrowLeft, Clock, ExternalLink, Gamepad2, Image as ImageIcon, ImageOff, PanelTop, RotateCcw, ShieldOff, Timer, Trophy} from 'lucide-react';
import {Badge} from '@/components/ui/badge';
import {Button} from '@/components/ui/button';
@@ -24,6 +24,8 @@ import {apiFetch} from '../utils/api.js';
import {hasSession} from '../utils/auth.js';
import {isSteamKey} from '../utils/manualGames.js';
const SPEEDRUN_PREFIX = 'https://www.speedrun.com/';
const formatUnlockedAt = (instant, locale) => {
if (!instant) return '';
try {
@@ -103,6 +105,9 @@ export default function GameDetail() {
const manual = data?.source === 'MANUAL';
const onSteam = !!data && isSteamKey(data.appid);
// Core checks the link too; a link from the API must never run script.
const speedrunUrl = typeof data?.speedrunUrl === 'string' && data.speedrunUrl.startsWith(SPEEDRUN_PREFIX)
? data.speedrunUrl : null;
const isBackground = !!data && appearance.backgroundAppid === data.appid;
const isBanner = !!data && appearance.showBanner && appearance.bannerAppid === data.appid;
@@ -154,6 +159,13 @@ export default function GameDetail() {
<div className="mt-3">
<TimeToBeat time={data.timeToBeat}/>
</div>
{speedrunUrl && (
<Button asChild variant="outline" size="sm" className="mt-3">
<a href={speedrunUrl} target="_blank" rel="noopener noreferrer">
<Timer/>{t('GAME_DETAIL.OPEN_IN_SPEEDRUN')}<ExternalLink/>
</a>
</Button>
)}
</div>
{/* Store page, background and banner need Steam art, so a game off Steam has none of them. */}
{onSteam && <div className="flex flex-wrap gap-2">