Skip to content

Instantly share code, notes, and snippets.

@Roy-Ermers
Created November 14, 2018 13:15
Show Gist options
  • Save Roy-Ermers/6a9bbd10efe0bfe4762ef9ed134e6cba to your computer and use it in GitHub Desktop.
Save Roy-Ermers/6a9bbd10efe0bfe4762ef9ed134e6cba to your computer and use it in GitHub Desktop.
a custom webcomponent slider with previews of images on various screens.
class slider extends HTMLElement {
constructor() {
super();
this.images = [];
this.attachShadow({
mode: "open"
});
// #region HTML/css
this.shadowRoot.innerHTML = /*html*/ `
<style>
.site-preview,
:host {
display: block;
position: relative;
min-height: 100px;
padding: 1em;
z-index: 1;
text-align: center;
}
.site-preview .mobile,
:host .mobile {
display: inline-block;
border: 5px solid black;
border-radius: 15px;
width: 10%;
padding-top: 21.6666667%;
position: relative;
filter: drop-shadow(0 0 24px rgba(0, 0, 0, 0.32));
z-index: 1;
}
.site-preview .mobile::before,
:host .mobile::before {
content: "";
z-index: 1;
background-color: #000;
position: absolute;
width: 65%;
height: 10px;
top: 0;
left: 50%;
transform: translate(-50%);
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
.site-preview .mobile .screen,
:host .mobile .screen {
border-radius: 8px;
}
.site-preview .tablet,
:host .tablet {
z-index: 1;
display: inline-block;
border: 15px solid black;
position: relative;
border-top-width: 25px;
border-bottom-width: 35px;
border-radius: 15px;
width: 17%;
padding-top: 22.6666666667%;
filter: drop-shadow(0 0 24px rgba(0, 0, 0, 0.32));
}
.site-preview .tablet::before,
:host .tablet::before {
z-index: 1;
content: "";
background-color: #333;
position: absolute;
top: -17px;
left: 50%;
transform: translate(-50%);
height: 5px;
width: 5px;
border-radius: 100%;
}
.site-preview .tablet::after,
:host .tablet::after {
z-index: 1;
content: "";
background-color: #333;
position: absolute;
bottom: -25px;
left: 50%;
transform: translate(-50%);
height: 15px;
width: 15px;
border-radius: 100%;
}
.site-preview .desktop,
:host .desktop {
display: inline-block;
border: 15px solid black;
position: relative;
border-radius: 25px;
margin: 0 -50px;
border-bottom-width: 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
width: 50%;
padding-top: 28.125%;
margin-bottom: 100px;
z-index: 0;
}
.site-preview .desktop .screen,
:host .desktop .screen {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}
.site-preview .desktop::after,
:host .desktop::after {
z-index: 1;
position: absolute;
display: block;
content: "";
width: calc(100% + 30px);
left: -15px;
bottom: -60px;
height: 50px;
background-color: #c2c2c2;
border-bottom-left-radius: 15px;
border-bottom-right-radius: 15px;
}
.site-preview .desktop::before,
:host .desktop::before {
z-index: 1;
position: absolute;
display: block;
content: "";
background-color: #acacac;
width: 25%;
height: 50px;
bottom: -110px;
left: 50%;
transform: translate(-50%);
border: #c2c2c2 5px solid;
border-left: transparent 10px solid;
border-right: transparent 10px solid;
}
.site-preview .screen,
:host .screen {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: block;
overflow: hidden;
background-color: #000;
}
.site-preview .screen .slide,
:host .screen .slide {
display: inline-block;
width: 100%;
height: 0;
transition: height 250ms ease-in-out;
object-fit: cover;
object-position: center center;
}
.site-preview .screen .slide.selected,
:host .screen .slide.selected {
height: 100%;
}
@media screen and (max-width: 500px) {
:host .mobile {
border-radius: 7px;
border-width: 2px;
}
:host .mobile .screen {
border-radius: 3px;
}
:host .mobile::before {
height: 5px;
}
:host .tablet {
border-width: 7px;
border-top-width: 12px;
border-bottom-width: 17px;
border-radius: 7px;
}
:host .tablet::before {
top: -10px;
height: 5px;
width: 5px;
}
:host .tablet::after {
bottom: -15px;
height: 10px;
width: 10px;
}
:host .desktop {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
border-width: 10px;
margin: 0 -20px;
margin-bottom: 70px;
}
:host .desktop .screen {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
:host .desktop::after {
bottom: -35px;
height: 25px;
width: calc(100% + 20px);
left: -10px;
}
:host .desktop::before {
bottom: -65px;
height: 35px;
}
}
</style>
<div class="tablet">
<div class="screen"></div>
</div>
<div class="desktop">
<div class="screen">
</div>
</div>
<div class="mobile">
<div class="screen"></div>
</div>
<slot></slot>`;
//#endregion
this.desktop = this.shadowRoot.querySelector(".desktop>.screen");
this.tablet = this.shadowRoot.querySelector(".tablet>.screen");
this.mobile = this.shadowRoot.querySelector(".mobile>.screen");
this.slides = 0;
this.currentSlide = 0;
window.addEventListener("resize", () => this.WidthChanged(this));
}
async connectedCallback() {
await new Promise((res) => requestAnimationFrame(res));
let slides = this.shadowRoot.querySelector("slot").assignedElements();
this.slides = Math.ceil(slides.length / 3);
if (slides.length > 0) {
slides.forEach(screenshot => {
if (!screenshot.hasAttribute("data-type")) return;
switch (screenshot.getAttribute("data-type")) {
case "desktop":
this.desktop.innerHTML += slider.slide.replace(`{url}`, screenshot.src);
break;
case "tablet":
this.tablet.innerHTML += slider.slide.replace(`{url}`, screenshot.src);
break;
case "mobile":
this.mobile.innerHTML += slider.slide.replace(`{url}`, screenshot.src);
break;
}
screenshot.remove();
});
this.desktop.firstElementChild.classList.add("selected");
this.tablet.firstElementChild.classList.add("selected");
this.mobile.firstElementChild.classList.add("selected");
} else
this.desktop.innerHTML = "<h1>No Slides found.</h1>";
setInterval(() => this.Scroll(this), this.getAttribute("data-interval") || 2500);
}
WidthChanged(elem) {
console.log(elem.clientWidth);
elem.classList.toggle("mobile", elem.clientWidth < 385);
}
async Scroll(elem) {
elem.currentSlide++;
if (elem.currentSlide >= elem.slides) elem.currentSlide = 0;
let screen = [elem.tablet, elem.desktop, elem.mobile];
screen.forEach((screen, i) => {
setTimeout(() => {
let current = screen.querySelector(".selected");
if (current && current.nextElementSibling && elem.currentSlide > 0) {
current.nextElementSibling.classList.add("selected");
current.classList.remove("selected");
} else {
screen.firstElementChild.classList.add("selected");
if (current && this.slides > 0)
current.classList.remove("selected");
}
}, (elem.getAttribute("data-delay") || 0) * i);
});
}
}
slider.slide = /*html*/ `<img src="{url}" class="slide">`;
customElements.define("app-slider", slider);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment