refactor(ui): use similar props in Header as in Section; use visual style props from Heading component
This commit is contained in:
		
							parent
							
								
									5e0efff73f
								
							
						
					
					
						commit
						167e663661
					
				| 
						 | 
				
			
			@ -278,7 +278,10 @@ fetchOwnedApps()
 | 
			
		|||
    main
 | 
			
		||||
    stack
 | 
			
		||||
  >
 | 
			
		||||
    <Header :h1="t('components.auth.Settings.header.accountSettings')" />
 | 
			
		||||
    <Header
 | 
			
		||||
      page-heading
 | 
			
		||||
      :h1="t('components.auth.Settings.header.accountSettings')"
 | 
			
		||||
    />
 | 
			
		||||
    <Layout
 | 
			
		||||
      form
 | 
			
		||||
      @submit.prevent="submitSettings()"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,7 +121,10 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
 | 
			
		|||
    no-gap
 | 
			
		||||
    align-left
 | 
			
		||||
  >
 | 
			
		||||
    <Header :h1="labels.title">
 | 
			
		||||
    <Header
 | 
			
		||||
      page-heading
 | 
			
		||||
      :h1="labels.title"
 | 
			
		||||
    >
 | 
			
		||||
      <template #action>
 | 
			
		||||
        <RadioButton
 | 
			
		||||
          v-if="store.state.favorites.count > 0"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -136,7 +136,10 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
 | 
			
		|||
    stack
 | 
			
		||||
    main
 | 
			
		||||
  >
 | 
			
		||||
    <Header :h1="t('components.library.Albums.header.browse')" />
 | 
			
		||||
    <Header
 | 
			
		||||
      page-heading
 | 
			
		||||
      :h1="t('components.library.Albums.header.browse')"
 | 
			
		||||
    />
 | 
			
		||||
    <Layout
 | 
			
		||||
      form
 | 
			
		||||
      flex
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -135,7 +135,9 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
 | 
			
		|||
    stack
 | 
			
		||||
    main
 | 
			
		||||
  >
 | 
			
		||||
    <Header :h1="t('components.library.Artists.header.browse')" />
 | 
			
		||||
    <Header :h1="t('components.library.Artists.header.browse')"
 | 
			
		||||
      page-heading
 | 
			
		||||
    />
 | 
			
		||||
    <Layout
 | 
			
		||||
      form
 | 
			
		||||
      flex
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,7 +70,10 @@ fetchData()
 | 
			
		|||
    main
 | 
			
		||||
    stack
 | 
			
		||||
  >
 | 
			
		||||
    <Header :h1="t('components.Sidebar.header.explore')" />
 | 
			
		||||
    <Header
 | 
			
		||||
      page-heading
 | 
			
		||||
      :h1="t('components.Sidebar.header.explore')"
 | 
			
		||||
    />
 | 
			
		||||
    <album-widget
 | 
			
		||||
      :filters="{scope: scope, playable: true, ordering: '-creation_date', ...qualityFilters}"
 | 
			
		||||
      :limit="4"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -137,6 +137,7 @@ const { to: upload } = useModal('upload')
 | 
			
		|||
    main
 | 
			
		||||
  >
 | 
			
		||||
    <Header
 | 
			
		||||
      page-heading
 | 
			
		||||
      :h1="t('components.library.Podcasts.header.browse')"
 | 
			
		||||
    />
 | 
			
		||||
    <Layout
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,7 +119,10 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
 | 
			
		|||
    stack
 | 
			
		||||
    gap-64
 | 
			
		||||
  >
 | 
			
		||||
    <Header :h1="t('components.library.Radios.header.browse')" />
 | 
			
		||||
    <Header
 | 
			
		||||
      page-heading
 | 
			
		||||
      :h1="t('components.library.Radios.header.browse')"
 | 
			
		||||
    />
 | 
			
		||||
    <Section
 | 
			
		||||
      align-left
 | 
			
		||||
      :h2="t('components.library.Radios.header.instance')"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
