feat(ui): [WIP] new `Link` component, use for sidebar links

This commit is contained in:
upsiflu 2024-12-13 14:16:03 +01:00
parent 8ea49dd251
commit ad9e3dd4b0
4 changed files with 211 additions and 2 deletions

View File

@ -0,0 +1,182 @@
<script setup lang="ts">
import { computed } from 'vue';
import { type RouterLinkProps, RouterLink } from 'vue-router';
const { to, icon } = defineProps<RouterLinkProps & {
icon?: string;
variant?: 'solid' | 'outline' | 'ghost'
}>()
const isExternalLink = computed(() => {
return typeof to === 'string' && to.startsWith('http')
})
</script>
<template>
<a v-if="isExternalLink" :class="$style.external" :href="to?.toString()" target="_blank">
<slot />
</a>
<RouterLink v-if="to && !isExternalLink" :to="to" v-slot="{ isActive, href, navigate }">
<a :href="href" @click="navigate" :class="{ [$style.active]: isActive }">
<slot />
<i v-if="icon" :class="['bi', icon]" />
</a>
</RouterLink>
</template>
<style module lang="scss">
.active { background:red; }
.external { outline: 3px dotted blue; }
a {
background-color: var(--fw-bg-color);
color: var(--fw-text-color);
border: 1px solid var(--fw-bg-color);
position: relative;
display: inline-flex;
align-items: center;
white-space: nowrap;
font-family: $font-main;
font-weight: 900;
font-size: 0.875em;
line-height: 1em;
padding: 0.642857142857em;
border-radius: var(--fw-border-radius);
margin: 0 0.5ch;
transform: translateX(var(--fw-translate-x)) translateY(var(--fw-translate-y)) scale(var(--fw-scale));
transition: all .2s ease;
@include light-theme {
&.is-secondary.is-outline {
--fw-bg-color: var(--fw-gray-600);
--fw-text-color: var(--fw-gray-700);
&[disabled] {
--fw-bg-color: var(--fw-gray-600) !important;
--fw-text-color: var(--fw-gray-600) !important;
}
&.is-hovered,
&:hover {
--fw-bg-color: var(--fw-gray-700) !important;
--fw-text-color: var(--fw-gray-800) !important;
}
&.is-active,
&:active {
--fw-text-color: var(--fw-red-010) !important;
border: 1px solid var(--fw-gray-600) !important;
}
}
&.is-outline {
&:not(:active):not(.is-active) {
background-color: transparent !important;
--fw-text-color:--fw-gray-400;
}
}
&.is-ghost {
&:not(:active):not(.is-active):not(:hover):not(.is-hovered) {
background-color: transparent !important;
border-color: transparent !important;
--fw-text-color:--fw-gray-400;
}
}
}
@include dark-theme {
&.is-secondary.is-outline {
--fw-bg-color: var(--fw-gray-500);
--fw-text-color: var(--fw-gray-400);
&[disabled] {
--fw-bg-color: var(--fw-gray-600) !important;
--fw-text-color: var(--fw-gray-700) !important;
}
&.is-hovered,
&:hover {
--fw-bg-color: var(--fw-gray-600) !important;
--fw-text-color: var(--fw-gray-500) !important;
}
&.is-active,
&:active {
--fw-text-color: var(--fw-red-010) !important;
--fw-bg-color: var(--fw-gray-700) !important;
border: 1px solid var(--fw-gray-600) !important;
}
}
&.is-outline {
&:not(:active):not(.is-active) {
background-color: transparent !important;
}
}
&.is-ghost {
&:not(:active):not(.is-active):not(:hover):not(.is-hovered) {
background-color: transparent !important;
border-color: transparent !important;
}
}
&.is-aligned-center {
justify-content: center;
}
&.is-aligned-left {
justify-content: flex-start;
}
&.is-aligned-right {
justify-content: flex-end;
}
&.is-shadow {
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.2);
}
&:not(.icon-only):not(.is-auto) {
min-width: 8.5rem;
}
&.is-full {
display: block;
}
&.is-round {
border-radius: 100vh;
}
&[disabled] {
font-weight: normal;
pointer-events: none;
}
&.is-loading {
@extend .is-active;
> span {
opacity: 0;
}
}
i.bi {
font-size: 1.2rem;
}
i.bi + span:not(:empty) {
margin-left: 1ch;
}
}
}
</style>

View File

@ -7,6 +7,7 @@ import { useStore } from '~/store'
import Button from '~/components/ui/Button.vue'
import Input from '~/components/ui/Input.vue'
import Pill from '~/components/ui/Pill.vue'
import Link from '~/components/ui/Link.vue'
const searchQuery = ref('')
@ -99,13 +100,13 @@ const uploads = useUploadsStore()
<h3>Explore</h3>
<nav class="button-list">
<Button
<Link to="/content"
color="secondary"
variant="ghost"
icon="bi-compass"
>
All Funkwhale
</Button>
</Link>
<Button
color="secondary"
variant="ghost"

View File

@ -39,6 +39,9 @@ export default defineConfig({
{ text: 'Tabs', link: '/components/ui/tabs' },
],
},
{ text: 'Link',
link: 'components/ui/link'
},
{
text: 'Form',
items: [

View File

@ -0,0 +1,23 @@
<script setup lang="ts">
import Link from '~/components/ui/Link.vue'
</script>
# Link
Will render an `<a href...>` element.
This component only adds some styles to a `<RouterLink>`.
```vue-html
<Link to="/">
Home
</Link>
```
<Link to="/">
Home
</Link>
Instead of a route, you can set the prop `to` to any web address starting with `http`.