๐ก NavLink
Work in progress - this component is not yet ready for use.
Basic
NNavLink
is a component that renders a link to a page in your application. It is a wrapper around the NButton
and NuxtLink
component that adds some additional functionality.
refer to the NButton and NuxtLink documentation for more information on the props that can be passed to those components.
Variants & Colors
nav-link-{variant}-{color}
- add a variant to the navigation. The default variant is text-primary
.
nav-link-active-{variant}-{color}
- add a variant to the navigation when the link is active
. The default variant is text-primary
.
nav-link-inactive-{variant}-{color}
- add a variant to the navigation when the link is inactive
. The default variant is text-gray
.
Variant | Description |
---|---|
text | The text variant (default) |
solid | The solid variant. |
~ | The unstyle or base variant |
You can wrap the
nav-link
component with a dark
class to force the component to use the dark variant always.Props
import type { NBadgeProps } from './badge'
import type { NButtonProps } from './button'
export interface NNavLinkProps extends Omit<NButtonProps, 'una'> {
navLink?: string
navLinkInactive?: string
navLinkActive?: string
badge?: NBadgeProps
una?: {
navLinkDefaultVariant?: string
navLink?: string
navLinkActive?: string
navLinkInactive?: string
} & NButtonProps['una']
}
Presets
type NavLinkPrefix = 'nav-link'
export const staticNavLink: Record<`${NavLinkPrefix}-${string}` | NavLinkPrefix, string> = {
// config
'nav-link-default-variant': 'nav-link-text-primary',
// base
'nav-link': 'transition-base leading-6 justify-start gap-x-3 rounded-md',
// badge
'nav-link-badge': 'min-w-max whitespace-nowrap rounded-full px-2.5 py-.5 leading-5',
// text-variant
'nav-link-text-gray': 'hover:bg-$c-gray-100 hover:text-$c-gray-950',
'nav-link-active-text-gray': 'bg-$c-gray-100 text-$c-gray-950',
'nav-link-inactive-text-gray': 'text-$c-gray-950',
}
export const dynamicNavLink: [RegExp, (params: RegExpExecArray) => string][] = [
// text-variant
[/^nav-link-active-text(-(\S+))?$/, ([, , c = 'primary']) => `bg-$c-gray-100 text-${c}-600 dark:text-${c}-500`],
[/^nav-link-inactive-text(-(\S+))?$/, ([, , c = 'gray']) => `text-${c}-800 dark:text-${c}-100`],
[/^nav-link-text(-(\S+))?$/, ([, , c = 'primary']) => `btn-focus-${c} hover:nav-link-active-text-${c}`],
// solid-variant
[/^nav-link-active-solid(-(\S+))?$/, ([, , c = 'primary']) => `bg-${c}-700 dark:bg-${c}-400 text-white dark:text-${c}-950`],
[/^nav-link-inactive-solid(-(\S+))?$/, ([, , c = 'primary']) => `text-white dark:text-${c}-950`],
[/^nav-link-solid(-(\S+))?$/, ([, , c = 'primary']) => `btn-focus-${c} hover:nav-link-active-solid-${c}`],
]
export const navLink = [
...dynamicNavLink,
staticNavLink,
]
Component
<script setup lang="ts">
import type { NNavLinkProps } from '../../types'
import { computed } from 'vue'
import { omitProps } from '../../utils'
import NBadge from '../elements/Badge.vue'
import NButton from '../elements/Button.vue'
import NIcon from '../elements/Icon.vue'
defineOptions({
inheritAttrs: false,
})
const props = withDefaults(
defineProps<NNavLinkProps>(),
{
navLinkActive: 'text-primary',
navLinkInactive: 'text-primary',
una: () => ({
btnDefaultVariant: '~',
navLinkDefaultVariant: 'nav-link-default-variant',
}),
},
)
const btnProps = omitProps(props.una, [
'navLinkDefaultVariant',
'navLink',
'navLinkActive',
'navLinkInactive',
])
const navLinkVariants = ['text', 'solid'] as const
const hasVariant = computed(() => navLinkVariants.some(navLinkVariants => props.navLink?.includes(navLinkVariants)))
const isBaseVariant = computed(() => props.navLink?.includes('~') || props.una.navLink?.includes('~'))
</script>
<template>
<NButton
:nav-link="navLink"
:nav-link-active="navLinkActive"
:nav-link-inactive="navLinkInactive"
:una="btnProps"
class="nav-link"
:class="[
!hasVariant && !isBaseVariant ? una?.navLinkDefaultVariant : null,
{ 'btn-reverse': reverse },
]"
v-bind="{
...omitProps(props, ['badge', 'una']),
...$attrs,
}"
>
<template #leading>
<NIcon
v-if="leading"
:name="leading"
:class="una?.btnLeading"
btn="leading"
/>
</template>
<template #default>
<span
btn="label"
class="w-full text-left"
:class="una?.btnLabel"
>
{{ label }}
</span>
</template>
<template v-if="badge" #trailing>
<!-- TODO: move to una preset -->
<NBadge
v-bind="badge"
:una="{
badgeDefaultVariant: 'badge-outline-white',
...props.badge?.una,
}"
class="min-w-max whitespace-nowrap rounded-full px-2.5 py-0.5 leading-5"
/>
</template>
</NButton>
</template>
Table of Contents