import type { RouterLinkProps } from 'vue-router'
 | 
			
		||||
import type { ComponentProps } from 'vue-component-type-helpers'
 | 
			
		||||
import { useAttrs } from 'vue'
 | 
			
		||||
 | 
			
		||||
import Layout from '~/components/ui/Layout.vue'
 | 
			
		||||
| 
						 | 
				
			
			@ -12,18 +12,17 @@ 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()
 | 
			
		||||
  columnsPerItem?: 1 | 2 | 3 | 4
 | 
			
		||||
  alignLeft?: boolean
 | 
			
		||||
  action?: { text: string } & (ComponentProps<typeof Link> | ComponentProps<typeof Button>)
 | 
			
		||||
  icon?: string
 | 
			
		||||
} & {
 | 
			
		||||
  [H in `h${ '1' | '2' | '3' | '4' | '5' | '6' }`]? : string
 | 
			
		||||
} & {
 | 
			
		||||
  [S in 'page-heading' | 'section-heading' | 'subsection-heading' | 'caption' | 'title' | 'radio' | 'secondary' ]? : true
 | 
			
		||||
} & {
 | 
			
		||||
  [Operation in 'expand' | 'collapse']?: () => void
 | 
			
		||||
}>()
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
| 
						 | 
				
			
			@ -51,20 +50,34 @@ const { style, ...fallthroughProps } = useAttrs()
 | 
			
		|||
          :size="68"
 | 
			
		||||
          style="align-self: baseline;"
 | 
			
		||||
        />
 | 
			
		||||
        <div
 | 
			
		||||
          v-if="icon"
 | 
			
		||||
          style="display: flex; justify-content: center; align-items: center; width: 48px;"
 | 
			
		||||
        >
 | 
			
		||||
          <i
 | 
			
		||||
            :class="['bi', icon]"
 | 
			
		||||
            style="font-size: 18px;"
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
        <slot name="topleft" />
 | 
			
		||||
        <Heading
 | 
			
		||||
          v-bind="heading"
 | 
			
		||||
          style="align-self: baseline; padding:0  0 24px 0; margin:0;"
 | 
			
		||||
          v-bind="props"
 | 
			
		||||
          style="
 | 
			
		||||
            align-self: baseline;
 | 
			
		||||
            padding: 0 0 24px 0;
 | 
			
		||||
            margin: 0;
 | 
			
		||||
          "
 | 
			
		||||
        />
 | 
			
		||||
        <Spacer grow />
 | 
			
		||||
        <!-- Action! You can either specify `to` or `onClick`. -->
 | 
			
		||||
        <component
 | 
			
		||||
          :is="'onClick' in action ? actionComponents.Button : actionComponents.Link"
 | 
			
		||||
          v-if="action"
 | 
			
		||||
          :style="`margin-right: ${('primary' in props || 'secondary' in props || 'destructive' in props) ? '0px' : '-16px'}`"
 | 
			
		||||
          thin-font
 | 
			
		||||
          min-content
 | 
			
		||||
          align-self="baseline"
 | 
			
		||||
          v-bind="{...fallthroughProps, ...action}"
 | 
			
		||||
          :class="$style.action"
 | 
			
		||||
          v-bind="action"
 | 
			
		||||
        >
 | 
			
		||||
          {{ action?.text }}
 | 
			
		||||
        </component>
 | 
			
		||||
