The orange "gamepad selection" lift+glow was plain CSS :focus styling on
[data-controller-container] — any tap on a tabindex card lit it up (worst
on mobile), and useControllerNav's autoFocusMain programmatically focused
the first card on mount and every route change, painting the ring with no
controller input at all.
Gate it behind html.controller-nav, toggled by actual input modality:
arrow-key navigation and gamepad connection turn it on, any pointerdown
turns it off. autoFocusMain now no-ops outside directional-nav mode (a
first arrow press focuses the first container instead of spatially
navigating from <body>), so pointer users never get surprise rings while
keyboard/gamepad users keep the exact same navigation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On kiosk, chromium runs software-composited (--in-process-gpu or
--disable-gpu, one raster thread). The dashboard's 3D-transformed
will-change background layers and the infinite mix-blend-mode:multiply
fixed overlays routinely fail to repaint there after the first
interaction/route change, leaving the container's black fill (or a stuck
multiply layer) covering the screen.
A kiosk-mode class is now set on <html> (localStorage kiosk flag, ?kiosk
param, or the /kiosk boot path) and gates CSS overrides: background
layers become plain 2D opacity crossfades (no preserve-3d/translateZ/
will-change) and the animated multiply overlays are disabled.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Top-level Cloud tabs get their own orange-tinted switcher (clearly
distinct from the category pills); full-width thirds on mobile
- 'All Files' tab renamed Folders; categories only show on the file-list
tabs (My Files / Peer Files / search)
- My Files is now a flat list of every own file rendered with FileCard —
real actions (share/download/delete) and clicking opens the FILE
(media lightbox incl. audio, downloads for documents), never a folder;
own search results get the same treatment
- Folder list rows get card backgrounds (readable over the wallpaper),
same info as before
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Native select arrows rendered with inconsistent right padding across
views and long labels could overflow into the icon. Global select rule:
appearance-none + a single SVG chevron at a fixed inset, uniform
padding-right (overrides ad-hoc pr-* utilities), ellipsis truncation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Brave Android (custom bottom toolbar) and some other mobile browsers report
dvh taller than the actually visible area while position:fixed elements track
the visible viewport — so 100dvh containers extended under the browser tab
bar and the bottom of every page could never be scrolled into view.
main.ts now keeps --visual-viewport-height synced to window.innerHeight
(resize / orientationchange / visualViewport events — the same reference
frame as the fixed tab bar), and the dashboard shell, chat, and app-session
mobile heights consume it with 100dvh as fallback. The app now scales with
the browser chrome as it shows/hides. Scroll clearance margin 16px → 28px.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 100dvh pin only applied below 768px; between 768–920px mobile browsers
still sized the dashboard to 100vh, hiding the bottom of every page behind
the browser tab bar with no way to scroll it into view. Apply the same pin
at ≤920px so pages always scroll fully clear with the scroll-pad margin.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Mesh: fix 920-1280px bottom margin (phantom mobile-nav reservation
leaking into the desktop-sidebar range), let the mesh view scale to
full width on wide screens instead of capping at 1600px, and make the
Device panel collapsible on desktop (previously mobile-only)
- Search/controller-nav: a global gamepad/keyboard-nav feature was
auto-clicking "the next button in the DOM" on Enter in any text input,
which cleared the mesh peer search and popped the sideload modal from
the App Store/My Apps search boxes. Opt out via data-controller-no-submit
on all filter inputs; bump the mesh clear button's touch target
- Modals: several (sideload, credential, Lightning channel open, identity
create) used ad-hoc blue buttons and non-fullscreen backdrops that only
covered the main content area, not the sidebar. Teleport them to body,
unify backdrop/button theming to the dark+orange convention, fix the
sideload modal's square bottom corners on desktop, and standardize
close buttons to the ghost-icon style
- Web5: remove the redundant/dead "Messages" tab from Connected Nodes
(its deep-link was unreachable dead code); fix the "view message" toast
to actually open the Archipelago channel instead of silently failing to
match a LoRa peer; make identity rows responsive via a container query
(viewport-based breakpoints don't work in the page's 2-column grid) and
right-justify their action icons; collapse DID/DHT/Wallet/Nostr/Connected
Nodes by default on mobile
- Apps/App Store: match the search bar and sideload button's height,
padding, and background to the mode-switcher tabs beside them
- Mesh chat: keep the compose input focused after sending
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 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>
- Apps tab: a horizontal swipe that starts on an app icon no longer flips the
top tab — it lets the app-page scroll / icon tap win (swipe empty space to
change tab). Fixes the swipe conflict with two pages of apps.
- Files: file cover tiles are forced square on mobile (aspect driven by CSS,
not a Tailwind arbitrary class) so the grid is uniform and tappable.
- Files: scroll container gets bottom safe-area + tab-bar padding so the last
row clears the mobile back button / bottom nav.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
UI (this session):
- Global audio player now scales the whole interface into the space above it
on desktop (sidebar + main) and docks directly above the tab bar on mobile;
it stays visible while navigating.
- Mesh mobile redesign: floating Chat / BTC / Dead Man / AI / Map tab strip
with a single fixed, internally-scrolling pane (page no longer scrolls);
tabs hide while a conversation is open; floating back button; collapsible
Device panel (starts collapsed); keyboard-aware conversation sizing via
VisualViewport so the chat sits just above the keyboard.
- Cloud file grid: uniform 4/3 card heights (folders + images match).
- Swipe left/right switches tabs on the Apps and Web5 screens.
- Map tool fills its pane (no bottom gap); fix skewed Share Location toggle
on mobile (global min-height rule was deforming the switch).
- Trim redundant helper copy from the mesh AI tab.
Also bundles pre-existing in-progress work that was already in the tree:
mesh listener/session + wallet + container + bitcoin-status backend changes,
docker UI updates, and assorted other UI tweaks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The kiosk attached-display showed a separate app-tile launcher grid
(Kiosk.vue at /kiosk) instead of the normal onboarding/login/dashboard.
The grid is auth-gated, so it only surfaced once the kiosk browser held a
persisted session; otherwise it bounced to login — masking the issue.
Remove the grid entirely. /kiosk now just persists kiosk mode + safe-area
insets and redirects to the root app. The launcher keeps pointing at
/kiosk (not directly at /) so the 'kiosk' localStorage flag is still set —
App.vue uses it to skip the remote relay, which would otherwise double
xdotool input on the kiosk display. Route made public so the auth guard
doesn't bounce it before the redirect runs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add AppIconGrid: 4-column swipeable icon grid with page dots for My Apps on mobile
- Tab bar: remove text labels, square icon-only buttons (w-14 h-14), doubled padding
- Hide tab bar and top context tabs when app session is open
- App session header hidden on mobile, replaced with floating glass close button
- App sessions now render fullscreen on mobile without nav chrome
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- fix: login disconnect — verify session before WebSocket connect
- fix: 403 on app install — distinguish CSRF vs RBAC errors, only retry CSRF
- fix: health monitor now watches ALL containers (removed skip list for
backend services like nbxplorer, databases, UI containers)
- fix: server.get-state added to CSRF-exempt list (read-only)
- fix: ISO build includes container-specs.sh and lib/common.sh in rootfs
so reconcile actually works on fresh installs
- fix: gamepad nav — improved Server tab zone nav, focus styles, autofocus
- chore: move L484 web-only apps to Services tab
- chore: install store for cross-view install tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove path-action-button from focus-visible suppression list
- Orange glow now shows on Continue when autofocused
- Bump autofocus delay to 500ms to clear slide transition
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- glass-button gets orange glow on focus-visible (was suppressed)
- Input fields get orange border on focus-visible
- Restore link made focusable (tabindex, role, keydown.enter)
- Gamepad nav sounds play via existing fallback handler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mode-switcher-btn-active gets orange glass (bg, border, glow).
mode-switcher-btn:focus-visible gets orange ring on gamepad focus.
Sidebar nav-tab-active reverted to original white/black glass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Nav-tab-active now uses orange glass (bg, border, glow, gradient)
- Sidebar focus-visible uses matching orange tint
- Enter on containers skips uninstall button, finds primary action
- Down/Right from grid edges falls back to all focusable elements
- Global fallback for standalone buttons in empty/error states
- Full gamepad nav map for all onboarding screens + login modes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- rpc-client: don't redirect to /login on 401 during onboarding flow,
which caused session expired kicks on fresh installs
- style.css: add translateZ(0) + isolation:isolate to glass-card,
glass-strong, path-option-card to fix Chromium compositor bug where
backdrop-filter + animated fixed overlays cause black rectangles
- App.vue: pause background animations when tab hidden, force
compositor layer rebuild on tab return to prevent stale renders
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- F29-F32: Split 4 views (Marketplace 1293→505, Server 1132→486, Home 1059→394, AppDetails 1036→386)
- F20: Add aria-current="page" to Dashboard nav links
- F21: Add 150ms search debounce in Marketplace and Apps views
- F22: Reduce backdrop-filter blur to 8px on mobile for GPU performance
- F23: Track and clear WebSocket connect check interval in all paths
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New Discover.vue with hero banner, featured sovereignty stack apps,
principle cards, manifesto footer, and full app grid
- Featured apps (Bitcoin Knots, LND, BTCPay, Vaultwarden) with
expanded privacy/sovereignty descriptions
- Discover is first tab in categories bar on App Store pages
- Smart back navigation: detail pages return to Discover when navigated from there
- Category clicks from Discover navigate to Marketplace with category pre-selected
- Cypherpunk aesthetic: terminal tags, scanline overlays, gradient accents,
animated Bitcoin orange headings
- Global CSS classes: discover-hero, discover-terminal-tag, discover-featured-card,
discover-principle-card, discover-manifesto
- Route added: /dashboard/discover
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show 'core' (orange) and 'recommended' (blue) badges next to app titles
- getAppTier() classifies apps matching backend get_app_tier()
- Global .tier-badge, .tier-badge-core, .tier-badge-recommended CSS classes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Settings page shows all Tor hidden services with toggle switches
(enable/disable per app) and a Rotate button for the main node address.
Added RPC client methods for tor.list-services, tor.toggle-app,
tor.rotate-service, tor.cleanup-rotated. Toggle CSS classes in style.css.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All modals now close with Escape key. Interactive card divs respond to
Enter key. Skip-to-content link added to Dashboard layout. All Web5 and
Settings modals get role=dialog, aria-modal, and escape handlers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Onboarding:
- Fixed viewport to use dvh units with position:fixed container
- All views use scrollable glass containers that fit within viewport
- Responsive typography and spacing (mobile-first breakpoints)
- Tighter padding/margins on small screens
- RootRedirect checks localStorage first for instant redirect
- Spinner only appears after 500ms delay to avoid flash
Filebrowser:
- Fix CloudFolder null initialPath crash (watch both useNativeUI + section)
- Remove unused `host` computed (was causing TS error)
- Add mock GET /app/filebrowser/ landing page
- Increase express.json limit to 50mb
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The My Apps page went blank after installing apps because pkg['static-files'].icon
was accessed without optional chaining on dynamically installed packages that lack
the static-files property.
- Make static-files optional in PackageDataEntry type
- Add defensive ?.icon access with fallback in Apps.vue and AppDetails.vue
- Add filebrowser to mock backend staticDevApps (enables Cloud page in demo)
- Expand portMappings and marketplaceMetadata for all marketplace apps
- installPackage now uses staticApp() format for consistent data shape
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The credential issuance and verification handlers used
Handle::block_on() directly inside the tokio runtime, causing a
deadlock. Wrapped with block_in_place() to properly yield the
runtime thread.
Also completed full feature verification across all 25 test groups
(~175 checks) on live server.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>