- Add native Cloud file browser with FileBrowser API integration - Add cloud store, filebrowser-client, useAudioPlayer, useFileType composables - Add Cloud components: FileGrid, FileCard, FileCardGrid, CloudToolbar - Add Claude authentication section to Settings with OAuth status check - Harden deploy script to preserve /aiui/ and claude-login.html - Add nginx proxies for btcpay, homeassistant, filebrowser (HTTPS block) - Add app configs for filebrowser, searxng, penpot in package.rs - Update goal progress tracking with app aliases - Improve mobile back button composable with ResizeObserver - Update various views with cloud integration and UI refinements Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
100 lines
2.8 KiB
TypeScript
100 lines
2.8 KiB
TypeScript
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
|
|
|
|
/**
|
|
* Composable for mobile back button positioning
|
|
* Ensures back buttons are always 8px above the mobile tab bar
|
|
* Uses ResizeObserver to reactively update when tab bar height changes
|
|
*/
|
|
export function useMobileBackButton() {
|
|
const tabBarHeight = ref<number>(72) // Default fallback height
|
|
|
|
// Computed property for bottom position - always 16px above tab bar
|
|
const bottomPosition = computed(() => {
|
|
return `${tabBarHeight.value + 8}px`
|
|
})
|
|
|
|
// Computed property for Tailwind class (for use in class bindings)
|
|
const bottomClass = computed(() => {
|
|
// Use Tailwind arbitrary value with the computed height
|
|
return `bottom-[${tabBarHeight.value + 8}px]`
|
|
})
|
|
|
|
let resizeObserver: ResizeObserver | null = null
|
|
let mutationObserver: MutationObserver | null = null
|
|
let intervalId: ReturnType<typeof setInterval> | null = null
|
|
|
|
function updateTabBarHeight() {
|
|
if (typeof window === 'undefined') return
|
|
|
|
// Try to find the mobile tab bar element
|
|
const tabBar = document.querySelector('[data-mobile-tab-bar]') as HTMLElement
|
|
if (tabBar) {
|
|
tabBarHeight.value = tabBar.offsetHeight
|
|
} else {
|
|
// Fallback: read from CSS variable if available
|
|
const cssVar = getComputedStyle(document.documentElement)
|
|
.getPropertyValue('--mobile-tab-bar-height')
|
|
.trim()
|
|
|
|
if (cssVar) {
|
|
const height = parseFloat(cssVar)
|
|
if (!isNaN(height)) {
|
|
tabBarHeight.value = height
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
// Initial update
|
|
updateTabBarHeight()
|
|
|
|
// Watch for CSS variable changes
|
|
mutationObserver = new MutationObserver(() => {
|
|
updateTabBarHeight()
|
|
})
|
|
|
|
mutationObserver.observe(document.documentElement, {
|
|
attributes: true,
|
|
attributeFilter: ['style'],
|
|
})
|
|
|
|
// Watch for tab bar size changes
|
|
const tabBar = document.querySelector('[data-mobile-tab-bar]') as HTMLElement
|
|
if (tabBar && 'ResizeObserver' in window) {
|
|
resizeObserver = new ResizeObserver(() => {
|
|
updateTabBarHeight()
|
|
})
|
|
resizeObserver.observe(tabBar)
|
|
}
|
|
|
|
// Also listen to window resize as fallback
|
|
window.addEventListener('resize', updateTabBarHeight)
|
|
|
|
// Periodic check to ensure we're always in sync (safety net)
|
|
intervalId = setInterval(() => {
|
|
updateTabBarHeight()
|
|
}, 1000)
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
if (mutationObserver) {
|
|
mutationObserver.disconnect()
|
|
}
|
|
if (resizeObserver) {
|
|
resizeObserver.disconnect()
|
|
}
|
|
if (intervalId) {
|
|
clearInterval(intervalId)
|
|
}
|
|
window.removeEventListener('resize', updateTabBarHeight)
|
|
})
|
|
|
|
return {
|
|
bottomPosition,
|
|
bottomClass,
|
|
tabBarHeight,
|
|
}
|
|
}
|
|
|