docs(design): redesign game-folder button as icon + label + dot
The previous design squeezed the full game-directory path into the
top-bar button as truncated `ui-monospace` (e.g.
`…s/Desktop/eti_games_AFTER_LAN_2025`). In practice the leading-ellipsis
truncation rarely showed the meaningful part of the path on real-world
configurations, ate horizontal space the new 3-zone top bar needs for
its actual primary controls, and competed with the filter / search /
sort cluster for attention.
Replace the inline path with an icon + short label + colored status
dot. The full path moves into the tooltip and `aria-label`, where it's
still one mouseover (and screen-reader friendly) away. The button now
communicates the *state* of the configuration at a glance — which is
what users actually need.
Two visual states, both 36 px tall with the same surface as the other
top-bar controls:
- **Set & valid** — label `Game folder`, green dot (`--ok`) with a
soft glow, default border, tooltip = full path.
- **Not set / invalid** — label `Set game folder`, red dot (`--danger`)
with a soft glow, a red-tinted border, and a faint red wash on
hover so the bad state reads as "this is what you need to fix".
Tooltip = `Please select a game folder`.
"Invalid" (a path is stored but doesn't exist on disk) is collapsed
into the same visual state as "not set" — the user's required action
is identical (open the picker, pick a folder), so a third state
isn't worth the visual budget yet. If we later want to surface a
*last-known* path so the user can re-attach an external drive,
introduce a distinct missing state then.
Implementation notes:
- `DirectoryButton` now takes a single `path: string | null` prop and
picks state from `!!(path && path.trim())`. Children are
`Icon.folder`, the label, and an 8 px `.dirbtn-status-dot` sibling
— the dot is an inline flex sibling, not a corner badge, because
the button is now wider than tall and a corner pin would feel
misplaced.
- `.dirbtn` is `inline-flex` with `padding: 0 14px 0 12px`, gap 8 px,
`white-space: nowrap`, and `flex-shrink: 0`. The `max-width: 360px`
cap from the path-truncation era is gone — the button is now
intrinsically sized.
- Dot glow uses `box-shadow: 0 0 6px color-mix(...)` so it still
reads through the launcher's translucent top-bar background.
- The Tweaks panel grows a dev-only `Game folder set` toggle (under
the new *Library* section) that flips a `gameFolderSet` flag wired
into the Launcher, so reviewers can see both states without
fiddling with real filesystem state. The README explicitly calls
this out as **dev-only** — production state comes from the
settings store, not a user-facing toggle.
The README gains a new *Game-folder button* section with the full
spec, a state table, and a rationale paragraph; the "Changes since v2"
list and the interactions list are updated to reflect the new label
and behavior.
Test Plan
- Open `design_reference/SoftLAN Launcher.html` and locate the Tweaks
panel's *Library → Game folder set* toggle.
- With the toggle **on**: the top-bar button shows `Game folder`
with a green dot; hovering the button reveals the full mock path
in the native tooltip.
- With the toggle **off**: the label switches to `Set game folder`,
the dot turns red, the border picks up a red tint, and hovering
the button reveals `Please select a game folder`.
- Inspect the button with a screen reader / DevTools accessibility
pane: the `aria-label` should read `Game folder: <path>` when set
and `Set game folder` when unset.
This commit is contained in:
@@ -359,29 +359,41 @@
|
||||
|
||||
/* ─── Directory button ─── */
|
||||
.dirbtn {
|
||||
position: relative;
|
||||
display: inline-flex; align-items: center; gap: 8px;
|
||||
height: 36px; padding: 0 12px;
|
||||
height: 36px; padding: 0 14px 0 12px;
|
||||
background: var(--bg-2);
|
||||
border: 1px solid var(--bd-1);
|
||||
border-radius: 8px;
|
||||
color: var(--t-2);
|
||||
font: inherit; font-size: 12.5px;
|
||||
color: var(--t-1);
|
||||
font: inherit; font-size: 12.5px; font-weight: 600;
|
||||
cursor: pointer;
|
||||
max-width: 360px;
|
||||
transition: border-color .15s, color .15s;
|
||||
flex-shrink: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.dirbtn:hover { border-color: var(--bd-2); color: var(--t-1); }
|
||||
.dirbtn-label { color: var(--t-1); font-weight: 600; flex-shrink: 0; }
|
||||
.dirbtn-path {
|
||||
color: var(--t-3);
|
||||
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
||||
font-size: 11.5px;
|
||||
transition: border-color .15s, color .15s, background .15s;
|
||||
flex-shrink: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
min-width: 0;
|
||||
}
|
||||
.dirbtn:hover { border-color: var(--bd-2); }
|
||||
.dirbtn-label { line-height: 1; }
|
||||
.dirbtn-status-dot {
|
||||
width: 8px; height: 8px;
|
||||
margin-left: 2px;
|
||||
border-radius: 999px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.dirbtn-set .dirbtn-status-dot {
|
||||
background: var(--ok);
|
||||
box-shadow: 0 0 6px color-mix(in srgb, var(--ok) 70%, transparent);
|
||||
}
|
||||
.dirbtn-unset .dirbtn-status-dot {
|
||||
background: var(--danger);
|
||||
box-shadow: 0 0 6px color-mix(in srgb, var(--danger) 70%, transparent);
|
||||
}
|
||||
.dirbtn-unset {
|
||||
border-color: color-mix(in srgb, var(--danger) 35%, var(--bd-1));
|
||||
}
|
||||
.dirbtn-unset:hover {
|
||||
border-color: color-mix(in srgb, var(--danger) 55%, var(--bd-2));
|
||||
background: color-mix(in srgb, var(--danger) 8%, var(--bg-2));
|
||||
}
|
||||
|
||||
/* ─── Kebab menu ─── */
|
||||
|
||||
Reference in New Issue
Block a user