feat(ui): implement link styles; use growing Spacers in Sidebar

This commit is contained in:
upsiflu 2024-12-17 01:37:37 +01:00
parent 302781d1fe
commit 1ca7f41ac2
5 changed files with 151 additions and 57 deletions

View File

@ -1,14 +1,14 @@
<script setup lang="ts">
import { computed } from 'vue'
import { type RouterLinkProps, RouterLink } from 'vue-router'
import { type ColorProps, propsToColor } from '~/composables/colors'
import { type ColorProps, type VariantProps, propsToColor } from '~/composables/colors';
const { to, icon, inline, ...otherProps } = defineProps<RouterLinkProps
& ColorProps
const { to, icon, inline, round, ...otherProps } = defineProps<RouterLinkProps
& {
icon?: string;
round?: boolean
inline?: true
}>()
} & ColorProps & VariantProps>()
const isExternalLink = computed(() => {
return typeof to === 'string' && to.startsWith('http')
@ -17,8 +17,13 @@ const isExternalLink = computed(() => {
<template>
<a v-if="isExternalLink"
:v-bind="propsToColor(otherProps)"
:class="[$style.link, $style.external, inline && $style.inline]"
v-bind="propsToColor(otherProps)"
:class="[
'interactive',
$style.link,
$style.external,
round && $style['is-round']
]"
:href="to?.toString()"
target="_blank"
>
@ -27,8 +32,12 @@ const isExternalLink = computed(() => {
</a>
<RouterLink v-else
:to="to"
:v-bind="propsToColor(otherProps)"
:class="[$style.link, inline && $style.inline]"
v-bind="propsToColor(otherProps)"
:class="[
'interactive',
$style.link,
round && $style['is-round']
]"
>
<i v-if="icon" :class="['bi', icon]" />
<slot />
@ -38,13 +47,8 @@ const isExternalLink = computed(() => {
<style module lang="scss">
.active { outline: 3px solid red; }
.external { outline: 3px dotted blue; }
.inline { display:inline-flex; }
.button {
background-color: var(--fw-bg-color);
color: var(--fw-text-color);
border: 1px solid var(--fw-bg-color);
display: flex;
.link {
display: inline-flex;
align-items: center;
white-space: nowrap;
@ -72,5 +76,9 @@ const isExternalLink = computed(() => {
background-color:transparent;
border-color:transparent;
}
&.is-round {
border-radius: 100vh;
}
}
</style>

View File

@ -22,13 +22,13 @@
}
&:not(.is-raw) {
color: var(--fw-link-color);
color: var(--link-color);
cursor: pointer;
text-decoration: underline;
&:hover,
&.is-hovered {
color: var(--fw-link-hover-color);
color: var(--link-hover-color);
}
}
}

View File

@ -118,12 +118,12 @@
background-color: var(--pressed-background-color, var(--active-background-color));
border-color: var(--pressed-background-color, var(--active-background-color));
}
&:hover{
&:hover {
color:var(--hover-color);
background-color:var(--hover-background-color);
border-color: var(--hover-background-color);
}
&:active{
&:is(:active, .active) {
color:var(--active-color);
background-color:var(--active-background-color);
border-color: var(--active-background-color);
@ -142,13 +142,13 @@
border: 1px solid transparent;
&.interactive{
&:hover{
border: 1px solid var(--hover-background-color);
&:hover {
border-color: var(--hover-background-color);
}
&:active{
border: 1px solid var(--active-background-color);
&:is(:active, .active) {
border-color: var(--active-background-color);
&.router-link-exact-active {
border: 1px solid var(--exact-active-background-color);
border-color: var(--exact-active-background-color);
}
}
&[disabled] {
@ -164,12 +164,12 @@
&.interactive{
&:hover{
border: 1px solid var(--hover-background-color);
border-color: var(--hover-background-color);
}
&:active{
border: 1px solid var(--active-background-color);
&:is(:active, .active) {
border-color: var(--active-background-color);
&.router-link-exact-active {
background: 1px solid var(--exact-active-background-color);
background-color: var(--exact-active-background-color);
}
}
}
@ -201,6 +201,9 @@
--background-color:var(--fw-beige-300);
--border-color:var(--fw-beige-400);
}
--link-color:var(--fw-blue-400);
--link-hover-color:var(--fw-blue-500);
}
.secondary, button {
@ -229,12 +232,18 @@
--hover-background-color:var(--fw-gray-400);
--active-background-color:var(--fw-gray-500);
}
--link-color:var(--fw-blue-600);
--link-hover-color:var(--fw-blue-700);
}
.primary {
--color: var(--fw-blue-010);
--background-color:var(--fw-blue-400);
--border-color:var(--fw-blue-010);
--border-color:var(--fw-blue-400);
&> .primary {
--border-color:var(--fw-blue-010);
}
--hover-color: var(--fw-blue-010);
--hover-background-color:var(--fw-blue-500);
@ -254,6 +263,11 @@
--hover-background-color:var(--fw-blue-600);
--active-background-color:var(--fw-blue-700);
}
&:not(:is(.ghost, .outline)) {
--link-color:var(--fw-blue-010);
--link-hover-color:white;
}
}
.destructive {
@ -272,6 +286,11 @@
--disabled-color:var(--fw-gray-500);
--disabled-background-color:var(--fw-gray-100);
--disabled-border-color:var(--fw-gray-100);
&:not(:is(.ghost, .outline)) {
--link-color:var(--fw-blue-010);
--link-hover-color:white;
}
}
.blue {
@ -285,6 +304,9 @@
--disabled-border-color: var(--fw-gray-400);
--disabled-background-color: transparent;
}
--link-color:var(--fw-blue-010);
--link-hover-color:white;
}
.red {
@ -298,6 +320,9 @@
--disabled-border-color: var(--fw-gray-400);
--disabled-background-color: transparent;
}
--link-color:var(--fw-blue-010);
--link-hover-color:white;
}
.purple {
@ -311,6 +336,9 @@
--disabled-border-color: var(--fw-gray-400);
--disabled-background-color: transparent;
}
--link-color:var(--fw-blue-010);
--link-hover-color:white;
}
.green {
@ -324,6 +352,9 @@
--disabled-border-color: var(--fw-gray-400);
--disabled-background-color: transparent;
}
--link-color:var(--fw-blue-010);
--link-hover-color:white;
}
.yellow {
@ -337,6 +368,9 @@
--disabled-border-color: var(--fw-gray-400);
--disabled-background-color: transparent;
}
--link-color:var(--fw-blue-010);
--link-hover-color:white;
}
}
@ -365,6 +399,9 @@
--background-color:var(--fw-gray-900);
--border-color:var(--fw-gray-600);
}
--link-color:var(--fw-gray-300);
--link-hover-color:var(--fw-gray-400)
}
.secondary, button {
@ -396,6 +433,9 @@
--active-color:var(--fw-gray-400);
--active-background-color:var(--fw-gray-900);
}
--link-color:var(--fw-gray-500);
--link-hover-color:var(--fw-gray-600)
}
.primary {

View File

@ -10,6 +10,8 @@ import Link from '~/components/ui/Link.vue'
import ActorAvatar from '~/components/common/ActorAvatar.vue'
import UserMenu from './UserMenu.vue'
import Button from '~/components/ui/Button.vue'
import Layout from '~/components/ui/Layout.vue'
import Spacer from '~/components/ui/layout/Spacer.vue'
const searchQuery = ref('')
@ -25,7 +27,7 @@ const uploads = useUploadsStore()
</script>
<template>
<aside :class="[$style.sidebar, $style['sticky-content']]">
<aside :class="[$style.sidebar, $style['sticky-content']]" v-bind="color('default solid raised')">
<header :class="$style['header-wrapper']">
<Link to="/" :class="$style['logo']">
<img
@ -64,16 +66,16 @@ const uploads = useUploadsStore()
</nav>
</header>
<div :class="$style.search">
<Input
v-model="searchQuery"
type="search"
icon="bi-search"
:placeholder="t('components.audio.SearchBar.placeholder.search')"
/>
</div>
<nav :class="$style['button-list']">
<Layout no-gap stack :class="$style['button-list']">
<div :class="$style.search">
<Input
v-model="searchQuery"
type="search"
icon="bi-search"
:placeholder="t('components.audio.SearchBar.placeholder.search')"
/>
</div>
<nav style="display:contents;">
<Link to="/library"
ghost
secondary
@ -112,7 +114,7 @@ const uploads = useUploadsStore()
>
{{ t('components.Sidebar.link.radios') }}
</Link>
<Link to="/library/podcasts">
<Link to="/library/podcasts"
ghost
secondary
icon="bi-mic"
@ -127,8 +129,10 @@ const uploads = useUploadsStore()
{{ t('components.Sidebar.link.favorites') }}
</Link>
</nav>
<Spacer grow />
<h3>{{ t('components.Sidebar.link.channels') }}</h3>
<nav :class="$style['button-list']">
<Spacer grow />
<nav>
<Link inline to="/about">
{{ t('components.Sidebar.link.about') }}
</Link>
@ -139,6 +143,7 @@ const uploads = useUploadsStore()
Legal
</Link>
</nav>
</Layout>
</aside>
</template>
@ -153,7 +158,6 @@ const uploads = useUploadsStore()
height: 100%;
display:flex;
flex-direction:column;
background-color: var(--fw-gray-900);
&.sticky-content {
position: sticky;
@ -260,24 +264,11 @@ const uploads = useUploadsStore()
> h3 {
margin: 0;
padding: 0 32px 8px;
color: var(--fw-gray-700);
@include light-theme {
color: var(--fw-gray-700);
}
@include dark-theme {
color: var(--fw-blue-100);
}
font-size: 14px;
line-height: 1.2;
}
nav.button-list {
.button-list {
padding: 0 16px 32px;
button {
margin: 2px 0;
justify-content: start;
width: 100%;
}
}
}
}

View File

@ -1,5 +1,6 @@
<script setup lang="ts">
import Link from '~/components/ui/Link.vue'
import Button from '~/components/ui/Button.vue'
</script>
# Link
@ -21,3 +22,57 @@ This component only adds some styles to a `<RouterLink>`.
</Link>
Instead of a route, you can set the prop `to` to any web address starting with `http`.
## Colors and Variants
###### Solid:
<Link primary solid to="/">
Home
</Link>
<Link secondary solid to="/">
Home
</Link>
<Link destructive solid to="/">
Home
</Link>
###### Outline:
<Link primary outline to="/">
Home
</Link>
<Link secondary outline to="/">
Home
</Link>
<Link destructive outline to="/">
Home
</Link>
###### Ghost:
<Link primary ghost to="/">
Home
</Link>
<Link secondary ghost to="/">
Home
</Link>
<Link destructive ghost to="/">
Home
</Link>
<Button>
I'm a button
</Button>
## Shapes
<Link primary solid round to="/">
Home
</Link>