refactor(ui): add heading component for visual consistency and maintainability
This commit is contained in:
parent
7e19fd23f0
commit
c5be51e779
|
@ -0,0 +1,37 @@
|
|||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
[H in `h${'1' | '2' | '3' | '4' | '5' | '6' | '7'}`]? : true
|
||||
} & {[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 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;">
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Page heading */
|
||||
.pageHeading { font-size: 36px; font-weight: 900; letter-spacing: -1px; }
|
||||
|
||||
/* Section heading, Modal heading [DEFAULT] */
|
||||
.sectionHeading { font-size: 20px; font-weight: 700; letter-spacing: -.5px; }
|
||||
|
||||
/* Form subsection */
|
||||
.subsectionHeading {font-size: 16px; font-weight: 600; letter-spacing: 0; }
|
||||
|
||||
/* input caption */
|
||||
.caption {font-size: 14px; font-weight: 600; letter-spacing: .25px; }
|
||||
|
||||
/* Tab title, Channel title, Card title, Activity title */
|
||||
.title { font-size: 16px; font-weight: 700; }
|
||||
|
||||
/* Primary radio title */
|
||||
.radio { font-size: 28px; font-weight: 900; letter-spacing: -.5px; }
|
||||
|
||||
/* Secondary radio title */
|
||||
.secondary { font-size: 28px; font-weight: 300; letter-spacing: -.5px; }
|
||||
</style>
|
|
@ -6,6 +6,7 @@ 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 props = defineProps<{
|
||||
[M in 'no-items' | 'tiny-items' | 'small-items' | 'medium-items']?: true }
|
||||
|
@ -14,9 +15,9 @@ const props = defineProps<{
|
|||
& { action?: { text: string } & (RouterLinkProps | { onClick: (...args: any[]) => void | Promise<void> }) }>()
|
||||
|
||||
const [headingLevel, title] =
|
||||
props.h1 ? ['h1', props.h1]
|
||||
: props.h2 ? ['h2', props.h2]
|
||||
: ['h3', props.h3]
|
||||
props.h1 ? ['h1', props.h1] as const
|
||||
: props.h2 ? ['h2', props.h2] as const
|
||||
: ['h3', props.h3] as const
|
||||
|
||||
const numberOfColumnsPerItem =
|
||||
'noItems' in props && props.noItems ? 1 : 'tinyItems' in props && props.tinyItems ? 2 : 'smallItems' in props && props['smallItems'] ? 3 : 4
|
||||
|
@ -44,10 +45,15 @@ const headerGrid =
|
|||
style="align-self: baseline;"
|
||||
/>
|
||||
<!-- Flexible row content -->
|
||||
<!-- Note that the `h3` uses its padding to create the 24px bottom gap -->
|
||||
<component :is="headingLevel" style="align-self: baseline; padding:0 0 24px 0; margin:0;">
|
||||
<Heading h1 v-if="headingLevel==='h1'" pageHeading style="align-self: baseline; padding:0 0 24px 0; margin:0;">
|
||||
{{ title }}
|
||||
</component>
|
||||
</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>
|
||||
<Spacer grow />
|
||||
<!-- Action! You can either specify `to` or `onClick`. -->
|
||||
<Button v-if="props.action && 'onClick' in props.action"
|
||||
|
|
|
@ -45,6 +45,7 @@ export default defineConfig({
|
|||
{ text: 'Toggle', link: '/components/ui/toggle' },
|
||||
],
|
||||
},
|
||||
{ text: 'Heading', link: '/components/ui/heading' },
|
||||
{
|
||||
text: 'Layout', link: '/components/ui/layout/',
|
||||
items: [
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
<script setup>
|
||||
import Heading from "~/components/ui/Heading.vue"
|
||||
</script>
|
||||
|
||||
```ts
|
||||
import Heading from "~/components/ui/Heading.vue";
|
||||
```
|
||||
|
||||
# Heading
|
||||
|
||||
Use a heading when the content or the page structure requires it. Define the visual style independently from the logical hierarchy.
|
||||
|
||||
- Each page has exactly one `h1` with the visual size `page-heading`.
|
||||
- Headings always describe the content below. Do not use headings for input captions.
|
||||
- Try to avoid gaps in the hierarchy.
|
||||
|
||||
## Semantic heading level
|
||||
|
||||
Use heading levels wherever you want to add logical (not necessarily visual) hierarchy.
|
||||
|
||||
Consult [the allyproject for a comprehensive guide on headings](https://www.a11yproject.com/posts/how-to-accessible-heading-structure/).
|
||||
|
||||
## Visual sizes for page sections and subsections
|
||||
|
||||
---
|
||||
|
||||
<Heading h1 page-heading>Page heading</Heading>
|
||||
|
||||
Use this visual size on the main heading of the page.
|
||||
|
||||
---
|
||||
|
||||
<Heading h3 section-heading>Section heading</Heading>
|
||||
|
||||
Use section headings to subdivide the main content on the page. Also use for modal headings. This is the default visual size.
|
||||
|
||||
---
|
||||
|
||||
<Heading h3 subsection-heading>Subsection heading</Heading>
|
||||
|
||||
Use subsection headings to break long sections or forms with several groups into digestible subsections.
|
||||
|
||||
## Visual sizes for special elements
|
||||
|
||||
---
|
||||
|
||||
<Heading h4 caption>Caption</Heading>
|
||||
|
||||
Caption-style headings are found only within forms.
|
||||
|
||||
---
|
||||
|
||||
<Heading h3 title>Title</Heading>
|
||||
|
||||
Use this visual size to title [Tabs](/components/ui/tabs), Channels, [Cards](/components/ui/card) and [Activities](/components/ui/activity).
|
||||
|
||||
---
|
||||
|
||||
<Heading h3 radio>Radio</Heading>
|
||||
|
||||
Radio cards have giant titles.
|
||||
|
||||
---
|
||||
|
||||
<Heading h3 secondary>Secondary</Heading>
|
||||
|
||||
A card may have a secondary title, [as exemplified in the designs](https://design.funkwhale.audio/#/workspace/a4e0101a-252c-80ef-8003-918b4c2c3927/e3a187f0-0f5e-11ed-adb9-fff9e854a67c?page-id=5e293790-52d3-11ed-9497-8deeaf0bfa97).
|
Loading…
Reference in New Issue