From 7abc419b97a994e7f69dfa1d0d929b5d8d34342a Mon Sep 17 00:00:00 2001 From: Nijat Babakhanov Date: Sun, 7 Apr 2024 17:48:54 +0200 Subject: [PATCH] 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 --- .eslintrc.cjs | 1 + .hintrc | 2 +- .../autoscrolling-images-arrow.svg | 3 + .../autoscrolling-images.css | 177 ++++++++++++++++++ .../autoscrolling-images.jdd.tsx | 164 ++++++++++++++++ .../autoscrolling-images.stimulus.ts | 67 +++++++ src/back/jdd-components/components.ts | 3 + src/back/routes/components.css | 1 + src/front/controllers.ts | 3 + src/includes.css | 1 + 10 files changed, 421 insertions(+), 1 deletion(-) create mode 100644 src/back/jdd-components/autoscrolling-images/autoscrolling-images-arrow.svg create mode 100644 src/back/jdd-components/autoscrolling-images/autoscrolling-images.css create mode 100644 src/back/jdd-components/autoscrolling-images/autoscrolling-images.jdd.tsx create mode 100644 src/back/jdd-components/autoscrolling-images/autoscrolling-images.stimulus.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 73bbdb3..7df9ee9 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -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, diff --git a/.hintrc b/.hintrc index 29b634a..593bc8e 100644 --- a/.hintrc +++ b/.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", { diff --git a/src/back/jdd-components/autoscrolling-images/autoscrolling-images-arrow.svg b/src/back/jdd-components/autoscrolling-images/autoscrolling-images-arrow.svg new file mode 100644 index 0000000..03dd402 --- /dev/null +++ b/src/back/jdd-components/autoscrolling-images/autoscrolling-images-arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/back/jdd-components/autoscrolling-images/autoscrolling-images.css b/src/back/jdd-components/autoscrolling-images/autoscrolling-images.css new file mode 100644 index 0000000..87438cd --- /dev/null +++ b/src/back/jdd-components/autoscrolling-images/autoscrolling-images.css @@ -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; + } +} diff --git a/src/back/jdd-components/autoscrolling-images/autoscrolling-images.jdd.tsx b/src/back/jdd-components/autoscrolling-images/autoscrolling-images.jdd.tsx new file mode 100644 index 0000000..bce8bef --- /dev/null +++ b/src/back/jdd-components/autoscrolling-images/autoscrolling-images.jdd.tsx @@ -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 { + getArguments() { + return component_arguments; + } + + toHTML( + { + title, + interval, + imagesPerPage, + images, + }: ExtractStructuredComponentArgumentsValues, + { 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 ( +
+ + +
+
+

{titleUpperCase}

+
+ + +
+
+ ); + } +} diff --git a/src/back/jdd-components/autoscrolling-images/autoscrolling-images.stimulus.ts b/src/back/jdd-components/autoscrolling-images/autoscrolling-images.stimulus.ts new file mode 100644 index 0000000..d4b1934 --- /dev/null +++ b/src/back/jdd-components/autoscrolling-images/autoscrolling-images.stimulus.ts @@ -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 { + 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(); + } +} diff --git a/src/back/jdd-components/components.ts b/src/back/jdd-components/components.ts index 647173c..3d8516d 100644 --- a/src/back/jdd-components/components.ts +++ b/src/back/jdd-components/components.ts @@ -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); diff --git a/src/back/routes/components.css b/src/back/routes/components.css index c19070c..d6389de 100644 --- a/src/back/routes/components.css +++ b/src/back/routes/components.css @@ -79,6 +79,7 @@ * { transition: all 150ms; } + container-type: inline-size; } @media (scripting: none) { diff --git a/src/front/controllers.ts b/src/front/controllers.ts index 900e884..07343c1 100644 --- a/src/front/controllers.ts +++ b/src/front/controllers.ts @@ -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); diff --git a/src/includes.css b/src/includes.css index 711a57f..f1031be 100644 --- a/src/includes.css +++ b/src/includes.css @@ -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";