feat(ui): mobile mesh tabs, AIUI-style audio player, cloud grid + map fixes

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>
This commit is contained in:
archipelago
2026-06-19 09:52:26 -04:00
co-authored by Claude Opus 4.8
parent c4855526fe
commit 1bce694ebb
37 changed files with 1260 additions and 208 deletions
+35 -4
View File
@@ -1,12 +1,10 @@
<template>
<!-- Spacer to prevent content from being hidden behind the player -->
<div v-if="audioPlayer.currentName.value" class="h-14"></div>
<Teleport to="body">
<Transition name="slide-up">
<div
v-if="audioPlayer.currentName.value"
class="fixed bottom-0 left-0 right-0 z-50 audio-player-bar"
ref="barEl"
class="fixed left-0 right-0 z-40 audio-player-bar"
>
<!-- Progress bar (clickable) -->
<div
@@ -60,9 +58,38 @@
</template>
<script setup lang="ts">
import { ref, watch, nextTick, onBeforeUnmount } from 'vue'
import { useAudioPlayer } from '@/composables/useAudioPlayer'
const audioPlayer = useAudioPlayer()
const barEl = ref<HTMLElement | null>(null)
// Publish the player's height as a CSS variable so page scroll containers can
// reserve space for it (the same mechanism the mobile tab bar uses). This is
// what pushes the rest of the site up instead of letting the fixed bar overlap
// and block the bottom controls — on desktop AND mobile, on every page.
function setPlayerHeightVar() {
if (typeof document === 'undefined') return
const h = barEl.value?.offsetHeight || 60
document.documentElement.style.setProperty('--audio-player-height', `${h}px`)
document.documentElement.classList.add('audio-active')
}
function clearPlayerHeightVar() {
if (typeof document === 'undefined') return
document.documentElement.style.setProperty('--audio-player-height', '0px')
document.documentElement.classList.remove('audio-active')
}
watch(() => audioPlayer.currentName.value, (name) => {
if (name) {
nextTick(setPlayerHeightVar)
} else {
clearPlayerHeightVar()
}
}, { immediate: true })
onBeforeUnmount(clearPlayerHeightVar)
function togglePlay() {
if (audioPlayer.playing.value) {
@@ -90,6 +117,10 @@ function formatTime(seconds: number): string {
<style scoped>
.audio-player-bar {
/* Sit directly above the mobile tab bar (its height is published as
--mobile-tab-bar-height). On desktop the tab bar is hidden so the variable
resolves to 0px and the bar docks flush to the bottom of the viewport. */
bottom: var(--mobile-tab-bar-height, 0px);
background: rgba(15, 15, 15, 0.55);
backdrop-filter: blur(24px) saturate(1.4);
-webkit-backdrop-filter: blur(24px) saturate(1.4);