refactor(ui): add icon, slot, and action button/link props to Section
This commit is contained in:
parent
027ad5ddae
commit
779cdbd66d
|
@ -109,7 +109,6 @@ const save = async () => {
|
|||
<template>
|
||||
<Section
|
||||
align-left
|
||||
no-items
|
||||
:h2="group.label"
|
||||
>
|
||||
<form
|
||||
|
|
|
@ -29,7 +29,6 @@ const canEdit = store.state.auth.availablePermissions.library
|
|||
<Layout stack>
|
||||
<Spacer />
|
||||
<Section
|
||||
no-items
|
||||
align-left
|
||||
:h2="canEdit
|
||||
? t('components.library.ArtistEdit.header.edit')
|
||||
|
|
|
@ -579,7 +579,6 @@ const isServerDisclosureOpen = ref(false)
|
|||
<Section
|
||||
:h2="t('components.library.FileUpload.header.server')"
|
||||
align-left
|
||||
no-items
|
||||
v-bind="
|
||||
isServerDisclosureOpen
|
||||
? { collapse: () => { isServerDisclosureOpen = false } }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, computed, useSlots, onMounted, watch, onUnmounted, nextTick } from 'vue'
|
||||
import { ref, computed, useSlots, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
|
||||
import { type ColorProps, type VariantProps, type DefaultProps, type RaisedProps, type PastelProps, color } from '~/composables/color'
|
||||
import { type WidthProps, width } from '~/composables/width'
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
[H in `h${'1' | '2' | '3' | '4' | '5' | '6' | '7'}`]? : string
|
||||
} & {[S in 'page-heading' | 'section-heading' | 'subsection-heading' | 'caption' | 'title' | 'radio' | 'secondary' ]? : true}>()
|
||||
[H in `h${ '1' | '2' | '3' | '4' | '5' | '6' }`]? : string
|
||||
} & {
|
||||
[S in 'page-heading' | 'section-heading' | 'subsection-heading' | 'caption' | 'title' | 'radio' | 'secondary' ]? : true
|
||||
}>()
|
||||
|
||||
const [level, title] = Object.entries(props).find(([key, value]) => value && key.startsWith('h')) || ['h1', '']
|
||||
const size = computed(() => (Object.entries(props).find(([key, value]) => value && key !== level)?.[0] || 'section-heading').replace('-', '').toLowerCase())
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import type { RouterLinkProps } from 'vue-router'
|
||||
import { useAttrs } from 'vue'
|
||||
import type { ComponentProps } from 'vue-component-type-helpers'
|
||||
|
||||
import Layout from '~/components/ui/Layout.vue'
|
||||
import Spacer from '~/components/ui/Spacer.vue'
|
||||
|
@ -12,54 +11,45 @@ const actionComponents
|
|||
= { Button, Link }
|
||||
|
||||
const props = defineProps<{
|
||||
[M in 'no-items' | 'tiny-items' | 'small-items' | 'medium-items']?: true
|
||||
}
|
||||
& {
|
||||
alignLeft?: boolean;
|
||||
action?: { text: string } & (RouterLinkProps | { onClick: (...args: any[]) => void | Promise<void> })
|
||||
}
|
||||
& {
|
||||
[Operation in 'expand' | 'collapse']?: () => void
|
||||
}
|
||||
& { [H in 'h1' | 'h2' | 'h3']?: string }
|
||||
>()
|
||||
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
|
||||
}>()
|
||||
|
||||
const heading
|
||||
= props.h1
|
||||
? ({ h1: props.h1, pageHeading: true }) 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
|
||||
|
||||
const { style, ...fallthroughProps } = useAttrs()
|
||||
|
||||
const headerGrid
|
||||
= `auto / repeat(auto-fit, calc(46px * ${numberOfColumnsPerItem} + 32px * ${numberOfColumnsPerItem - 1}))`
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section style="flex-grow: 1;">
|
||||
<Layout
|
||||
header
|
||||
:grid="headerGrid"
|
||||
:style="`
|
||||
${ 'alignLeft' in props && props.alignLeft ? 'justify-content: start' : '' };
|
||||
${ expand || collapse ? '' : 'margin-top: -64px;' }`
|
||||
v-bind="columnsPerItem
|
||||
? { grid: `auto / repeat(auto-fit, calc(46px * ${columnsPerItem} + 32px * ${(columnsPerItem) - 1}))` }
|
||||
: { flex: true }
|
||||
"
|
||||
:class="[alignLeft && $style.left, expand || collapse ? $style.collapsible : $style.uncollapsible]"
|
||||
>
|
||||
<!-- 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;
|
||||
align-items: baseline;
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
"
|
||||
>
|
||||
<!-- Accordion? -->
|
||||
|
||||
<template v-if="expand || collapse">
|
||||
<Button
|
||||
full
|
||||
|
@ -67,14 +57,12 @@ const headerGrid
|
|||
align-self="end"
|
||||
:class="$style.summary"
|
||||
:aria-pressed="!!collapse"
|
||||
v-bind="action"
|
||||
raised
|
||||
@click="() => expand ? expand() : collapse ? collapse() : (() => { return })()"
|
||||
>
|
||||
<Heading
|
||||
v-if="heading"
|
||||
v-bind="heading"
|
||||
caption
|
||||
/>
|
||||
<slot name="topleft" />
|
||||
<Heading v-bind="props" />
|
||||
</Button>
|
||||
<i
|
||||
:class="!!expand ? 'bi bi-chevron-down' : 'bi bi-chevron-up'"
|
||||
|
@ -86,18 +74,28 @@ const headerGrid
|
|||
"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- Normal (non-accordion)? -->
|
||||
|
||||
<template v-else>
|
||||
<!-- Set distance between baseline and previous row -->
|
||||
<Spacer
|
||||
v
|
||||
:size="64"
|
||||
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-if="heading"
|
||||
v-bind="heading"
|
||||
v-bind="props"
|
||||
style="
|
||||
align-self: baseline;
|
||||
padding: 0 0 24px 0;
|
||||
margin: 0;
|
||||
"
|
||||
|
@ -108,17 +106,11 @@ const headerGrid
|
|||
<component
|
||||
:is="'onClick' in action ? actionComponents.Button : actionComponents.Link"
|
||||
v-if="action"
|
||||
ghost
|
||||
thin-font
|
||||
min-content
|
||||
align-self="baseline"
|
||||
:align-text="expand || collapse ? 'start' : undefined"
|
||||
:aria-pressed="collapse"
|
||||
:class="{
|
||||
[$style.action]: true,
|
||||
[$style.transparent]: 'primary' in props || 'secondary' in props || 'destructive' in props,
|
||||
[$style.full]: expand || collapse
|
||||
}"
|
||||
v-bind="{ ...fallthroughProps, ...action, [expand || collapse ? 'full' : 'min-content']: true }"
|
||||
:class="$style.action"
|
||||
v-bind="action"
|
||||
>
|
||||
{{ action?.text }}
|
||||
</component>
|
||||
|
@ -144,9 +136,12 @@ const headerGrid
|
|||
: ''
|
||||
}
|
||||
position: relative;
|
||||
transition: max-height .5s, grid-template-rows .3s, padding .2s;`
|
||||
transition: max-height .5s, grid-template-rows .3s, padding .2s;
|
||||
`"
|
||||
v-bind="columnsPerItem
|
||||
? { grid: `auto / repeat(auto-fit, 46px)` }
|
||||
: { flex: true }
|
||||
"
|
||||
grid="auto / repeat(auto-fit, 46px)"
|
||||
>
|
||||
<slot />
|
||||
</Layout>
|
||||
|
@ -154,6 +149,15 @@ const headerGrid
|
|||
</template>
|
||||
|
||||
<style module lang="scss">
|
||||
// Thank you, css, for offering this weird alternative to !important
|
||||
header.left.left {
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.uncollapsible {
|
||||
margin-top: -64px;
|
||||
}
|
||||
|
||||
.summary {
|
||||
align-self: baseline;
|
||||
min-width: calc(100% + 32px);
|
||||
|
@ -161,12 +165,8 @@ const headerGrid
|
|||
--fw-border-radius: 32px;
|
||||
}
|
||||
|
||||
.action {
|
||||
&.transparent {
|
||||
margin-right: 16px;
|
||||
}
|
||||
&.full {
|
||||
min-width: 100%;
|
||||
}
|
||||
// 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>
|
||||
|
|
|
@ -104,7 +104,6 @@ const recentActivity = ref(0)
|
|||
</span>
|
||||
<!-- TODO: Translate Edit Link -->
|
||||
<Section
|
||||
no-items
|
||||
:h1="props.username"
|
||||
:action="{ text:'Edit profile', to:'/settings' }"
|
||||
solid
|
||||
|
|
|
@ -148,10 +148,11 @@ const showCreateModal = ref(false)
|
|||
:h1="t('views.channels.SubscriptionsList.title')"
|
||||
:action="{
|
||||
text: t('views.channels.SubscriptionsList.link.addNew'),
|
||||
onClick: ()=> showSubscribeModal = true
|
||||
onClick: () => { showSubscribeModal = true },
|
||||
primary: true,
|
||||
icon: 'bi-plus'
|
||||
}"
|
||||
icon="bi-plus"
|
||||
primary
|
||||
page-heading
|
||||
/>
|
||||
<Modal
|
||||
v-model="showSubscribeModal"
|
||||
|
@ -203,10 +204,11 @@ const showCreateModal = ref(false)
|
|||
:h1="t('views.auth.ProfileOverview.header.channels')"
|
||||
:action="{
|
||||
text: t('views.channels.SubscriptionsList.link.addNew'),
|
||||
onClick: ()=> showCreateModal = true
|
||||
onClick: () => { showCreateModal = true },
|
||||
primary: true,
|
||||
icon: 'bi-plus'
|
||||
}"
|
||||
icon="bi-plus"
|
||||
primary
|
||||
page-heading
|
||||
/>
|
||||
<Layout
|
||||
form
|
||||
|
|
|
@ -68,10 +68,11 @@ const showSubscribeModal = ref(false)
|
|||
:h1="labels.title"
|
||||
:action="{
|
||||
text: t('views.channels.SubscriptionsList.link.addNew'),
|
||||
onClick: ()=> showSubscribeModal = true
|
||||
onClick: () => { showSubscribeModal = true },
|
||||
primary: true,
|
||||
icon: 'bi-plus'
|
||||
}"
|
||||
icon="bi-plus"
|
||||
primary
|
||||
page-heading
|
||||
/>
|
||||
<Modal
|
||||
v-model="showSubscribeModal"
|
||||
|
|
|
@ -123,13 +123,14 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
:action="{
|
||||
onClick: () => { store.commit('playlists/showModal', true) },
|
||||
text: t('views.playlists.List.button.manage'),
|
||||
primary: true,
|
||||
icon: 'bi-music-note-list',
|
||||
ariaPressed: store.state.playlists.showModal
|
||||
}"
|
||||
icon="bi-music-note-list"
|
||||
primary
|
||||
:aria-pressed="store.state.playlists.showModal"
|
||||
/>
|
||||
<Header
|
||||
v-else
|
||||
page-heading
|
||||
:h1="t('views.playlists.List.header.browse')"
|
||||
/>
|
||||
|
||||
|
@ -222,7 +223,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
<Spacer v-if="result && result.results.length > 0" />
|
||||
|
||||
<!-- Search results -->
|
||||
<Section small-items>
|
||||
<Section :columns-per-item="3">
|
||||
<Loader v-if="isLoading" />
|
||||
<Alert
|
||||
v-if="result && result.results.length === 0"
|
||||
|
|
|
@ -7,6 +7,7 @@ import Card from '~/components/ui/Card.vue'
|
|||
import Layout from '~/components/ui/Layout.vue'
|
||||
import Toggle from '~/components/ui/Toggle.vue'
|
||||
import Spacer from '~/components/ui/Spacer.vue'
|
||||
import Pill from '~/components/ui/Pill.vue'
|
||||
import Activity from '~/components/ui/Activity.vue'
|
||||
import Section from '~/components/ui/Section.vue'
|
||||
|
||||
|
@ -109,67 +110,184 @@ import Section from '~/components/ui/Section.vue'
|
|||
|
||||
# Layout section
|
||||
|
||||
Sections divide the page vertically. Choose an appropriate heading level for each section: `h1` or `h2` or `h3`.
|
||||
Sections divide the page vertically. Choose an appropriate heading level for each section.
|
||||
You can use all props for [Heading](../heading.md), including `h1` to `h6` and [stylistic variants](../heading.md#visual-sizes-for-page-sections-and-subsections) such as `radio` or `page-heading`.
|
||||
|
||||
```vue-html
|
||||
<Section h3="My title" />
|
||||
<Section h1="My title" />
|
||||
```
|
||||
|
||||
### Align the section to the page
|
||||
<Spacer />
|
||||
|
||||
<Section h1="My title" />
|
||||
|
||||
```vue-html
|
||||
<Section h3="My title" alignLeft />
|
||||
<Section
|
||||
h2="My title"
|
||||
radio
|
||||
/>
|
||||
```
|
||||
|
||||
<Spacer />
|
||||
|
||||
<Section
|
||||
h2="My title"
|
||||
radio
|
||||
/>
|
||||
|
||||
## Align the section
|
||||
|
||||
```vue-html
|
||||
<Section h2="My title" alignLeft />
|
||||
```
|
||||
|
||||
### Make the section header align with the section contents
|
||||
|
||||
The section aligns its title and items to a grid, following the designs. To make sure the header of a section exactly aligns with its contents, set the item width:
|
||||
The section aligns its title and items to a grid, following the designs. To make sure the header of a section exactly aligns with its contents, set the item width (in number of columns). For example,
|
||||
|
||||
Do you want to align the header to
|
||||
<style module>
|
||||
.table {
|
||||
margin: 0 -184px;
|
||||
transform: scale(80%);
|
||||
}
|
||||
.table div[class*='language-'] {
|
||||
margin: -8px -16px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
- `no-items` (mixed content),
|
||||
- `tiny-items` (each item is one column wide),
|
||||
- `small-items` (each item is two columns wide, e.g. default cards),
|
||||
- `medium-items` (each item is three columns wide, such as Activities or medium cards)?
|
||||
|
||||
If all items stretch all columns (`style=grid-column: 1 / -1`), use `no-items`.
|
||||
<Layout grid :class="$style.table">
|
||||
<Card title="Mixed content">
|
||||
|
||||
```vue-html
|
||||
<Section medium-items />
|
||||
:columns-per-item="1"
|
||||
```
|
||||
|
||||
### Provide an action
|
||||
|
||||
The link or button will be shown on the right side of the header.
|
||||
</Card>
|
||||
<Card title="Normal cards">
|
||||
|
||||
```vue-html
|
||||
<Layout stack gap-64>
|
||||
<Spacer />
|
||||
<Section h3="With a link"
|
||||
:action="{ text:'My library', to:'/' }" />
|
||||
:columns-per-item="3"
|
||||
```
|
||||
|
||||
<Section h3="With a button"
|
||||
:action="{ text:'Say hello!', onClick:()=>console.log('Hello') }" />
|
||||
</Card>
|
||||
<Card title="Large cards, Activities">
|
||||
|
||||
```vue-html
|
||||
:columns-per-item="4"
|
||||
```
|
||||
|
||||
</Card>
|
||||
</Layout>
|
||||
|
||||
For a complete overview of column widths for common funkwhale components, see [the table in using-width](../using-width.md#widths-in-the-grid)
|
||||
|
||||
### Move individual items within and across grid-cells
|
||||
|
||||
For child items, you can use all known CSS grid placement techniques:
|
||||
|
||||
<Layout grid :class="$style.table">
|
||||
<Card title="Stretch over all columns">
|
||||
|
||||
```css
|
||||
grid-column: 1 / -1;
|
||||
```
|
||||
|
||||
Fill the whole grid, no matter how wide the screen is
|
||||
|
||||
</Card>
|
||||
<Card title="Span multiple rows/columns">
|
||||
|
||||
```css
|
||||
grid-row: span 3
|
||||
```
|
||||
|
||||
</Card>
|
||||
<Card title="Move within grid cell">
|
||||
|
||||
```css
|
||||
align-self: start;
|
||||
justify-self: center;
|
||||
```
|
||||
|
||||
Place individual items to the edge of their current cell or cells
|
||||
|
||||
</Card>
|
||||
</Layout>
|
||||
|
||||
## Provide an action
|
||||
|
||||
The link or button will be shown on the right side of the header. Use `action.text` to set the label (required).
|
||||
You can use all [`Link` props](../link.md) or [`Button` props](../button.md) inside the `action` prop! Note that the button or link label will be in line with the heading.
|
||||
|
||||
```vue-html
|
||||
<Spacer />
|
||||
<Layout stack gap-64>
|
||||
<Section
|
||||
h2="With a link"
|
||||
:action="{
|
||||
text: 'My library',
|
||||
to: '/',
|
||||
icon: 'bi-star'
|
||||
}"
|
||||
/>
|
||||
<Section
|
||||
h2="With a button"
|
||||
:action="{
|
||||
text: 'Say hello!',
|
||||
onClick: ()=>console.log('Hello'),
|
||||
primary: true,
|
||||
solid: true
|
||||
}"
|
||||
/>
|
||||
</Layout>
|
||||
```
|
||||
|
||||
<Spacer />
|
||||
<Layout stack gap-64>
|
||||
<Section h3="With a link" :action="{ text:'My library', to:'/' }" />
|
||||
<Section h3="With a button" :action="{ text:'Say hello!', onClick:()=>console.log('Hello') }" />
|
||||
<Section
|
||||
h2="With a link"
|
||||
:action="{
|
||||
text: 'My library',
|
||||
to: '/',
|
||||
icon: 'bi-star'
|
||||
}"
|
||||
/>
|
||||
<Section
|
||||
h2="With a button"
|
||||
:action="{
|
||||
text: 'Say hello!',
|
||||
onClick: ()=>console.log('Hello'),
|
||||
primary: true,
|
||||
solid: true
|
||||
}"
|
||||
/>
|
||||
</Layout>
|
||||
|
||||
You can add props to the Link or Button, for example to make them `primary` or add an icon:
|
||||
## Add icons and slots
|
||||
|
||||
```vue-html{1}
|
||||
<Section solid primary icon="bi-star"
|
||||
h3="Example" :action="{ text:'Say hello!', onClick:()=>console.log('Hello') }" />
|
||||
```vue-html
|
||||
<Section
|
||||
icon="bi-heart"
|
||||
>
|
||||
<template #topleft>
|
||||
<Pill>#Audiology</Pill>
|
||||
<Spacer size-12 />
|
||||
<Pill>#Phonologics</Pill>
|
||||
</template>
|
||||
</Section>
|
||||
```
|
||||
|
||||
<Spacer :size="40"/>
|
||||
<Spacer />
|
||||
|
||||
<Section solid primary icon="bi-star"
|
||||
h3="Example" :action="{ text:'Say hello!', onClick:()=>console.log('Hello') }" />
|
||||
<Section
|
||||
icon="bi-heart"
|
||||
>
|
||||
<template #topleft>
|
||||
<Pill>#Audiology</Pill>
|
||||
<Spacer size-12 />
|
||||
<Pill>#Phonologics</Pill>
|
||||
</template>
|
||||
</Section>
|
||||
|
||||
## Set gaps between consecutive sections
|
||||
|
||||
|
@ -177,22 +295,6 @@ Place consecutive sections into a [Layout stack](../layout) with a 64px gap (`ga
|
|||
|
||||
Note the spacer above the layout. By default, sections begin at the baseline of the heading. This enables us to explicitly define the vertical rhythm, independently of the heading's line height.
|
||||
|
||||
```vue-html
|
||||
<Spacer/>
|
||||
<Layout stack gap-64>
|
||||
<Section h3="Section 1" />
|
||||
<Section h3="Section 2" />
|
||||
</Layout>
|
||||
```
|
||||
|
||||
<Spacer />
|
||||
<Layout stack gap-64>
|
||||
<Section h3="Section 1" />
|
||||
<Section h3="Section 2" />
|
||||
</Layout>
|
||||
|
||||
<Spacer />
|
||||
|
||||
## Mix sections of different item widths
|
||||
|
||||
```vue-html
|
||||
|
@ -204,28 +306,40 @@ Note the spacer above the layout. By default, sections begin at the baseline of
|
|||
|
||||
<Layout stack gap-64>
|
||||
|
||||
<Section :alignLeft="alignLeft" small-items h3="Cards (small items)" :action="{ text:'more...', to:'/' }">
|
||||
<Card small title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
</Card>
|
||||
<Card small title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
</Card>
|
||||
<Card small title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
</Card>
|
||||
</Section>
|
||||
|
||||
<Section
|
||||
<Section
|
||||
:alignLeft="alignLeft"
|
||||
medium-items
|
||||
h3="Activities (medium items)"
|
||||
:action="{ text:'more...', to:'/' }"
|
||||
>
|
||||
:columns-per-item="2"
|
||||
h2="Cards (2-wide items)"
|
||||
:action="{
|
||||
text:'Documentation on Cards',
|
||||
to:'../card'
|
||||
}"
|
||||
>
|
||||
<Card small default solid raised title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
</Card>
|
||||
<Card small default solid raised title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
</Card>
|
||||
<Card small default solid raised title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
</Card>
|
||||
</Section>
|
||||
|
||||
<Section
|
||||
:alignLeft="alignLeft"
|
||||
:columns-per-item="3"
|
||||
h2="Activities (3-wide items)"
|
||||
:action="{
|
||||
text:'Delete selected items',
|
||||
onClick:()=>console.log('Deleted :-)')
|
||||
}"
|
||||
>
|
||||
<Activity :track="track" :user="user" />
|
||||
<Activity :track="track" :user="user" />
|
||||
<Activity :track="track" :user="user" />
|
||||
</Section>
|
||||
</Section>
|
||||
|
||||
</Layout>
|
||||
```
|
||||
|
||||
|
@ -239,7 +353,15 @@ Note the spacer above the layout. By default, sections begin at the baseline of
|
|||
|
||||
<Layout stack gap-64 class="preview" style="margin: 0 -40px; padding: 0 25px;">
|
||||
|
||||
<Section :alignLeft="alignLeft" small-items h3="Cards (small items)" :action="{ text:'Documentation on Cards', to:'../card' }">
|
||||
<Section
|
||||
:alignLeft="alignLeft"
|
||||
:columns-per-item="3"
|
||||
h2="Cards (2-wide items)"
|
||||
:action="{
|
||||
text:'Documentation on Cards',
|
||||
to:'../card'
|
||||
}"
|
||||
>
|
||||
<Card small default solid raised title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
</Card>
|
||||
|
@ -249,20 +371,28 @@ Note the spacer above the layout. By default, sections begin at the baseline of
|
|||
<Card small default solid raised title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
</Card>
|
||||
</Section>
|
||||
</Section>
|
||||
|
||||
<Section :alignLeft="alignLeft" medium-items h3="Activities (medium items)" :action="{ text:'Delete selected items', onClick:()=>console.log('Deleted :-)') }">
|
||||
<Section
|
||||
:alignLeft="alignLeft"
|
||||
:columns-per-item="4"
|
||||
h2="Activities (3-wide items)"
|
||||
:action="{
|
||||
text:'Delete selected items',
|
||||
onClick:()=>console.log('Deleted :-)')
|
||||
}"
|
||||
>
|
||||
<Activity :track="track" :user="user" />
|
||||
<Activity :track="track" :user="user" />
|
||||
<Activity :track="track" :user="user" />
|
||||
</Section>
|
||||
</Section>
|
||||
|
||||
</Layout>
|
||||
|
||||
## Collapse and expand the section
|
||||
|
||||
By adding either `collapse` or `expand` to the props, you add Accordion behavior to the section.
|
||||
The heading will become clickable.
|
||||
The heading will become a clickable button.
|
||||
|
||||
```ts
|
||||
const sections = ref([false, false, false])
|
||||
|
@ -272,11 +402,12 @@ const sections = ref([false, false, false])
|
|||
<Section
|
||||
v-for="(section, index) in sections"
|
||||
:key="`${index}${section}`"
|
||||
:h3="`Section ${index} (${section})`"
|
||||
:h2="`Section ${index} (${section})`"
|
||||
align-left
|
||||
v-bind="
|
||||
section
|
||||
? { collapse: () => { console.log('collapse!'); sections[index] = false } }
|
||||
: { expand: () => { console.log('expand!'); sections[index] = true } }
|
||||
? { collapse: () => { sections[index] = false } }
|
||||
: { expand: () => { sections[index] = true } }
|
||||
"
|
||||
>
|
||||
Content {{ section }}
|
||||
|
@ -286,13 +417,12 @@ const sections = ref([false, false, false])
|
|||
<Section
|
||||
v-for="(section, index) in sections"
|
||||
:key="`${index}${section}`"
|
||||
:h3="`Section ${index}`"
|
||||
:h2="`Section ${index}`"
|
||||
align-left
|
||||
no-items
|
||||
v-bind="
|
||||
section
|
||||
? { collapse: () => { console.log('collapse!'); sections[index] = false } }
|
||||
: { expand: () => { console.log('expand!'); sections[index] = true } }
|
||||
? { collapse: () => { sections[index] = false } }
|
||||
: { expand: () => { sections[index] = true } }
|
||||
"
|
||||
>
|
||||
<Card
|
||||
|
|
|
@ -25,7 +25,15 @@ The page grid consists of 46px wide tracks, separated by 32px wide gaps. [See ex
|
|||
Use the [Layout Section component](/components/ui/layout/section) to structure the page into separate sections, each with a heading. Make sure the heading level hierarchy makes sense.
|
||||
|
||||
```vue-html
|
||||
<Section :alignLeft="alignLeft" small-items h3="My albums" :action="{ text:'Go to library', to:'/' }">
|
||||
<Section
|
||||
:alignLeft="alignLeft"
|
||||
:columns-per-item="3"
|
||||
h2="My albums"
|
||||
:action="{
|
||||
text:'Go to library',
|
||||
to:'/'
|
||||
}"
|
||||
>
|
||||
<Card small solid yellow title="Album 1" />
|
||||
<Card small solid green title="Album 2" />
|
||||
<Card small solid blue title="Album 3" />
|
||||
|
@ -34,7 +42,15 @@ Use the [Layout Section component](/components/ui/layout/section) to structure t
|
|||
|
||||
<Spacer :size="32" />
|
||||
|
||||
<Section :alignLeft="alignLeft" small-items h3="My albums" :action="{ text:'Go to library', to:'/' }">
|
||||
<Section
|
||||
:alignLeft="alignLeft"
|
||||
:columns-per-item="3"
|
||||
h2="My albums"
|
||||
:action="{
|
||||
text:'Go to library',
|
||||
to:'/'
|
||||
}"
|
||||
>
|
||||
<Card small solid yellow title="Album 1" />
|
||||
<Card small solid green title="Album 2" />
|
||||
<Card small solid blue title="Album 3" />
|
||||
|
|
Loading…
Reference in New Issue