feat(wizard): redesign environment step - upscaling options

- Replace FSR Version with flexible Upscaler Type + Version
- Add new upscaler options: AMD FSR, NVIDIA DLSS, Intel XeSS, Lossless Scaling FG, Other
- Expand Frame Gen options: lsfg, other
- Add Estimated Battery Life field (minutes)
- Add Custom / Modified System toggle
- Update review step with new summary rows
- Update submit body with new fields
This commit is contained in:
2026-04-27 07:24:23 +08:00
parent bcc0382001
commit 4943f24fd4
3 changed files with 104 additions and 32 deletions
+5 -2
View File
@@ -43,7 +43,7 @@ export function GameEntryWizard({ gameId, gameVersionId }: GameEntryWizardProps)
// Step 4: Environment // Step 4: Environment
const [environment, setEnvironment] = useState<EnvironmentData>({ const [environment, setEnvironment] = useState<EnvironmentData>({
fsrVersion: "none", upscalerType: "none",
frameGenMethod: "none", frameGenMethod: "none",
}) })
@@ -122,9 +122,12 @@ export function GameEntryWizard({ gameId, gameVersionId }: GameEntryWizardProps)
loadTimeSd: performance.loadTimeSd !== undefined ? Number(performance.loadTimeSd) : null, loadTimeSd: performance.loadTimeSd !== undefined ? Number(performance.loadTimeSd) : null,
protonVersion: environment.protonVersion || null, protonVersion: environment.protonVersion || null,
osVersion: environment.osVersion || null, osVersion: environment.osVersion || null,
fsrVersion: environment.fsrVersion ?? "none", upscalerType: environment.upscalerType ?? "none",
upscalerVersion: environment.upscalerVersion || null,
frameGenMethod: environment.frameGenMethod ?? "none", frameGenMethod: environment.frameGenMethod ?? "none",
launchOptions: environment.launchOptions || null, launchOptions: environment.launchOptions || null,
estimatedBatteryMin: environment.estimatedBatteryMin ?? null,
customSystem: environment.customSystem ?? false,
settingsJson: settingsJson.length > 0 ? settingsJson : null, settingsJson: settingsJson.length > 0 ? settingsJson : null,
userNotes: userNotes || null, userNotes: userNotes || null,
}), }),
+84 -11
View File
@@ -2,28 +2,35 @@
import { useEffect, useRef, useState, useCallback } from "react" import { useEffect, useRef, useState, useCallback } from "react"
import { motion, AnimatePresence } from "motion/react" import { motion, AnimatePresence } from "motion/react"
import { Terminal, ChevronDown, Loader2 } from "lucide-react" import { Terminal, ChevronDown, Loader2, ToggleLeft, ToggleRight } from "lucide-react"
import { api } from "@/lib/eden" import { api } from "@/lib/eden"
const FSR_OPTIONS = [ export const UPSCALER_TYPE_OPTIONS = [
{ value: "none", label: "None" }, { value: "none", label: "None" },
{ value: "fsr1", label: "FSR 1" }, { value: "fsr", label: "AMD FSR" },
{ value: "fsr2", label: "FSR 2" }, { value: "dlss", label: "NVIDIA DLSS" },
{ value: "fsr3", label: "FSR 3" }, { value: "xess", label: "Intel XeSS" },
{ value: "lsfg", label: "Lossless Scaling FG" },
{ value: "other", label: "Other" },
] as const ] as const
const FRAME_GEN_OPTIONS = [ export const FRAME_GEN_OPTIONS = [
{ value: "none", label: "None" }, { value: "none", label: "None" },
{ value: "fsr_fg", label: "FSR Frame Generation" }, { value: "fsr_fg", label: "FSR Frame Generation" },
{ value: "dlss_fg", label: "DLSS Frame Generation" }, { value: "dlss_fg", label: "DLSS Frame Generation" },
{ value: "lsfg", label: "Lossless Scaling FG" },
{ value: "other", label: "Other" },
] as const ] as const
export interface EnvironmentData { export interface EnvironmentData {
protonVersion?: string protonVersion?: string
osVersion?: string osVersion?: string
fsrVersion?: string upscalerType?: string
upscalerVersion?: string
frameGenMethod?: string frameGenMethod?: string
launchOptions?: string launchOptions?: string
estimatedBatteryMin?: number
customSystem?: boolean
} }
interface EnvironmentStepProps { interface EnvironmentStepProps {
@@ -184,14 +191,14 @@ export function EnvironmentStep({ value, onChange }: EnvironmentStepProps) {
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div className="space-y-1.5"> <div className="space-y-1.5">
<label className="text-xs font-medium text-text/60">FSR Version</label> <label className="text-xs font-medium text-text/60">Upscaler Type</label>
<div className="relative"> <div className="relative">
<select <select
value={value.fsrVersion ?? "none"} value={value.upscalerType ?? "none"}
onChange={(e) => update("fsrVersion", e.target.value)} onChange={(e) => update("upscalerType", e.target.value)}
className="w-full appearance-none px-4 py-3 rounded-lg border border-border bg-text/5 text-text text-sm outline-none focus:border-primary focus:ring-2 focus:ring-primary/50 transition-colors cursor-pointer" className="w-full appearance-none px-4 py-3 rounded-lg border border-border bg-text/5 text-text text-sm outline-none focus:border-primary focus:ring-2 focus:ring-primary/50 transition-colors cursor-pointer"
> >
{FSR_OPTIONS.map((opt) => ( {UPSCALER_TYPE_OPTIONS.map((opt) => (
<option key={opt.value} value={opt.value}> <option key={opt.value} value={opt.value}>
{opt.label} {opt.label}
</option> </option>
@@ -201,6 +208,21 @@ export function EnvironmentStep({ value, onChange }: EnvironmentStepProps) {
</div> </div>
</div> </div>
{value.upscalerType && value.upscalerType !== "none" && (
<div className="space-y-1.5">
<label className="text-xs font-medium text-text/60">Upscaler Version</label>
<input
type="text"
value={value.upscalerVersion ?? ""}
onChange={(e) => update("upscalerVersion", e.target.value)}
placeholder="e.g. 3.1"
className="w-full px-4 py-3 rounded-lg border border-border bg-text/5 text-text text-sm placeholder:text-text/40 outline-none focus:border-primary focus:ring-2 focus:ring-primary/50 transition-colors"
/>
</div>
)}
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div className="space-y-1.5"> <div className="space-y-1.5">
<label className="text-xs font-medium text-text/60">Frame Gen Method</label> <label className="text-xs font-medium text-text/60">Frame Gen Method</label>
<div className="relative"> <div className="relative">
@@ -233,6 +255,57 @@ export function EnvironmentStep({ value, onChange }: EnvironmentStepProps) {
Steam launch options or environment variables used. Steam launch options or environment variables used.
</p> </p>
</div> </div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 pt-2">
<div className="space-y-1.5">
<label className="text-xs font-medium text-text/60">
Estimated Battery Life (minutes)
</label>
<input
type="number"
min={1}
step={1}
value={value.estimatedBatteryMin ?? ""}
onChange={(e) => {
const val = e.target.value
onChange({
...value,
estimatedBatteryMin: val === "" ? undefined : Number(val),
})
}}
placeholder="e.g. 90"
className="w-full px-4 py-3 rounded-lg border border-border bg-text/5 text-text text-sm placeholder:text-text/40 outline-none focus:border-primary focus:ring-2 focus:ring-primary/50 transition-colors"
/>
<p className="text-xs text-text/40">
Approximate battery life in minutes while playing this game.
</p>
</div>
<div className="space-y-1.5">
<label className="text-xs font-medium text-text/60">
Custom / Modified System
</label>
<div className="flex items-center gap-3 py-3">
<button
type="button"
onClick={() => onChange({ ...value, customSystem: !value.customSystem })}
className={`flex items-center gap-2 text-sm cursor-pointer transition-colors ${
value.customSystem ? "text-primary" : "text-text/40"
}`}
>
{value.customSystem ? (
<ToggleRight className="h-5 w-5" />
) : (
<ToggleLeft className="h-5 w-5" />
)}
{value.customSystem ? "Yes" : "No"}
</button>
<span className="text-xs text-text/40">
Check if using custom firmware, OS, or mods that affect performance.
</span>
</div>
</div>
</div>
</div> </div>
) )
} }
+15 -19
View File
@@ -6,6 +6,7 @@ import { TiptapEditor } from "@/components/tiptap-editor"
import type { SettingCategory } from "@/components/wizard/settings-editor" import type { SettingCategory } from "@/components/wizard/settings-editor"
import type { PerformanceData } from "./performance-step" import type { PerformanceData } from "./performance-step"
import type { EnvironmentData } from "./environment-step" import type { EnvironmentData } from "./environment-step"
import { UPSCALER_TYPE_OPTIONS, FRAME_GEN_OPTIONS } from "./environment-step"
export interface ReviewData { export interface ReviewData {
hardwareSlug: string hardwareSlug: string
@@ -57,25 +58,18 @@ export function ReviewStep({
}: ReviewStepProps) { }: ReviewStepProps) {
const { hardwareName, performance, environment, settings } = data const { hardwareName, performance, environment, settings } = data
const fsrLabel = const upscalerLabel = (() => {
environment.fsrVersion === "none" if (!data.environment.upscalerType || data.environment.upscalerType === "none") return "None"
? "None" const opt = UPSCALER_TYPE_OPTIONS.find(o => o.value === data.environment.upscalerType)
: environment.fsrVersion === "fsr1" const base = opt?.label ?? data.environment.upscalerType
? "FSR 1" return data.environment.upscalerVersion ? `${base} ${data.environment.upscalerVersion}` : base
: environment.fsrVersion === "fsr2" })()
? "FSR 2"
: environment.fsrVersion === "fsr3"
? "FSR 3"
: "Not set"
const frameGenLabel = const frameGenLabel = (() => {
environment.frameGenMethod === "none" if (!environment.frameGenMethod || environment.frameGenMethod === "none") return "None"
? "None" const opt = FRAME_GEN_OPTIONS.find(o => o.value === environment.frameGenMethod)
: environment.frameGenMethod === "fsr_fg" return opt?.label ?? environment.frameGenMethod
? "FSR Frame Generation" })()
: environment.frameGenMethod === "dlss_fg"
? "DLSS Frame Generation"
: "Not set"
return ( return (
<div className="space-y-6"> <div className="space-y-6">
@@ -112,8 +106,10 @@ export function ReviewStep({
<SectionHeader icon={Terminal} label="Environment" /> <SectionHeader icon={Terminal} label="Environment" />
<SummaryRow label="Proton Version" value={environment.protonVersion || "Not set"} /> <SummaryRow label="Proton Version" value={environment.protonVersion || "Not set"} />
<SummaryRow label="OS Version" value={environment.osVersion || "Not set"} /> <SummaryRow label="OS Version" value={environment.osVersion || "Not set"} />
<SummaryRow label="FSR Version" value={fsrLabel} /> <SummaryRow label="Upscaler" value={upscalerLabel} />
<SummaryRow label="Frame Gen" value={frameGenLabel} /> <SummaryRow label="Frame Gen" value={frameGenLabel} />
<SummaryRow label="Estimated Battery" value={environment.estimatedBatteryMin ? `${environment.estimatedBatteryMin} min` : "Not set"} />
<SummaryRow label="Custom System" value={environment.customSystem ? "Yes" : "No"} />
{environment.launchOptions && ( {environment.launchOptions && (
<SummaryRow <SummaryRow
label="Launch Options" label="Launch Options"