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:
co-authored by
Claude Opus 4.8
parent
c4855526fe
commit
1bce694ebb
@@ -22,6 +22,6 @@ RUN sed -i 's/^user nginx;/user root;/' /etc/nginx/nginx.conf && \
|
||||
mkdir -p /var/cache/nginx/client_temp /var/cache/nginx/proxy_temp \
|
||||
/var/cache/nginx/fastcgi_temp /var/cache/nginx/uwsgi_temp \
|
||||
/var/cache/nginx/scgi_temp
|
||||
EXPOSE 80
|
||||
EXPOSE 18083
|
||||
ENTRYPOINT []
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
+30
-32
@@ -433,8 +433,12 @@
|
||||
const host = window.location.hostname;
|
||||
|
||||
function getBackendUrl() {
|
||||
// Same-origin by default: the app's own nginx (:18083) proxies these
|
||||
// paths to the archipelago backend, so a relative base ('') avoids
|
||||
// any cross-origin/CORS issues (which broke this on http-only nodes).
|
||||
// ?backend=http://HOST:5678 still overrides for local dev.
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
return params.get('backend') || (window.location.protocol + '//' + window.location.hostname);
|
||||
return params.get('backend') || '';
|
||||
}
|
||||
|
||||
function setSettingsTab(tabId) {
|
||||
@@ -499,42 +503,36 @@
|
||||
async function loadLogs() {
|
||||
const logsContent = document.getElementById('logsContent');
|
||||
const backendUrl = getBackendUrl();
|
||||
if (backendUrl) {
|
||||
logsContent.textContent = 'Loading logs...';
|
||||
try {
|
||||
const res = await fetch(backendUrl + '/api/container/logs?app_id=lnd&lines=200');
|
||||
if (!res.ok) throw new Error(res.statusText);
|
||||
const json = await res.json();
|
||||
const lines = json.result || json.logs || (Array.isArray(json) ? json : []);
|
||||
logsContent.textContent = Array.isArray(lines) ? lines.join('\n') : String(lines);
|
||||
} catch (e) {
|
||||
logsContent.textContent = 'Could not load logs: ' + e.message;
|
||||
}
|
||||
} else {
|
||||
logsContent.textContent = 'Open this app with ?backend=http://HOST:5678 to load logs from the server.';
|
||||
logsContent.textContent = 'Loading logs...';
|
||||
try {
|
||||
const res = await fetch(backendUrl + '/api/container/logs?app_id=lnd&lines=200', { credentials: 'include' });
|
||||
if (!res.ok) throw new Error(res.statusText);
|
||||
const json = await res.json();
|
||||
const lines = json.result || json.logs || (Array.isArray(json) ? json : []);
|
||||
logsContent.textContent = Array.isArray(lines) ? lines.join('\n') : String(lines);
|
||||
} catch (e) {
|
||||
logsContent.textContent = 'Could not load logs: ' + e.message;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchLiveData() {
|
||||
const backendUrl = getBackendUrl();
|
||||
const data = { channelCount: 0, restReachable: false, grpcReachable: false };
|
||||
if (backendUrl) {
|
||||
try {
|
||||
const getinfoRes = await fetch(backendUrl + '/proxy/lnd/v1/getinfo');
|
||||
if (getinfoRes.ok) {
|
||||
data.getinfo = await getinfoRes.json();
|
||||
data.restReachable = true;
|
||||
}
|
||||
} catch (_) {}
|
||||
try {
|
||||
const chRes = await fetch(backendUrl + '/proxy/lnd/v1/channels');
|
||||
if (chRes.ok) {
|
||||
const ch = await chRes.json();
|
||||
data.channelCount = (ch.channels && ch.channels.length) || 0;
|
||||
}
|
||||
} catch (_) {}
|
||||
data.grpcReachable = data.restReachable;
|
||||
}
|
||||
try {
|
||||
const getinfoRes = await fetch(backendUrl + '/proxy/lnd/v1/getinfo', { credentials: 'include' });
|
||||
if (getinfoRes.ok) {
|
||||
data.getinfo = await getinfoRes.json();
|
||||
data.restReachable = true;
|
||||
}
|
||||
} catch (_) {}
|
||||
try {
|
||||
const chRes = await fetch(backendUrl + '/proxy/lnd/v1/channels', { credentials: 'include' });
|
||||
if (chRes.ok) {
|
||||
const ch = await chRes.json();
|
||||
data.channelCount = (ch.channels && ch.channels.length) || 0;
|
||||
}
|
||||
} catch (_) {}
|
||||
data.grpcReachable = data.restReachable;
|
||||
applyLiveData(data);
|
||||
}
|
||||
|
||||
@@ -629,7 +627,7 @@
|
||||
|
||||
async function fetchConnectInfo() {
|
||||
try {
|
||||
const resp = await fetch(window.location.protocol + '//' + window.location.hostname + '/lnd-connect-info', { credentials: 'include' });
|
||||
const resp = await fetch(getBackendUrl() + '/lnd-connect-info', { credentials: 'include' });
|
||||
if (!resp.ok) throw new Error('HTTP ' + resp.status);
|
||||
const data = await resp.json();
|
||||
if (data.cert_base64url) {
|
||||
|
||||
@@ -1,13 +1,63 @@
|
||||
server {
|
||||
listen 80;
|
||||
# Host-networked: listen on the app's own port directly (NOT 80, which the
|
||||
# host's main nginx already owns). The app is reached at http(s)://<node>:18083.
|
||||
listen 18083;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# lnd-connect-info is fetched via absolute URL path,
|
||||
# handled by the host nginx → backend at :5678 directly
|
||||
# Proxy the archipelago backend same-origin so the browser never makes a
|
||||
# cross-origin request (no CORS, no host-nginx route dependency). The app is
|
||||
# served on this node's :18083; cookies are scoped by host (not port), so the
|
||||
# browser already carries the `session` (HttpOnly) and `csrf_token` cookies
|
||||
# set by the main UI. We forward both, plus the X-CSRF-Token header, to the
|
||||
# backend on 127.0.0.1:5678 (reachable because this container is host-networked).
|
||||
#
|
||||
# This mirrors fips-ui / electrs-ui. The old bridge + 18083→80 mapping forced
|
||||
# cross-origin fetches that broke on http-only nodes (blank fields, QR
|
||||
# "failed to fetch").
|
||||
location = /lnd-connect-info {
|
||||
proxy_pass http://127.0.0.1:5678/lnd-connect-info;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Cookie $http_cookie;
|
||||
proxy_set_header X-CSRF-Token $http_x_csrf_token;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_read_timeout 60s;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
|
||||
location /proxy/lnd/ {
|
||||
proxy_pass http://127.0.0.1:5678/proxy/lnd/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Cookie $http_cookie;
|
||||
proxy_set_header X-CSRF-Token $http_x_csrf_token;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_read_timeout 60s;
|
||||
add_header Cache-Control "no-store";
|
||||
}
|
||||
|
||||
location /api/container/logs {
|
||||
proxy_pass http://127.0.0.1:5678/api/container/logs;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Cookie $http_cookie;
|
||||
proxy_set_header X-CSRF-Token $http_x_csrf_token;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_read_timeout 30s;
|
||||
add_header Cache-Control "no-store";
|
||||
}
|
||||
|
||||
location / {
|
||||
add_header Cache-Control "no-cache";
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user