fix(ui): treat missing game folders as unset
Validate the persisted game directory before sending it to the backend or showing library content for it. When the saved path no longer exists, the launcher keeps the top bar visible but shows the folder picker empty state and labels the Game Folder button as an unset folder. This keeps stale local data from being presented as the active library when an old path is deleted or disconnected. Test Plan: - git diff --check - just frontend-test - just build
This commit is contained in:
@@ -7,11 +7,7 @@ interface Props {
|
||||
export const NoDirectoryState = ({ onChooseDirectory }: Props) => (
|
||||
<div className="empty-state">
|
||||
<div className="empty-state-icon"><Icon.folder /></div>
|
||||
<h2 className="empty-state-title">Pick a game directory</h2>
|
||||
<p className="empty-state-hint">
|
||||
SoftLAN scans the folder you point it at for installable game bundles
|
||||
and tracks what your peers on the LAN have available.
|
||||
</p>
|
||||
<h2 className="empty-state-title">Please select a game folder</h2>
|
||||
<button type="button" className="ghost-btn" onClick={onChooseDirectory}>
|
||||
<Icon.folder />
|
||||
<span>Choose folder</span>
|
||||
|
||||
@@ -2,19 +2,21 @@ import { Icon } from '../Icon';
|
||||
|
||||
interface Props {
|
||||
path: string | null;
|
||||
exists: boolean;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export const DirectoryButton = ({ path, onClick }: Props) => {
|
||||
export const DirectoryButton = ({ path, exists, onClick }: Props) => {
|
||||
const isSet = !!(path && path.trim());
|
||||
const label = isSet ? 'Game folder' : 'Set game folder';
|
||||
const tooltip = isSet ? (path as string) : 'Please select a game folder';
|
||||
const ariaLabel = isSet ? `Game folder: ${path}` : 'Set game folder';
|
||||
const isValid = isSet && exists;
|
||||
const label = isValid ? 'Game folder' : 'Set game folder';
|
||||
const tooltip = isValid ? (path as string) : 'Please select a game folder';
|
||||
const ariaLabel = isValid ? `Game folder: ${path}` : 'Set game folder';
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={`dirbtn ${isSet ? 'dirbtn-set' : 'dirbtn-unset'}`}
|
||||
className={`dirbtn ${isValid ? 'dirbtn-set' : 'dirbtn-unset'}`}
|
||||
title={tooltip}
|
||||
aria-label={ariaLabel}
|
||||
onClick={onClick}
|
||||
|
||||
@@ -18,6 +18,7 @@ interface Props {
|
||||
sort: GameSort;
|
||||
setSort: (value: GameSort) => void;
|
||||
gameDir: string;
|
||||
gameDirExists: boolean;
|
||||
onPickDirectory: () => void;
|
||||
kebabItems: ReadonlyArray<KebabItem>;
|
||||
}
|
||||
@@ -32,6 +33,7 @@ export const TopBar = ({
|
||||
sort,
|
||||
setSort,
|
||||
gameDir,
|
||||
gameDirExists,
|
||||
onPickDirectory,
|
||||
kebabItems,
|
||||
}: Props) => (
|
||||
@@ -49,7 +51,7 @@ export const TopBar = ({
|
||||
<div className="topbar-right-lead">
|
||||
<SortMenu value={sort} onChange={setSort} />
|
||||
</div>
|
||||
<DirectoryButton path={gameDir} onClick={onPickDirectory} />
|
||||
<DirectoryButton path={gameDir} exists={gameDirExists} onClick={onPickDirectory} />
|
||||
<KebabMenu items={kebabItems} />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
Reference in New Issue
Block a user