| 
						 | 
				
			
			@ -79,3 +92,10 @@ const { style, ...fallthroughProps } = useAttrs()
 | 
			
		|||
    </Layout>
 | 
			
		||||
  </Layout>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style module lang="scss">
 | 
			
		||||
  // Visually push ghost link and non-solid button to the edge
 | 
			
		||||
  .action:global(.interactive:not(:is(.primary, .solid, .destructive, .secondary)):is(button, a.ghost)) {
 | 
			
		||||
    margin-right: -16px;
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,15 +100,18 @@ const markAllAsRead = async () => {
 | 
			
		|||
 | 
			
		||||
<template>
 | 
			
		||||
  <Layout
 | 
			
		||||
    v-title="labels.title"
 | 
			
		||||
    main
 | 
			
		||||
    stack
 | 
			
		||||
    v-title="labels.title"
 | 
			
		||||
    class="main page-notifications"
 | 
			
		||||
  >
 | 
			
		||||
    <div
 | 
			
		||||
      v-if="additionalNotifications"
 | 
			
		||||
    >
 | 
			
		||||
      <Header :h1="t('views.Notifications.header.messages')" />
 | 
			
		||||
      <Header
 | 
			
		||||
        page-heading
 | 
			
		||||
        :h1="t('views.Notifications.header.messages')"
 | 
			
		||||
      />
 | 
			
		||||
      <Layout flex>
 | 
			
		||||
        <div
 | 
			
		||||
          v-if="showInstanceSupportMessage"
 | 
			
		||||
| 
						 | 
				
			
			@ -223,7 +226,10 @@ const markAllAsRead = async () => {
 | 
			
		|||
        </Alert>
 | 
			
		||||
      </Layout>
 | 
			
		||||
    </div>
 | 
			
		||||
    <Header :h1="t('views.Notifications.header.notifications')" />
 | 
			
		||||
    <Header
 | 
			
		||||
      page-heading
 | 
			
		||||
      :h1="t('views.Notifications.header.notifications')"
 | 
			
		||||
    />
 | 
			
		||||
    <Toggle
 | 
			
		||||
      id="show-read-notifications"
 | 
			
		||||
      v-model="filters.is_read"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,10 @@ const title = computed(() => labels.value[props.type])
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <Header :h1="title" />
 | 
			
		||||
  <Header
 | 
			
		||||
    page-heading
 | 
			
		||||
    :h1="title"
 | 
			
		||||
  />
 | 
			
		||||
  <invitation-form v-if="type === 'invitations'" />
 | 
			
		||||
  <accounts-table
 | 
			
		||||
    v-if="type === 'accounts'"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -180,7 +180,10 @@ await nextTick()
 | 
			
		|||
    :class="['ui', {'loading': isLoading}]"
 | 
			
		||||
  >
 | 
			
		||||
    <Loader v-if="isLoading" />
 | 
			
		||||
    <Header :h1="labels.settings" />
 | 
			
		||||
    <Header
 | 
			
		||||
      page-heading
 | 
			
		||||
      :h1="labels.settings"
 | 
			
		||||
    />
 | 
			
		||||
    <div
 | 
			
		||||
      v-if="settingsData"
 | 
			
		||||
      id="settings-grid"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,8 +22,7 @@ const labels = computed(() => ({
 | 
			
		|||
 | 
			
		||||
<template>
 | 
			
		||||
  <Header
 | 
			
		||||
    align-left
 | 
			
		||||
    no-items
 | 
			
		||||
    page-heading
 | 
			
		||||
    :h1="t('views.admin.library.EditsList.header.edits')"
 | 
			
		||||
  />
 | 
			
		||||
  <edits-card-list
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,7 +60,10 @@ const createDomain = async () => {
 | 
			
		|||
      form
 | 
			
		||||
      @submit.prevent="createDomain"
 | 
			
		||||
    >
 | 
			
		||||
      <Header :h1="t('views.admin.moderation.DomainsList.header.domains')" />
 | 
			
		||||
      <Header
 | 
			
		||||
        page-heading
 | 
			
		||||
        :h1="t('views.admin.moderation.DomainsList.header.domains')"
 | 
			
		||||
      />
 | 
			
		||||
      <Alert
 | 
			
		||||
        v-if="errors && errors.length > 0"
 | 
			
		||||
        red
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,7 +108,10 @@ const labels = computed(() => ({
 | 
			
		|||
    v-title="labels.reports"
 | 
			
		||||
    stack
 | 
			
		||||
  >
 | 
			
		||||
    <Header :h1="t('views.admin.moderation.ReportsList.header.reports')" />
 | 
			
		||||
    <Header
 | 
			
		||||
      page-heading
 | 
			
		||||
      :h1="t('views.admin.moderation.ReportsList.header.reports')"
 | 
			
		||||
    />
 | 
			
		||||
    <div class="ui inline form">
 | 
			
		||||
      <div class="fields">
 | 
			
		||||
        <div class="ui field">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,7 +98,10 @@ const labels = computed(() => ({
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <Header :h1="t('views.admin.moderation.RequestsList.header.userRequests')" />
 | 
			
		||||
  <Header
 | 
			
		||||
    page-heading
 | 
			
		||||
    :h1="t('views.admin.moderation.RequestsList.header.userRequests')"
 | 
			
		||||
  />
 | 
			
		||||
  <Spacer />
 | 
			
		||||
  <div class="ui inline form">
 | 
			
		||||
    <div class="fields">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,8 @@ const { t } = useI18n()
 | 
			
		|||
  >
 | 
			
		||||
    <Header
 | 
			
		||||
      align-left
 | 
			
		||||
      medium-items
 | 
			
		||||
      page-heading
 | 
			
		||||
      :columns-per-item="4"
 | 
			
		||||
      :h1="t('views.auth.ProfileBase.link.overview')"
 | 
			
		||||
    >
 | 
			
		||||
      <template #action>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -99,7 +99,10 @@ const updateUploads = (count: number) => {
 | 
			
		|||
    main
 | 
			
		||||
  >
 | 
			
		||||
    <Loader v-if="isLoading" />
 | 
			
		||||
    <Header :h1="object.name">
 | 
			
		||||
    <Header
 | 
			
		||||
      page-heading
 | 
			
		||||
      :h1="object.name"
 | 
			
		||||
    >
 | 
			
		||||
      <template #action>
 | 
			
		||||
        <Popover>
 | 
			
		||||
          <template #default="{ toggleOpen }">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,6 +84,7 @@ const deleteRadio = async () => {
 | 
			
		|||
    <Header
 | 
			
		||||
      v-if="!isLoading && radio"
 | 
			
		||||
      v-title="radio.name"
 | 
			
		||||
      page-heading
 | 
			
		||||
      :h1="radio.name"
 | 
			
		||||
    />
 | 
			
		||||
    <h2 class="sub header">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,13 +11,21 @@ import Header from '~/components/ui/Header.vue'
 | 
			
		|||
 | 
			
		||||
# Page header
 | 
			
		||||
 | 
			
		||||
Place the `Header` at the beginning of a page. Choose an appropriate heading level: `h1` or `h2` or `h3`. Choose `h1` unless the header is part of a page subsection or a modal.
 | 
			
		||||
Place the `Header` at the beginning of a page. Choose an appropriate heading level: `h1` or `h2` or `h3`. Choose `h1` unless the header is part of a page subsection or a modal. You can use all props for [Heading](../heading.md), including the [stylistic variants](../heading.md#visual-sizes-for-page-sections-and-subsections) such as `radio` or `page-heading`.
 | 
			
		||||
 | 
			
		||||
```vue-html
 | 
			
		||||
<Header h1="My title" />
 | 
			
		||||
<Header
 | 
			
		||||
  page-heading
 | 
			
		||||
  h1="My title"
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<Header h1="My title" />
 | 
			
		||||
<Header
 | 
			
		||||
  page-heading
 | 
			
		||||
  h1="My title"
 | 
			
		||||
/>
 | 
			
		||||
 | 
			
		||||
For a detailed explanation of the props, read [the entry on `Section`](section.md)
 | 
			
		||||
 | 
			
		||||
### Add an image
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue