feat: bitcoin-ui CSS fix, HTTPS proxy support, deploy script improvements

Bitcoin UI:
- Replace cdn.tailwindcss.com with locally bundled tailwind.css (CSP blocks external scripts)
- Make all asset paths relative for nginx proxy compatibility
- Add bitcoin-ui build/deploy to deploy-to-target.sh (was missing entirely)
- Use --network host (bitcoin-ui proxies Bitcoin RPC at 127.0.0.1:8332)

HTTPS mixed content fix:
- Add HTTPS_PROXY_PATHS in AppSession.vue — when parent page is HTTPS,
  iframe loads through nginx proxy instead of direct HTTP port
- Prevents browser blocking HTTP iframes inside HTTPS pages
- All Tailscale servers use HTTPS, this was breaking all app iframes

Deploy & first-boot improvements:
- first-boot-containers.sh auto-detects disk size for pruning vs txindex
- first-boot-containers.sh checks fallback source path for UI containers
- Added mempool-electrs to APP_PORTS mapping
- ElectrumX container creation in first-boot
- Podman doctor/fix/uptime skills added

Also includes: session persistence, identity management, LND transactions,
ElectrumX status UI, nostr-provider improvements, Web5 enhancements

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-16 12:58:35 +00:00
co-authored by Claude Opus 4.6
parent 07e46dce56
commit 30164fd12a
49 changed files with 6180 additions and 495 deletions
+35 -2
View File
@@ -81,8 +81,9 @@
:key="item.path"
:to="item.path"
class="sidebar-nav-item flex items-center gap-3 px-4 py-3 rounded-lg text-white/80 hover:bg-white/10 hover:text-white transition-colors"
:class="{ 'nav-tab-active': item.isCombined && (route.path.includes('/apps') || route.path.includes('/marketplace')) }"
:class="{ 'nav-tab-active': item.isCombined && (route.path.includes('/apps') || route.path.includes('/marketplace') || route.path.includes('/app-session') || (item.path === '/dashboard/apps' && !!appLauncher.panelAppId)) }"
:exact-active-class="item.isCombined ? undefined : 'nav-tab-active'"
@click="appLauncher.closePanel()"
:style="{ '--nav-stagger': idx }"
>
<svg class="w-5 h-5" aria-hidden="true" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -292,6 +293,13 @@
</RouterView>
</div>
</div>
<!-- Panel mode app session renders alongside current page content -->
<Transition name="panel-slide">
<div v-if="appLauncher.panelAppId" class="app-panel-container">
<AppSession :app-id-prop="appLauncher.panelAppId" @close="appLauncher.closePanel()" />
</div>
</Transition>
</main>
<!-- Mobile Bottom Tab Bar - glass piece 5 -->
@@ -308,11 +316,12 @@
v-for="item in mobileNavItems"
:key="item.path"
:to="item.path"
@click="appLauncher.closePanel()"
class="flex flex-col items-center justify-center w-full py-1.5 rounded-lg text-white/70 transition-all duration-300 relative z-10 gap-0.5"
:class="{
'nav-tab-active': item.isCombined
? (item.path === '/dashboard/apps'
? (route.path.includes('/apps') || route.path.includes('/marketplace'))
? (route.path.includes('/apps') || route.path.includes('/marketplace') || route.path.includes('/app-session'))
: (route.path.includes('/cloud') || route.path.includes('/server')))
: undefined
}"
@@ -385,6 +394,8 @@ import { computed, ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { RouterLink, RouterView, useRouter, useRoute, type RouteLocationNormalizedLoaded } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { useAppStore } from '../stores/app'
import { useAppLauncherStore } from '../stores/appLauncher'
import AppSession from '@/views/AppSession.vue'
const { t } = useI18n()
import { useLoginTransitionStore } from '../stores/loginTransition'
@@ -405,6 +416,7 @@ const chatFullscreen = computed(() => route.path === '/dashboard/chat')
const router = useRouter()
const route = useRoute()
const store = useAppStore()
const appLauncher = useAppLauncherStore()
const loginTransition = useLoginTransitionStore()
const web5Badge = useWeb5BadgeStore()
@@ -1257,6 +1269,27 @@ aside:not(.sidebar-animate) .sidebar-logout-btn {
}
/* Wrapper to contain perspective without clipping */
/* Panel mode app session — fills content area, sidebar stays untouched */
.app-panel-container {
position: absolute;
inset: 0;
z-index: 100;
}
.panel-slide-enter-active {
transition: opacity 0.25s ease;
}
.panel-slide-leave-active {
transition: transform 0.3s ease, opacity 0.3s ease;
}
.panel-slide-enter-from {
opacity: 0;
}
.panel-slide-leave-to {
transform: translateX(40px) scale(0.97);
opacity: 0;
}
.perspective-container-wrapper {
position: relative;
overflow: hidden;