merge: hub auth-aware ghosting + login dock slot
This commit is contained in:
commit
95d8b2e307
1 changed files with 20 additions and 6 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
import { useAuth } from '@/composables/useAuthService'
|
import { useAuth } from '@/composables/useAuthService'
|
||||||
import { useTheme } from '@/components/theme-provider'
|
import { useTheme } from '@/components/theme-provider'
|
||||||
import { useLocale } from '@/composables/useLocale'
|
import { useLocale } from '@/composables/useLocale'
|
||||||
|
|
@ -7,7 +8,7 @@ import { toast } from 'vue-sonner'
|
||||||
import {
|
import {
|
||||||
Castle, ListTodo, Newspaper, MessageCircle, Wallet, CalendarDays,
|
Castle, ListTodo, Newspaper, MessageCircle, Wallet, CalendarDays,
|
||||||
Store, UtensilsCrossed,
|
Store, UtensilsCrossed,
|
||||||
User as UserIcon, Sun, Moon, Monitor, Globe, Coins,
|
User as UserIcon, LogIn, Sun, Moon, Monitor, Globe, Coins,
|
||||||
} from 'lucide-vue-next'
|
} from 'lucide-vue-next'
|
||||||
import {
|
import {
|
||||||
DropdownMenu, DropdownMenuTrigger, DropdownMenuContent,
|
DropdownMenu, DropdownMenuTrigger, DropdownMenuContent,
|
||||||
|
|
@ -19,6 +20,7 @@ import {
|
||||||
} from '@/components/ui/sheet'
|
} from '@/components/ui/sheet'
|
||||||
import ProfileSettings from '@/modules/base/components/ProfileSettings.vue'
|
import ProfileSettings from '@/modules/base/components/ProfileSettings.vue'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
const { isAuthenticated } = useAuth()
|
const { isAuthenticated } = useAuth()
|
||||||
const { theme, setTheme, currentTheme } = useTheme()
|
const { theme, setTheme, currentTheme } = useTheme()
|
||||||
const { currentLocale, locales, setLocale } = useLocale()
|
const { currentLocale, locales, setLocale } = useLocale()
|
||||||
|
|
@ -31,6 +33,8 @@ interface Module {
|
||||||
glow: string
|
glow: string
|
||||||
envKey?: string
|
envKey?: string
|
||||||
status?: string
|
status?: string
|
||||||
|
/** When true, the tile is ghosted out unless the user is logged in. */
|
||||||
|
authRequired?: boolean
|
||||||
/** Unread count for the corner badge. Wire to real data via #32. */
|
/** Unread count for the corner badge. Wire to real data via #32. */
|
||||||
unread?: number
|
unread?: number
|
||||||
}
|
}
|
||||||
|
|
@ -39,12 +43,12 @@ interface Module {
|
||||||
const modules: Module[] = [
|
const modules: Module[] = [
|
||||||
{ label: 'Restaurant', chakra: 'Muladhara', icon: UtensilsCrossed, bgClass: '', glow: 'rgba(255,80,80,0.5)', status: 'coming soon' },
|
{ label: 'Restaurant', chakra: 'Muladhara', icon: UtensilsCrossed, bgClass: '', glow: 'rgba(255,80,80,0.5)', status: 'coming soon' },
|
||||||
{ label: 'Market', chakra: 'Muladhara', icon: Store, bgClass: '', glow: 'rgba(255,80,80,0.5)', envKey: 'VITE_HUB_MARKET_URL', status: 'alpha' },
|
{ label: 'Market', chakra: 'Muladhara', icon: Store, bgClass: '', glow: 'rgba(255,80,80,0.5)', envKey: 'VITE_HUB_MARKET_URL', status: 'alpha' },
|
||||||
{ label: 'Wallet', chakra: 'Manipura', icon: Wallet, bgClass: '', glow: 'rgba(255,200,0,0.5)', envKey: 'VITE_HUB_WALLET_URL', status: 'alpha' },
|
{ label: 'Wallet', chakra: 'Manipura', icon: Wallet, bgClass: '', glow: 'rgba(255,200,0,0.5)', envKey: 'VITE_HUB_WALLET_URL', status: 'alpha', authRequired: true },
|
||||||
{ label: 'Activities', chakra: 'Swadhisthana', icon: CalendarDays, bgClass: '', glow: 'rgba(255,165,0,0.5)', envKey: 'VITE_HUB_ACTIVITIES_URL', status: 'beta' },
|
{ label: 'Activities', chakra: 'Swadhisthana', icon: CalendarDays, bgClass: '', glow: 'rgba(255,165,0,0.5)', envKey: 'VITE_HUB_ACTIVITIES_URL', status: 'beta' },
|
||||||
{ label: 'Chat', chakra: 'Anahata', icon: MessageCircle, bgClass: '', glow: 'rgba(0,200,80,0.5)', envKey: 'VITE_HUB_CHAT_URL', status: 'alpha' },
|
{ label: 'Chat', chakra: 'Anahata', icon: MessageCircle, bgClass: '', glow: 'rgba(0,200,80,0.5)', envKey: 'VITE_HUB_CHAT_URL', status: 'alpha', authRequired: true },
|
||||||
{ label: 'Forum', chakra: 'Vishuddha', icon: Newspaper, bgClass: '', glow: 'rgba(60,120,255,0.5)', envKey: 'VITE_HUB_FORUM_URL', status: 'alpha' },
|
{ label: 'Forum', chakra: 'Vishuddha', icon: Newspaper, bgClass: '', glow: 'rgba(60,120,255,0.5)', envKey: 'VITE_HUB_FORUM_URL', status: 'alpha' },
|
||||||
{ label: 'Tasks', chakra: 'Ajna', icon: ListTodo, bgClass: '', glow: 'rgba(99,80,200,0.5)', envKey: 'VITE_HUB_TASKS_URL', status: 'alpha' },
|
{ label: 'Tasks', chakra: 'Ajna', icon: ListTodo, bgClass: '', glow: 'rgba(99,80,200,0.5)', envKey: 'VITE_HUB_TASKS_URL', status: 'alpha' },
|
||||||
{ label: 'Castle', chakra: 'Sahasrara', icon: Castle, bgClass: '', glow: 'rgba(160,80,220,0.5)', envKey: 'VITE_HUB_CASTLE_URL', status: 'beta' },
|
{ label: 'Castle', chakra: 'Sahasrara', icon: Castle, bgClass: '', glow: 'rgba(160,80,220,0.5)', envKey: 'VITE_HUB_CASTLE_URL', status: 'beta', authRequired: true },
|
||||||
]
|
]
|
||||||
// Crown at top, root at bottom
|
// Crown at top, root at bottom
|
||||||
const orderedModules = computed(() => [...modules].reverse())
|
const orderedModules = computed(() => [...modules].reverse())
|
||||||
|
|
@ -53,6 +57,8 @@ const token = computed(() => localStorage.getItem('lnbits_access_token') || '')
|
||||||
|
|
||||||
function hubLink(m: Module): string | null {
|
function hubLink(m: Module): string | null {
|
||||||
if (!m.envKey) return null
|
if (!m.envKey) return null
|
||||||
|
// Auth-only modules (wallet, chat, castle) are ghosted when not logged in.
|
||||||
|
if (m.authRequired && !isAuthenticated.value) return null
|
||||||
const url = import.meta.env[m.envKey] as string | undefined
|
const url = import.meta.env[m.envKey] as string | undefined
|
||||||
if (!url) return null
|
if (!url) return null
|
||||||
if (isAuthenticated.value && token.value) {
|
if (isAuthenticated.value && token.value) {
|
||||||
|
|
@ -134,8 +140,8 @@ function notImplemented() {
|
||||||
style="padding-bottom: env(safe-area-inset-bottom)"
|
style="padding-bottom: env(safe-area-inset-bottom)"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-around h-14 max-w-lg mx-auto">
|
<div class="flex items-center justify-around h-14 max-w-lg mx-auto">
|
||||||
<!-- Profile -->
|
<!-- Profile (when logged in) / Log in (when not) -->
|
||||||
<Sheet v-model:open="showProfile">
|
<Sheet v-if="isAuthenticated" v-model:open="showProfile">
|
||||||
<SheetTrigger as-child>
|
<SheetTrigger as-child>
|
||||||
<button class="flex flex-col items-center justify-center gap-0.5 flex-1 h-full text-muted-foreground hover:text-foreground transition-colors">
|
<button class="flex flex-col items-center justify-center gap-0.5 flex-1 h-full text-muted-foreground hover:text-foreground transition-colors">
|
||||||
<UserIcon class="w-5 h-5" />
|
<UserIcon class="w-5 h-5" />
|
||||||
|
|
@ -152,6 +158,14 @@ function notImplemented() {
|
||||||
</div>
|
</div>
|
||||||
</SheetContent>
|
</SheetContent>
|
||||||
</Sheet>
|
</Sheet>
|
||||||
|
<button
|
||||||
|
v-else
|
||||||
|
class="flex flex-col items-center justify-center gap-0.5 flex-1 h-full text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
@click="router.push('/login')"
|
||||||
|
>
|
||||||
|
<LogIn class="w-5 h-5" />
|
||||||
|
<span class="text-[10px] font-medium">Log in</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- Theme -->
|
<!-- Theme -->
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue