diff options
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/app.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/app.js | 74 |
1 files changed, 55 insertions, 19 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js index 4091ae7..f49d412 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js @@ -569,7 +569,8 @@ function TransferWidget() { // ── Nav ────────────────────────────────────────────────────────────────────── -function Nav({ user, theme, onThemeChange, onLogout, onMenuToggle, unreadCount }) { +function Nav({ user, theme, onThemeChange, onLogout, onMenuToggle, unreadCount, + hubUnset }) { return html` <nav class="nav"> <div class="nav-left"> @@ -590,7 +591,7 @@ function Nav({ user, theme, onThemeChange, onLogout, onMenuToggle, unreadCount } ${user ? html` <${UserMenu} user=${user} theme=${theme} onThemeChange=${onThemeChange} onLogout=${onLogout} /> - ` : html` + ` : hubUnset ? null : html` <a class="nav-btn" href="#/login">${t('nav.login')}</a> `} </div> @@ -681,18 +682,21 @@ function FirstRunPage({ onSet }) { }; return html` - <div class="auth-page"> - <h2>${t('firstrun.title')}</h2> - <p class="settings-hint">${t('firstrun.hint')}</p> - <form onSubmit=${submit}> - <input type="url" placeholder="https://meshbay.org" required - value=${url} onInput=${e => setUrl(e.target.value)} /> - <button type="submit" disabled=${busy}> - ${busy ? '…' : t('firstrun.btn')} - </button> - </form> - ${error && html`<p class="error-msg">${error}</p>`} - <p class="settings-hint">${t('firstrun.note')}</p> + <div class="page-center"> + <div class="card login-card"> + <h2>${t('firstrun.title')}</h2> + <p class="settings-hint" style="margin-bottom:16px">${t('firstrun.hint')}</p> + <form onSubmit=${submit}> + <input type="text" placeholder="https://meshbay.org" required + autofocus value=${url} + onInput=${e => setUrl(e.target.value)} /> + <button type="submit" disabled=${busy}> + ${busy ? t('firstrun.checking') : t('firstrun.btn')} + </button> + </form> + ${error && html`<div class="error-msg">${error}</div>`} + <p class="settings-hint" style="margin-top:16px">${t('firstrun.note')}</p> + </div> </div> `; } @@ -1185,6 +1189,26 @@ const PIPELINE_WINDOW = 8; */ async function _openDownloadTarget(filename, size = 0, pickerOpts = {}, swSize = size) { + // On a desktop build this is the whole answer, and it comes first. + // + // The two browser paths below are both unavailable there — `showDirectoryPicker` + // does not exist, and Chromium refuses a service worker on a custom scheme — + // so without this the chain fell all the way through to its floor, which + // collects the file in the page and hands the browser a blob. A gigabyte of + // film meant a gigabyte of RAM, and a Save As dialog at the *end*. + if (platform.capabilities.nativeSave) { + try { + const native = await platform.nativeSave( + filename, { auto: downloads.getMode() === 'auto' }); + // Null means the person dismissed the dialog, which is not an error and + // must not start a transfer. + return native || false; + } catch (err) { + console.warn('[MeshBay] native save failed:', platform.bridgeMessage(err)); + return false; + } + } + try { const target = await downloads.openTarget(filename); if (target) return target; @@ -4013,10 +4037,20 @@ function SettingsPage({ user, theme, onThemeChange, groups }) { hubFetch('/v1/hub/version').then(setHubInfo).catch(() => {}); }, []); - useEffect(() => { downloads.savedDirectory().then(setDlDir); }, []); + useEffect(() => { + // The desktop build remembers a path; the browser remembers a handle. Both + // answer "where do downloads go", and the row below renders either. + if (platform.folder.available) platform.folder.get().then(setDlDir); + else downloads.savedDirectory().then(setDlDir); + }, []); const pickFolder = useCallback(async () => { try { + if (platform.folder.available) { + const dir = await platform.folder.choose(); + if (dir) setDlDir(dir); + return; + } const handle = await downloads.chooseDirectory(); setDlDir(handle); } catch (err) { @@ -4033,7 +4067,7 @@ function SettingsPage({ user, theme, onThemeChange, groups }) { <div class="settings-section"> <h3 class="settings-heading">${t('settings.downloads')}</h3> - ${!downloads.SUPPORTED + ${!(downloads.SUPPORTED || platform.folder.available) ? html`<p class="settings-hint">${t('settings.dl_unsupported')}</p>` : html` <label class="settings-choice"> @@ -4054,7 +4088,8 @@ function SettingsPage({ user, theme, onThemeChange, groups }) { </label> <div class="settings-row" style="margin-top:10px"> <span class="settings-label"> - ${dlDir ? t('settings.dl_folder', { name: dlDir.name }) + ${dlDir ? t('settings.dl_folder', + { name: dlDir.name || String(dlDir) }) : t('settings.dl_no_folder')} </span> <span> @@ -4063,7 +4098,8 @@ function SettingsPage({ user, theme, onThemeChange, groups }) { </button> ${dlDir && html` <button class="btn-secondary" onClick=${async () => { - await downloads.forgetDirectory(); + if (platform.folder.available) await platform.folder.forget(); + else await downloads.forgetDirectory(); setDlDir(null); }}>${t('settings.dl_forget')}</button> `} @@ -4869,7 +4905,7 @@ function App() { onThemeChange=${changeTheme} onLogout=${authCtx.logout} onMenuToggle=${() => setMenuOpen(o => !o)} - unreadCount=${unreadCount} /> + unreadCount=${unreadCount} hubUnset=${needsHub} /> <div class="layout"> ${user && html`<${Sidebar} groups=${groups} |