feat(neode-ui): mobile app-launch UX — store-driven panel, loader, ElectrumX icon

- Mobile launches use the store-driven panel (no route push) so the background
  tab no longer changes and closing returns to where you launched from.
- Tab-only apps open directly (in-app WebView on companion / new tab on PWA) —
  no "this app opens in a tab" interstitial.
- Shared AppLoadingScreen (app icon + progress bar) on the app session and the
  legacy iframe overlay instead of a black screen.
- Pin the dashboard to 100dvh on mobile so the mesh chat/tools panes stop sliding
  under the bottom tab bar in mobile browsers (no-op in the companion WebView).
- ElectrumX/electrs/electrs-ui ids now resolve to the real ElectrumX icon in My Apps.
- isMobile made reactive so overlay/footer/teleport decisions track the viewport.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-06-23 03:48:57 -04:00
co-authored by Claude Opus 4.8
parent db7d424bff
commit a7c7c44843
11 changed files with 387 additions and 56 deletions
+24 -2
View File
@@ -11,15 +11,37 @@
*/
interface ArchipelagoNativeBridge {
openExternal?: (url: string) => void
openInApp?: (url: string) => void
}
function nativeBridge(): ArchipelagoNativeBridge | undefined {
return (window as unknown as { ArchipelagoNative?: ArchipelagoNativeBridge }).ArchipelagoNative
}
export function openExternalUrl(url: string): void {
if (!url) return
const native = (window as unknown as { ArchipelagoNative?: ArchipelagoNativeBridge })
.ArchipelagoNative
const native = nativeBridge()
if (native && typeof native.openExternal === 'function') {
native.openExternal(url)
return
}
window.open(url, '_blank', 'noopener,noreferrer')
}
/**
* Launch an app that can't be embedded in an iframe (X-Frame-Options) from a
* mobile surface — with NO "this app opens in a tab" interstitial.
*
* - Android companion: hand it to the in-app WebView (`openInApp`) so it stays
* inside Archipelago with the native back/forward/reload/close controls.
* - Plain mobile browser (PWA): open directly in a new browser tab.
*/
export function openInAppOrNewTab(url: string): void {
if (!url) return
const native = nativeBridge()
if (native && typeof native.openInApp === 'function') {
native.openInApp(url)
return
}
window.open(url, '_blank', 'noopener,noreferrer')
}