autoscrolling-images
Summary: Ref T2829 Reviewers: #testers, kuba-orlik Reviewed By: #testers, kuba-orlik Subscribers: kuba-orlik, jenkins-user Maniphest Tasks: T2829 Differential Revision: https://hub.sealcode.org/D1413
This commit is contained in:
parent
62a07fa5b7
commit
7abc419b97
@ -20,6 +20,7 @@ module.exports = {
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": [2, { varsIgnorePattern: "TempstreamJSX" }],
|
||||
"no-unused-vars": [2, { varsIgnorePattern: "TempstreamJSX" }],
|
||||
"@typescript-eslint/require-await": 0,
|
||||
/* "jsdoc/require-description": 2, */
|
||||
"no-await-in-loop": 2,
|
||||
|
2
.hintrc
2
.hintrc
@ -11,7 +11,7 @@
|
||||
"doctype": "error",
|
||||
"apple-touch-icons": "error",
|
||||
"button-type": "error",
|
||||
"compat-api/css": "error",
|
||||
"compat-api/css": "warning",
|
||||
"compat-api/html": [
|
||||
"error",
|
||||
{
|
||||
|
@ -0,0 +1,3 @@
|
||||
<svg width="32" height="12" viewBox="0 0 32 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 5.25C0.585786 5.25 0.25 5.58579 0.25 6C0.25 6.41421 0.585786 6.75 1 6.75V5.25ZM31.5303 6.53033C31.8232 6.23744 31.8232 5.76256 31.5303 5.46967L26.7574 0.696699C26.4645 0.403806 25.9896 0.403806 25.6967 0.696699C25.4038 0.989593 25.4038 1.46447 25.6967 1.75736L29.9393 6L25.6967 10.2426C25.4038 10.5355 25.4038 11.0104 25.6967 11.3033C25.9896 11.5962 26.4645 11.5962 26.7574 11.3033L31.5303 6.53033ZM1 6.75H31V5.25H1V6.75Z" fill="#0D4D69"/>
|
||||
</svg>
|
After Width: | Height: | Size: 555 B |
@ -0,0 +1,177 @@
|
||||
.autoscrolling-images {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.autoscrolling-images-wrapper {
|
||||
display: grid;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.autoscrolling-images__title-wrapper {
|
||||
max-width: 940px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.autoscrolling-images__title {
|
||||
font-size: 32px;
|
||||
color: #0d4d69;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.autoscrolling-images__arrow-carousel-container {
|
||||
position: absolute;
|
||||
top: -51px;
|
||||
right: -90px;
|
||||
width: 92px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.autoscrolling-images__arrow-carousel {
|
||||
transition: none !important;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
}
|
||||
|
||||
.autoscrolling-images__arrow-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
scroll-snap-align: start;
|
||||
flex: 1 0 100%;
|
||||
}
|
||||
|
||||
.autoscrolling-images__arrow img {
|
||||
max-width: 30px;
|
||||
}
|
||||
|
||||
.autoscrolling-images__arrow:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.autoscrolling-images__img-arrow-left {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.autoscrolling-images__carousel-container {
|
||||
position: relative;
|
||||
max-width: 940px;
|
||||
}
|
||||
|
||||
.autoscrolling-images__imgs-carousel {
|
||||
overflow-x: clip;
|
||||
}
|
||||
|
||||
.autoscrolling-images__carousel {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
}
|
||||
|
||||
.autoscrolling-images__carousel-page {
|
||||
align-items: center;
|
||||
scroll-snap-align: start;
|
||||
box-sizing: border-box;
|
||||
|
||||
flex: 1 0 100%;
|
||||
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
|
||||
max-width: 940px;
|
||||
}
|
||||
|
||||
.autoscrolling-images__img-wrapper {
|
||||
width: 288px;
|
||||
height: 150px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.autoscrolling-images__radio {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.autoscrolling-images__dots-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.autoscrolling-images__dots {
|
||||
cursor: pointer;
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
background-color: #cadae4;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
.autoscrolling-images__dots:hover {
|
||||
background-color: #0d4d69;
|
||||
}
|
||||
|
||||
@keyframes autoscrolling-images-infiniteScroll {
|
||||
0% {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(calc(-100% + 100cqw));
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
}
|
||||
|
||||
@container (width < 1115px) {
|
||||
.autoscrolling-images__arrow-carousel-container {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@container (width < 800px) {
|
||||
.autoscrolling-images__arrow-carousel-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.autoscrolling-images__dots-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.autoscrolling-images__carousel {
|
||||
max-width: none;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.autoscrolling-images__carousel-container {
|
||||
margin: 0;
|
||||
max-width: calc(100cqw - 20px);
|
||||
}
|
||||
|
||||
.autoscrolling-images__carousel-page {
|
||||
display: flex;
|
||||
flex: none !important;
|
||||
margin: 0;
|
||||
flex-wrap: nowrap !important;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.autoscrolling-images__img-wrapper {
|
||||
min-width: 288px;
|
||||
}
|
||||
|
||||
.autoscrolling-images__carousel {
|
||||
animation-name: autoscrolling-images-infiniteScroll;
|
||||
animation-duration: var(--animation-length);
|
||||
animation-iteration-count: infinite;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
import arrow from "./autoscrolling-images-arrow.svg";
|
||||
|
||||
import { FlatTemplatable, TempstreamJSX } from "tempstream";
|
||||
import {
|
||||
Component,
|
||||
ComponentArguments,
|
||||
ExtractStructuredComponentArgumentsValues,
|
||||
JDDContext,
|
||||
} from "@sealcode/jdd";
|
||||
|
||||
const component_arguments = {
|
||||
title: new ComponentArguments.ShortText(),
|
||||
interval: new ComponentArguments.ShortText().setExampleValues(["5"]),
|
||||
imagesPerPage: new ComponentArguments.ShortText().setExampleValues(["6"]),
|
||||
images: new ComponentArguments.List(
|
||||
new ComponentArguments.Structured({
|
||||
image: new ComponentArguments.Image(),
|
||||
alt: new ComponentArguments.ShortText(),
|
||||
})
|
||||
),
|
||||
} as const;
|
||||
|
||||
export class AutoscrollingImages extends Component<typeof component_arguments> {
|
||||
getArguments() {
|
||||
return component_arguments;
|
||||
}
|
||||
|
||||
toHTML(
|
||||
{
|
||||
title,
|
||||
interval,
|
||||
imagesPerPage,
|
||||
images,
|
||||
}: ExtractStructuredComponentArgumentsValues<typeof component_arguments>,
|
||||
{ render_image }: JDDContext
|
||||
): FlatTemplatable {
|
||||
const imageNumberPerPage = parseInt(imagesPerPage);
|
||||
let parsedImagesArray = [];
|
||||
|
||||
for (let i = 0; i < images.length; i += imageNumberPerPage) {
|
||||
parsedImagesArray.push(images.slice(i, i + imageNumberPerPage));
|
||||
}
|
||||
|
||||
const radioButtonIdPrefix = "r" + Math.floor(100 + Math.random() * 900);
|
||||
const numberOfImages = images.length * 5;
|
||||
const titleUpperCase = title.toUpperCase();
|
||||
|
||||
return (
|
||||
<div
|
||||
class="autoscrolling-images"
|
||||
data-controller="autoscrolling-images"
|
||||
data-autoscrolling-images-interval={interval}
|
||||
>
|
||||
<style>
|
||||
{parsedImagesArray
|
||||
.map(
|
||||
(_, pageIndex) =>
|
||||
`#${radioButtonIdPrefix}-autoscrolling-images__radio-${pageIndex}:checked ~ .autoscrolling-images__imgs-carousel > .autoscrolling-images__carousel {
|
||||
transform: translateX(calc(${pageIndex} * (-100%)));
|
||||
}
|
||||
|
||||
#${radioButtonIdPrefix}-autoscrolling-images__radio-${pageIndex}:checked ~ .autoscrolling-images__arrow-carousel-container
|
||||
> .autoscrolling-images__arrow-carousel {
|
||||
transform: translateX(calc(${pageIndex} * (-100%)));
|
||||
|
||||
}
|
||||
|
||||
#${radioButtonIdPrefix}-autoscrolling-images__radio-${pageIndex}:checked ~ .autoscrolling-images__dots-container
|
||||
> label:nth-child(${pageIndex + 1}) {
|
||||
background-color: #0d4d69;
|
||||
|
||||
}`
|
||||
)
|
||||
.join("\n")}
|
||||
</style>
|
||||
|
||||
<div
|
||||
class="autoscrolling-images-wrapper"
|
||||
data-carousel-id-prefix={radioButtonIdPrefix}
|
||||
>
|
||||
<div class="autoscrolling-images__title-wrapper">
|
||||
<h2 class="autoscrolling-images__title">{titleUpperCase}</h2>
|
||||
</div>
|
||||
|
||||
<div class="autoscrolling-images__carousel-container">
|
||||
{parsedImagesArray.map((_, pageIndex) => (
|
||||
<input
|
||||
class="autoscrolling-images__radio"
|
||||
type="radio"
|
||||
name="autoscrolling-images__radio"
|
||||
value={pageIndex}
|
||||
id={`${radioButtonIdPrefix}-autoscrolling-images__radio-${pageIndex}`}
|
||||
checked={pageIndex === 0}
|
||||
data-action="autoscrolling-images#handleRadiochange"
|
||||
/>
|
||||
))}
|
||||
<div class="autoscrolling-images__arrow-carousel-container">
|
||||
<div class="autoscrolling-images__arrow-carousel">
|
||||
{parsedImagesArray.map((_, pageIndex) => (
|
||||
<div class="autoscrolling-images__arrow-container">
|
||||
<label
|
||||
for={`${radioButtonIdPrefix}-autoscrolling-images__radio-${
|
||||
pageIndex == 0
|
||||
? parsedImagesArray.length - 1
|
||||
: pageIndex - 1
|
||||
}`}
|
||||
class="autoscrolling-images__arrow"
|
||||
>
|
||||
<img
|
||||
class="autoscrolling-images__img-arrow-left"
|
||||
src={arrow.url}
|
||||
/>
|
||||
</label>
|
||||
<label
|
||||
for={`${radioButtonIdPrefix}-autoscrolling-images__radio-${
|
||||
pageIndex == parsedImagesArray.length - 1
|
||||
? 0
|
||||
: pageIndex + 1
|
||||
}`}
|
||||
class="autoscrolling-images__arrow"
|
||||
>
|
||||
<img src={arrow.url} />
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div class="autoscrolling-images__imgs-carousel">
|
||||
<div
|
||||
class="autoscrolling-images__carousel"
|
||||
style={`--animation-length: ${numberOfImages}s`}
|
||||
>
|
||||
{parsedImagesArray.map((page) => (
|
||||
<div class="autoscrolling-images__carousel-page">
|
||||
{page.map((image) => (
|
||||
<div class="autoscrolling-images__img-wrapper">
|
||||
{render_image(image.image, {
|
||||
container: {
|
||||
width: 288,
|
||||
height: 150,
|
||||
objectFit: "contain",
|
||||
},
|
||||
alt: image.alt,
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div class="autoscrolling-images__dots-container">
|
||||
{parsedImagesArray.map((pageIndex) => (
|
||||
<label
|
||||
for={`${radioButtonIdPrefix}-autoscrolling-images__radio-${pageIndex}`}
|
||||
class="autoscrolling-images__dots"
|
||||
></label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
import { Controller } from "stimulus";
|
||||
|
||||
export default class AutoscrollingImages extends Controller {
|
||||
currentIndex = 0;
|
||||
interval_id: number;
|
||||
|
||||
getInterval(): number {
|
||||
return parseInt(
|
||||
this.element.getAttribute("data-autoscrolling-images-interval") || "5"
|
||||
);
|
||||
}
|
||||
|
||||
getRadioButtons(): Array<HTMLInputElement> {
|
||||
return Array.from(this.element.querySelectorAll(".autoscrolling-images__radio"));
|
||||
}
|
||||
|
||||
handleRadioChange() {
|
||||
const selectedRadio = this.getRadioButtons().findIndex(
|
||||
(radio: HTMLInputElement) => radio.checked
|
||||
);
|
||||
this.currentIndex = selectedRadio !== -1 ? selectedRadio : 0;
|
||||
}
|
||||
|
||||
async connect() {
|
||||
this.currentIndex = 0;
|
||||
|
||||
let intervalTime: number;
|
||||
const interval = this.getInterval();
|
||||
if (!interval) {
|
||||
intervalTime = interval * 1000;
|
||||
} else {
|
||||
intervalTime = 5000;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
this.interval_id = setInterval(
|
||||
() => this.next_slide(),
|
||||
intervalTime
|
||||
) as unknown as number;
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
clearInterval(this.interval_id);
|
||||
}
|
||||
|
||||
next_slide() {
|
||||
const carouselPages = this.element.querySelectorAll(
|
||||
".autoscrolling-images__carousel-page"
|
||||
);
|
||||
|
||||
const radioButtonIdPrefix = this.element
|
||||
.querySelector(".autoscrolling-images-wrapper")
|
||||
.getAttribute("data-carousel-id-prefix");
|
||||
|
||||
const nextIndex = (this.currentIndex + 1) % carouselPages.length;
|
||||
|
||||
const nextButton =
|
||||
radioButtonIdPrefix + "-autoscrolling-images__radio-" + nextIndex;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
(document.getElementById(nextButton) as HTMLInputElement).checked = true;
|
||||
|
||||
this.currentIndex = nextIndex;
|
||||
|
||||
// this.handleRadioChange();
|
||||
}
|
||||
}
|
@ -3,6 +3,9 @@ import { Registry } from "@sealcode/jdd";
|
||||
|
||||
export const registry = new Registry();
|
||||
|
||||
import { AutoscrollingImages } from "./autoscrolling-images/autoscrolling-images.jdd.js";
|
||||
registry.add("autoscrolling-images", AutoscrollingImages);
|
||||
|
||||
import { ImageDemo } from "./image-demo/image-demo.jdd.js";
|
||||
registry.add("image-demo", ImageDemo);
|
||||
|
||||
|
@ -79,6 +79,7 @@
|
||||
* {
|
||||
transition: all 150ms;
|
||||
}
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
@media (scripting: none) {
|
||||
|
@ -10,6 +10,9 @@ application.register("refresh-on-ts-changes", RefreshOnTsChanges);
|
||||
import { default as RefreshStyles } from "./../back/html-controllers/refresh-styles.stimulus.js";
|
||||
application.register("refresh-styles", RefreshStyles);
|
||||
|
||||
import { default as AutoscrollingImages } from "./../back/jdd-components/autoscrolling-images/autoscrolling-images.stimulus.js";
|
||||
application.register("autoscrolling-images", AutoscrollingImages);
|
||||
|
||||
import { default as MapWithPins } from "./../back/jdd-components/map-with-pins/map-with-pins.stimulus.js";
|
||||
application.register("map-with-pins", MapWithPins);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* DO NOT EDIT! This file is generated automaticaly with npx sealgen generate-css-includes */
|
||||
|
||||
@import "../node_modules/@sealcode/sealgen/src/forms/forms.css";
|
||||
@import "back/jdd-components/autoscrolling-images/autoscrolling-images.css";
|
||||
@import "back/jdd-components/image-demo/image-demo.css";
|
||||
@import "back/jdd-components/map-with-pins/map-with-pins.css";
|
||||
@import "back/jdd-components/nice-box/nice-box.css";
|
||||
|
Loading…
x
Reference in New Issue
Block a user