feat(ui): simplify Heading and Section components

This commit is contained in:
upsiflu 2025-01-20 18:51:00 +02:00
parent f15f675a91
commit 83023aaeb1
2 changed files with 18 additions and 31 deletions

View File

@ -1,14 +1,15 @@
<script setup lang="ts">
const props = defineProps<{
[H in `h${'1' | '2' | '3' | '4' | '5' | '6' | '7'}`]? : true
[H in `h${'1' | '2' | '3' | '4' | '5' | '6' | '7'}`]? : string
} & {[S in 'page-heading' | 'section-heading' | 'subsection-heading' | 'caption' | 'title' | 'radio' | 'secondary' ]? : true}>()
const level = Object.entries(props).find(([key, value]) => value && key.startsWith('h'))?.[0] || 'h1'
const [level, title] = Object.entries(props).find(([key, value]) => value && key.startsWith('h')) || ['h1', '']
const size = Object.entries(props).find(([key, value]) => value && key!==level)?.[0] || 'section-heading'
</script>
<template>
<component :is="level" :class="size" style="margin: 0; padding:0; line-height: 40px; vertical-align: baseline;">
{{ title }}
<slot />
</component>
</template>

View File

@ -8,16 +8,21 @@ import Button from '~/components/ui/Button.vue'
import Link from '~/components/ui/Link.vue'
import Heading from '~/components/ui/Heading.vue'
const actionComponents =
{ Button, Link }
const props = defineProps<{
[M in 'no-items' | 'tiny-items' | 'small-items' | 'medium-items']?: true }
& { alignLeft?: boolean;}
& { [H in 'h1' | 'h2' | 'h3']?: string }
& { action?: { text: string } & (RouterLinkProps | { onClick: (...args: any[]) => void | Promise<void> }) }>()
const [headingLevel, title] =
props.h1 ? ['h1', props.h1] as const
: props.h2 ? ['h2', props.h2] as const
: ['h3', props.h3] as const
const heading =
props.h1 ? ({ h1: props.h1, pageHeading: true }) as const
: props.h2 ? ({ h2: props.h2 }) as const
: ({ h3: props.h3 }) as const
console.log("HEADING", heading)
const numberOfColumnsPerItem =
'noItems' in props && props.noItems ? 1 : 'tinyItems' in props && props.tinyItems ? 2 : 'smallItems' in props && props['smallItems'] ? 3 : 4
@ -34,7 +39,6 @@ const headerGrid =
:style="`${'alignLeft' in props && props.alignLeft ? 'justify-content: start' : ''};
margin-top: -64px;`"
>
<!-- The title row's width is a multiple of the expected items' column span -->
<Layout flex no-gap
style="grid-column: 1 / -1; align-self: baseline;"
@ -44,34 +48,16 @@ const headerGrid =
:size="64"
style="align-self: baseline;"
/>
<!-- Flexible row content -->
<Heading h1 v-if="headingLevel==='h1'" pageHeading style="align-self: baseline; padding:0 0 24px 0; margin:0;">
{{ title }}
</Heading>
<Heading h2 v-if="headingLevel==='h2'" sectionHeading style="align-self: baseline; padding:0 0 24px 0; margin:0;">
{{ title }}
</Heading>
<Heading h3 v-if="headingLevel==='h3'" sectionHeading style="align-self: baseline; padding:0 0 24px 0; margin:0;">
{{ title }}
</Heading>
<Heading v-bind="heading" style="align-self: baseline; padding:0 0 24px 0; margin:0;"/>
<Spacer grow />
<!-- Action! You can either specify `to` or `onClick`. -->
<Button v-if="props.action && 'onClick' in props.action"
ghost thin-font min-content align-self="baseline"
<component v-if="action" :is="'onClick' in action ? actionComponents.Button : actionComponents.Link"
ghost force-underline thin-font min-content align-self="baseline"
:style="`margin-right: ${('primary' in props || 'secondary' in props || 'destructive' in props) ? '0px' : '-16px'}`"
:onClick="props.action.onClick"
v-bind="fallthroughProps"
>
{{ props.action.text }}
</Button>
<Link v-if="props.action && 'to' in props.action"
ghost force-underline thinFont align-self="baseline"
:style="`margin-right: ${('primary' in props || 'secondary' in props || 'destructive' in props) ? '0px' : '-16px'}`"
:to="props.action.to"
v-bind="fallthroughProps"
v-bind="{...fallthroughProps, ...action}"
>
{{ props.action.text }}
</Link>
{{ action?.text }}
</component>
</Layout>
</Layout>
<Layout main