61c73f394d
Sidenav becomes a full-screen overlay on mobile with slide-in animation. Dialog goes full-screen on small screens. Settings dialog gets a mobile nav with hamburger menu. Touch targets and text sizes scaled up for mobile. Slider gets visual checked/unchecked colors. Sidebar auto-closes on mobile route navigation. Resize handle hidden on mobile.
72 lines
3.6 KiB
Vue
72 lines
3.6 KiB
Vue
<script setup lang="ts">
|
|
import type { DialogType } from '~/composables/useDialog';
|
|
|
|
const { user, signOut } = useAuth();
|
|
|
|
// to prevent the user details from going blank for a
|
|
// single frame when the user logs out (yes I am that
|
|
// particular)
|
|
const cachedUser = ref(user.value);
|
|
|
|
const dropdownOpen = ref(false);
|
|
|
|
watch(user, () => {
|
|
if (user.value === null) return;
|
|
|
|
cachedUser.value = user.value;
|
|
})
|
|
|
|
const { openDialog } = useDialog();
|
|
|
|
const { isHovered } = useSidenavContext();
|
|
|
|
const handleLogout = async () => {
|
|
await signOut();
|
|
|
|
await navigateTo('/auth/login');
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<header class="flex items-center justify-between overflow-hidden">
|
|
<button @click="dropdownOpen = !dropdownOpen"
|
|
class="flex gap-1 pr-1 items-center @hover:bg-[var(--color-hover)] focus-visible:bg-[var(--color-hover)] rounded-lg transition-colors duration-200 ease-[cubic-bezier(0.5,_1,_0.89,_1)]">
|
|
<div
|
|
:class="['w-9 h-9 md:w-7 md:h-7 flex-shrink-0 rounded-lg overflow-hidden bg-[var(--bg-surface)] flex items-center justify-center', user?.image ? '' : 'border border-[var(--color-border)]']">
|
|
<img v-if="cachedUser?.image" :src="cachedUser.image" class="w-full h-full object-cover" />
|
|
<span v-else class="w-5.5 h-5.5 md:h-4 md:w-4 i-mynaui-user text-[var(--text-secondary)]"></span>
|
|
</div>
|
|
<span
|
|
class="md:text-sm font-medium text-ellipsis overflow-hidden text-[var(--text-primary)] whitespace-nowrap">
|
|
{{ cachedUser?.name }}
|
|
</span>
|
|
<div :class="['transform-origin-left-center flex-shrink-0 w-5 h-5 md:w-4 md:h-4 text-[var(--text-secondary)] transition-all duration-200 ease-[cubic-bezier(0.5,_1,_0.89,_1)] overflow-hidden transform-origin-center-left',
|
|
isHovered ? 'opacity-100 scale-100' : 'opacity-0 scale-40'
|
|
]">
|
|
<span
|
|
class="i-mynaui-chevron-down inline-block text-5 md:text-4 transition-transform duration-250 ease-in-out"
|
|
:class="dropdownOpen ? 'rotate-180' : ''"></span>
|
|
</div>
|
|
</button>
|
|
|
|
<Transition enter-active-class="transition-all duration-150 ease-[cubic-bezier(0.5,_1,_0.89,_1)]"
|
|
enter-from-class="opacity-0 scale-95" enter-to-class="opacity-100 scale-100"
|
|
leave-active-class="transition-all duration-100 ease-[cubic-bezier(0.5,_1,_0.89,_1)]"
|
|
leave-from-class="opacity-100 scale-100" leave-to-class="opacity-0 scale-95">
|
|
<div v-if="dropdownOpen" v-click-outside="() => dropdownOpen = false"
|
|
class="w-full top-full text-sm mt-1 absolute z-30 bg-[var(--bg-surface)] border border-[var(--color-border)] rounded-xl p-1.5 flex flex-col gap-2">
|
|
<button @click="dropdownOpen = false; openDialog(DialogType.Settings)"
|
|
class="text-left px-3 py-1.5 items-center gap-1 @hover:bg-[var(--color-hover)] rounded-lg transition-colors duration-200 ease-[cubic-bezier(0.5,_1,_0.89,_1)]">
|
|
<span class="i-mynaui-cog-four text-4.5"></span>
|
|
<span>Settings</span>
|
|
</button>
|
|
<hr class="border-t border-[var(--color-border)]" />
|
|
<button @click="handleLogout"
|
|
class="text-left px-3 py-1.5 items-center gap-1 @hover:bg-[var(--color-hover)] rounded-lg transition-colors duration-200 ease-[cubic-bezier(0.5,_1,_0.89,_1)]">
|
|
<span class="i-mynaui-logout text-4.5"></span>
|
|
<span>Log out</span>
|
|
</button>
|
|
</div>
|
|
</Transition>
|
|
</header>
|
|
</template> |