forked from npmx-dev/npmx.dev
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBase.vue
More file actions
133 lines (121 loc) · 4.66 KB
/
Base.vue
File metadata and controls
133 lines (121 loc) · 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<script setup lang="ts">
import type { NuxtLinkProps } from '#app'
import type { IconClass } from '~/types'
const props = withDefaults(
defineProps<{
/** Disabled links will be displayed as plain text */
disabled?: boolean
/**
* `type` should never be used, because this will always be a link.
* */
type?: never
/** Visual style of the link */
variant?: 'button-primary' | 'button-secondary' | 'link'
/** Size (only applicable for button variants) */
size?: 'small' | 'medium'
/** Makes the link take full width */
block?: boolean
/** Keyboard shortcut hint */
ariaKeyshortcuts?: string
/**
* Don't use this directly. This will automatically be set to `_blank` for external links passed via `to`.
*/
target?: never
/**
* Don't use this directly. This will automatically be set for external links passed via `to`.
*/
rel?: never
/** Icon class to display */
classicon?: IconClass
/** Link destination (internal or external URL) */
to?: NuxtLinkProps['to']
/** always use `to` instead of `href` */
href?: never
/** should only be used for links where the context makes it very clear they are clickable. Don't just use this, because you don't like underlines. */
noUnderline?: boolean
/**
* Hide external link icon (deprecated)
* @deprecated @todo remove this property and add separate clean component without this logic
*/
noNewTabIcon?: boolean
}>(),
{ variant: 'link', size: 'medium' },
)
const isLinkExternal = computed(
() =>
!!props.to &&
typeof props.to === 'string' &&
(props.to.startsWith('http:') || props.to.startsWith('https:') || props.to.startsWith('//')),
)
const isLinkAnchor = computed(
() => !!props.to && typeof props.to === 'string' && props.to.startsWith('#'),
)
/** size is only applicable for button like links */
const isLink = computed(() => props.variant === 'link')
const isButton = computed(() => !isLink.value)
const isButtonSmall = computed(() => props.size === 'small' && !isLink.value)
const isButtonMedium = computed(() => props.size === 'medium' && !isLink.value)
const keyboardShortcutsEnabled = useKeyboardShortcuts()
</script>
<template>
<span
v-if="disabled"
:class="{
'flex': block,
'inline-flex': !block,
'opacity-50 gap-x-1 items-center justify-center font-mono border border-transparent rounded-md':
isButton,
'text-sm px-4 py-2': isButtonMedium,
'text-xs px-2 py-0.5': isButtonSmall,
'text-bg bg-fg': variant === 'button-primary',
'bg-transparent text-fg': variant === 'button-secondary',
}"
><slot
/></span>
<NuxtLink
v-bind="props"
v-else
class="group/link gap-x-1 items-center"
:class="{
'flex': block,
'inline-flex': !block,
'underline-offset-[0.2rem] underline decoration-1 decoration-fg/30':
!isLinkAnchor && isLink && !noUnderline,
'justify-start font-mono text-fg hover:(decoration-accent text-accent) focus-visible:(decoration-accent text-accent) transition-colors duration-200':
isLink,
'justify-center font-mono border border-border rounded-md transition-all duration-200':
isButton,
'text-sm px-4 py-2': isButtonMedium,
'text-xs px-2 py-0.5': isButtonSmall,
'bg-transparent text-fg hover:(bg-fg/10 text-accent) focus-visible:(bg-fg/10 text-accent) aria-[current=true]:(bg-fg/10 text-accent border-fg/20 hover:enabled:(bg-fg/20 text-fg/50))':
variant === 'button-secondary',
'text-bg bg-fg hover:(bg-fg/80 text-bg) focus-visible:(bg-fg/80 text-bg) aria-current:(bg-fg text-bg border-fg hover:enabled:(text-bg/50))':
variant === 'button-primary',
}"
:to="to"
:aria-keyshortcuts="keyboardShortcutsEnabled ? ariaKeyshortcuts : undefined"
:target="isLinkExternal ? '_blank' : undefined"
>
<span v-if="classicon" class="size-[1em]" :class="classicon" aria-hidden="true" />
<slot />
<!-- automatically show icon indicating external link -->
<span
v-if="isLinkExternal && !classicon && !noNewTabIcon"
class="i-lucide:external-link rtl-flip size-[1em] opacity-50"
aria-hidden="true"
/>
<span
v-else-if="isLinkAnchor && isLink"
class="i-lucide:link size-[1em] opacity-0 group-hover/link:opacity-100 transition-opacity duration-200"
aria-hidden="true"
/>
<kbd
v-if="keyboardShortcutsEnabled && ariaKeyshortcuts"
data-kbd-hint
class="ms-2 hidden sm:inline-flex items-center justify-center size-4 text-xs text-fg bg-bg-muted border border-border rounded no-underline"
aria-hidden="true"
>
{{ ariaKeyshortcuts }}
</kbd>
</NuxtLink>
</template>