feat(ui): more consistent props

This commit is contained in:
upsiflu 2024-12-22 02:27:20 +01:00
parent 37d99e1a53
commit c65b4bd4f0
13 changed files with 105 additions and 64 deletions

View File

@ -90,9 +90,9 @@ onMounted(() => {
line-height: 1em;
padding: 0.642857142857em 0.714em 0.714em 0.714em;
padding: 9px 10px 11px 10px;
&.is-icon-only {
padding: 0.675em 0.714em 0.678em 0.714em;
padding: 10px;
}
border-radius: var(--fw-border-radius);
@ -161,6 +161,8 @@ onMounted(() => {
&.large {
font-size:2rem;
}
/* Must not increase the height of the button */
margin: -0.5rem 0;
}
i.bi + span:not(:empty) {

View File

@ -16,21 +16,35 @@ const props = defineProps<{
tags?: string[]
image?: string | { src: string, style?: "withPadding" }
icon?: string
} & ({
[Width in 'small' | 'auto']?: true
} | { width: string }) & Partial<RouterLinkProps> & (PastelProps | ColorProps | DefaultProps) & RaisedProps & VariantProps>()
} & (
{ [Width in 'large' | 'medium' | 'small' | 'auto']?: true } | { width?: string }
) & Partial<RouterLinkProps> & (PastelProps | ColorProps | DefaultProps) & RaisedProps & VariantProps>()
const image = typeof props.image === 'string' ? { src: props.image } : props.image
const width =
'width' in props && props.width
? props.width
: 'auto' in props && props.auto
? 'auto'
: 'large' in props && props.large ?
'304px'
: 'medium' in props && props.medium ?
'208px'
: 'small' in props && props.small ?
'min-content'
: '304px'
console.log("WIDTH", width, props)
const isExternalLink = computed(() => {
return typeof props.to === 'string' && props.to.startsWith('http')
})
</script>
<template>
<Layout stack
<Layout stack no-gap
:class="{ [$style.card]: true, [$style['is-category']]: category }"
style="--gap:16px"
v-bind="propsToColor({...(props.to? { interactive: true, solid: true, default: true } : {}), ...props})"
>
@ -46,7 +60,7 @@ const isExternalLink = computed(() => {
</div>
<img v-else-if="image" :src="image?.src"
:class="{ [$style.image]: true, [$style['with-padding']]: image?.style === 'withPadding' }" />
<Spacer v-else :size="'small' in props ? 4 : 12" />
<Spacer v-else :size="'small' in props ? 20 : 28" />
<!-- Icon -->
@ -83,15 +97,14 @@ const isExternalLink = computed(() => {
<slot name="action" />
</div>
<Spacer v-if="!$slots.footer && !$slots.action" :size="'small' in props? 8 : 16" />
<Spacer v-if="!$slots.footer && !$slots.action" :size="'small' in props? 24 : 32" />
</Layout>
</template>
<style module>
.card {
/* Override --width with your preferred value */
--fw-card-width: var(--width, v-bind("'small' in props ? 'min-content' : 'auto' in props ? 'auto' : props.width || '320px'"));
--fw-card-width: v-bind(width);
--fw-card-padding: v-bind("props.small ? '16px' : '24px'");
position: relative;
@ -169,6 +182,9 @@ const isExternalLink = computed(() => {
font-size: 1.75em;
padding-bottom: .125em;
}
&:has(>.image:not(.with-padding))>.title {
margin-top:16px;
}
>.alert {
padding-left: var(--fw-card-padding);
@ -178,6 +194,7 @@ const isExternalLink = computed(() => {
>.tags {
/* Tags have an inherent padding which we offset here: */
padding: 0 calc(var(--fw-card-padding) - 12px);
margin-top: 8px;
}
>.content {
@ -185,6 +202,7 @@ const isExternalLink = computed(() => {
/* Consider making all line height, vertical paddings, margins and borders,
a multiple of a global vertical rhythm so that side-by-side lines coincide */
line-height: 24px;
margin-top: 16px;
}
>.footer {
@ -203,6 +221,7 @@ const isExternalLink = computed(() => {
background: color-mix(in oklab, var(--fw-bg-color) 80%, var(--fw-gray-500));
border-bottom-left-radius: var(--fw-border-radius);
border-bottom-right-radius: var(--fw-border-radius);
margin-top:16px;
>*:not(.with-padding) {
margin: 0;

View File

@ -2,7 +2,8 @@
const props = defineProps<{
columnWidth?: number,
noGap?:true,
noRule?:true
noRule?:true,
noWrap?:true
}
& { [P in "stack" | "grid" | "flex" | "columns"]?: true | string }
& { [C in "nav" | "aside" | "header" | "footer" | "main"]?:true }>()
@ -15,6 +16,7 @@ const columnWidth = props.columnWidth ?? 320
:class="[
$style.layout,
noGap || $style.gap,
noWrap || $style.wrap,
props.grid ? $style[props.grid===true ? 'grid' : 'grid-custom']
: props.flex ? $style.flex
: props.columns? $style.columns
@ -77,7 +79,7 @@ const columnWidth = props.columnWidth ?? 320
&.flex {
display: flex;
flex-direction: row;
flex-wrap: wrap;
flex-wrap: v-bind('props.noWrap ? "no-wrap" : "wrap"');
}
}

View File

@ -108,9 +108,9 @@ const isSimple = propsToColor(colorProps).class === ''
border-radius: var(--fw-border-radius);
margin: 0 0.5ch;
padding: 0.642857142857em 0.714em 0.714em 0.714em;
padding: 9px 10px 11px 10px;
&.is-icon-only {
padding: 0.675em 0.714em 0.678em 0.714em;
padding: 10px;
}
&.no-spacing{
padding: 0;

View File

@ -12,8 +12,7 @@ const props = defineProps<PastelProps | ColorProps>()
<template>
<button
type="button"
class="funkwhale is-colored pill"
class="funkwhale pill outline"
v-bind="propsToColor({...props, interactive:true})"
@click.stop="handleClick"
>

View File

@ -1,17 +1,23 @@
<script setup lang="ts">
import { ref, watchEffect } from 'vue';
const { grow, shrink, title, size = 16 } = defineProps<{ grow?:true, shrink?:true, title?:string, size?:number }>()
const { grow, shrink, title, size = 16, ...direction } = defineProps<{
grow?:true;
shrink?:true;
title?:string;
size?:number;
} & { [Direction in 'h' | 'v']? : true }>()
const minSize = 32
const minSize = 0;
const measure = ref()
watchEffect(() => { measure.value = {
size: `${Math.max(size, minSize)}px`,
margin: `${(size-Math.max(size, minSize))/2}px`
}
watchEffect(() => measure.value = {
size: `${Math.max(size, minSize)}px`,
margin: `${(size-Math.max(size, minSize))/2}px`
})
console.log(size)
</script>
<template>
@ -22,8 +28,8 @@ watchEffect(() => { measure.value = {
<style module lang="scss">
.spacer {
width: v-bind('measure.size');
height: v-bind('measure.size');
width: v-bind('direction.v ? 0 : measure.size');
height: v-bind('direction.h ? 0 : measure.size');
margin: v-bind('measure.margin');
flex-grow:v-bind('grow ? 1 : 0');
flex-shrink:v-bind('shrink ? 1 : 0');

View File

@ -91,7 +91,7 @@
--hover-color:var(--fw-gray-800);
--hover-background-color:var(--fw-beige-200);
--hover-border-color:var(--fw-gray-800);
--hover-border-color:var(--fw-gray-500);
--active-color:var(--fw-gray-900);
--active-background-color:var(--fw-beige-400);
@ -573,9 +573,9 @@
background-color: transparent;
border: 1px solid var(--border-color);
&.interactive{
&:hover{
border-color: var(--hover-background-color);
&.interactive, button {
&:hover {
border-color: var(--hover-border-color);
}
&[aria-pressed=true] {
color: var(--pressed-color, var(--active-color));

View File

@ -10,7 +10,6 @@
main {
padding: 56px 48px;
font-size: 16px;
max-width: 78rem;
}
</style>

View File

@ -99,34 +99,34 @@ Category cards are basic cards that contain only a title. To create a category c
Pass an image source to the `image` prop or set both `image.src` and `image.style` by passing an object.
<Layout :columnWidth="200" grid>
<Layout grid>
<div style="max-width: 320px;">
```vue-html{4,11-12}
<Card
style="--width:208px"
<Card medium
title="For music lovers"
image="https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1&dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb">
/>
<Card
style="--width:208px"
<Card medium
title="For music lovers"
:image="{ src:'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1&dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb',
style:'withPadding' }"
/>
```
</div>
<Layout stack class="preview">
<Card
<Card medium
title="For music lovers"
style="--width:208px"
image="https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1&dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb"
/>
<Card
<Card medium
title="For music lovers"
style="--width:208px"
:image="{ src:'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1&dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb',
style:'withPadding' }"
/>
@ -212,7 +212,7 @@ Large Buttons or links at the bottom edge of the card serve as Call-to-Actions (
<Card title="Join an existing pod">
The easiest way to get started with Funkwhale is to register an account on a public pod.
<template #action>
<Button @click="alert('Open the pod picker')">Action!
<Button secondary @click="alert('Open the pod picker')">Action!
</Button>
</template>
</Card>
@ -222,7 +222,7 @@ Large Buttons or links at the bottom edge of the card serve as Call-to-Actions (
<Card title="Join an existing pod">
The easiest way to get started with Funkwhale is to register an account on a public pod.
<template #action>
<Button @click="alert('Open the pod picker')">Action!
<Button secondary @click="alert('Open the pod picker')">Action!
</Button>
</template>
</Card>
@ -231,28 +231,28 @@ Large Buttons or links at the bottom edge of the card serve as Call-to-Actions (
If there are multiple actions, they will be presented in a row:
```vue-html{4,7}
<Card title="Delete this pod?">
You cannot undo this action.
<Card title="Creating a new playlist...">
All items have been assimilated. Ready to go!
<template #action>
<Button style="justify-content: flex-start;" icon="bi-chevron-left" color="secondary" variant="ghost">
<Button secondary ghost style="justify-content: flex-start;" icon="bi-chevron-left">
Back
</Button>
<Button style="flex-grow:0;" color="destructive" @click="alert('Deleted')">
Delete
<Button style="flex-grow:0;" primary @click="alert('Yay')">
Create
</Button>
</template>
</Card>
```
<div class="preview">
<Card title="Delete this pod?">
You cannot undo this action.
<Card title="Creating a new playlist...">
All items have been assimilated. Ready to go!
<template #action>
<Button style="width:50%; justify-content: flex-start;" icon="bi-chevron-left" color="secondary" variant="ghost">
<Button secondary ghost style="width:50%; justify-content: flex-start;" icon="bi-chevron-left">
Back
</Button>
<Button style="width:50%" color="destructive" @click="alert('Deleted')">
Delete
<Button style="width:50%" primary @click="alert('Yay')">
Next: Pick a color
</Button>
</template>
</Card>

View File

@ -18,28 +18,28 @@ const noGap = ref(true)
The following containers are responsive. Change your window's size or select a device preset from your browser's dev tools to see how layouts are affected by available space.
<Layout grid="auto / repeat(auto-fit, minmax(min-content, 163px))" style="--gap:8px">
<Card auto title="flex" to="./layout/flex" >
<Layout flex style="--gap:8px">
<Card width="163px" title="flex" to="./layout/flex" >
<Layout flex>
<Button primary icon="bi-eye" />
<Button secondary icon="bi-eye" />
<Button destructive icon="bi-eye" />
</Layout>
</Card>
<Card auto title="grid" to="./layout/grid" >
<Card width="163px" title="grid" to="./layout/grid" >
<Layout grid column-width="40">
<Button primary icon="bi-eye" />
<Button secondary icon="bi-eye" style="grid-row: span 2; height: 100%;" />
<Button destructive icon="bi-eye" />
</Layout>
</Card>
<Card auto title="stack" to="./layout/stack" >
<Card width="163px" title="stack" to="./layout/stack" >
<Layout stack style="--gap:0; margin:-8px;">
<Button primary icon="bi-eye" />
<Button secondary icon="bi-eye" />
<Button destructive icon="bi-eye" />
</Layout></Card>
<Card auto title="columns" to="./layout/columns" >
<Card width="163px" title="columns" to="./layout/columns" >
<Layout columns column-width="40">
<Button primary icon="bi-eye" />
<Button secondary icon="bi-eye" />

View File

@ -30,22 +30,18 @@ By default, all items in a row assume the same (maximum) height.
</Layout>
```
<div class="preview">
<Layout flex>
<Layout flex class="preview">
<Card title="A" style="width:100px; min-width:100px"></Card>
<Card title="B" :tags="['funk', 'dunk', 'punk']"></Card>
<Card title="C" style="width:100px; min-width:100px"></Card>
<Card title="D"></Card>
</Layout>
</div>
## Use additional `flexbox` properties
<Layout flex
class="preview"
style="font-size:11px; font-weight:bold; --gap: 4px;"
>
style="font-size:11px; font-weight:bold; --gap: 4px;">
--gap: 4px

View File

@ -108,7 +108,7 @@ const size = ref(1);
</div>
</Layout>
## Make the Spacer elastic
## Make the Spacer elastic (responsive)
<Layout flex>
@ -154,3 +154,15 @@ const size = ref(1);
</div>
</Layout>
## Use the Spacer to vary an element's dimensions
<Layout flex style="align-items:flex-start">
<Input v-model="size" type="range" />
<Card small title="h">
<Spacer h :size="size * 4" style="border:5px dashed;" />
</Card>
<Card small title="v">
<Spacer v :size="size * 4" style="border:5px dashed;" />
</Card>
</Layout>

View File

@ -13,11 +13,17 @@ const route = useRoute();
const here = route.path
</script>
<Link disabled to="#theme-color-definitions">Want to fix colors?</Link>
<Alert blue style="margin: 0 -48px">
Want to fix colors?
<Spacer h />
<Layout flex no-gap>
<Link solid primary to="#change-a-color-value">Change a color value</Link>
<Link solid primary to="#alter-the-shade-of-a-color">Alter the shade of a color</Link>
<Link solid primary to="#choose-a-different-style-for-a-specific-variant">Modify a specific variant</Link>
</Layout>
</Alert>
<Spacer />
# Using Color
## Add color via props