Rename ImageCarousel => Carousel

This commit is contained in:
Vadim
2021-01-22 20:27:25 +03:00
parent 92d7ee043a
commit 5154887d93
6 changed files with 38 additions and 39 deletions

View File

@@ -0,0 +1,27 @@
import CarouselView from './CarouselView.svelte';
import CarouselViewCustomDots from './CarouselViewCustomDots.svelte';
import CarouselViewCustomArrows from './CarouselViewCustomArrows.svelte';
export default {
title: 'Carousel',
component: CarouselView
};
const Template = ({ ...args }) => ({
Component: CarouselView,
props: args
});
export const Primary = Template.bind({});
const TemplateCustomDots = ({ ...args }) => ({
Component: CarouselViewCustomDots,
props: args
});
export const WithCustomDots = TemplateCustomDots.bind({});
const TemplateCustomArrows = ({ ...args }) => ({
Component: CarouselViewCustomArrows,
props: args
});
export const WithCustomArrows = TemplateCustomArrows.bind({});

View File

@@ -0,0 +1,223 @@
<script>
// TODO: rename image carousel to just carousel
import { onDestroy, onMount } from 'svelte'
import { store } from '../store'
import {
getPageIndex,
getPagesCount,
getSlidesToShowTail,
getSlideSize,
getIsNotCompletePage
} from '../utils/size'
import Dots from '../Dots/Dots.svelte'
import Arrow from '../Arrow/Arrow.svelte'
/**
* Enable Next/Prev arrows
*/
export let arrows = true
/**
* Infinite looping
*/
export let infinite = true
/**
* Number of slides to show at a time
*/
export let slidesToShow = 1
/**
* Page to start on
*/
export let initialPageIndex = 1
/**
* Transition speed (ms)
*/
export let speed = 500
/**
* Enables auto play of slides
*/
export let autoplay = false
/**
* Auto play change interval
*/
export let autoplaySpeed = 3000
/**
* Auto play change direction ('next', 'prev')
*/
export let autoplayDirection = 'next'
/**
* Current page indicator dots
*/
export let dots = true
let currentPageIndex = 0
let pagesCount = 0
let pageWidth = 0
let offset
let contentContainerElement
let innerContentContainerElement
const unsubscribe = store.subscribe(value => {
currentPageIndex = value.currentPageIndex
})
function applySlideSizes() {
const children = innerContentContainerElement ? innerContentContainerElement.children : []
pageWidth = contentContainerElement.clientWidth
const slidesCount = children.length
pagesCount = getPagesCount({ slidesCount, slidesToShow })
const slidesToShowTail = getSlidesToShowTail({ pagesCount, slidesToShow, slidesCount })
for (let slideIndex=0; slideIndex<children.length; slideIndex++) {
const pageIndex = getPageIndex({ slideIndex, slidesToShow })
const isNotCompletePage = getIsNotCompletePage({ pageIndex, pagesCount })
const slideSizePx = getSlideSize({ isNotCompletePage, pageWidth, slidesToShow, slidesToShowTail })
children[slideIndex].style.minWidth = `${slideSizePx}px`
children[slideIndex].style.maxWidth = `${slideSizePx}px`
}
}
function applyAutoplay() {
const autoplayDirectionFnDescription = {
'next': showNextPage,
'prev': showPrevPage
}
let interval
if (autoplay) {
interval = setInterval(() => {
autoplayDirectionFnDescription[autoplayDirection]()
}, autoplaySpeed)
}
return {
teardownAutoplay: () => {
interval && clearInterval(interval)
}
}
}
onMount(() => {
store.init(initialPageIndex)
applySlideSizes()
const { teardownAutoplay } = applyAutoplay()
window.addEventListener('resize', applySlideSizes)
return () => {
window.removeEventListener('resize', applySlideSizes)
teardownAutoplay()
}
})
onDestroy(() => {
unsubscribe()
})
function handlePageChange(event) {
showPage(event.detail)
}
function applyOffset() {
offset = -currentPageIndex * pageWidth
}
function showPage(pageIndex) {
store.moveToPage({ pageIndex, pagesCount })
applyOffset()
}
function showPrevPage() {
store.prev({ infinite, pagesCount })
applyOffset()
}
function showNextPage() {
store.next({ infinite, pagesCount })
applyOffset()
}
</script>
<div class="main-container">
<div class="carousel-container">
{#if arrows}
<slot name="prev" {showPrevPage}>
<div class="side-container">
<Arrow direction="prev" on:click={showPrevPage} />
</div>
</slot>
{/if}
<div
class="content-container"
bind:this={contentContainerElement}
>
<div
style="
transform: translateX({offset}px);
transition-duration: {speed}ms;
"
bind:this={innerContentContainerElement}
>
<slot></slot>
</div>
</div>
{#if arrows}
<slot name="next" {showNextPage}>
<div class="side-container">
<Arrow direction="next" on:click={showNextPage} />
</div>
</slot>
{/if}
</div>
{#if dots}
<slot
name="dots"
currentPageIndex={currentPageIndex}
{pagesCount}
{showPage}
>
<Dots
{pagesCount}
currentPageIndex={currentPageIndex}
on:pageChange={handlePageChange}
></Dots>
</slot>
{/if}
</div>
<style>
.main-container {
display: flex;
width: 100%;
flex-direction: column;
align-items: center;
}
.carousel-container {
display: flex;
width: 100%;
}
.content-container {
flex: 1;
display: flex;
overflow: hidden;
box-sizing: border-box;
}
.content-container > div {
width: 100%;
display: flex; /* to put child elements in one row */
transition-timing-function: ease-in-out;
transition-property: transform;
}
.side-container {
height: 100%;
padding: 5px;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
}
</style>

View File

@@ -0,0 +1,102 @@
<script>
import Carousel from './Carousel.svelte'
/**
* Enable Next/Previos arrows
*/
export let arrows = true;
/**
* Infinite looping
*/
export let infinite = true;
/**
* Number of slides to show at a time
*/
export let slidesToShow = 1;
/**
* Page to start on
*/
export let initialPageIndex = 1
/**
* Transition speed (ms)
*/
export let speed = 500
/**
* Enables auto play of slides
*/
export let autoplay = false
/**
* Auto play change interval
*/
export let autoplaySpeed = 3000
/**
* Auto play change direction ('next', 'prev')
*/
export let autoplayDirection = 'next'
/**
* Current page indicator dots
*/
export let dots = true
const colors = [
'#e5f9f0',
'#ccf3e2',
'#b2edd3',
'#99e7c5',
'#7fe1b7',
'#66dba8',
'#4cd59a',
'#32cf8b',
'#19c97d',
'#00c36f'
]
</script>
<div class="main-container">
<Carousel
{arrows}
{infinite}
{slidesToShow}
{initialPageIndex}
{speed}
{autoplay}
{autoplaySpeed}
{autoplayDirection}
{dots}
>
{#each colors as color (color)}
<div
class="color-container"
style="background-color: {color};"
>
<p>{color}</p>
</div>
{/each}
</Carousel>
</div>
<style>
.main-container {
display: flex;
width: 100%;
}
.color-container {
height: 100px;
display: flex;
align-items: center;
justify-content: center;
}
.color-container > p {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-style: italic;
font-size: 18px;
}
</style>

View File

@@ -0,0 +1,129 @@
<script>
import Carousel from './Carousel.svelte'
/**
* Enable Next/Previos arrows
*/
export let arrows = true;
/**
* Infinite looping
*/
export let infinite = true;
/**
* Number of slides to show at a time
*/
export let slidesToShow = 1;
/**
* Page to start on
*/
export let initialPageIndex = 1
/**
* Transition speed (ms)
*/
export let speed = 500
/**
* Enables auto play of slides
*/
export let autoplay = false
/**
* Auto play change interval
*/
export let autoplaySpeed = 3000
/**
* Auto play change direction ('next', 'prev')
*/
export let autoplayDirection = 'next'
/**
* Current page indicator dots
*/
export let dots = true
const colors = [
'#e5f9f0',
'#ccf3e2',
'#b2edd3',
'#99e7c5',
'#7fe1b7',
'#66dba8',
'#4cd59a',
'#32cf8b',
'#19c97d',
'#00c36f'
]
</script>
<div class="main-container">
<Carousel
{arrows}
{infinite}
{slidesToShow}
{initialPageIndex}
{speed}
{autoplay}
{autoplaySpeed}
{autoplayDirection}
{dots}
let:showPrevPage
let:showNextPage
>
{#each colors as color (color)}
<div
class="color-container"
style="background-color: {color};"
>
<p>{color}</p>
</div>
{/each}
<div slot="prev" class="arrow-container">
<div class="arrow" on:click={showPrevPage}>
<span>&lt;&lt;&lt;</span>
</div>
</div>
<div slot="next" class="arrow-container">
<div class="arrow" on:click={showNextPage}>
<span>&gt;&gt;&gt;</span>
</div>
</div>
</Carousel>
</div>
<style>
.main-container {
display: flex;
width: 100%;
}
.color-container {
height: 100px;
display: flex;
align-items: center;
justify-content: center;
}
.color-container > p {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-style: italic;
font-size: 18px;
}
.arrow-container {
display: flex;
align-items: center;
justify-content: center;
padding: 10px;
}
.arrow {
background-color: darkgray;
border-radius: 5px;
padding: 5px;
font-weight: bold;
cursor: pointer;
user-select: none;
}
</style>

View File

@@ -0,0 +1,139 @@
<script>
import Carousel from './Carousel.svelte'
/**
* Enable Next/Previos arrows
*/
export let arrows = true;
/**
* Infinite looping
*/
export let infinite = true;
/**
* Number of slides to show at a time
*/
export let slidesToShow = 1;
/**
* Page to start on
*/
export let initialPageIndex = 1
/**
* Transition speed (ms)
*/
export let speed = 500
/**
* Enables auto play of slides
*/
export let autoplay = false
/**
* Auto play change interval
*/
export let autoplaySpeed = 3000
/**
* Auto play change direction ('next', 'prev')
*/
export let autoplayDirection = 'next'
/**
* Current page indicator dots
*/
export let dots = true
function onPageChange(event, showPage) {
showPage(event.target.value)
}
const colors = [
'#e5f9f0',
'#ccf3e2',
'#b2edd3',
'#99e7c5',
'#7fe1b7',
'#66dba8',
'#4cd59a',
'#32cf8b',
'#19c97d',
'#00c36f'
]
</script>
<div class="main-container">
<Carousel
{arrows}
{infinite}
{slidesToShow}
{initialPageIndex}
{speed}
{autoplay}
{autoplaySpeed}
{autoplayDirection}
{dots}
let:currentPageIndex
let:pagesCount
let:showPage
>
{#each colors as color (color)}
<div
class="color-container"
style="background-color: {color};"
>
<p>{color}</p>
</div>
{/each}
<div slot="dots">
<div class="select-container">
<select
value={currentPageIndex}
on:change="{(event) => onPageChange(event, showPage)}"
on:blur="{(event) => onPageChange(event, showPage)}"
>
{#each Array(pagesCount) as _, pageIndex (pageIndex)}
<option value={pageIndex} class:active={currentPageIndex === pageIndex}>
{pageIndex}
</option>
{/each}
</select>
</div>
</div>
</Carousel>
</div>
<style>
.main-container {
display: flex;
width: 100%;
}
.color-container {
height: 100px;
display: flex;
align-items: center;
justify-content: center;
}
.color-container > p {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-style: italic;
font-size: 18px;
}
.active {
background-color: grey;
color: white;
}
.select-container {
padding: 5px 0;
}
.select-container > select {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-style: italic;
height: 25px;
width: 100px;
border-radius: 5px;
}
</style>