feat(ui): allow custom width (via composable props)

This commit is contained in:
upsiflu 2024-12-30 11:46:49 +01:00
parent a588726a54
commit 2ebda850c7
3 changed files with 44 additions and 16 deletions

View File

@ -105,7 +105,7 @@ const federationEnabled = computed(() => {
<Card :title="t('components.About.header.signup')" <Card :title="t('components.About.header.signup')"
v-if="!store.state.auth.authenticated" v-if="!store.state.auth.authenticated"
style="--width:256px" width="256px"
> >
<template v-if="openRegistrations"> <template v-if="openRegistrations">
@ -156,7 +156,7 @@ const federationEnabled = computed(() => {
<Card :title="t('components.About.message.greeting', {username: store.state.auth.username})" <Card :title="t('components.About.message.greeting', {username: store.state.auth.username})"
v-else v-else
style="--width:256px" width= "256px"
> >
<p v-if="defaultUploadQuota"> <p v-if="defaultUploadQuota">
@ -171,7 +171,7 @@ const federationEnabled = computed(() => {
</Card> </Card>
<Card :title="podName" <Card :title="podName"
style="--width:256px" width="256px"
> >
<section <section
:class="['ui', 'head', {'with-background': banner}, 'vertical', 'center', 'aligned', 'stripe', 'segment']" :class="['ui', 'head', {'with-background': banner}, 'vertical', 'center', 'aligned', 'stripe', 'segment']"
@ -234,7 +234,7 @@ const federationEnabled = computed(() => {
<Layout flex style="justify-content: center;"> <Layout flex style="justify-content: center;">
<Card style="--width:256px" <Card width="256px"
to="/" to="/"
:title="t('components.About.header.publicContent')" :title="t('components.About.header.publicContent')"
icon="bi-box-arrow-up-right" icon="bi-box-arrow-up-right"
@ -243,7 +243,7 @@ const federationEnabled = computed(() => {
{{ t('components.About.description.publicContent') }} {{ t('components.About.description.publicContent') }}
</Card> </Card>
<Card style="--width:256px" <Card width="256px"
:title="t('components.About.link.findOtherPod')" :title="t('components.About.link.findOtherPod')"
to="https://funkwhale.audio/#get-started" to="https://funkwhale.audio/#get-started"
icon="bi-box-arrow-up-right" icon="bi-box-arrow-up-right"
@ -251,7 +251,7 @@ const federationEnabled = computed(() => {
{{ t('components.About.description.publicContent') }} {{ t('components.About.description.publicContent') }}
</Card> </Card>
<Card style="--width:256px" <Card width="256px"
:title="t('components.About.header.findApp')" :title="t('components.About.header.findApp')"
to="https://funkwhale.audio/apps" to="https://funkwhale.audio/apps"
icon="bi-box-arrow-up-right" icon="bi-box-arrow-up-right"

View File

@ -1,4 +1,4 @@
import type { KeysOfUnion } from "type-fest" import type { Entries, KeysOfUnion } from "type-fest"
export type WidthProps = export type WidthProps =
| { minContent?: true } | { minContent?: true }
@ -8,9 +8,10 @@ export type WidthProps =
| { medium?: true } | { medium?: true }
| { auto?: true } | { auto?: true }
| { full?: true } | { full?: true }
| { width?: string }
export type Key = KeysOfUnion<WidthProps> export type Key = KeysOfUnion<WidthProps>
const styles : Record<Key, string> = { const styles = {
minContent: 'width: min-content;', minContent: 'width: min-content;',
tiny: "width: 124px; grid-column: span 2;", tiny: "width: 124px; grid-column: span 2;",
buttonWidth: "width: 136px; grid-column: span 2; flex-grow:0;", buttonWidth: "width: 136px; grid-column: span 2; flex-grow:0;",
@ -18,7 +19,19 @@ const styles : Record<Key, string> = {
medium: "width: 280px; grid-column: span 4;", medium: "width: 280px; grid-column: span 4;",
auto: "width: auto;", auto: "width: auto;",
full: "width: auto; grid-column: 1 / -1; align-self: auto; flex-grow:1;", full: "width: auto; grid-column: 1 / -1; align-self: auto; flex-grow:1;",
}; width: (w:string)=>`width: ${w}; flex-grow:0;`,
} as const satisfies Record<Key, string|((w:string)=>string)>;
const getStyle = (props : Partial<WidthProps>) => (key : Key) =>
(typeof styles[key] !== 'string' && key in props) ?
styles[key](
// TODO: Make the typescript compiler understand `key in props`
// @ts-ignore
props[key]
)
: styles[key]
// All keys are exclusive // All keys are exclusive
const conflicts: Set<Key>[] = [ const conflicts: Set<Key>[] = [
@ -30,22 +43,25 @@ const conflicts: Set<Key>[] = [
* Widths are designed to work both in a page-grid context and in a flex or normal context. * Widths are designed to work both in a page-grid context and in a flex or normal context.
* *
* (1) Add `& WidthProps` to your `Props` type * (1) Add `& WidthProps` to your `Props` type
* (2) Call `v-bind="propsToWidth(props)"` on your component template * (2) Call `v-bind="width(props)"` on your component template
* (3) Now your component accepts width props such as `small`, `medium`, `stretch`. * (3) Now your component accepts width props such as `small`, `medium`, `stretch`.
* *
* @param props Your component's props (or ...rest props if you have destructured them already) * @param props Your component's props (or ...rest props if you have destructured them already)
* @returns the corresponding `style` object * @returns the corresponding `{ style }` object
*/ */
export const width = (props: Partial<WidthProps>, defaults: Key[] = []) => ({ export const width = <TProps extends Partial<WidthProps>>(
props: TProps,
defaults: Key[] = []
) => ({
style: style:
Object.entries(props).reduce( (Object.entries(props) as Entries<TProps>).reduce(
((acc, [key, value]) => ((acc, [key, value]) =>
value && key in styles ? value && key in styles ?
acc.filter(accKey => !conflicts.find(set => set.has(accKey) && set.has(key as Key))) acc.filter(accKey => !conflicts.find(set => set.has(accKey) && set.has(key)))
.concat([key as Key]) .concat([key])
: acc : acc
), ),
defaults defaults
).map(key => styles[key]) ).map(getStyle(props))
.join(' ') .join(' ')
}) })

View File

@ -26,6 +26,7 @@ const here = route.path
<Card small title='small' /> <Card small title='small' />
<Card medium title='medium' /> <Card medium title='medium' />
<Card auto title='auto' /> <Card auto title='auto' />
<Card width="170.5px" title='width=170.5px' />
<Card full title='full' /> <Card full title='full' />
``` ```
@ -35,5 +36,16 @@ const here = route.path
<Card small title='small' /> <Card small title='small' />
<Card medium title='medium' /> <Card medium title='medium' />
<Card auto title='auto' /> <Card auto title='auto' />
<Card width="170.5px" title='width=170.5px' />
<Card full title='full' /> <Card full title='full' />
</Layout> </Layout>
## Widths in the grid
::: details Default widths
![alt text](image-1.png)
:::
[Designing Pages — The grid](designing-pages#grid)