Skip to content

Commit d2b12b3

Browse files
lehjuFabianWilmslangehm
authored
✨ 272 slider component (#357)
* 272: add slider component * 272: add slider component * 272: format code * 272: add emit and accessibility * 272: format code * 272: delete console log * 272: disable vertical scroll * 272: format code * 272: change package-lock.json * 💚 use fork of vue-splide to fix ts-errors * replaced buttons with muc-buttons * using templateRef to access ref * using templateRef to access ref * 272: pr feedback * 272: format code * 272: adjust package-lock.json * 272: format code * 272: rename SliderOptions.ts in MucSliderOptions.ts --------- Co-authored-by: fabian.wilms <fabian.wilms@muenchen.de> Co-authored-by: langehm <38280183+langehm@users.noreply.github.com> Co-authored-by: langehm <langehm@users.noreply.github.com>
1 parent 5333c35 commit d2b12b3

File tree

8 files changed

+244
-0
lines changed

8 files changed

+244
-0
lines changed

package-lock.json

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,8 @@
7676
"vite-plugin-dts": "4.4.0",
7777
"vitest": "2.1.8",
7878
"vue-tsc": "2.2.0"
79+
},
80+
"dependencies": {
81+
"@splidejs/vue-splide": "github:joris-gallot/vue-splide"
7982
}
8083
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import MucCard from "../Card/MucCard.vue";
2+
import MucSlider from "./MucSlider.vue";
3+
import MucSliderItem from "./MucSliderItem.vue";
4+
5+
export default {
6+
components: { MucSliderItem, MucSlider },
7+
component: MucSlider,
8+
title: "MucSlider",
9+
tags: ["autodocs"],
10+
parameters: {
11+
docs: {
12+
description: {
13+
component: `A wrapping layout to show elements in a carousel and slide them, for example [MucCards](/docs/muccard--docs).
14+
15+
🔗 Patternlab-Docs (https://patternlab.muenchen.space/?p=components-slider-quote)
16+
`,
17+
},
18+
},
19+
},
20+
};
21+
22+
export const Template = () => ({
23+
components: { MucCard, MucSlider, MucSliderItem },
24+
template: `
25+
<MucSlider>
26+
<MucSliderItem v-for="index in 5" :key="index">
27+
<MucCard
28+
title="Lorem Ipsum"
29+
tagline="Dolor"
30+
>
31+
<template #content>
32+
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et
33+
dolore magna aliquyam erat, sed diam voluptua.
34+
</template>
35+
</MucCard>
36+
</MucSliderItem>
37+
</MucSlider>
38+
`,
39+
});

