55 lines
1.8 KiB
Vue
55 lines
1.8 KiB
Vue
<script setup lang="ts">
|
|
import type { RouterLinkProps } from 'vue-router'
|
|
import { useAttrs } from 'vue'
|
|
|
|
import Layout from '~/components/ui/Layout.vue'
|
|
import Spacer from '~/components/ui/Spacer.vue'
|
|
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 }
|
|
& { [H in 'h1' | 'h2' | 'h3']?: string }
|
|
& { action?: { text: string } & (RouterLinkProps | { onClick: (...args: any[]) => void | Promise<void> }) }>()
|
|
|
|
const heading =
|
|
props.h1 ? ({ h1: props.h1, pageHeading: true }) as const
|
|
: props.h2 ? ({ h2: props.h2 }) as const
|
|
: ({ h3: props.h3 }) as const
|
|
|
|
const { style, ...fallthroughProps } = useAttrs()
|
|
</script>
|
|
|
|
<template>
|
|
<Layout header flex gap-24>
|
|
<div v-if="$slots.image">
|
|
<slot name="image" />
|
|
</div>
|
|
<Layout stack no-gap style="flex-grow: 1;">
|
|
<Layout flex no-gap
|
|
style="align-self: stretch;"
|
|
>
|
|
<!-- Set distance between baseline and previous row -->
|
|
<Spacer v
|
|
:size="68"
|
|
style="align-self: baseline;"
|
|
/>
|
|
<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`. -->
|
|
<component v-if="action" :is="'onClick' in action ? actionComponents.Button : actionComponents.Link"
|
|
force-underline thin-font min-content align-self="baseline"
|
|
v-bind="{...fallthroughProps, ...action}"
|
|
>
|
|
{{ action?.text }}
|
|
</component>
|
|
</Layout>
|
|
<slot />
|
|
</Layout>
|
|
</Layout>
|
|
</template>
|