elk/components/nav/NavSideItem.vue

111 lines
2.9 KiB
Vue
Raw Normal View History

2022-11-27 02:35:26 +00:00
<script setup lang="ts">
const props = withDefaults(defineProps<{
2022-11-27 16:59:33 +00:00
text?: string
2022-11-27 02:35:26 +00:00
icon: string
to: string | Record<string, string>
userOnly?: boolean
2022-12-29 19:31:29 +00:00
command?: boolean
}>(), {
userOnly: false,
})
2022-11-27 16:59:33 +00:00
defineSlots<{
icon: (props: object) => void
default: (props: object) => void
2022-11-27 16:59:33 +00:00
}>()
const router = useRouter()
useCommand({
scope: 'Navigation',
2022-12-01 13:45:13 +00:00
name: () => props.text ?? (typeof props.to === 'string' ? props.to as string : props.to.name),
icon: () => props.icon,
2022-12-29 19:31:29 +00:00
visible: () => props.command,
onActivate() {
router.push(props.to)
},
})
const activeClass = ref('text-primary')
2023-01-15 08:38:02 +00:00
onHydrated(async () => {
// TODO: force NuxtLink to reevaluate, we now we are in this route though, so we should force it to active
// we don't have currentServer defined until later
activeClass.value = ''
await nextTick()
activeClass.value = 'text-primary'
})
// Optimize rendering for the common case of being logged in, only show visual feedback for disabled user-only items
// when we know there is no user.
2023-01-15 08:38:02 +00:00
const noUserDisable = computed(() => !isHydrated.value || (props.userOnly && !currentUser.value))
const noUserVisual = computed(() => isHydrated.value && props.userOnly && !currentUser.value)
2022-11-27 02:35:26 +00:00
</script>
<template>
<NuxtLink
:to="to"
:disabled="noUserDisable"
:class="noUserVisual ? 'op25 pointer-events-none ' : ''"
:active-class="activeClass"
group focus:outline-none disabled:pointer-events-none
:tabindex="noUserDisable ? -1 : null"
@click="$scrollToTop"
>
<CommonTooltip :disabled="!isMediumOrLargeScreen" :content="text" placement="right">
<div
class="item"
flex items-center gap4
2023-01-04 23:17:30 +00:00
xl="ml0 mr5 px5 w-auto"
:class="isSmallScreen
? `
w-full
px5 sm:mxa
transition-colors duration-200 transform
hover-bg-gray-100 hover-dark:(bg-gray-700 text-white)
` : `
w-fit rounded-3
px2 mx3 sm:mxa
transition-100
elk-group-hover-bg-active
group-focus-visible:ring-2
group-focus-visible:ring-current
`"
>
<slot name="icon">
<div :class="icon" text-xl />
</slot>
<slot>
<span block sm:hidden xl:block select-none>{{ isHydrated ? text : '&nbsp;' }}</span>
</slot>
</div>
</CommonTooltip>
2022-11-27 02:35:26 +00:00
</NuxtLink>
</template>
<style scoped>
.item {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
@media screen and ( max-height: 820px ) and ( min-width: 1280px ) {
.item {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
}
2023-05-16 07:38:25 +00:00
@media screen and ( max-height: 780px ) and ( min-width: 640px ) {
.item {
padding-top: 0.35rem;
padding-bottom: 0.35rem;
}
}
2023-05-16 07:38:25 +00:00
@media screen and ( max-height: 780px ) and ( min-width: 1280px ) {
.item {
padding-top: 0.05rem;
padding-bottom: 0.05rem;
}
}
</style>