Sections

Tabs with horizontal Swiper

05 Jul 2023

Tabs with animation current tab indicator
HTML
SCSS
PostCSS
JS
                            <section class="section services">
	<div class="cont">
		<h2 class="section__title" data-aos="fade-right">Services</h2>
		<div class="services__main-title" data-aos="fade-right">
			Huntress Services
		</div>
		<div class="services-list-slider" data-aos="fade-up">
			<div class="swiper-wrapper">
				<div class="swiper-slide" data-adaptive-cursor="invert">
					<div class="text">Volume Recruitment</div>
				</div>
				<div class="swiper-slide" data-adaptive-cursor="invert">
					Payroll Services
				</div>
				<!--  -->
				<div class="swiper-slide" data-adaptive-cursor="invert">
					Delivery into Managed Service
				</div>
				<div class="swiper-slide" data-adaptive-cursor="invert">
					Exclusive Partnerships
				</div>
				<div class="swiper-slide" data-adaptive-cursor="invert">
					Urgent Cover
				</div>
				<div class="swiper-slide" data-adaptive-cursor="invert">
					CSS Non-surgical staffing
				</div>
			</div>
		</div>
		<div class="services-info-slider" data-aos="fade-up">
			<div class="swiper-wrapper">
				<div class="swiper-slide">
					<div class="services-info-slider__slide">
						<div class="services-info-slider__slide-text">
							A dedicated recruitment coordinator, experienced in volume
							campaigns, will fully manage the process from advertising to
							interviews to the first day in the role.
						</div>
						<div class="services-info-slider__slide-btns">
							<button class="btn">More about this service</button>
							<button class="btn outline-btn">Contact us</button>
						</div>
					</div>
				</div>
				<div class="swiper-slide">
					<div class="services-info-slider__slide">
						<div class="services-info-slider__slide-text">
							Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid,
							iure.
						</div>
						<div class="services-info-slider__slide-btns">
							<button class="btn">More about this service</button>
							<button class="btn outline-btn">Contact us</button>
						</div>
					</div>
				</div>
				<div class="swiper-slide">
					<div class="services-info-slider__slide">
						<div class="services-info-slider__slide-text">
							Lorem ipsum dolor sit amet, consectetur adipisicing elit. Illum,
							optio. Suscipit quos iure laboriosam ipsum possimus, nesciunt
							officiis harum alias magnam illo temporibus, impedit accusamus.
							Doloremque earum enim atque incidunt.
						</div>
						<div class="services-info-slider__slide-btns">
							<button class="btn">More about this service</button>
							<button class="btn outline-btn">Contact us</button>
						</div>
					</div>
				</div>
				<div class="swiper-slide">
					<div class="services-info-slider__slide">
						<div class="services-info-slider__slide-text">
							Lorem, ipsum dolor sit amet consectetur adipisicing elit.
							Obcaecati temporibus voluptatibus eveniet quisquam odit
							laboriosam!
						</div>
						<div class="services-info-slider__slide-btns">
							<button class="btn">More about this service</button>
							<button class="btn outline-btn">Contact us</button>
						</div>
					</div>
				</div>
				<div class="swiper-slide">
					<div class="services-info-slider__slide">
						<div class="services-info-slider__slide-text">
							Lorem ipsum dolor sit, amet consectetur adipisicing elit.
							Architecto.
						</div>
						<div class="services-info-slider__slide-btns">
							<button class="btn">More about this service</button>
							<button class="btn outline-btn">Contact us</button>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>
</section>

                        
                            .services-list-slider {
  --indicator-pos: 0px;
  --indicator-w: 50px;

  position: relative;
  z-index: 1;

  margin-bottom: ac(50px, 40px);

  background: var(--light-bege);

  &.show-indicator {
    &::before {
      display: block;
    }
  }

  &::before {
    display: none;

    content: "";
    position: absolute;
    top: 50%;
    right: 0;
    z-index: 2;
    transform: translateY(-50%);

    width: 40px;
    height: 40px;

    border-radius: 999px;

    opacity: 0;
    background: var(--white);
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);

    pointer-events: none;
    transition: setTransition(transform);

    animation: swipe-animation 2000ms infinite;

    @keyframes swipe-animation {
      0% {
        opacity: 0;
        transform: translate(0px, -50%);
      }
      75% {
        opacity: 1;
        transform: translate(-70px, -50%);
      }
      100% {
        opacity: 0;
        transform: translate(-70px, -50%);
      }
    }
  }

  .swiper-wrapper {
    padding-bottom: 17px;

    &::before {
      content: "";
      position: absolute;
      top: 100%;
      left: 0;
      transform: translateY(-50%);

      /* width: 100%; */
      width: var(--line-w);
      height: 2px;

      border-radius: 999px;

      background: var(--galaxy-cl);
    }

    &::after {
      content: "";
      position: absolute;
      top: 100%;
      left: var(--indicator-pos);
      transform: translateY(-50%);

      width: var(--indicator-w);
      height: 5px;

      border-radius: 999px;

      background: var(--primary-cl);
      transition: setTransition(width, left);
    }
  }

  .swiper-slide {
    width: fit-content;

    font-size: 18px;

    cursor: pointer;
  }
}

