2025-01-03 12:42:39 +00:00
< script setup lang = "ts" >
2025-01-20 16:52:52 +00:00
import { ref } from 'vue'
2025-01-03 12:42:39 +00:00
import { type Track, type User } from '~/types'
import Card from '~/components/ui/Card.vue'
import Layout from '~/components/ui/Layout.vue'
import Toggle from '~/components/ui/Toggle.vue'
2025-01-09 23:46:57 +00:00
import Spacer from '~/components/ui/Spacer.vue'
2025-01-03 12:42:39 +00:00
import Activity from '~/components/ui/Activity.vue'
2025-01-09 23:46:57 +00:00
import Section from '~/components/ui/Section.vue'
2025-01-03 12:42:39 +00:00
2025-01-09 23:46:57 +00:00
const alignLeft = ref(true)
2025-01-03 12:42:39 +00:00
const track: Track = {
id: 0,
fid: "",
title: 'Some lovely track',
description: {
content_type: 'text/markdown',
text: `**New:** Music for the eyes!`
},
cover: {
uuid: "",
urls: {
original: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1& dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg& w=640& q=80& fm=jpg& crop=entropy& cs=tinysrgb',
medium_square_crop: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1& dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg& w=640& q=80& fm=jpg& crop=entropy& cs=tinysrgb',
large_square_crop: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1& dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg& w=640& q=80& fm=jpg& crop=entropy& cs=tinysrgb'
}
},
tags: ["example"],
uploads: [],
downloads_count: 1927549377,
artist_credit: [{
artist: {
id: 0,
fid: "",
name: "The Artist",
description: {
content_type: 'text/markdown',
text: `I'm a musician based on the internet.
Find all my music on [Funkwhale ](https://funkwhale.audio )!`},
tags: [],
content_category: 'music',
albums: [],
tracks_count: 1,
attributed_to: {
id: 0,
summary: "",
preferred_username: "User12345",
full_username: "User12345",
is_local: false,
domain: "myDomain.io"
},
is_local: false,
is_playable: true
},
credit: "",
joinphrase: " and ",
index: 22
}],
disc_number: 7,
listen_url: "https://funkwhale.audio",
creation_date: "12345",
attributed_to: {
id: 0,
summary: "",
preferred_username: "User12345",
full_username: "User12345",
is_local: false,
domain: "myDomain.io"
},
is_playable: true,
is_local: false
}
const user: User = {
id: 12,
avatar: {
uuid: "",
urls: {
original: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1& dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg& w=640& q=80& fm=jpg& crop=entropy& cs=tinysrgb',
medium_square_crop: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1& dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg& w=640& q=80& fm=jpg& crop=entropy& cs=tinysrgb',
large_square_crop: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1& dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg& w=640& q=80& fm=jpg& crop=entropy& cs=tinysrgb'
}
},
email: "user12345@example.org",
summary: { text: "Hi! I'm Example from The Internet.", content_type: "text" },
username: "user12345",
full_username: "user12345",
instance_support_message_display_date: "?",
funkwhale_support_message_display_date: "?",
is_superuser: true,
privacy_level: "everyone"
}
< / script >
2025-01-10 00:22:17 +00:00
```ts
2025-01-20 16:52:52 +00:00
import Section from "~/components/ui/Section.vue";
2025-01-10 00:22:17 +00:00
```
2025-01-03 12:42:39 +00:00
# Layout section
2025-01-03 15:25:46 +00:00
Sections divide the page vertically. Choose an appropriate heading level for each section: `h1` or `h2` or `h3` .
```vue-html
< Section h3 = "My title" / >
```
### Align the section to the page
2025-01-03 14:06:49 +00:00
```vue-html
2025-01-10 00:22:17 +00:00
< Section h3 = "My title" alignLeft / >
2025-01-03 14:06:49 +00:00
```
2025-01-03 15:25:46 +00:00
### Make the section header align with the section contents
2025-01-03 14:06:49 +00:00
2025-01-06 19:32:47 +00:00
Do you want to align the header to no, tiny, small or medium items?
If all items stretch all columns (`style=grid-column: 1 / -1`), use `no-items` .
2025-01-03 14:06:49 +00:00
```vue-html
< Section medium-items / >
```
2025-01-03 15:25:46 +00:00
### Provide an action
2025-01-03 14:06:49 +00:00
2025-01-03 15:25:46 +00:00
The link or button will be shown on the right side of the header.
2025-01-03 14:06:49 +00:00
```vue-html
2025-01-06 14:00:25 +00:00
< Layout stack gap-64 >
< Spacer / >
2025-01-20 16:52:52 +00:00
< Section h3 = "With a link"
2025-01-10 00:22:17 +00:00
:action="{ text:'My library', to:'/' }" />
2025-01-03 14:06:49 +00:00
2025-01-20 16:52:52 +00:00
< Section h3 = "With a button"
2025-01-10 00:22:17 +00:00
:action="{ text:'Say hello!', onClick:()=>console.log('Hello') }" />
2025-01-06 14:00:25 +00:00
< / Layout >
2025-01-03 15:25:46 +00:00
```
2025-01-03 14:06:49 +00:00
2025-01-10 00:22:17 +00:00
< Spacer / >
2025-01-06 14:00:25 +00:00
< Layout stack gap-64 >
2025-01-03 15:25:46 +00:00
< Section h3 = "With a link" :action = "{ text:'My library', to:'/' }" / >
< Section h3 = "With a button" :action = "{ text:'Say hello!', onClick:()=>console.log('Hello') }" / >
2025-01-06 14:00:25 +00:00
< / Layout >
2025-01-03 14:06:49 +00:00
2025-01-03 15:25:46 +00:00
You can add props to the Link or Button, for example to make them `primary` or add an icon:
2025-01-03 14:06:49 +00:00
2025-01-03 15:25:46 +00:00
```vue-html{1}
< Section solid primary icon = "bi-star"
2025-01-10 00:22:17 +00:00
h3="Example" :action="{ text:'Say hello!', onClick:()=>console.log('Hello') }" />
2025-01-03 14:06:49 +00:00
```
2025-01-06 14:14:00 +00:00
< Spacer :size = "40" / >
2025-01-06 14:00:25 +00:00
2025-01-03 15:25:46 +00:00
< Section solid primary icon = "bi-star"
2025-01-10 00:22:17 +00:00
h3="Example" :action="{ text:'Say hello!', onClick:()=>console.log('Hello') }" />
2025-01-03 14:06:49 +00:00
2025-01-20 16:52:52 +00:00
## Set gaps between consecutive sections
2025-01-06 14:00:25 +00:00
2025-01-20 16:52:52 +00:00
Place consecutive sections into a [Layout stack ](../layout ) with a 64px gap (`gap-64`) to give them a regular vertical rhythm. Use different sizes for very small or very large headings.
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.
2025-01-06 14:00:25 +00:00
```vue-html
2025-01-20 16:52:52 +00:00
< Spacer / >
2025-01-06 14:00:25 +00:00
< Layout stack gap-64 >
2025-01-10 00:22:17 +00:00
< Section h3 = "Section 1" / >
< Section h3 = "Section 2" / >
2025-01-06 14:00:25 +00:00
< / Layout >
```
2025-01-20 16:52:52 +00:00
< Spacer / >
2025-01-06 14:00:25 +00:00
< Layout stack gap-64 >
2025-01-10 00:22:17 +00:00
< Section h3 = "Section 1" / >
< Section h3 = "Section 2" / >
2025-01-06 14:00:25 +00:00
< / Layout >
2025-01-10 00:22:17 +00:00
< Spacer / >
2025-01-20 16:52:52 +00:00
## Mix sections of different item widths
2025-01-03 14:06:49 +00:00
```vue-html
< Layout flex >
< Toggle v-model = "alignLeft" label = "Left-align the layout" / >
< / Layout >
2025-01-06 14:00:25 +00:00
< Spacer / >
< Layout stack gap-64 >
2025-01-03 15:25:46 +00:00
< Section :alignLeft = "alignLeft" small-items h3 = "Cards (small items)" :action = "{ text:'more...', to:'/' }" >
2025-01-03 14:06:49 +00:00
< 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 >
2025-01-03 15:25:46 +00:00
< / Section >
2025-01-03 14:06:49 +00:00
2025-01-06 14:00:25 +00:00
< Section
2025-01-03 14:06:49 +00:00
:alignLeft="alignLeft"
medium-items
h3="Activities (medium items)"
:action="{ text:'more...', to:'/' }"
>
< Activity :track = "track" :user = "user" / >
< Activity :track = "track" :user = "user" / >
< Activity :track = "track" :user = "user" / >
2025-01-06 14:00:25 +00:00
< / Section >
< / Layout >
2025-01-03 14:06:49 +00:00
```
2025-01-03 12:42:39 +00:00
< Layout flex >
< Toggle v-model = "alignLeft" label = "Left-align the layout" / >
< / Layout >
---
2025-01-10 00:22:17 +00:00
< Spacer / >
2025-01-06 14:00:25 +00:00
< Layout stack gap-64 class = "preview" style = "margin: 0 -40px; padding: 0 25px;" >
2025-01-03 12:42:39 +00:00
2025-01-10 00:22:17 +00:00
< Section :alignLeft = "alignLeft" small-items h3 = "Cards (small items)" :action = "{ text:'Documentation on Cards', to:'../card' }" >
2025-01-03 12:42:39 +00:00
< 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 >
2025-01-03 15:25:46 +00:00
< / Section >
2025-01-03 12:42:39 +00:00
2025-01-03 15:25:46 +00:00
< Section :alignLeft = "alignLeft" medium-items h3 = "Activities (medium items)" :action = "{ text:'Delete selected items', onClick:()=>console.log('Deleted :-)') }" >
2025-01-03 12:42:39 +00:00
< Activity :track = "track" :user = "user" / >
< Activity :track = "track" :user = "user" / >
< Activity :track = "track" :user = "user" / >
2025-01-03 15:25:46 +00:00
< / Section >
2025-01-03 13:36:06 +00:00
2025-01-06 14:00:25 +00:00
< / Layout >
2025-01-03 15:25:46 +00:00
## Responsivity
2025-01-20 16:52:52 +00:00
- Cards and Activities snap to the grid columns. They have intrinsic widths, expressed in the number of columns they span. For `Card` , it is `3` and for `Activity` , it is `4` .
- On a typical laptop screen, you may have 4 album cards or 3 activities side-by-side. On a typical mobile screen, you will have one medium card or two small ones in a row.
2025-01-03 15:25:46 +00:00
- The remaining space is evenly distributed.
2025-01-20 16:52:52 +00:00
- Title rows align with the content below them. The action on the right will always end with the last item in the grid. Resize the window to observe how the items move.