Skip to content

Commit

Permalink
feat(dashboard): create carousel component and use it for recent spaces
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasRichel committed Apr 13, 2021
1 parent d9fb58e commit 554b764
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 10 deletions.
33 changes: 33 additions & 0 deletions src/components/generic/carousel-list/CarouselList.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.carousel-list {
$button-size: 44px;

position: relative;
padding: $spacing-unit;

&__container {
overflow-x: hidden;

&__slider {
position: relative;
transition: transform 0.5s ease-out;
}
}

&__btn-previous,
&__btn-next {
position: absolute;
z-index: 2;
top: calc(50% - #{$button-size / 2});
width: $button-size;
height: $button-size;
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.1);
}

&__btn-previous {
left: -$button-size / 2;
}

&__btn-next {
right: -$button-size / 2;
}
}
131 changes: 131 additions & 0 deletions src/components/generic/carousel-list/CarouselList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<template>
<div class="carousel-list">
<BIMDataButton
v-show="index > 0"
class="carousel-list__btn-previous"
color="default"
fill
rounded
icon
@click="index--"
>
<BIMDataIcon name="chevron" size="s" :rotate="180" />
</BIMDataButton>
<div class="carousel-list__container">
<div
class="carousel-list__container__slider"
ref="slider"
:style="{
transform: `translateX(-${translations[index]}px)`
}"
>
<slot></slot>
</div>
</div>
<BIMDataButton
v-show="index < maxIndex"
class="carousel-list__btn-next"
color="default"
fill
rounded
icon
@click="index++"
>
<BIMDataIcon name="chevron" size="s" />
</BIMDataButton>
</div>
</template>

<script>
import { onBeforeUnmount, onMounted, ref } from "vue";
// Components
import BIMDataButton from "@bimdata/design-system/dist/js/BIMDataComponents/vue3/BIMDataButton";
import BIMDataIcon from "@bimdata/design-system/dist/js/BIMDataComponents/vue3/BIMDataIcon";
// Slider padding:
const sliderPadding = 12; // px
// Minimum amount of space between items:
const minGap = 24; // px
export default {
components: {
BIMDataButton,
BIMDataIcon
},
setup() {
const slider = ref(null);
const index = ref(0);
const maxIndex = ref(0);
const translations = ref([]);
const distributeItems = () => {
const sliderWidth = slider.value.getBoundingClientRect().width;
// Compute the actual width that will be available to distribute items
const contentWidth = sliderWidth - 2 * sliderPadding;
const children = Array.from(slider.value.children);
if (children.length > 0) {
// Note: it is assumed that all items have the same dimensions (width/height)
const {
width: itemWidth,
height: itemHeight
} = children[0].getBoundingClientRect();
// Set slider height according to items height and slider padding
slider.value.style.height = `${itemHeight + 2 * sliderPadding}px`;
// Calculate the maximum number of items that can be displayed
// at the same time according to slider width and items height
// taking minimum gap into account
const nbDisplayed = Math.floor(contentWidth / (itemWidth + minGap));
// Calculate the actual gap between items
let gap = minGap;
if (nbDisplayed > 1) {
gap = (contentWidth - nbDisplayed * itemWidth) / (nbDisplayed - 1);
}
// Compute offset (translation) list and set items styles
let offset;
const offsetUnit = itemWidth + gap;
const offsets = [];
for (let i = 0; i < children.length; i++) {
offset = i * offsetUnit;
offsets.push(offset);
Object.assign(children[i].style, {
position: "absolute",
top: `${sliderPadding}px`,
left: `${sliderPadding + offset}px`
});
}
maxIndex.value = children.length - nbDisplayed;
translations.value = offsets;
}
};
let resizeObserver;
onMounted(() => {
distributeItems();
resizeObserver = new ResizeObserver(() => distributeItems());
resizeObserver.observe(slider.value);
});
onBeforeUnmount(() => {
resizeObserver.disconnect();
});
return {
// References
index,
maxIndex,
slider,
translations
};
}
};
</script>

<style scoped lang="scss" src="./CarouselList.scss"></style>
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
.dashboard-space-list {
padding: $spacing-unit * 2;

&__title {
padding: $spacing-unit/2 $spacing-unit;
font-weight: bold;
}

&__content {
display: flex;
gap: $spacing-unit * 2;
padding: $spacing-unit;
overflow-x: auto;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,26 @@
<div class="dashboard-space-list__title">
{{ $t("DashboardSpaceList.title") }}
</div>
<div class="dashboard-space-list__content">
<CarouselList>
<SpaceCard
v-for="space in displayedSpaces"
:key="space.id"
:space="space"
:actionMenu="false"
/>
</div>
</CarouselList>
</div>
</template>

<script>
import { ref, watchEffect } from "vue";
// Components
import CarouselList from "@/components/generic/carousel-list/CarouselList";
import SpaceCard from "@/components/specific/spaces/space-card/SpaceCard";
export default {
components: {
CarouselList,
SpaceCard
},
props: {
Expand Down

0 comments on commit 554b764

Please sign in to comment.