2025-01-03 12:42:39 +00:00
< script setup lang = "ts" >
import { computed, ref } from 'vue'
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'
import Spacer from '~/components/ui/layout/Spacer.vue'
import Button from '~/components/ui/Button.vue'
import Activity from '~/components/ui/Activity.vue'
2025-01-03 15:25:46 +00:00
import Section from '~/components/ui/layout/Section.vue'
2025-01-03 12:42:39 +00:00
const alignLeft = ref(false)
const attributes = computed(() => ({
style: alignLeft.value ? 'justify-content: start' : ''
}))
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 >
# 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
< Section alignLeft / >
```
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
Do you want to align the header to tiny, small or medium items?
```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 / >
< Section h3 = "With a link" :action = "{ text:'My library', to:'/' }" / >
2025-01-03 14:06:49 +00:00
2025-01-06 14:00:25 +00:00
< Section h3 = "With a button" :action = "{ text:'Say hello!', onClick:()=>console.log('Hello') }" / >
< / Layout >
2025-01-03 15:25:46 +00:00
```
2025-01-03 14:06:49 +00:00
2025-01-06 14:00:25 +00:00
< Layout stack gap-64 >
< Spacer / >
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"
h3="Do it!" :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"
h3="Do it!" :action="{ text:'Say hello!', onClick:()=>console.log('Hello') }" />
2025-01-03 14:06:49 +00:00
2025-01-06 14:00:25 +00:00
::: tip Gaps between consecutive sections
Place consecutive sections into a `<Layout stack gap-64></Layout>` to space them out.
You can add spacers (negatice or positive) if you want to manually make one distance smaller or larger.
```vue-html
< Layout stack gap-64 >
< Spacer / >
< Section h3 = "Section 1" > < / Section >
< Section h3 = "Section 2" > < / Section >
< / Layout >
```
< Layout stack gap-64 >
< Spacer / >
< Section h3 = "Section 1" > < / Section >
< Section h3 = "Section 2" > < / Section >
< / Layout >
:::
2025-01-03 14:06:49 +00:00
## Example
```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-06 14:00:25 +00:00
< Spacer / >
2025-01-03 12:42:39 +00:00
---
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-03 15:25:46 +00:00
< Section :alignLeft = "alignLeft" small-items h3 = "Cards (small items)" :action = "{ text:'Go to library', to:'/' }" >
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
- 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 will have 4 albums or 3 activities side-by-side. On a typical mobile screen, you will have 1 medium card or 2 small ones in a row.
- The remaining space is evenly distributed.
- Title rows align with the content below them.
Resize the window to observe how the items move.