Update favicon and enhance UI components for improved user experience

- Replaced PNG favicon with SVG for better scalability and visual quality across devices.
- Updated Vite configuration to include the new SVG favicon and adjusted asset paths.
- Enhanced various UI components with improved focus management and accessibility features.
- Introduced new styles to hide scrollbars while maintaining scroll functionality for a cleaner interface.
This commit is contained in:
Dorian
2026-02-17 22:10:38 +00:00
parent 8a32e36d85
commit b63612c5ae
21 changed files with 486 additions and 107 deletions
+25 -3
View File
@@ -383,10 +383,11 @@
<div
v-if="uninstallModal.show"
class="fixed inset-0 z-50 flex items-center justify-center p-4"
@click="uninstallModal.show = false"
@click="closeUninstallModal()"
>
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm"></div>
<div
ref="uninstallModalRef"
@click.stop
class="glass-card p-6 md:p-8 max-w-md w-full relative z-10"
>
@@ -407,7 +408,7 @@
<div class="flex flex-col-reverse md:flex-row gap-3 md:justify-end">
<button
@click="uninstallModal.show = false"
@click="closeUninstallModal()"
class="w-full md:w-auto px-6 py-3 glass-button rounded-lg text-sm font-medium"
>
Cancel
@@ -432,6 +433,7 @@ import { useAppStore } from '../stores/app'
import { useAppLauncherStore } from '../stores/appLauncher'
import { PackageState } from '../types/api'
import { useMobileBackButton } from '../composables/useMobileBackButton'
import { useModalKeyboard } from '@/composables/useModalKeyboard'
import { dummyApps } from '../utils/dummyApps'
const { bottomPosition } = useMobileBackButton()
@@ -510,6 +512,18 @@ const uninstallModal = ref({
show: false,
appTitle: ''
})
const uninstallModalRef = ref<HTMLElement | null>(null)
const uninstallRestoreFocusRef = ref<HTMLElement | null>(null)
function closeUninstallModal() {
uninstallRestoreFocusRef.value?.focus?.()
uninstallModal.value.show = false
}
useModalKeyboard(
uninstallModalRef,
computed(() => uninstallModal.value.show),
closeUninstallModal,
{ restoreFocusRef: uninstallRestoreFocusRef }
)
// Determine back button text based on where user came from
const backButtonText = computed(() => {
@@ -607,6 +621,10 @@ function launchApp() {
dev: 'http://localhost:8103',
prod: 'http://localhost:8103' // Self-hosted splash screen
},
'indeedhub': {
dev: 'http://localhost:7777',
prod: 'http://localhost:7777' // Containerized indeehub prototype
},
// Dummy apps - replace with real URLs when packaged
'bitcoin': {
dev: 'http://localhost:8332',
@@ -663,7 +681,11 @@ function launchApp() {
}
if (appUrls[id]) {
const url = isDev ? appUrls[id].dev : appUrls[id].prod
let url = isDev ? appUrls[id].dev : appUrls[id].prod
// Replace localhost with current hostname for remote access
if (url.includes('localhost')) {
url = url.replace('localhost', window.location.hostname)
}
useAppLauncherStore().open({ url, title: pkg.value.manifest.title })
return
}
+22 -2
View File
@@ -28,6 +28,7 @@
v-for="[id, pkg] in sortedPackageEntries"
:key="id"
data-controller-container
:data-controller-launch="canLaunch(pkg) ? '' : undefined"
tabindex="0"
class="glass-card p-6 transition-all hover:-translate-y-1 cursor-pointer relative min-w-0 overflow-hidden"
@click="goToApp(id as string)"
@@ -75,6 +76,7 @@
<div class="mt-4 flex gap-2">
<button
v-if="canLaunch(pkg)"
data-controller-launch-btn
@click.stop="launchApp(id as string)"
class="flex-1 px-4 py-2 gradient-button rounded-lg text-sm font-medium"
>
@@ -125,10 +127,11 @@
<div
v-if="uninstallModal.show"
class="fixed inset-0 z-50 flex items-center justify-center p-4"
@click="uninstallModal.show = false"
@click="closeUninstallModal()"
>
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm"></div>
<div
ref="uninstallModalRef"
@click.stop
class="glass-card p-6 max-w-md w-full relative z-10"
>
@@ -149,7 +152,7 @@
<div class="flex gap-3 justify-end">
<button
@click="uninstallModal.show = false"
@click="closeUninstallModal()"
class="px-4 py-2 glass-button rounded-lg text-sm font-medium"
>
Cancel
@@ -173,6 +176,7 @@ import { useRouter, RouterLink } from 'vue-router'
import { useAppStore } from '../stores/app'
import { useAppLauncherStore } from '../stores/appLauncher'
import { PackageState } from '../types/api'
import { useModalKeyboard } from '@/composables/useModalKeyboard'
const router = useRouter()
const store = useAppStore()
@@ -200,6 +204,18 @@ const uninstallModal = ref({
appId: '',
appTitle: ''
})
const uninstallModalRef = ref<HTMLElement | null>(null)
const uninstallRestoreFocusRef = ref<HTMLElement | null>(null)
function closeUninstallModal() {
uninstallRestoreFocusRef.value?.focus?.()
uninstallModal.value.show = false
}
useModalKeyboard(
uninstallModalRef,
computed(() => uninstallModal.value.show),
closeUninstallModal,
{ restoreFocusRef: uninstallRestoreFocusRef }
)
function canLaunch(pkg: any): boolean {
// For dummy apps, allow launch if running (they have interface addresses)
@@ -237,6 +253,10 @@ function launchApp(id: string) {
'k484': {
dev: 'http://localhost:8103',
prod: 'http://localhost:8103' // Self-hosted splash screen
},
'indeedhub': {
dev: 'http://localhost:7777',
prod: 'http://localhost:7777' // Containerized indeehub prototype
}
}
+22 -7
View File
@@ -218,12 +218,12 @@
<div
v-if="showSideloadModal"
class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm"
@click.self="showSideloadModal = false"
@click.self="closeSideloadModal()"
>
<div class="glass-card p-8 max-w-2xl w-full relative">
<div ref="sideloadModalRef" class="glass-card p-8 max-w-2xl w-full relative">
<!-- Close Button -->
<button
@click="showSideloadModal = false"
@click="closeSideloadModal()"
class="absolute top-4 right-4 text-white/60 hover:text-white transition-colors"
>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -289,14 +289,14 @@
<div
v-if="showFilterModal"
class="fixed inset-0 z-50 flex items-end justify-center md:hidden bg-black/60 backdrop-blur-sm"
@click.self="showFilterModal = false"
@click.self="closeFilterModal()"
>
<div class="glass-card p-6 w-full rounded-t-3xl max-h-[80vh] overflow-y-auto">
<div ref="filterModalRef" class="glass-card p-6 w-full rounded-t-3xl max-h-[80vh] overflow-y-auto">
<!-- Header -->
<div class="flex items-center justify-between mb-6">
<h2 class="text-2xl font-bold text-white">Filter by Category</h2>
<button
@click="showFilterModal = false"
@click="closeFilterModal()"
class="text-white/60 hover:text-white transition-colors"
>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -310,7 +310,7 @@
<button
v-for="category in categoriesWithApps"
:key="category.id"
@click="selectedCategory = category.id; showFilterModal = false"
@click="selectedCategory = category.id; closeFilterModal()"
:class="[
'p-4 rounded-xl font-medium transition-all text-left',
selectedCategory === category.id
@@ -372,6 +372,7 @@ import { useAppStore } from '@/stores/app'
import { rpcClient } from '@/api/rpc-client'
import { useMarketplaceApp } from '@/composables/useMarketplaceApp'
import { useMobileBackButton } from '@/composables/useMobileBackButton'
import { useModalKeyboard } from '@/composables/useModalKeyboard'
const router = useRouter()
const store = useAppStore()
@@ -408,6 +409,13 @@ const maxAttempts = ref(60)
// Sideload modal state
const showSideloadModal = ref(false)
const sideloadModalRef = ref<HTMLElement | null>(null)
const sideloadRestoreFocusRef = ref<HTMLElement | null>(null)
function closeSideloadModal() {
sideloadRestoreFocusRef.value?.focus?.()
showSideloadModal.value = false
}
useModalKeyboard(sideloadModalRef, showSideloadModal, closeSideloadModal, { restoreFocusRef: sideloadRestoreFocusRef })
const sideloadUrl = ref('')
const sideloading = ref(false)
const sideloadError = ref('')
@@ -415,6 +423,13 @@ const sideloadSuccess = ref('')
// Filter modal state (for mobile)
const showFilterModal = ref(false)
const filterModalRef = ref<HTMLElement | null>(null)
const filterRestoreFocusRef = ref<HTMLElement | null>(null)
function closeFilterModal() {
filterRestoreFocusRef.value?.focus?.()
showFilterModal.value = false
}
useModalKeyboard(filterModalRef, showFilterModal, closeFilterModal, { restoreFocusRef: filterRestoreFocusRef })
// Community marketplace state
const loadingCommunity = ref(false)
+7 -2
View File
@@ -108,9 +108,9 @@
<div
v-if="showChangePasswordModal"
class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm"
@click.self="showChangePasswordModal = false"
@click.self="closeChangePasswordModal()"
>
<div class="glass-card p-6 max-w-md w-full">
<div ref="changePasswordModalRef" class="glass-card p-6 max-w-md w-full">
<h3 class="text-lg font-semibold text-white mb-4">Change Password</h3>
<p class="text-white/70 text-sm mb-4">Updates both web login and SSH access. Use a strong password (12+ chars, upper, lower, digit, special).</p>
<form @submit.prevent="handleChangePassword" class="space-y-4">
@@ -206,6 +206,7 @@ import { useRouter } from 'vue-router'
import { useAppStore } from '../stores/app'
import ControllerIndicator from '@/components/ControllerIndicator.vue'
import { rpcClient } from '@/api/rpc-client'
import { useModalKeyboard } from '@/composables/useModalKeyboard'
const router = useRouter()
const store = useAppStore()
@@ -225,6 +226,9 @@ const userDid = computed(() => {
const copiedOnion = ref(false)
const showChangePasswordModal = ref(false)
const changePasswordModalRef = ref<HTMLElement | null>(null)
const changePasswordRestoreFocusRef = ref<HTMLElement | null>(null)
useModalKeyboard(changePasswordModalRef, showChangePasswordModal, closeChangePasswordModal, { restoreFocusRef: changePasswordRestoreFocusRef })
const changingPassword = ref(false)
const changePasswordError = ref('')
const changePasswordSuccess = ref('')
@@ -301,6 +305,7 @@ async function copyOnionAddress() {
}
function closeChangePasswordModal() {
changePasswordRestoreFocusRef.value?.focus?.()
showChangePasswordModal.value = false
changePasswordError.value = ''
changePasswordSuccess.value = ''
+11 -3
View File
@@ -108,8 +108,8 @@
<!-- Send Message Modal -->
<Teleport to="body">
<div v-if="showSendMessageModal" class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm" @click.self="showSendMessageModal = false">
<div class="glass-card p-6 max-w-md w-full max-h-[90vh] overflow-y-auto">
<div v-if="showSendMessageModal" class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm" @click.self="closeSendMessageModal()">
<div ref="sendMessageModalRef" class="glass-card p-6 max-w-md w-full max-h-[90vh] overflow-y-auto">
<h3 class="text-lg font-semibold text-white mb-4">Send Message (over Tor)</h3>
<p class="text-white/70 text-sm mb-4">Messages are sent over the Tor network to the selected peer.</p>
<div class="space-y-4">
@@ -144,7 +144,7 @@
{{ sendingMessage ? 'Sending...' : 'Send' }}
</button>
<button
@click="showSendMessageModal = false"
@click="closeSendMessageModal()"
class="px-4 py-2 rounded-lg bg-white/10 text-white font-medium hover:bg-white/20 transition-colors"
>
Cancel
@@ -630,6 +630,7 @@ import { ref, computed, onMounted, nextTick, watch } from 'vue'
import { useRoute } from 'vue-router'
import { rpcClient } from '@/api/rpc-client'
import { useMessageToast } from '@/composables/useMessageToast'
import { useModalKeyboard } from '@/composables/useModalKeyboard'
const route = useRoute()
const messageToast = useMessageToast()
@@ -666,6 +667,13 @@ const connectedNodesCount = computed(() => peers.value.length)
// Send Message modal
const showSendMessageModal = ref(false)
const sendMessageModalRef = ref<HTMLElement | null>(null)
const sendMessageRestoreFocusRef = ref<HTMLElement | null>(null)
function closeSendMessageModal() {
sendMessageRestoreFocusRef.value?.focus?.()
showSendMessageModal.value = false
}
useModalKeyboard(sendMessageModalRef, showSendMessageModal, closeSendMessageModal, { restoreFocusRef: sendMessageRestoreFocusRef })
const sendMessageTo = ref('')
const sendMessageText = ref('')
const sendingMessage = ref(false)