.services-list-indicator {
  position: absolute;
  top: 100%;
  transform: translateY(-50%);

  width: 50px;
  height: 5px;

  border-radius: 999px;

  background: var(--primary-cl);
}

.services-info-slider__slide {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: ac(40px, 30px);

  @include media(769) {
    flex-direction: column;
  }
}

.services-info-slider__slide-text {
  max-width: 740px;

  font-size: ac(22px, 18px);
  line-height: 1.45;
}

.services-info-slider__slide-btns {
  display: flex;
  align-items: center;
  justify-content: end;
  gap: ac(25px, 20px);
  flex-grow: 1;
  flex-shrink: 0;

  @include media(769) {
    flex-wrap: wrap;
    justify-content: start;
  }

  @include media(651) {
    flex-direction: column;
    align-items: start;
  }
}
                        
                            .services-list-slider {
	--indicator-pos: 0px;
	--indicator-w: 50px;

	position: relative;
	z-index: 1;

	margin-bottom: ac(50px, 40px);

	background: var(--light-bege);

	&.show-indicator {
		&::before {
			display: block;
		}
	}

	&::before {
		display: none;

		content: "";
		position: absolute;
		top: 50%;
		right: 0;
		z-index: 2;
		transform: translateY(-50%);

		width: 40px;
		height: 40px;

		border-radius: 999px;

		opacity: 0;
		background: var(--white);
		box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);

		pointer-events: none;
		transition: setTransition(transform);

		animation: swipe-animation 2000ms infinite;

		@keyframes swipe-animation {
			0% {
				opacity: 0;
				transform: translate(0px, -50%);
			}
			75% {
				opacity: 1;
				transform: translate(-70px, -50%);
			}
			100% {
				opacity: 0;
				transform: translate(-70px, -50%);
			}
		}
	}

	.swiper-wrapper {
		padding-bottom: 17px;

		&::before {
			content: "";
			position: absolute;
			top: 100%;
			left: 0;
			transform: translateY(-50%);

			/* width: 100%; */
			width: var(--line-w);
			height: 2px;

			border-radius: 999px;

			background: var(--galaxy-cl);
		}

		&::after {
			content: "";
			position: absolute;
			top: 100%;
			left: var(--indicator-pos);
			transform: translateY(-50%);

			width: var(--indicator-w);
			height: 5px;

			border-radius: 999px;

			background: var(--primary-cl);
			transition: setTransition(width, left);
		}
	}

	.swiper-slide {
		width: fit-content;

		font-size: 18px;

		cursor: pointer;
	}
}

.services-list-indicator {
	position: absolute;
	top: 100%;
	transform: translateY(-50%);

	width: 50px;
	height: 5px;

	border-radius: 999px;

	background: var(--primary-cl);
}

.services-info-slider__slide {
	display: flex;
	align-items: start;
	justify-content: space-between;
	gap: ac(40px, 30px);

	@mixin media 769 {
		flex-direction: column;
	}
}

.services-info-slider__slide-text {
	max-width: 740px;

	font-size: ac(22px, 18px);
	line-height: 1.45;
}

.services-info-slider__slide-btns {
	display: flex;
	align-items: center;
	justify-content: end;
	gap: ac(25px, 20px);
	flex-grow: 1;
	flex-shrink: 0;

	@mixin media 769 {
		flex-wrap: wrap;
		justify-content: start;
	}

	@mixin media 651 {
		flex-direction: column;
		align-items: start;
	}
}
                        
                            import { valueObserver } from "./meta-settings.js";

const servicesSection = document.querySelector(".services");
if (servicesSection) {
	const servicesListSlider = servicesSection.querySelector(
		".services-list-slider"
	);
	const serviceItems = servicesListSlider.querySelectorAll(".swiper-slide");

	if (servicesListSlider) {
		const servicesListSwiper = new Swiper(servicesListSlider, {
			freeMode: true,
			slidesPerView: "auto",
			spaceBetween: 50,
			on: {
				afterInit({ wrapperEl, isEnd }) {
					if (!isEnd) servicesListSlider.classList.add("show-indicator");

					servicesListSlider.style.setProperty(
						"--line-w",
						wrapperEl.scrollWidth + "px"
					);
				},
				sliderMove() {
					servicesListSlider.classList.remove("show-indicator");
				},
			},
		});
	}

	const serviceInfoSlider = servicesSection.querySelector(
		".services-info-slider"
	);

	let serviceInfoSwiper = null;

	if (serviceInfoSlider) {
		serviceInfoSwiper = new Swiper(serviceInfoSlider, {
			slidesPerView: 1,
			effect: "fade",
			// autoHeight: true,
			fadeEffect: {
				crossFade: true,
			},
		});
	}

	const handleServiceClick = (idx) => {
		const el = serviceItems[idx];
		servicesListSlider.style.setProperty(
			"--indicator-pos",
			el.offsetLeft + "px"
		);
		servicesListSlider.style.setProperty(
			"--indicator-w",
			el.clientWidth + "px"
		);

		serviceInfoSwiper.slideTo(idx);
	};

	const activeServiceIdx = valueObserver(0, handleServiceClick, true);

	serviceItems.forEach((item, idx) =>
		item.addEventListener("click", () => (activeServiceIdx.value = idx))
	);
}
                        
0