funkwhale/front/src/components/ui/Link.vue

124 lines
2.7 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue'
import { type RouterLinkProps } from 'vue-router'
import { type ColorProps, type DefaultProps, type VariantProps, color, isNoColors } from '~/composables/color';
import { type WidthProps, width } from '~/composables/width'
import { type AlignmentProps, align } from '~/composables/alignment'
const props = defineProps<{
thickWhenActive?: true
thin?: true
icon?: string;
round?: true;
} & RouterLinkProps
& (ColorProps | DefaultProps)
& VariantProps
& WidthProps
& AlignmentProps>()
const isExternalLink = computed(() =>
typeof props.to === 'string' && props.to.startsWith('http')
)
const [fontWeight, activeFontWeight] = props.thickWhenActive ? [600, 900] : [400, 400]
const isIconOnly = computed(() => !!props.icon)
</script>
<template>
<component :is="isExternalLink ? 'a' : 'RouterLink'"
v-bind="color(props, ['interactive'])(
width(props, ['auto'])(
align(props, { alignText:'center' })
()))"
:class="[
$style.link,
round && $style['is-round'],
isIconOnly && $style['is-icon-only'],
isNoColors(props) && $style['force-underline'],
isNoColors(props) && $style['no-spacing'],
]"
:href="isExternalLink ? to.toString() : undefined"
:to="isExternalLink ? undefined : to"
:target="isExternalLink ? '_blank' : undefined"
>
<i v-if="icon" :class="['bi', icon]" />
<span>
<slot />
</span>
</component>
</template>
<style module lang="scss">
.link {
// Layout
--padding: 10px;
position: relative;
display: inline-flex;
white-space: nowrap;
justify-content: space-between;
padding: 9px 10px 11px 10px;
&.is-icon-only {
padding: 10px;
}
&.no-spacing{
padding: 0;
margin: 0;
font-size: 1em;
}
// Font
font-family: $font-main;
font-weight: v-bind(fontWeight);
font-size: 14px;
line-height: 1em;
// Decoration
cursor: pointer;
transform: translateX(var(--fw-translate-x)) translateY(var(--fw-translate-y)) scale(var(--fw-scale));
transition:background-color .2s, border-color .3s;
&:not(.force-underline) {
text-decoration: none;
// background-color: transparent;
// border-color: transparent;
}
border-radius: var(--fw-border-radius);
&.is-round {
border-radius: 100vh;
}
// States
&:global(.router-link-exact-active) {
font-weight: v-bind(activeFontWeight);
}
// Icon
> i:global(.bi) {
font-size: 1.2rem;
&.large {
font-size:2rem;
}
&+span:not(:empty) {
margin-left: 1ch;
}
}
}
</style>