docs: document download peer count chip
Update the launcher design reference so active downloads show how many LAN peers are currently seeding the transfer. The reference now places the peer chip between speed and ETA, describes the singular/plural copy, and records how the ETA and peer count collapse in narrow modal layouts. Test Plan: - git diff --cached --check
This commit is contained in:
+7
-4
@@ -251,10 +251,11 @@ grid-template-areas:
|
|||||||
```
|
```
|
||||||
|
|
||||||
- **Primary row** (`.dl-lg-primary`, top-left) — pulse dot + the uppercase live label `DOWNLOADING` in `color-mix(in srgb, var(--accent) 80%, white)`, 13px / 600, `letter-spacing: 0.02em`. This is the only place the word "Downloading" appears in the component.
|
- **Primary row** (`.dl-lg-primary`, top-left) — pulse dot + the uppercase live label `DOWNLOADING` in `color-mix(in srgb, var(--accent) 80%, white)`, 13px / 600, `letter-spacing: 0.02em`. This is the only place the word "Downloading" appears in the component.
|
||||||
- **Secondary row** (`.dl-lg-secondary`, bottom-left) — the live stats. 12px, three groups separated by `·` (0.45 opacity):
|
- **Secondary row** (`.dl-lg-secondary`, bottom-left) — the live stats. 12px, four groups separated by `·` (0.45 opacity):
|
||||||
1. `<strong>11.4 GB</strong> / 35 GB` (`var(--t-1)` strong + `var(--t-2)` rest)
|
1. `<strong>11.4 GB</strong> / 35 GB` (`var(--t-1)` strong + `var(--t-2)` rest)
|
||||||
2. `47.6 MB/s` (`var(--t-1)`)
|
2. `47.6 MB/s` (`var(--t-1)`)
|
||||||
3. `8 min left` (`var(--t-2)`)
|
3. `[users-icon] from <strong>5</strong> peers` — `.dl-peers`, inline-flex with 5px gap, icon at 0.7 opacity, count bold + tabular-nums in `var(--t-1)`, rest in `var(--t-2)`. Singular/plural switches on `peers === 1`. Hidden entirely when `game.peers` is falsy. Communicates that this is a LAN swarm transfer, not a single-source pull.
|
||||||
|
4. `8 min left` (`var(--t-2)`)
|
||||||
- **pct column** — large percentage, 20px / 700, `letter-spacing: -0.01em`, `var(--t-1)`. `%` glyph at 12px / 600 / 0.55 opacity.
|
- **pct column** — large percentage, 20px / 700, `letter-spacing: -0.01em`, `var(--t-1)`. `%` glyph at 12px / 600 / 0.55 opacity.
|
||||||
- **cancel column** — 28×28 square, `1px solid var(--bd-2)`, `border-radius: 6px`, X icon. Hover: bg `rgba(239,68,68,0.12)`, border `rgba(239,68,68,0.40)`, text `#fca5a5`. Cancelling reverts the game to its prior state (`local` if any data was kept, `none` otherwise) — dev decides the underlying behavior.
|
- **cancel column** — 28×28 square, `1px solid var(--bd-2)`, `border-radius: 6px`, X icon. Hover: bg `rgba(239,68,68,0.12)`, border `rgba(239,68,68,0.40)`, text `#fca5a5`. Cancelling reverts the game to its prior state (`local` if any data was kept, `none` otherwise) — dev decides the underlying behavior.
|
||||||
|
|
||||||
@@ -262,9 +263,10 @@ grid-template-areas:
|
|||||||
|
|
||||||
```css
|
```css
|
||||||
@container (max-width: 380px) { .dl-lg-secondary .dl-eta, .dl-lg-secondary .dl-sep-eta { display: none; } }
|
@container (max-width: 380px) { .dl-lg-secondary .dl-eta, .dl-lg-secondary .dl-sep-eta { display: none; } }
|
||||||
|
@container (max-width: 300px) { .dl-lg-secondary .dl-peers, .dl-lg-secondary .dl-sep-peers { display: none; } }
|
||||||
```
|
```
|
||||||
|
|
||||||
The ETA drops first if the modal narrows; bytes + speed stay (they're the actionable numbers). The pct/cancel column never collapses.
|
ETA drops first, then peers; bytes + speed always stay (they're the actionable numbers). The pct/cancel column never collapses.
|
||||||
|
|
||||||
### Number formatting
|
### Number formatting
|
||||||
|
|
||||||
@@ -287,10 +289,11 @@ type Game = {
|
|||||||
state: 'installed' | 'local' | 'downloading' | 'none';
|
state: 'installed' | 'local' | 'downloading' | 'none';
|
||||||
progress?: number; // 0–1, only when state === 'downloading'
|
progress?: number; // 0–1, only when state === 'downloading'
|
||||||
speed?: number; // current throughput in MB/s
|
speed?: number; // current throughput in MB/s
|
||||||
|
peers?: number; // number of LAN peers currently seeding
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
In the real app, `progress` and `speed` come from the download worker (Tauri command emitting events). The mock's `useLiveDownload(game)` hook (in `components.jsx`) is just a placeholder — 600ms `setInterval` advancing `progress` proportional to `speed`, with `speed` smoothed via a low-pass filter and small random drift so the number doesn't look fake. Replace with a `useEffect` that subscribes to your real progress events; the rendering layer needs nothing else.
|
In the real app, `progress`, `speed`, and `peers` come from the download worker (Tauri command emitting events). The mock's `useLiveDownload(game)` hook (in `components.jsx`) is just a placeholder — 600ms `setInterval` advancing `progress` proportional to `speed`, with `speed` smoothed via a low-pass filter and small random drift so the number doesn't look fake. `peers` is read straight off the game object (static in the mock); in production, push updates as peers join/leave the swarm — the `.dl-peers` chip re-renders silently. Replace the hook with a `useEffect` that subscribes to your real progress events; the rendering layer needs nothing else.
|
||||||
|
|
||||||
Filter changes:
|
Filter changes:
|
||||||
- `Local` filter includes `installed` + `local` + `downloading` (in-flight downloads belong on the Local tab — you're managing them).
|
- `Local` filter includes `installed` + `local` + `downloading` (in-flight downloads belong on the Local tab — you're managing them).
|
||||||
|
|||||||
@@ -159,6 +159,15 @@ function DownloadProgress({ game, accent, size = 'md', full = false }) {
|
|||||||
</span>
|
</span>
|
||||||
<span className="dl-sep">·</span>
|
<span className="dl-sep">·</span>
|
||||||
<span className="dl-speed">{fmtSpeed(speed)}</span>
|
<span className="dl-speed">{fmtSpeed(speed)}</span>
|
||||||
|
{game.peers > 0 && (
|
||||||
|
<React.Fragment>
|
||||||
|
<span className="dl-sep dl-sep-peers">·</span>
|
||||||
|
<span className="dl-peers" title={`Downloading from ${game.peers} ${game.peers === 1 ? 'peer' : 'peers'} on the LAN`}>
|
||||||
|
<Icon.users/>
|
||||||
|
<span>from <strong>{game.peers}</strong> {game.peers === 1 ? 'peer' : 'peers'}</span>
|
||||||
|
</span>
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
<span className="dl-sep dl-sep-eta">·</span>
|
<span className="dl-sep dl-sep-eta">·</span>
|
||||||
<span className="dl-eta">{fmtEta(etaSec)} left</span>
|
<span className="dl-eta">{fmtEta(etaSec)} left</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const GAMES = [
|
|||||||
{
|
{
|
||||||
id: 'avp', title: 'Aliens vs. Predator', size: 35.0, version: '2019.10.01',
|
id: 'avp', title: 'Aliens vs. Predator', size: 35.0, version: '2019.10.01',
|
||||||
desc: "Three campaigns, three nightmares. Be the alien stalking the dark, the predator hunting both, or the marine just trying to make it home with a working flashlight.",
|
desc: "Three campaigns, three nightmares. Be the alien stalking the dark, the predator hunting both, or the marine just trying to make it home with a working flashlight.",
|
||||||
state: 'downloading', progress: 0.32, speed: 49.4, players: '2–16', tags: ['FPS', 'Horror', 'Multiplayer'],
|
state: 'downloading', progress: 0.32, speed: 49.4, peers: 5, players: '2–16', tags: ['FPS', 'Horror', 'Multiplayer'],
|
||||||
cover: { c1: '#064e3b', c2: '#020617', accent: '#34d399', mood: 'dark' },
|
cover: { c1: '#064e3b', c2: '#020617', accent: '#34d399', mood: 'dark' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -120,7 +120,7 @@ const GAMES = [
|
|||||||
{
|
{
|
||||||
id: 'quake3', title: 'Quake III Arena', size: 0.5, version: '2010.08.15',
|
id: 'quake3', title: 'Quake III Arena', size: 0.5, version: '2010.08.15',
|
||||||
desc: "Arena FPS in its most distilled form. Rocket jumps, rail-gun duels, and a netcode that's still the benchmark.",
|
desc: "Arena FPS in its most distilled form. Rocket jumps, rail-gun duels, and a netcode that's still the benchmark.",
|
||||||
state: 'downloading', progress: 0.71, speed: 12.8, players: '2–16', tags: ['FPS', 'Arena', 'LAN'],
|
state: 'downloading', progress: 0.71, speed: 12.8, peers: 3, players: '2–16', tags: ['FPS', 'Arena', 'LAN'],
|
||||||
cover: { c1: '#7f1d1d', c2: '#0a0a0a', accent: '#fbbf24', mood: 'dark' },
|
cover: { c1: '#7f1d1d', c2: '#0a0a0a', accent: '#fbbf24', mood: 'dark' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -784,6 +784,12 @@
|
|||||||
}
|
}
|
||||||
.dl-lg-secondary .dl-bytes .dl-of { color: var(--t-2); font-weight: 500; }
|
.dl-lg-secondary .dl-bytes .dl-of { color: var(--t-2); font-weight: 500; }
|
||||||
.dl-lg-secondary .dl-speed { color: var(--t-1); font-weight: 600; white-space: nowrap; }
|
.dl-lg-secondary .dl-speed { color: var(--t-1); font-weight: 600; white-space: nowrap; }
|
||||||
|
.dl-lg-secondary .dl-peers {
|
||||||
|
display: inline-flex; align-items: center; gap: 5px;
|
||||||
|
color: var(--t-2); white-space: nowrap;
|
||||||
|
}
|
||||||
|
.dl-lg-secondary .dl-peers strong { color: var(--t-1); font-weight: 600; font-variant-numeric: tabular-nums; }
|
||||||
|
.dl-lg-secondary .dl-peers svg { opacity: 0.7; }
|
||||||
.dl-lg-secondary .dl-eta { white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
.dl-lg-secondary .dl-eta { white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.dl-sep { opacity: 0.45; }
|
.dl-sep { opacity: 0.45; }
|
||||||
|
|
||||||
@@ -792,6 +798,11 @@
|
|||||||
.dl-lg-secondary .dl-eta,
|
.dl-lg-secondary .dl-eta,
|
||||||
.dl-lg-secondary .dl-sep-eta { display: none; }
|
.dl-lg-secondary .dl-sep-eta { display: none; }
|
||||||
}
|
}
|
||||||
|
/* Even narrower: drop peers too, keep size + speed */
|
||||||
|
@container (max-width: 300px) {
|
||||||
|
.dl-lg-secondary .dl-peers,
|
||||||
|
.dl-lg-secondary .dl-sep-peers { display: none; }
|
||||||
|
}
|
||||||
|
|
||||||
.dl-lg-pct {
|
.dl-lg-pct {
|
||||||
grid-area: pct;
|
grid-area: pct;
|
||||||
|
|||||||
Reference in New Issue
Block a user