Skip to content

Commit 6def460

Browse files
committed
footer slots
1 parent 9151e51 commit 6def460

4 files changed

Lines changed: 179 additions & 6 deletions

File tree

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
<script setup lang="ts">
2+
import { useSlots } from 'vue';
3+
24
defineOptions({ name: 'StackFooter' });
5+
6+
const slots = useSlots();
37
</script>
48

59
<template>
610
<div
711
data-ui-stack-footer
812
class="bg-gray-50 p-4 border-t border-gray-200"
913
>
10-
<slot />
14+
<template v-if="slots['start'] || slots['end']">
15+
<div class="flex justify-between items-center">
16+
<div class="flex items-center gap-2">
17+
<slot name="start" />
18+
</div>
19+
<slot />
20+
<div class="flex items-center gap-2">
21+
<slot name="end" />
22+
</div>
23+
</div>
24+
</template>
25+
26+
<slot v-else />
1127
</div>
1228
</template>

resources/js/components/ui/Stack/Stack.vue

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {hasComponent} from "@/composables/has-component.js";
1515
import { Button, Heading } from "@ui";
1616
import Content from './Content.vue';
1717
import Header from './Header.vue';
18+
import Footer from './Footer.vue';
1819
import { FocusScope, Primitive } from 'reka-ui';
1920
2021
const slots = useSlots();
@@ -242,6 +243,17 @@ provide('closeStack', close);
242243
243244
<slot v-else v-bind="slotProps" />
244245
246+
<template v-if="slots['footer-start'] || slots['footer-end']">
247+
<Footer>
248+
<template #start v-if="slots['footer-start']">
249+
<slot name="footer-start" />
250+
</template>
251+
<template #end v-if="slots['footer-end']">
252+
<slot name="footer-end" />
253+
</template>
254+
</Footer>
255+
</template>
256+
245257
<div
246258
v-if="shouldShowFloatingCloseButton"
247259
class="fixed top-4 right-4"

resources/js/stories/Stack.stories.ts

Lines changed: 138 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,13 +338,12 @@ export const AutomaticHeader: Story = {
338338
}),
339339
};
340340

341-
export const Composed: Story = {
341+
export const Footer: Story = {
342342
parameters: {
343343
docs: {
344344
source: {
345345
code: `
346346
<Stack>
347-
<StackHeader title="Composed Header" icon="cog" />
348347
<StackContent>Lots of content...</StackContent>
349348
<StackFooter>I'm the footer.</StackFooter>
350349
</Stack>
@@ -359,7 +358,6 @@ export const Composed: Story = {
359358
<template #trigger>
360359
<Button text="Open" />
361360
</template>
362-
<StackHeader title="Composed Header" icon="cog" />
363361
<StackContent>
364362
<div v-for="n in 200" :key="n">Lots of content...</div>
365363
</StackContent>
@@ -369,6 +367,143 @@ export const Composed: Story = {
369367
}),
370368
};
371369

370+
export const FooterStartSlot: Story = {
371+
parameters: {
372+
docs: {
373+
source: {
374+
code: `
375+
<Stack>
376+
Lots of content...
377+
<template #footer-start>I'm at the start (left)</template>
378+
</Stack>
379+
`
380+
}
381+
}
382+
},
383+
render: () => ({
384+
components: { Stack, Button },
385+
template: `
386+
<Stack>
387+
<template #trigger>
388+
<Button text="Open" />
389+
</template>
390+
<div v-for="n in 200" :key="n">Lots of content...</div>
391+
<template #footer-start>I'm at the start (left)</template>
392+
</Stack>
393+
`
394+
}),
395+
};
396+
397+
export const FooterEndSlot: Story = {
398+
parameters: {
399+
docs: {
400+
source: {
401+
code: `
402+
<Stack>
403+
Lots of content...
404+
<template #footer-end>I'm at the end (right)</template>
405+
</Stack>
406+
`
407+
}
408+
}
409+
},
410+
render: () => ({
411+
components: { Stack, Button },
412+
template: `
413+
<Stack>
414+
<template #trigger>
415+
<Button text="Open" />
416+
</template>
417+
<div v-for="n in 200" :key="n">Lots of content...</div>
418+
<template #footer-end>I'm at the end (right)</template>
419+
</Stack>
420+
`
421+
}),
422+
};
423+
424+
export const FooterBothSlots: Story = {
425+
parameters: {
426+
docs: {
427+
source: {
428+
code: `
429+
<Stack>
430+
Lots of content...
431+
432+
<template #footer-start>
433+
I'm at the start (left)
434+
</template>
435+
<template #footer-end>
436+
<Button text="I'm at the" />
437+
<Button text="end (right)" />
438+
</template>
439+
</Stack>
440+
`
441+
}
442+
}
443+
},
444+
render: () => ({
445+
components: { Stack, Button },
446+
template: `
447+
<Stack>
448+
<template #trigger>
449+
<Button text="Open" />
450+
</template>
451+
<div v-for="n in 200" :key="n">Lots of content...</div>
452+
<template #footer-start>I'm at the start (left)</template>
453+
<template #footer-end>
454+
<Button text="I'm at the" />
455+
<Button text="end (right)" />
456+
</template>
457+
</Stack>
458+
`
459+
}),
460+
};
461+
462+
export const FooterComposed: Story = {
463+
parameters: {
464+
docs: {
465+
source: {
466+
code: `
467+
<Stack>
468+
<StackContent>
469+
Lots of content...
470+
</StackContent>
471+
<StackFooter>
472+
<template #start>I'm at the start (left)</template>
473+
<template #end>
474+
<Button text="I'm at the" />
475+
<Button text="end (right)" />
476+
</template>
477+
I'm in between
478+
</StackFooter>
479+
</Stack>
480+
`
481+
}
482+
}
483+
},
484+
render: () => ({
485+
components: { Stack, StackContent, StackFooter, Button },
486+
template: `
487+
<Stack>
488+
<template #trigger>
489+
<Button text="Open" />
490+
</template>
491+
<StackContent>
492+
<div v-for="n in 200" :key="n">Lots of content...</div>
493+
</StackContent>
494+
<StackFooter>
495+
<template #start>I'm at the start (left)</template>
496+
<template #end>
497+
<Button text="I'm at the" />
498+
<Button text="end (right)" />
499+
</template>
500+
I'm in between
501+
</StackFooter>
502+
</Stack>
503+
`
504+
}),
505+
};
506+
372507
export const HeaderActions: Story = {
373508
render: () => ({
374509
components: { Stack, StackHeader, StackContent, Button },

resources/js/stories/docs/Stack.mdx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,19 @@ You may use the `header-actions` slot to add buttons or other elements to the he
5252

5353
## Footer
5454

55-
A footer can be a good place to put buttons and other actions at the bottom of the stack. It will remain fixed.
55+
A footer can be a good place to put buttons and other actions at the bottom of the stack. It will remain fixed. You can use the `footer-start` and `footer-end` slots.
5656

57-
<Canvas of={StackStories.Composed} sourceState={'shown'} />
57+
<Canvas of={StackStories.FooterBothSlots} sourceState={'shown'} />
58+
59+
Note that when using these slots, flex will be applied to space buttons (the most common use case) appropriately.
60+
61+
If you need full control, you can compose the footer yourself using the `StackFooter` component.
62+
63+
<Canvas of={StackStories.Footer} sourceState={'shown'} />
64+
65+
Or, you may use the `start` and `end` slots, and anything in the default slot will be positioned between them.
66+
67+
<Canvas of={StackStories.FooterComposed} sourceState={'shown'} />
5868

5969
## Sizes
6070

0 commit comments

Comments
 (0)