Skip to content

Instantly share code, notes, and snippets.

@tlux
Last active October 15, 2021 12:59
Show Gist options
  • Save tlux/88dfd5f84cb587892a3495fef7734f68 to your computer and use it in GitHub Desktop.
Save tlux/88dfd5f84cb587892a3495fef7734f68 to your computer and use it in GitHub Desktop.
Cube component with CSS transitions Svelte + TS
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import { CubeSide } from './CubeSide';
export let view: CubeSide = CubeSide.Front;
export let transition: boolean = false;
export let transitionDuration: number = 2000;
export let backface: boolean = false;
export let perspective: string = '1000px';
export let width: string = '100%';
export let height: string = '100%';
let style!: string;
$: {
style = [
`--cube-width: ${width}`,
`--cube-height: ${height}`,
`--cube-perspective: ${perspective}`,
transition && `--cube-transition-duration: ${transitionDuration}ms`,
].filter(Boolean).join(';');
}
const dispatch = createEventDispatcher();
function onTransitionEnd() {
dispatch('transitionend', { view });
}
</script>
<div
class="cube cube--view-{view}"
class:cube--backface={backface}
class:cube--transition={transition}
{style}
>
<div class="cube__body" on:transitionend|self={onTransitionEnd}>
<div class="cube__side cube__side--front">
<slot name="front" />
</div>
<div class="cube__side cube__side--back">
<slot name="back" />
</div>
<div class="cube__side cube__side--left">
<slot name="left" />
</div>
<div class="cube__side cube__side--right">
<slot name="right" />
</div>
<div class="cube__side cube__side--top">
<slot name="top" />
</div>
<div class="cube__side cube__side--bottom">
<slot name="bottom" />
</div>
</div>
</div>
<style>
.cube {
position: relative;
width: var(--cube-width);
height: var(--cube-height);
perspective: var(--cube-perspective);
perspective-origin: center;
}
.cube--view-front {
--rotate-x: 0;
--rotate-y: 0;
}
.cube--view-left {
--rotate-x: 0;
--rotate-y: 90;
}
.cube--view-right {
--rotate-x: 0;
--rotate-y: -90;
}
.cube--view-back {
--rotate-x: 0;
--rotate-y: 180;
}
.cube--view-top {
--rotate-x: -90;
--rotate-y: 0;
}
.cube--view-bottom {
--rotate-x: 90;
--rotate-y: 0;
}
.cube__body {
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
transform: rotateY(-90deg) translateX(-50%) rotateY(90deg)
rotateY(calc(var(--rotate-y) * 1deg))
rotateX(calc(var(--rotate-x) * 1deg));
}
.cube--transition .cube__body {
transition-property: transform;
transition-duration: var(--cube-transition-duration);
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
.cube__side {
position: absolute;
inset: 0;
backface-visibility: hidden;
}
.cube--backface .cube__side {
backface-visibility: inherit;
}
.cube__side--front {
transform: rotateY(90deg) translateX(-50%) rotateY(-90deg);
}
.cube__side--back {
transform: rotateY(90deg) translateX(50%) rotateY(90deg);
}
.cube__side--left {
transform: rotateY(0deg) translateX(-50%) rotateY(-90deg);
}
.cube__side--right {
transform: rotateY(0deg) translateX(50%) rotateY(90deg);
}
.cube__side--top {
transform: translateY(-50%) rotateX(90deg);
}
.cube__side--bottom {
transform: translateY(50%) rotateX(-90deg);
}
</style>
export enum CubeSide {
Front = 'front',
Back = 'back',
Left = 'left',
Right = 'right',
Top = 'top',
Bottom = 'bottom'
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment