refactor(ui): additional size props for button, input and link
This commit is contained in:
parent
952d81bfaa
commit
72649a48e3
|
@ -38,11 +38,6 @@ const fontWeight = props.thinFont ? 400 : 900
|
||||||
|
|
||||||
const button = ref()
|
const button = ref()
|
||||||
|
|
||||||
const attributes = computed(() =>
|
|
||||||
color(props, ['interactive'])(
|
|
||||||
width(props, [isIconOnly.value ? 'minContent' : 'buttonWidth'])(
|
|
||||||
align(props, { alignSelf:'start', alignText:'center' })()
|
|
||||||
)))
|
|
||||||
|
|
||||||
const click = async (...args: any[]) => {
|
const click = async (...args: any[]) => {
|
||||||
internalLoader.value = true
|
internalLoader.value = true
|
||||||
|
@ -60,17 +55,18 @@ onMounted(() => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<button ref="button"
|
<button ref="button"
|
||||||
v-bind="attributes"
|
v-bind="color(props, ['interactive'])(
|
||||||
|
width(props, isIconOnly ? ['square'] : ['normalHeight', 'buttonWidth'])(
|
||||||
|
align(props, { alignSelf:'start', alignText:'center' })(
|
||||||
|
)))"
|
||||||
class="funkwhale button"
|
class="funkwhale button"
|
||||||
:aria-pressed="props.ariaPressed"
|
:aria-pressed="props.ariaPressed"
|
||||||
:class="{
|
:class="{
|
||||||
'is-active': isActive,
|
|
||||||
'is-loading': isLoading,
|
'is-loading': isLoading,
|
||||||
'is-icon-only': isIconOnly,
|
'is-icon-only': isIconOnly,
|
||||||
'has-icon': !!icon,
|
'has-icon': !!icon,
|
||||||
'is-round': round,
|
'is-round': round,
|
||||||
'is-shadow': shadow,
|
'is-shadow': shadow,
|
||||||
'is-low-height': lowHeight
|
|
||||||
}"
|
}"
|
||||||
@click="click"
|
@click="click"
|
||||||
>
|
>
|
||||||
|
@ -97,23 +93,20 @@ onMounted(() => {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
padding: calc(var(--padding) - var(--shift-by)) var(--padding) calc(var(--padding) + var(--shift-by)) var(--padding);
|
padding: calc(var(--padding) / 2 - var(--shift-by)) var(--padding) calc(var(--padding) / 2 + var(--shift-by)) var(--padding);
|
||||||
&.is-icon-only {
|
&.is-icon-only {
|
||||||
padding: var(--padding);
|
padding: var(--padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-low-height {
|
|
||||||
--padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Font
|
// Font
|
||||||
|
|
||||||
font-family: $font-main;
|
font-family: $font-main;
|
||||||
font-weight: v-bind(fontWeight);
|
font-weight: v-bind(fontWeight);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
||||||
line-height: 1em;
|
line-height: 14px;
|
||||||
|
|
||||||
// Decoration
|
// Decoration
|
||||||
|
|
||||||
|
@ -144,6 +137,13 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Content
|
||||||
|
|
||||||
|
> span {
|
||||||
|
position: relative;
|
||||||
|
top: calc(0px - var(--shift-by));
|
||||||
|
}
|
||||||
|
|
||||||
// Icon
|
// Icon
|
||||||
|
|
||||||
i.bi {
|
i.bi {
|
||||||
|
@ -160,7 +160,7 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-icon-only i.bi {
|
&.is-icon-only i.bi {
|
||||||
margin: -2px;
|
margin: -6px;
|
||||||
&.large {
|
&.large {
|
||||||
margin: -8px;
|
margin: -8px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import type { RouterLinkProps } from 'vue-router';
|
|
||||||
import { type ColorProps, type DefaultProps, type PastelProps, type RaisedProps, type VariantProps, color } from '~/composables/color'
|
import { type ColorProps, type DefaultProps, type PastelProps, type RaisedProps, type VariantProps, color } from '~/composables/color'
|
||||||
import { type WidthProps, width } from '~/composables/width'
|
import { type WidthProps, width } from '~/composables/width'
|
||||||
|
|
||||||
|
@ -78,16 +77,17 @@ const attributes = computed(() => ({
|
||||||
grid-template-columns:
|
grid-template-columns:
|
||||||
repeat(auto-fit, v-bind(columnWidth));
|
repeat(auto-fit, v-bind(columnWidth));
|
||||||
grid-auto-flow: row dense;
|
grid-auto-flow: row dense;
|
||||||
place-content: center;
|
|
||||||
/* If the grid has a fixed size smaller than its container, center it */
|
/* If the grid has a fixed size smaller than its container, center it */
|
||||||
|
place-content: center;
|
||||||
|
align-items: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
&[layout=grid-custom] {
|
&[layout=grid-custom] {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid: v-bind("props.grid");
|
grid: v-bind("props.grid");
|
||||||
grid-auto-flow: row dense;
|
grid-auto-flow: row dense;
|
||||||
place-content: center;
|
|
||||||
/* If the grid has a fixed size smaller than its container, center it */
|
/* If the grid has a fixed size smaller than its container, center it */
|
||||||
|
place-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&[layout=stack] {
|
&[layout=stack] {
|
||||||
|
|
|
@ -40,7 +40,7 @@ onMounted(() => {
|
||||||
<template>
|
<template>
|
||||||
<component :is="isExternalLink ? 'a' : 'RouterLink'"
|
<component :is="isExternalLink ? 'a' : 'RouterLink'"
|
||||||
v-bind="color(props, ['interactive'])(
|
v-bind="color(props, ['interactive'])(
|
||||||
width(props)(
|
width(props, isNoColors(props) ? [] : ['normalHeight', 'auto'])(
|
||||||
align(props)(
|
align(props)(
|
||||||
)))"
|
)))"
|
||||||
ref="button"
|
ref="button"
|
||||||
|
@ -75,14 +75,12 @@ onMounted(() => {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
padding: calc(var(--padding) - var(--shift-by)) var(--padding) calc(var(--padding) + var(--shift-by)) var(--padding);
|
padding: calc(var(--padding) / 2 - var(--shift-by)) var(--padding) calc(var(--padding) / 2 + var(--shift-by)) var(--padding);
|
||||||
&.is-icon-only {
|
&.is-icon-only {
|
||||||
padding: var(--padding);
|
padding: var(--padding);
|
||||||
}
|
}
|
||||||
.is-low-height {
|
|
||||||
--padding: 12px;
|
|
||||||
}
|
|
||||||
&.no-spacing{
|
&.no-spacing{
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -100,7 +98,8 @@ onMounted(() => {
|
||||||
// Content
|
// Content
|
||||||
|
|
||||||
> span {
|
> span {
|
||||||
line-height: initial;
|
position: relative;
|
||||||
|
top: calc(0px - var(--shift-by));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decoration
|
// Decoration
|
||||||
|
|
|
@ -11,9 +11,13 @@ export type WidthProps =
|
||||||
| { auto?: true }
|
| { auto?: true }
|
||||||
| { full?: true }
|
| { full?: true }
|
||||||
| { width?: string }
|
| { width?: string }
|
||||||
|
| { square?: true }
|
||||||
|
| { squareSmall?: true }
|
||||||
|
| { lowHeight?: true }
|
||||||
|
| { normalHeight?: true }
|
||||||
export type Key = KeysOfUnion<WidthProps>
|
export type Key = KeysOfUnion<WidthProps>
|
||||||
|
|
||||||
const styles = {
|
const widths = {
|
||||||
minContent: 'width: min-content;',
|
minContent: 'width: min-content;',
|
||||||
iconWidth: 'width: 40px;',
|
iconWidth: 'width: 40px;',
|
||||||
tiny: "width: 124px; grid-column: span 2;",
|
tiny: "width: 124px; grid-column: span 2;",
|
||||||
|
@ -23,6 +27,17 @@ const styles = {
|
||||||
auto: "width: auto;",
|
auto: "width: auto;",
|
||||||
full: "width: auto; grid-column: 1 / -1; place-self: stretch; flex-grow: 1;",
|
full: "width: auto; grid-column: 1 / -1; place-self: stretch; flex-grow: 1;",
|
||||||
width: (w: string) => `width: ${w}; flex-grow:0;`,
|
width: (w: string) => `width: ${w}; flex-grow:0;`,
|
||||||
|
} as const
|
||||||
|
|
||||||
|
const sizes = {
|
||||||
|
squareSmall: 'height: 40px; width: 40px; padding: 4px; grid-column: span 1; justify-content: center;',
|
||||||
|
square: 'height: 48px; width: 48px; grid-column: span 1; justify-content: center;',
|
||||||
|
lowHeight: 'height: 40px;',
|
||||||
|
normalHeight: 'height: 48px;',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
...widths, ...sizes
|
||||||
} as const satisfies Record<Key, string | ((w: string) => string)>;
|
} as const satisfies Record<Key, string | ((w: string) => string)>;
|
||||||
|
|
||||||
const getStyle = (props: Partial<WidthProps>) => (key: Key): string =>
|
const getStyle = (props: Partial<WidthProps>) => (key: Key): string =>
|
||||||
|
@ -39,7 +54,8 @@ const getStyle = (props: Partial<WidthProps>) => (key: Key): string =>
|
||||||
|
|
||||||
// All keys are exclusive
|
// All keys are exclusive
|
||||||
const conflicts: Set<Key>[] = [
|
const conflicts: Set<Key>[] = [
|
||||||
new Set(Object.keys(styles) as Key[])
|
new Set(Object.keys(widths) as Key[]),
|
||||||
|
new Set(Object.keys(sizes) as Key[]),
|
||||||
]
|
]
|
||||||
|
|
||||||
const merge = (rules: string[]) => (attributes: HTMLAttributes = {}) =>
|
const merge = (rules: string[]) => (attributes: HTMLAttributes = {}) =>
|
||||||
|
|
|
@ -36,7 +36,7 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Layout aside default raised solid gap-12 :class="[$style.sidebar, $style['sticky-content']]">
|
<Layout aside default raised solid gap-12 :class="[$style.sidebar, $style['sticky-content']]">
|
||||||
<Layout header flex no-gap style="justify-content:space-between; padding-right:8px;">
|
<Layout header flex no-gap style="justify-content:space-between; align-items:center; padding-right:8px;">
|
||||||
<Link
|
<Link
|
||||||
:to="{name: logoUrl}"
|
:to="{name: logoUrl}"
|
||||||
:class="$style['logo']"
|
:class="$style['logo']"
|
||||||
|
@ -52,17 +52,16 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
||||||
v-if="store.state.auth.availablePermissions['settings'] || store.state.auth.availablePermissions['moderation']"
|
v-if="store.state.auth.availablePermissions['settings'] || store.state.auth.availablePermissions['moderation']"
|
||||||
to="/manage/settings"
|
to="/manage/settings"
|
||||||
round
|
round
|
||||||
|
square-small
|
||||||
icon="bi-wrench"
|
icon="bi-wrench"
|
||||||
ghost
|
ghost
|
||||||
>
|
/>
|
||||||
</Link>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
v-if="store.state.auth.authenticated"
|
v-if="store.state.auth.authenticated"
|
||||||
align-self="center"
|
|
||||||
round
|
round
|
||||||
|
square-small
|
||||||
icon="bi-upload"
|
icon="bi-upload"
|
||||||
icon-width
|
|
||||||
:class="[$style.button]"
|
:class="[$style.button]"
|
||||||
ghost
|
ghost
|
||||||
@click="store.commit('ui/toggleModal', 'upload')"
|
@click="store.commit('ui/toggleModal', 'upload')"
|
||||||
|
@ -87,8 +86,8 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
||||||
<Button
|
<Button
|
||||||
round
|
round
|
||||||
ghost
|
ghost
|
||||||
|
square-small
|
||||||
icon="bi-list large"
|
icon="bi-list large"
|
||||||
align-self="center"
|
|
||||||
class="hide-on-desktop"
|
class="hide-on-desktop"
|
||||||
:class="$style.menu"
|
:class="$style.menu"
|
||||||
@click="isCollapsed=!isCollapsed"/>
|
@click="isCollapsed=!isCollapsed"/>
|
||||||
|
@ -212,29 +211,6 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
|
||||||
& > nav {
|
|
||||||
a,
|
|
||||||
button.button {
|
|
||||||
height: 40px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu {
|
|
||||||
/* TODO: Fix important */
|
|
||||||
color: red;
|
|
||||||
padding: 8px !important;
|
|
||||||
height: 40px;
|
|
||||||
width: 40px !important;
|
|
||||||
|
|
||||||
i {
|
|
||||||
font-size: 24px !important;
|
|
||||||
margin: -1px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.sticky-content {
|
&.sticky-content {
|
||||||
max-height: 100dvh;
|
max-height: 100dvh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
|
@ -45,12 +45,9 @@ const labels = computed(() => ({
|
||||||
<template>
|
<template>
|
||||||
<Popover raised v-model:open="isOpen">
|
<Popover raised v-model:open="isOpen">
|
||||||
<Button
|
<Button
|
||||||
min-content
|
|
||||||
@click="isOpen = !isOpen"
|
@click="isOpen = !isOpen"
|
||||||
round
|
round
|
||||||
default
|
square-small
|
||||||
align-self="center"
|
|
||||||
raised
|
|
||||||
ghost
|
ghost
|
||||||
:ariaPressed="isOpen ? true : undefined"
|
:ariaPressed="isOpen ? true : undefined"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import Card from "~/components/ui/Card.vue"
|
import Card from "~/components/ui/Card.vue"
|
||||||
|
import Button from "~/components/ui/Button.vue"
|
||||||
|
import Link from "~/components/ui/Link.vue"
|
||||||
import Layout from "~/components/ui/Layout.vue"
|
import Layout from "~/components/ui/Layout.vue"
|
||||||
|
import Spacer from "~/components/ui/layout/Spacer.vue";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# Using widths
|
# Using widths
|
||||||
|
@ -30,6 +33,66 @@ import Layout from "~/components/ui/Layout.vue"
|
||||||
<Card full title='full' />
|
<Card full title='full' />
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
## Small height and square aspect ratio
|
||||||
|
|
||||||
|
<Layout grid class="preview">
|
||||||
|
|
||||||
|
<div style="grid-column: 1 / 7; grid-row: span 2">
|
||||||
|
|
||||||
|
```vue-html
|
||||||
|
<Button outline icon="bi-star"/>
|
||||||
|
<Button outline icon="bi-star large"/>
|
||||||
|
<Button outline square-small icon="bi-star" />
|
||||||
|
<Button outline square-small icon="bi-star large" />
|
||||||
|
<Button primary square >b</Button>
|
||||||
|
<Button primary >c</Button>
|
||||||
|
<Button primary square-small >a</Button>
|
||||||
|
<Button primary low-height >e</Button>
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button outline icon="bi-star"/>
|
||||||
|
<Button outline icon="bi-star large"/>
|
||||||
|
<Spacer />
|
||||||
|
<Button outline square-small icon="bi-star" />
|
||||||
|
<Button outline square-small icon="bi-star large" />
|
||||||
|
<Spacer />
|
||||||
|
<Button primary square >b</Button>
|
||||||
|
<Button primary >c</Button>
|
||||||
|
<Spacer />
|
||||||
|
<Button primary square-small >a</Button>
|
||||||
|
<Button primary low-height >e</Button>
|
||||||
|
|
||||||
|
</Layout>
|
||||||
|
<Layout grid class="preview">
|
||||||
|
|
||||||
|
<div style="grid-column: -1 / -6; grid-row: span 4">
|
||||||
|
|
||||||
|
```vue-html
|
||||||
|
<Link icon="bi-star" to="."/>
|
||||||
|
<Link square-small icon="bi-star" to="."/>
|
||||||
|
<Link square-small to=".">g</Link>
|
||||||
|
<Link square to=".">h</Link>
|
||||||
|
<Link to=".">i</Link>
|
||||||
|
<Link square-small to=".">j</Link>
|
||||||
|
<Link low-height to=".">k</Link>
|
||||||
|
<Link square low-height to=".">l</Link>
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Link icon="bi-star" to="."/>
|
||||||
|
<Link square-small icon="bi-star" to="."/>
|
||||||
|
<Link square-small to=".">g</Link>
|
||||||
|
<Link square to=".">h</Link>
|
||||||
|
<Link to=".">i</Link>
|
||||||
|
<Link square-small to=".">j</Link>
|
||||||
|
<Link low-height to=".">k</Link>
|
||||||
|
<Link square low-height to=".">l</Link>
|
||||||
|
|
||||||
|
</Layout>
|
||||||
|
|
||||||
## Widths in the grid
|
## Widths in the grid
|
||||||
|
|
||||||
::: details Default widths
|
::: details Default widths
|
||||||
|
|
Loading…
Reference in New Issue