Everything written this session that has not been through the device: rounds 43 to 48 (each patch adversarially verified, 43's transient-notice expectation fixed), a partial round 49, the pipeline scripts, the Android Auto design and the icon comparison mock. Also the two harness changes that were never A/B'd — adaptive waits, which may only shorten a declared wait and never lengthen it, and a ship that runs the mock walk and the deploy at the same time. The A/B and its 255-step baseline are in handoff/tools; main stays at what the phone has actually walked.
63 lines
3.2 KiB
JavaScript
63 lines
3.2 KiB
JavaScript
// Round seventeen: the nav's badges — the desktop's title-bar download ring
|
|
// as a count on You while transfers are in flight, and the unread chats
|
|
// on Community.
|
|
const fs = require('fs');
|
|
const root = process.env.SS_ROOT || 'F:/Coding/SoulStream/';
|
|
let p, s;
|
|
const load = (file) => { p = file; s = fs.readFileSync(root + p, 'utf8'); };
|
|
const save = () => fs.writeFileSync(root + p, s);
|
|
const once = (a) => {
|
|
const i = s.indexOf(a);
|
|
if (i < 0) throw new Error('missing in ' + p + ': ' + a.slice(0, 90));
|
|
if (s.indexOf(a, i + 1) >= 0) throw new Error('ambiguous in ' + p + ': ' + a.slice(0, 90));
|
|
return i;
|
|
};
|
|
const rep = (a, b) => { once(a); s = s.replace(a, () => b); };
|
|
|
|
load('src/mobile/Mobile.svelte');
|
|
rep(` import { transfers, bindTransfers } from "./transfers.svelte.js";`,
|
|
` import { transfers, bindTransfers, active as activeTransfers } from "./transfers.svelte.js";`);
|
|
rep(` import { slsk, bindSlsk, connectStored } from "./slsk.svelte.js";`,
|
|
` import { slsk, bindSlsk, connectStored, unreadTotal } from "./slsk.svelte.js";`);
|
|
rep(` <span class="gl"><Icon name={icon} size={22} /></span>
|
|
<span class="lb">{label}</span>
|
|
</button>
|
|
{/each}
|
|
</nav>`,
|
|
` <span class="gl">
|
|
<Icon name={icon} size={22} />
|
|
{#if id === "you" && activeTransfers().length}<span class="nb">{activeTransfers().length}</span>{/if}
|
|
{#if id === "community" && unreadTotal()}<span class="nb">{unreadTotal()}</span>{/if}
|
|
</span>
|
|
<span class="lb">{label}</span>
|
|
</button>
|
|
{/each}
|
|
</nav>`);
|
|
save();
|
|
|
|
load('src/mobile/shell.css');
|
|
s = s.replace(/\s*$/, String.fromCharCode(10)) + `
|
|
/* the nav's badges: transfers in flight on You, unread chats on Community */
|
|
.nav button .gl .nb { position: absolute; top: -3px; right: -12px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px; background: var(--accent); color: #04121a; font-size: 10px; font-weight: 800; line-height: 16px; text-align: center; box-shadow: 0 0 0 2px var(--nav-bg, #101014); }
|
|
`;
|
|
save();
|
|
|
|
load('tests/mobile/smoke.mjs');
|
|
rep(` countline: (document.querySelector('.countline .t-sub') || {}).textContent || '',`,
|
|
` countline: (document.querySelector('.countline .t-sub') || {}).textContent || '',
|
|
navBadges: [].map.call(document.querySelectorAll('.nav .nb'), function (b) { return b.textContent.trim(); }).join('|'),`);
|
|
// A record saving: You's badge counts the flight. The assertion belongs
|
|
// HERE and not on the Transfers screen two steps later — by the time the
|
|
// walk has settled and tapped its way to You, the mock's burst has already
|
|
// finished and the badge is correctly gone.
|
|
rep(` "cat-album-save": (i) => /^Saving \\d+ from /.test(i.save),`,
|
|
` "cat-album-save": (i) => /^Saving \\d+ from /.test(i.save) && /^\\d+$/.test(i.navBadges),`);
|
|
save();
|
|
|
|
load('ANDROID.md');
|
|
rep(`The Library's count line carries the collection's hours`, `The nav wears two badges the desktop's chrome has: transfers in flight on
|
|
You (the title bar's download ring) and unread chats on Community.
|
|
The Library's count line carries the collection's hours`);
|
|
save();
|
|
console.log('round seventeen wired');
|