feat(ui): Layout section component

This commit is contained in:
upsiflu 2025-01-03 14:36:06 +01:00
parent 860f12512c
commit 3f2dfc95b3
3 changed files with 17 additions and 160 deletions

View File

@ -31,8 +31,6 @@ const attributes = computed(() => ({
props.columns ? 'columns' :
'stack'
}))
console.log("GRID", props.grid, props.grid ? 'grid-custom' : 'none')
</script>
<template>

View File

@ -12,6 +12,7 @@ import Activity from '~/components/ui/Activity.vue'
const props = defineProps<{
[M in 'tiny-items' | 'small-items' | 'medium-items']?: true }
& { alignLeft?: boolean;}
& { [H in 'h1' | 'h2' | 'h3']?: string }
& { action?: { text: string } & (RouterLinkProps | { onClick: (...args: any[]) => void | Promise<void> }) }>()
@ -20,15 +21,18 @@ const [headingLevel, title] =
: props.h2 ? ['h2', props.h2]
: ['h3', props.h3]
const headerGrid =
`auto / repeat(auto-fit, calc(46px * ${props['tiny-items'] ? 2 : props['small-items'] ? 3 : 4} + 32px * 2))`
const numberOfColumnsPerItem =
'tinyItems' in props && props.tinyItems ? 2 : 'smallItems' in props && props['smallItems'] ? 3 : 4
console.log(headerGrid);
const headerGrid =
`auto / repeat(auto-fit, calc(46px * ${numberOfColumnsPerItem} + 32px * ${numberOfColumnsPerItem - 1}))`
</script>
<template>
<section>
<Layout header :grid="headerGrid">
<Layout header :grid="headerGrid"
:style="'alignLeft' in props && props.alignLeft ? 'justify-content: start' : ''"
>
<!-- The title row's width is a multiple of the expected items' column span -->
<Layout flex no-gap
@ -37,7 +41,7 @@ console.log(headerGrid);
<!-- Set distance between baseline and previous row -->
<Spacer v
:size="64"
style="outline:1px solid red; align-self: baseline;"
style="align-self: baseline;"
/>
<!-- Flexible row content -->
<!-- Note that the `h3` uses its padding to create the 24px bottom gap -->
@ -62,69 +66,11 @@ console.log(headerGrid);
</Layout>
</Layout>
<Layout main
style="position:relative;"
:style="'alignLeft' in props && props.alignLeft ? 'justify-content: start' : ''"
grid="auto / repeat(auto-fit, 46px)"
>
<slot />
</Layout>
</section>
</template>
<style module>
.layout {
transition: all .15s;
/* Override --gap with your preferred value */
gap: var(--gap, v-bind(gapWidth));
&:not(.gap) {
gap: 0;
}
/* Growth */
&:has(:global(>.grow)) {
>:not(:global(.grow)) {
flex-grow: 0;
}
}
/* Layout strategy */
&[layout=columns] {
column-count: auto;
column-width: v-bind(columnWidth);
display: block;
column-rule: 1px solid v-bind("noRule ? 'transparent' : 'var(--border-color)'");
}
&[layout=grid] {
display: grid;
grid-template-columns:
repeat(auto-fit, v-bind(columnWidth));
grid-auto-flow: row dense;
place-content: center;
/* If the grid has a fixed size smaller than its container, center it */
}
&[layout=grid-custom] {
display: grid;
grid: v-bind(grid);
grid-auto-flow: row dense;
place-content: center;
/* If the grid has a fixed size smaller than its container, center it */
}
&[layout=stack] {
display: flex;
flex-direction: column;
}
&[layout=flex] {
display: flex;
flex-direction: row;
flex-wrap: v-bind('props.noWrap ? "nowrap" : "wrap"');
}
}
</style>

View File

@ -9,7 +9,7 @@ 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'
import Section from '~/components/ui/layout/Section.vue'
import LayoutSection from '~/components/ui/layout/Section.vue'
const alignLeft = ref(false)
@ -116,7 +116,7 @@ const user: User = {
<div class="preview" style="margin: 0 -40px; padding: 0 25px;">
<Section small-items h1="Hello" :action="{ text:'more...', to:'/' }">
<LayoutSection :alignLeft="alignLeft" small-items h3="Cards (small items)" :action="{ text:'more...', to:'/' }">
<Card small title="Relatively Long Album Name">
Artist Name
13 tracks
@ -129,99 +129,12 @@ const user: User = {
Artist Name
13 tracks
</Card>
</Section>
</LayoutSection>
<Layout
grid="auto / repeat(auto-fit, calc(46px _ 3 + 32px _ 2))"
v-bind="attributes"
>
<!-- The title row's width is a multiple of 3 rows -->
<Layout flex no-gap
style="grid-column: 1 / -1; align-self: baseline;"
>
<!-- Set distance between baseline and previous row -->
<Spacer v
:size="64"
style="outline:1px solid red; align-self: baseline;"
/>
<!-- Flexible row content -->
<!-- Note that the `h3` uses its padding to create the 24px bottom gap -->
<h3 style="align-self: baseline; padding:0 0 24px 10px; margin:0;">
Albums
</h3>
<Spacer grow />
<Button ghost thin auto align-self="baseline"
style="grid-column:-1;"
>
Show all
</Button>
</Layout>
</Layout>
<Layout solid default
style="position:relative;"
grid="auto / repeat(auto-fit, 46px)"
v-bind="attributes"
>
<Card small title="Relatively Long Album Name">
Artist Name
13 tracks
</Card>
<Card small title="Relatively Long Album Name">
Artist Name
13 tracks
</Card>
<Card small title="Relatively Long Album Name">
Artist Name
13 tracks
</Card>
<Card small title="Relatively Long Album Name">
Artist Name
13 tracks
</Card>
<Card small title="Relatively Long Album Name">
Artist Name
13 tracks
</Card>
</Layout>
<Layout
grid="auto / repeat(auto-fit, calc(46px _ 4 + 32px _ 3))"
v-bind="attributes"
>
<Layout flex no-gap
style="grid-column: 1 / -1; align-self: baseline;"
>
<!-- Set distance between baseline and previous row -->
<Spacer v
:size="64"
style="outline:1px solid red; align-self: baseline;"
/>
<!-- Flexible row content -->
<!-- Note that the `h3` uses its padding to create the 24px bottom gap -->
<h3 style="align-self: baseline; padding:0 0 24px 10px; margin:0;">
Tracks
</h3>
<Spacer grow />
<Button ghost thin auto align-self="baseline"
style="grid-column:-1;"
>
Show all
</Button>
</Layout>
</Layout>
<Layout solid default
style="position:relative;"
grid="auto / repeat(auto-fit, 46px)"
v-bind="attributes"
>
<LayoutSection :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" />
</Layout>
</LayoutSection>
</div>