-
-
Notifications
You must be signed in to change notification settings - Fork 424
Expand file tree
/
Copy pathBase.vue
More file actions
126 lines (114 loc) · 4.28 KB
/
Base.vue
File metadata and controls
126 lines (114 loc) · 4.28 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
<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
variant?: 'button-primary' | 'button-secondary' | 'link'
size?: 'small' | 'medium'
block?: boolean
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
classicon?: IconClass
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
/**
* When `true`, suppresses the external-link icon even for external `to` URLs.
*
* @default false
*/
noExternalIcon?: boolean
}>(),
{ variant: 'link', size: 'medium', noUnderline: false, noExternalIcon: false },
)
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)
</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/50 text-accent) focus-visible:(bg-fg/50) aria-current:(bg-fg text-bg border-fg hover:enabled:(text-bg/50))':
variant === 'button-primary',
}"
:to="to"
:aria-keyshortcuts="ariaKeyshortcuts"
: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 && !noExternalIcon && !classicon"
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="ariaKeyshortcuts"
class="ms-2 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>