feat: update frontend for new upscaler/battery fields

- Replace fsrVersion with upscalerType/upscalerVersion in Preset interface
- Update StatsResponse to use upscalerType/upscalerVersion
- Replace FSR_OPTIONS with UPSCALER_OPTIONS (FSR, DLSS, XeSS, LSFG, Other)
- Update FRAMEGEN_OPTIONS to include LSFG and Other
- Update filter state from fsr to upscaler
- Update isRawPerformerPreset and getFpsColor to use upscalerType
- Update UpscalerBarChart interface and formatCombo function
- Update preset card technology tags to display upscaler version
This commit is contained in:
2026-04-27 07:28:52 +08:00
parent 4943f24fd4
commit ce2ccad578
2 changed files with 51 additions and 22 deletions
+34 -16
View File
@@ -73,7 +73,8 @@ interface Preset {
fpsAvg: number | null fpsAvg: number | null
fpsLow: number | null fpsLow: number | null
fpsHigh: number | null fpsHigh: number | null
fsrVersion: string | null upscalerType: string | null
upscalerVersion: string | null
frameGenMethod: string | null frameGenMethod: string | null
protonVersion: string | null protonVersion: string | null
osVersion: string | null osVersion: string | null
@@ -89,6 +90,7 @@ interface StatsResponse {
versionCount: number versionCount: number
} }
isRawPerformer: boolean isRawPerformer: boolean
isPoorPerformance: boolean
boxplot: Array<{ boxplot: Array<{
hardwareSlug: string hardwareSlug: string
hardwareName: string hardwareName: string
@@ -107,7 +109,8 @@ interface StatsResponse {
}> }>
}> }>
upscalerStats: Array<{ upscalerStats: Array<{
fsrVersion: string upscalerType: string
upscalerVersion?: string
frameGenMethod: string frameGenMethod: string
hardwareSlug: string hardwareSlug: string
avgFps: number avgFps: number
@@ -149,8 +152,8 @@ interface Props {
gameId: string gameId: string
} }
const FSR_OPTIONS = ["Any", "None", "FSR1", "FSR2", "FSR3"] const UPSCALER_OPTIONS = ["Any", "None", "FSR", "DLSS", "XeSS", "LSFG", "Other"]
const FRAMEGEN_OPTIONS = ["Any", "None", "FSR FG", "DLSS FG"] const FRAMEGEN_OPTIONS = ["Any", "None", "FSR FG", "DLSS FG", "LSFG", "Other"]
function formatDate(value: string | null): string { function formatDate(value: string | null): string {
if (!value) return "—" if (!value) return "—"
@@ -161,11 +164,15 @@ function isRawPerformerPreset(preset: Preset): boolean {
return ( return (
preset.fpsAvg !== null && preset.fpsAvg !== null &&
preset.fpsAvg >= 60 && preset.fpsAvg >= 60 &&
preset.fsrVersion === "none" && preset.upscalerType === "none" &&
preset.frameGenMethod === "none" preset.frameGenMethod === "none"
) )
} }
function isPoorPerformancePreset(preset: Preset): boolean {
return preset.fpsAvg !== null && preset.fpsAvg < 30
}
function getFpsColor(preset: Preset): string { function getFpsColor(preset: Preset): string {
if (preset.fpsAvg === null) return "text-text/60" if (preset.fpsAvg === null) return "text-text/60"
if (isRawPerformerPreset(preset)) return "text-green-400" if (isRawPerformerPreset(preset)) return "text-green-400"
@@ -173,7 +180,7 @@ function getFpsColor(preset: Preset): string {
if (preset.frameGenMethod === "dlss_fg") return "text-blue-400" if (preset.frameGenMethod === "dlss_fg") return "text-blue-400"
return "text-orange-400" return "text-orange-400"
} }
if (preset.fsrVersion && preset.fsrVersion !== "none") if (preset.upscalerType && preset.upscalerType !== "none")
return "text-orange-400" return "text-orange-400"
return "text-text/60" return "text-text/60"
} }
@@ -192,7 +199,7 @@ export function GamePageClient({
const [filters, setFilters] = useState({ const [filters, setFilters] = useState({
proton: "all", proton: "all",
os: "all", os: "all",
fsr: "all", upscaler: "all",
frameGen: "all", frameGen: "all",
}) })
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
@@ -243,7 +250,7 @@ export function GamePageClient({
const filterUpscaler = (arr: StatsResponse["upscalerStats"]) => const filterUpscaler = (arr: StatsResponse["upscalerStats"]) =>
arr.filter((item) => { arr.filter((item) => {
if (!deviceSet.has(item.hardwareSlug)) return false if (!deviceSet.has(item.hardwareSlug)) return false
if (filters.fsr !== "all" && item.fsrVersion !== filters.fsr) if (filters.upscaler !== "all" && item.upscalerType !== filters.upscaler)
return false return false
if ( if (
filters.frameGen !== "all" && filters.frameGen !== "all" &&
@@ -282,7 +289,7 @@ export function GamePageClient({
if (filters.proton !== "all" && p.protonVersion !== filters.proton) if (filters.proton !== "all" && p.protonVersion !== filters.proton)
return false return false
if (filters.os !== "all" && p.osVersion !== filters.os) return false if (filters.os !== "all" && p.osVersion !== filters.os) return false
if (filters.fsr !== "all" && p.fsrVersion !== filters.fsr) if (filters.upscaler !== "all" && p.upscalerType !== filters.upscaler)
return false return false
if ( if (
filters.frameGen !== "all" && filters.frameGen !== "all" &&
@@ -351,6 +358,11 @@ export function GamePageClient({
Raw Performer Raw Performer
</span> </span>
)} )}
{stats?.isPoorPerformance && (
<span className='inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-red-500/10 border border-red-500/20 text-red-400 text-[10px] font-semibold'>
Poor Performance
</span>
)}
</div> </div>
{/* Subtitle */} {/* Subtitle */}
@@ -636,11 +648,11 @@ export function GamePageClient({
} }
/> />
<FilterSelect <FilterSelect
label='FSR Version' label='Upscaler'
value={filters.fsr} value={filters.upscaler}
options={FSR_OPTIONS.map((o) => o.toLowerCase())} options={UPSCALER_OPTIONS.map((o) => o.toLowerCase())}
onChange={(v) => onChange={(v) =>
setFilters((f) => ({ ...f, fsr: v })) setFilters((f) => ({ ...f, upscaler: v }))
} }
/> />
<FilterSelect <FilterSelect
@@ -829,6 +841,11 @@ export function GamePageClient({
Raw Raw
</span> </span>
)} )}
{isPoorPerformancePreset(preset) && preset.fpsAvg !== null && (
<span className='inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded-full bg-red-500/10 border border-red-500/20 text-red-400 text-[9px] font-semibold'>
Slow
</span>
)}
</div> </div>
<p className='text-xs text-text/50 mt-0.5'> <p className='text-xs text-text/50 mt-0.5'>
{preset.hardwareName} {preset.hardwareName}
@@ -869,11 +886,12 @@ export function GamePageClient({
{/* Technology tags */} {/* Technology tags */}
<div className='flex flex-wrap items-center gap-1.5'> <div className='flex flex-wrap items-center gap-1.5'>
{preset.fsrVersion && {preset.upscalerType &&
preset.fsrVersion !== preset.upscalerType !==
"none" && ( "none" && (
<span className='px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-500/10 text-purple-400 border border-purple-500/20'> <span className='px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-500/10 text-purple-400 border border-purple-500/20'>
{preset.fsrVersion.toUpperCase()} {preset.upscalerType.toUpperCase()}
{preset.upscalerVersion ? ` ${preset.upscalerVersion}` : ""}
</span> </span>
)} )}
{preset.frameGenMethod && {preset.frameGenMethod &&
+17 -6
View File
@@ -5,17 +5,28 @@ import { EChartWrapper, CHART_THEME, getDeviceColor } from "./EChartWrapper"
import type { EChartsOption } from "echarts" import type { EChartsOption } from "echarts"
interface UpscalerStat { interface UpscalerStat {
fsrVersion: string upscalerType: string
upscalerVersion?: string | null
frameGenMethod: string frameGenMethod: string
hardwareSlug: string hardwareSlug: string
avgFps: number avgFps: number
count: number count: number
} }
function formatCombo(fsr: string, fg: string): string { function formatCombo(upscalerType: string, upscalerVersion: string | null | undefined, fg: string): string {
const parts: string[] = [] const parts: string[] = []
if (fsr !== "none") parts.push(fsr.toUpperCase()) if (upscalerType !== "none") {
if (fg !== "none") parts.push(fg === "fsr_fg" ? "FSR FG" : "DLSS FG") const upscalerLabel = upscalerVersion
? `${upscalerType.toUpperCase()} ${upscalerVersion}`
: upscalerType.toUpperCase()
parts.push(upscalerLabel)
}
if (fg !== "none") {
if (fg === "fsr_fg") parts.push("FSR FG")
else if (fg === "dlss_fg") parts.push("DLSS FG")
else if (fg === "lsfg") parts.push("LSFG")
else parts.push(fg.toUpperCase())
}
return parts.length > 0 ? parts.join(" + ") : "Native" return parts.length > 0 ? parts.join(" + ") : "Native"
} }
@@ -29,7 +40,7 @@ export function UpscalerBarChart({
const option = useMemo<EChartsOption>(() => { const option = useMemo<EChartsOption>(() => {
const combos = [ const combos = [
...new Set( ...new Set(
data.map((d) => formatCombo(d.fsrVersion, d.frameGenMethod)), data.map((d) => formatCombo(d.upscalerType, d.upscalerVersion, d.frameGenMethod)),
), ),
] ]
const deviceSlugs = [...new Set(data.map((d) => d.hardwareSlug))] const deviceSlugs = [...new Set(data.map((d) => d.hardwareSlug))]
@@ -40,7 +51,7 @@ export function UpscalerBarChart({
data: combos.map((combo) => { data: combos.map((combo) => {
const match = data.find( const match = data.find(
(d) => (d) =>
formatCombo(d.fsrVersion, d.frameGenMethod) === combo && formatCombo(d.upscalerType, d.upscalerVersion, d.frameGenMethod) === combo &&
d.hardwareSlug === slug, d.hardwareSlug === slug,
) )
return match?.avgFps ?? 0 return match?.avgFps ?? 0