Keep admin tabs in one row

This commit is contained in:
Dorian
2026-05-15 14:09:14 -05:00
parent 2903aa290c
commit 384cad78f5
3 changed files with 34 additions and 25 deletions

View File

@@ -381,14 +381,14 @@ const pwaInstallCopy = computed(() => {
? 'Install the app when prompted, then continue signup inside L484.'
: 'Open Chrome menu, choose Install app or Add to Home screen, then launch L484 from the app icon.'
return deferredInstallPrompt.value
? 'Install L484 as a desktop app when prompted, then continue signup.'
: 'Use your browser menu or address bar install icon to install L484, then open the installed app.'
? 'Use the browser install prompt to install L484, then continue signup.'
: 'Install L484 using the browser install icon in the address bar. The install prompt appears here when the browser makes it available.'
})
const pwaInstallPrimaryLabel = computed(() => {
if (isPwaStandalone.value) return 'Continue signup'
if (deferredInstallPrompt.value) return 'Install app'
if (installPlatform.value === 'ios') return 'I installed it'
return 'Continue after install'
return 'Install app'
})
const membershipBtcAmount = computed(() =>
bitcoinUsdPrice.value ? MEMBERSHIP_MONTHLY_USD / bitcoinUsdPrice.value : 0,
@@ -774,6 +774,11 @@ const handlePwaInstallPrimary = async () => {
return
}
if (installPlatform.value === 'desktop') {
formError.value = 'The browser install prompt is not available yet. Use the install icon in the address bar, or refresh once and press Install app again.'
return
}
formError.value = installPlatform.value === 'ios'
? 'Install L484 from Safari using Share, Add to Home Screen, then reopen it from the app icon.'
: 'Install L484 from your browser menu or address bar, then reopen the installed app to continue.'

View File

@@ -2,14 +2,14 @@ import { ref } from 'vue'
const permission = ref(typeof Notification === 'undefined' ? 'unsupported' : Notification.permission)
const urlBase64ToUint8Array = (base64String) => {
const urlBase64ToArrayBuffer = (base64String) => {
const clean = String(base64String || '').trim().replace(/^["']|["']$/g, '')
const padding = '='.repeat((4 - (clean.length % 4)) % 4)
const base64 = (clean + padding).replace(/-/g, '+').replace(/_/g, '/')
const rawData = window.atob(base64)
const key = new Uint8Array([...rawData].map((char) => char.charCodeAt(0)))
if (key.length !== 65 || key[0] !== 4) throw new Error('VAPID public key is not valid.')
return key
return key.buffer
}
export const notificationPermission = permission
@@ -34,13 +34,16 @@ const subscribeWithRetry = async (registration, applicationServerKey) => {
try {
return await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey })
} catch (error) {
await registration.update().catch(() => {})
await new Promise((resolve) => window.setTimeout(resolve, 350))
await registration.unregister().catch(() => {})
await new Promise((resolve) => window.setTimeout(resolve, 500))
const freshRegistration = await navigator.serviceWorker.register('/sw.js', { scope: '/' })
const readyRegistration = await navigator.serviceWorker.ready
const activeRegistration = readyRegistration || freshRegistration
try {
return await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey })
return await activeRegistration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey })
} catch {
const message = error instanceof Error ? error.message : 'Push service error.'
throw new Error(`Push registration failed: ${message}`)
throw new Error(`Push registration failed: ${message}. Close and reopen the installed app, then try again.`)
}
}
}
@@ -54,14 +57,14 @@ export const subscribeToNotifications = async () => {
const keyData = await keyResponse.json().catch(() => ({}))
if (!keyResponse.ok || !keyData.publicKey) throw new Error('VAPID public key is not configured.')
if (!keyData.configured) throw new Error('VAPID private key is not configured on the server.')
const applicationServerKey = urlBase64ToUint8Array(keyData.publicKey)
const applicationServerKey = urlBase64ToArrayBuffer(keyData.publicKey)
const requested = await Notification.requestPermission()
permission.value = requested
if (requested !== 'granted') throw new Error('Notification permission was not granted.')
const registration = await navigator.serviceWorker.register('/sw.js')
await navigator.serviceWorker.ready
await navigator.serviceWorker.register('/sw.js', { scope: '/' })
const registration = await navigator.serviceWorker.ready
const existing = await registration.pushManager.getSubscription()
if (existing) return saveSubscription(existing)

View File

@@ -1476,7 +1476,7 @@ body.menu-open {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: center;
gap: 1rem;
gap: clamp(0.45rem, 1.2vw, 1rem);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(5, 5, 5, 0.88);
padding: 0.65rem var(--admin-page-x);
@@ -1490,19 +1490,19 @@ body.menu-open {
.admin-profile-button {
display: flex;
align-items: center;
gap: 0.75rem;
gap: clamp(0.45rem, 0.8vw, 0.75rem);
border: 1px solid rgba(255, 255, 255, 0.13);
border-radius: 8px;
background: rgba(255, 255, 255, 0.055);
padding: 0.55rem 0.7rem;
padding: 0.55rem clamp(0.5rem, 0.8vw, 0.7rem);
color: white;
text-align: left;
}
.admin-avatar {
display: grid;
width: 2.25rem;
height: 2.25rem;
width: clamp(1.9rem, 2.4vw, 2.25rem);
height: clamp(1.9rem, 2.4vw, 2.25rem);
place-items: center;
border: 1px solid rgba(255, 255, 255, 0.16);
border-radius: 999px;
@@ -1517,14 +1517,14 @@ body.menu-open {
}
.admin-profile-text strong {
font-size: 0.82rem;
font-size: clamp(0.68rem, 0.9vw, 0.82rem);
line-height: 1;
}
.admin-profile-text small {
color: rgba(255, 255, 255, 0.48);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 0.68rem;
font-size: clamp(0.58rem, 0.75vw, 0.68rem);
}
.admin-profile-menu {
@@ -1586,8 +1586,9 @@ body.menu-open {
.admin-tabbar {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 0.5rem;
grid-auto-flow: column;
grid-auto-columns: minmax(0, 1fr);
gap: clamp(0.22rem, 0.7vw, 0.5rem);
min-width: 0;
}
@@ -1616,10 +1617,10 @@ body.menu-open {
}
.desktop-admin-tabbar .admin-tab {
gap: 0.42rem;
padding: 0.64rem 0.5rem;
font-size: 0.62rem;
letter-spacing: 0.1em;
gap: clamp(0.22rem, 0.5vw, 0.42rem);
padding: 0.62rem clamp(0.28rem, 0.7vw, 0.5rem);
font-size: clamp(0.5rem, 0.75vw, 0.62rem);
letter-spacing: clamp(0.055em, 0.15vw, 0.1em);
}
.admin-tab svg {