Newer
Older
<script setup lang="ts">
import type { ICarouselProps } from '@interfaces/componentsProps';
import CarouselButtonContainer from '@components/Carousel/CarouselButtonContainer.vue';
import { computed, ref } from 'vue';
import { convertThemeToColor, convertThemeToTextColor } from '@helpers/common';
import ArrowLeftShortIcon from '@icons/Mono/ArrowLeftShortIcon.vue';
import ArrowRightShortIcon from '@icons/Mono/ArrowRightShortIcon.vue';

Дмитрий Малюгин
committed
import { defaultProps, getNewValue } from './helpers';
const props = withDefaults(defineProps<ICarouselProps>(), {
size: 'normal',

Дмитрий Малюгин
committed
innerWidth: '300px',
perView: 1,
perScroll: 1,
theme: 'white',
darknessTheme: '500',

Дмитрий Малюгин
committed
const itemsLength = computed(() => props.itemsProps?.length ?? 3);
const color = computed(() => convertThemeToColor(props.theme, props.darknessTheme));
const textColor = computed(() => convertThemeToTextColor(props.theme, props.darknessTheme));

Дмитрий Малюгин
committed
const isStartDisabled = computed(() => (props.circular ? false : current.value === 1 || itemsLength.value <= 1));
const isEndDisabled = computed(() =>
props.circular ? false : current.value === Math.ceil(itemsLength.value / props.perView) || !itemsLength.value,
);
if (size === 'normal') return 1;
if (size === 'large') return 2;
if (size === 'huge') return 3;
return 0.75;
const iconSize = computed(() => 10 * sizeCoefficient.value);

Дмитрий Малюгин
committed
const itemWidth = computed(() => `calc(${props.innerWidth} / ${props.perView}`);
const buttonSize = computed(() => {
const size = props.size;
if (size === 'normal') return 12 * sizeCoefficient.value + 'px';
if (size === 'large') return 12 * sizeCoefficient.value + 'px';
if (size === 'huge') return 15 * sizeCoefficient.value + 'px';
return 9 * sizeCoefficient.value + 'px';

Дмитрий Малюгин
committed
const translate = computed(() => `translateX(calc(-${props.innerWidth} / ${props.perView} * ${current.value - 1}))`);

Дмитрий Малюгин
committed
<section class="carouselContainer">

Дмитрий Малюгин
committed
@click="!isStartDisabled ? (current = getNewValue('-', current, itemsLength, perScroll, perView)) : null"
:width="50 * sizeCoefficient + 'px'"
:borderRadius="5 * sizeCoefficient + 'px'"

Дмитрий Малюгин
committed
:textColor="textColor"

Дмитрий Малюгин
committed
:disable="isStartDisabled"
>

Дмитрий Малюгин
committed
<div class="content">
<ul class="list">
<li v-for="item of Array(itemsLength).keys()" :key="item" class="item">
<slot v-bind="itemsProps?.[item]" :key="current - 1" />
<div v-if="!$slots.default && !itemsProps">
<h2 style="text-align: center; margin-bottom: 10px">{{ defaultProps[item].header }}</h2>
<p>
{{ defaultProps[item].text }}
</p>
</div>
<div v-else-if="!$slots.default">
<h2 style="text-align: center; margin-bottom: 10px">{{ itemsProps[item].header }}</h2>
<p>
{{ itemsProps[item].text }}
</p>
</div>
</li>
</ul>
</div>

Дмитрий Малюгин
committed
@click="!isEndDisabled ? (current = getNewValue('+', current, itemsLength, perScroll, perView)) : null"
:width="50 * sizeCoefficient + 'px'"
:borderRadius="5 * sizeCoefficient + 'px'"

Дмитрий Малюгин
committed
:textColor="textColor"

Дмитрий Малюгин
committed
:disable="isEndDisabled"
>
</CarouselButtonContainer>
<div class="buttons" v-if="buttonsBelow">
<CarouselButtonContainer
v-for="item of Array(itemsLength - 1).keys()"

Дмитрий Малюгин
committed
:key="item"
:width="buttonSize"
borderRadius="50%"
:textColor="textColor"
:color="color"
@click="current = item + 1"
><div class="button" :style="`border-width: ${size === 'large' || size === 'huge' ? '2px' : '1px'}`"></div
</section>
</template>
<style scoped>
.carouselContainer {
display: flex;

Дмитрий Малюгин
committed
min-height: 100px;

Дмитрий Малюгин
committed
position: relative;
}
.content {
max-width: v-bind(innerWidth);
overflow: hidden;
}
.list {
display: flex;
transform: v-bind(translate);
transition: transform 0.3s ease-out;
}
.item {
min-width: v-bind(itemWidth);
}
.buttons {
position: absolute;
bottom: 0;
left: 50%;
transform: translate(-50%, 120%);
display: flex;
gap: 10px;

Дмитрий Малюгин
committed
}
.button {
background-color: v-bind(color);
border-radius: 50%;
cursor: pointer;
width: v-bind(buttonSize);
height: v-bind(buttonSize);
:hover {
filter: brightness(50%);
}