src/components/Slider/MucSlider.vue

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<template>
2+
<div
3+
class="m-component m-component-slider-comment"
4+
style="overflow: hidden"
5+
>
6+
<div class="container">
7+
<div class="m-component__grid">
8+
<div class="m-component__column">
9+
<section
10+
class="m-slider m-slider--visible-preview"
11+
aria-label="Slider mit Elementen"
12+
data-m-slider-splide="m-slider-comment"
13+
>
14+
<button
15+
v-if="showBackArrow"
16+
aria-label="Vorheriges Element"
17+
class="previous-button is-control"
18+
@click="prevSlide"
19+
>
20+
<svg class="icon">
21+
<use xlink:href="#icon-arrow-left"></use>
22+
</svg>
23+
</button>
24+
<Splide
25+
:options="mucSliderOptions"
26+
aria-label="Dies ist ein Karussell mit rotierenden Elementen. Verwenden Sie
27+
die Pfeiltaste links und rechts oder die Buttons um zu navigieren."
28+
ref="splide"
29+
>
30+
<slot />
31+
</Splide>
32+
<button
33+
v-if="showNextArrow"
34+
aria-label="Nächstes Element"
35+
class="next-button is-control"
36+
@click="nextSlide"
37+
>
38+
<svg class="icon">
39+
<use xlink:href="#icon-arrow-right"></use>
40+
</svg>
41+
</button>
42+
</section>
43+
</div>
44+
</div>
45+
</div>
46+
</div>
47+
</template>
48+
49+
<script setup lang="ts">
50+
import { Splide } from "@splidejs/vue-splide";
51+
import { computed, onMounted, ref, useTemplateRef } from "vue";
52+
53+
import { mucSliderOptions } from "./MucSliderOptions";
54+
55+
defineSlots<{
56+
/**
57+
* MucSliderItems can be put into this slot.
58+
*/
59+
default(): any;
60+
}>();
61+
62+
const emit = defineEmits<{
63+
/**
64+
* Triggered when an item is clicked.
65+
* @param id of the clicked item
66+
*/
67+
changeSlide: [index: number];
68+
}>();
69+
70+
const splide = useTemplateRef("splide");
71+
72+
/**
73+
* Index of the current silde
74+
*/
75+
const currentSlide = ref<number>(0);
76+
77+
/**
78+
* Length of the splide
79+
*/
80+
const splideLength = ref<number>(0);
81+
82+
/**
83+
* Set next slide
84+
*/
85+
const nextSlide = () => {
86+
if (splide.value) {
87+
splide.value.go(">");
88+
}
89+
};
90+
91+
/**
92+
* Set previous slide
93+
*/
94+
const prevSlide = () => {
95+
if (splide.value) {
96+
splide.value.go("<");
97+
}
98+
};
99+
100+
/**
101+
* Computed property set back button
102+
*/
103+
const showBackArrow = computed(() => currentSlide.value > 0);
104+
105+
/**
106+
* Computed property set next button
107+
*/
108+
const showNextArrow = computed(
109+
() => currentSlide.value < splideLength.value - 1
110+
);
111+
112+
onMounted(() => {
113+
if (splide.value && splide.value.splide) {
114+
splideLength.value = splide.value.length;
115+
splide.value.splide.on("move", () => {
116+
if (splide.value) {
117+
currentSlide.value = splide.value.splide!.index;
118+
emit("changeSlide", splide.value.splide!.index);
119+
}
120+
});
121+
}
122+
});
123+
</script>
124+
125+
<style scoped>
126+
.m-component-slider-comment {
127+
padding-right: 1.8rem;
128+
padding-left: 1.8rem;
129+
}
130+
</style>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<template>
2+
<SplideSlide>
3+
<slot />
4+
</SplideSlide>
5+
</template>
6+
7+
<script setup lang="ts">
8+
import { SplideSlide } from "@splidejs/vue-splide";
9+
10+
defineSlots<{
11+
/**
12+
* Elements can be put into this slot.
13+
*/
14+
default(): any;
15+
}>();
16+
</script>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type { Options } from "@splidejs/splide";
2+
3+
export const mucSliderOptions: Options = {
4+
autoplay: false,
5+
keyboard: true,
6+
slideFocus: true,
7+
lazyLoad: false,
8+
arrows: false,
9+
perMove: 1,
10+
gap: "0",
11+
type: "slide",
12+
perPage: 1,
13+
pagination: false,
14+
speed: 350,
15+
drag: true,
16+
swipe: true,
17+
swipeThreshold: 50,
18+
mediaQuery: "min",
19+
breakpoints: {
20+
1: {
21+
perPage: 1,
22+
gap: "1.5rem",
23+
},
24+
768: {
25+
perPage: 1,
26+
gap: "1.5rem",
27+
},
28+
1200: {
29+
perPage: 1,
30+
gap: "2rem",
31+
},
32+
},
33+
};

src/components/Slider/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import MucSlider from "./MucSlider.vue";
2+
import MucSliderItem from "./MucSliderItem.vue";
3+
4+
export { MucSlider, MucSliderItem };

src/components/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { MucIcon } from "./Icon";
2121
import { MucIntro } from "./Intro";
2222
import { MucLink } from "./Link";
2323
import { MucPercentageSpinner } from "./PercentageSpinner";
24+
import { MucSlider, MucSliderItem } from "./Slider";
2425
import { MucStepper } from "./Stepper";
2526

2627
export {
@@ -48,4 +49,6 @@ export {
4849
MucPercentageSpinner,
4950
MucStepper,
5051
MucCalendar,
52+
MucSlider,
53+
MucSliderItem,
5154
};

0 commit comments

Comments
 (0)