Added ImageCarousel component to product pages.
This commit is contained in:
parent
10b7d1c799
commit
a3483ccda9
211
src/components/ImageCarousel.astro
Normal file
211
src/components/ImageCarousel.astro
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
---
|
||||||
|
import type { Brand } from '../data/brands/brand';
|
||||||
|
|
||||||
|
export interface Image {
|
||||||
|
src: string;
|
||||||
|
alt?: string;
|
||||||
|
title?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
images: Image[];
|
||||||
|
dots: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { images } = Astro.props;
|
||||||
|
let index = 1;
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Slideshow container -->
|
||||||
|
<image-carousel>
|
||||||
|
<!-- Full-width images with number and caption text -->
|
||||||
|
{images?.map(image => (
|
||||||
|
<div class="carousel-slide carousel-fade">
|
||||||
|
<div class="carousel-number">
|
||||||
|
{index++} / {images.length}
|
||||||
|
</div>
|
||||||
|
<img class="carousel-img" src={image.src} defer />
|
||||||
|
{image.title &&
|
||||||
|
<div class="carousel-caption" class="text">
|
||||||
|
{image.title}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<!-- Next and previous buttons -->
|
||||||
|
<div class="carousel-btn-prev">
|
||||||
|
<a>
|
||||||
|
<span>❮</span>
|
||||||
|
<div class="dummy"></div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="carousel-btn-next">
|
||||||
|
<a>
|
||||||
|
<span>❯</span>
|
||||||
|
<div class="dummy"></div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</image-carousel>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
class ImageCarousel extends HTMLElement {
|
||||||
|
slideIndex: number;
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.slideIndex = 1;
|
||||||
|
const prevButton = $(this).find('.carousel-btn-prev');
|
||||||
|
const nextButton = $(this).find('.carousel-btn-next');
|
||||||
|
prevButton.click((evt: Event) => {
|
||||||
|
this.plusSlides(-1);
|
||||||
|
});
|
||||||
|
nextButton.click((evt: Event) => {
|
||||||
|
this.plusSlides(1);
|
||||||
|
});
|
||||||
|
this.showSlide(this.slideIndex);
|
||||||
|
}
|
||||||
|
slidesCount() {
|
||||||
|
return $(this).find('.carousel-slide').length || 0;
|
||||||
|
}
|
||||||
|
plusSlides(plusIncrement) {
|
||||||
|
this.showSlide(this.slideIndex + plusIncrement);
|
||||||
|
}
|
||||||
|
showSlide(slideIndex) {
|
||||||
|
const firstSlide = 1;
|
||||||
|
const slidesCount = this.slidesCount();
|
||||||
|
if (slideIndex < firstSlide) slideIndex = slidesCount;
|
||||||
|
if (slideIndex > slidesCount) slideIndex = 1;
|
||||||
|
this.slideIndex = slideIndex;
|
||||||
|
let slides = $(this).find('.carousel-slide');
|
||||||
|
slides.each((index) => $(slides[index]).toggleClass('carousel-slide-current', false));
|
||||||
|
$(slides[slideIndex-1]).toggleClass('carousel-slide-current', true);
|
||||||
|
console.log("Showing slide " + slideIndex + " of " + slidesCount + ".");
|
||||||
|
// var dots = $(carousel).find('.carousel-dot');
|
||||||
|
// for (var i = 0; i < dots.length; i++) {
|
||||||
|
// dots[i].className = dots[i].className.replace(" active", "");
|
||||||
|
// }
|
||||||
|
// dots[slideIndex-1].className += " active";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customElements.define('image-carousel', ImageCarousel);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
image-carousel {
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
.carousel-slide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.carousel-slide-current {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
.carousel-slide img {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
.carousel-btn-prev, .carousel-btn-next {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 40px;
|
||||||
|
height: 100%;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 18px;
|
||||||
|
transition: 0.6s ease;
|
||||||
|
text-decoration: none;
|
||||||
|
user-select: none;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 0;
|
||||||
|
display: flex;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.carousel-btn-prev {
|
||||||
|
border-radius: 7px 0 0 7px;
|
||||||
|
}
|
||||||
|
.carousel-btn-next {
|
||||||
|
right: 0;
|
||||||
|
border-radius: 0 7px 7px 0;
|
||||||
|
}
|
||||||
|
.carousel-btn-prev > a, .carousel-btn-next > a {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.carousel-btn-prev .dummy, .carousel-btn-next .dummy {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.carousel-btn-prev span, .carousel-btn-next span {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
position: relative;
|
||||||
|
top: 50%;
|
||||||
|
}
|
||||||
|
.carousel-btn-prev:is(:hover, :focus-within) > a, .carousel-btn-next:is(:hover, ::focus-within) > a {
|
||||||
|
background-color: #23262d;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.carousel-btn-prev:is(:hover, :focus-within), .carousel-btn-next:is(:hover, :focus-within) {
|
||||||
|
background-color: #23262d;
|
||||||
|
background-image: none;
|
||||||
|
background-size: 400%;
|
||||||
|
background-position: 100%;
|
||||||
|
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
|
||||||
|
background-position: 0;
|
||||||
|
background-image: var(--accent-gradient);
|
||||||
|
background-size: 400%;
|
||||||
|
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
.carousel-caption {
|
||||||
|
color: #000;
|
||||||
|
font-size: 15px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 8px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
filter: invert(1);
|
||||||
|
mix-blend-mode: difference;
|
||||||
|
}
|
||||||
|
.carousel-number {
|
||||||
|
color: #000;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 800;
|
||||||
|
padding: 8px 12px;
|
||||||
|
position: absolute;
|
||||||
|
left: 3em;
|
||||||
|
top: 0;
|
||||||
|
filter: invert(1);
|
||||||
|
mix-blend-mode: difference;
|
||||||
|
}
|
||||||
|
.carousel-dot {
|
||||||
|
cursor: pointer;
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
margin: 0 2px;
|
||||||
|
background-color: #bbb;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
transition: background-color 0.6s ease;
|
||||||
|
}
|
||||||
|
.active, .dot:hover {
|
||||||
|
background-color: #717171;
|
||||||
|
}
|
||||||
|
.carousel-fade {
|
||||||
|
animation-name: fade;
|
||||||
|
animation-duration: 1.5s;
|
||||||
|
}
|
||||||
|
@keyframes .carousel-fade {
|
||||||
|
from {opacity: .4}
|
||||||
|
to {opacity: 1}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -49,6 +49,7 @@ const { product } = Astro.props;
|
||||||
}
|
}
|
||||||
.product-card a img {
|
.product-card a img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
border-radius: 7px;
|
||||||
}
|
}
|
||||||
.product-card h2 {
|
.product-card h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
|
@ -52,16 +52,15 @@ delivery drivers like you.
|
||||||
"reviewCount": 917,
|
"reviewCount": 917,
|
||||||
"reviewRating": 4.6,
|
"reviewRating": 4.6,
|
||||||
"imageUrls": [
|
"imageUrls": [
|
||||||
// "https://m.media-amazon.com/images/I/31T40IfMVAL._AC_US100_.jpg",
|
|
||||||
"/assets/products/coast-polysteel-600/coast_polysteel200_master.png",
|
"/assets/products/coast-polysteel-600/coast_polysteel200_master.png",
|
||||||
"/assets/products/coast-polysteel-600/PS600-RevC-v02-C-Aplus_1500x1500_Slider-Twist_Focus_540x.png",
|
"/assets/products/coast-polysteel-600/PS600-RevC-v02-C-Aplus_1500x1500_Slider-Twist_Focus_540x.png",
|
||||||
"https://m.media-amazon.com/images/I/51ozxrobzGL._AC_SX466_.jpg",
|
"https://m.media-amazon.com/images/I/31T40IfMVAL._AC_US600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/41Sea-gpNwL._AC_US100_.jpg",
|
"https://m.media-amazon.com/images/I/51ozxrobzGL._AC_SX600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/41KMMRWQNzL._AC_US100_.jpg",
|
"https://m.media-amazon.com/images/I/41Sea-gpNwL._AC_US600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/51Qr9m7qgYL._AC_US100_.jpg",
|
"https://m.media-amazon.com/images/I/41KMMRWQNzL._AC_US600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/41-a5yLMVJL._AC_US100_.jpg",
|
"https://m.media-amazon.com/images/I/51Qr9m7qgYL._AC_US600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/41ESFePPBzL._AC_US100_.jpg",
|
"https://m.media-amazon.com/images/I/41-a5yLMVJL._AC_US600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/413guhKjtVL.SS125_PKplay-button-mb-image-grid-small_.jpg"
|
"https://m.media-amazon.com/images/I/41ESFePPBzL._AC_US600_.jpg"
|
||||||
],
|
],
|
||||||
"attributes": [
|
"attributes": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,13 +50,12 @@ need to treat minor injuries on the go.
|
||||||
"reviewRating": 4.7,
|
"reviewRating": 4.7,
|
||||||
"imageUrls": [
|
"imageUrls": [
|
||||||
// "https://m.media-amazon.com/images/I/413sfboF0mL._SX38_SY50_CR,0,0,38,50_.jpg",
|
// "https://m.media-amazon.com/images/I/413sfboF0mL._SX38_SY50_CR,0,0,38,50_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/413sfboF0mL._SX466_.jpg",
|
"https://m.media-amazon.com/images/I/413sfboF0mL._US600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/51PHxfhu09L._SX38_SY50_CR,0,0,38,50_.jpg",
|
"https://m.media-amazon.com/images/I/51PHxfhu09L._US600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/41DrWanEf2L._SX38_SY50_CR,0,0,38,50_.jpg",
|
"https://m.media-amazon.com/images/I/41DrWanEf2L._US600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/51vA72L9CkL._SX38_SY50_CR,0,0,38,50_.jpg",
|
"https://m.media-amazon.com/images/I/51vA72L9CkL._US600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/41UoP-S+XuL._SX38_SY50_CR,0,0,38,50_.jpg",
|
"https://m.media-amazon.com/images/I/41UoP-S+XuL._US600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/51XP7Me5+IL._SX38_SY50_CR,0,0,38,50_.jpg",
|
"https://m.media-amazon.com/images/I/51XP7Me5+IL._US600_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/81jMWjiouFL._SX35_SY46._CR0,0,35,46_BG85,85,85_BR-120_PKdp-play-icon-overlay__.jpg"
|
|
||||||
],
|
],
|
||||||
"attributes": [
|
"attributes": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,13 +47,12 @@ with confidence and clarity - no matter what the road throws your way.
|
||||||
"reviewRating": 4.6,
|
"reviewRating": 4.6,
|
||||||
"imageUrls": [
|
"imageUrls": [
|
||||||
"/assets/products/invisible-glass-19oz-aerosol/1.webp",
|
"/assets/products/invisible-glass-19oz-aerosol/1.webp",
|
||||||
"https://m.media-amazon.com/images/I/41W-6PIvxJL._AC_US800_.jpg",
|
// "https://m.media-amazon.com/images/I/41W-6PIvxJL._AC_US800_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/41fFxMnl31L._AC_US40_.jpg",
|
"https://m.media-amazon.com/images/I/41fFxMnl31L._AC_US800_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/51Rm5XiNTeL._AC_US40_.jpg",
|
"https://m.media-amazon.com/images/I/51Rm5XiNTeL._AC_US800_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/41b0XOGqWUL._AC_US40_.jpg",
|
"https://m.media-amazon.com/images/I/41b0XOGqWUL._AC_US800_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/51x3gJxPv6L._AC_US40_.jpg",
|
"https://m.media-amazon.com/images/I/51x3gJxPv6L._AC_US800_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/51gFmD6h6lL._AC_US40_.jpg",
|
"https://m.media-amazon.com/images/I/51gFmD6h6lL._AC_US800_.jpg",
|
||||||
"https://m.media-amazon.com/images/I/51S48oPL+3L.SS40_BG85,85,85_BR-120_PKdp-play-icon-overlay__.jpg"
|
|
||||||
],
|
],
|
||||||
"attributes": [
|
"attributes": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,8 @@ const gTag = config.GoogleAnalyticsGTag;
|
||||||
<meta name="generator" content={Astro.generator} />
|
<meta name="generator" content={Astro.generator} />
|
||||||
<meta name="description" content="Your one-stop shop for all your after-market Dasher supplies." />
|
<meta name="description" content="Your one-stop shop for all your after-market Dasher supplies." />
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://code.jquery.com/ui/1.13.3/jquery-ui.min.js" integrity="sha256-sw0iNNXmOJbQhYFuC9OF2kOlD5KQKe1y5lfBn4C9Sjg=" crossorigin="anonymous"></script>
|
||||||
<script src="https://unpkg.com/htmx.org@1.9.9" integrity="sha384-QFjmbokDn2DjBjq+fM+8LUIVrAgqcNW2s0PjAxHETgRn9l4fvX31ZxDxvwQnyMOX" crossorigin="anonymous"></script>
|
<script src="https://unpkg.com/htmx.org@1.9.9" integrity="sha384-QFjmbokDn2DjBjq+fM+8LUIVrAgqcNW2s0PjAxHETgRn9l4fvX31ZxDxvwQnyMOX" crossorigin="anonymous"></script>
|
||||||
<script src={bootstrap}></script>
|
<script src={bootstrap}></script>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { type Category, ALL_CATEGORIES } from '../data/categories';
|
||||||
import { type Product, ALL_PRODUCTS } from '../data/products';
|
import { type Product, ALL_PRODUCTS } from '../data/products';
|
||||||
import { type Brand, ALL_BRANDS } from '../data/brands';
|
import { type Brand, ALL_BRANDS } from '../data/brands';
|
||||||
import StarRating from '../components/StarRating.astro';
|
import StarRating from '../components/StarRating.astro';
|
||||||
|
import ImageCarousel from '../components/ImageCarousel.astro';
|
||||||
import markdownIt from 'markdown-it';
|
import markdownIt from 'markdown-it';
|
||||||
import markdownItAttrs from 'markdown-it-attrs';
|
import markdownItAttrs from 'markdown-it-attrs';
|
||||||
const md = markdownIt({
|
const md = markdownIt({
|
||||||
|
@ -48,7 +49,14 @@ const brand: Brand = ALL_BRANDS.find(b => b.slug === product.brandStoreSlug)!;
|
||||||
</h2>
|
</h2>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
{product?.amazonProductDetails?.imageUrls !== undefined && <img src={product!.amazonProductDetails?.imageUrls[0]} alt={product?.amazonProductDetails?.title} style="max-width: 100%;" />}
|
{product?.amazonProductDetails?.imageUrls !== undefined &&
|
||||||
|
product?.amazonProductDetails?.imageUrls.length == 1 &&
|
||||||
|
<img src={product?.amazonProductDetails?.imageUrls[0]} alt={product?.amazonProductDetails?.title} style="max-width: 100%;" />
|
||||||
|
}
|
||||||
|
{product?.amazonProductDetails?.imageUrls !== undefined &&
|
||||||
|
product?.amazonProductDetails?.imageUrls.length > 1 &&
|
||||||
|
<ImageCarousel images={product?.amazonProductDetails?.imageUrls.map((productUrl) => { return { src: productUrl }; } )} />
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-8">
|
<div class="col-8">
|
||||||
<h5 class="card-title">
|
<h5 class="card-title">
|
||||||
|
|
Loading…
Reference in New Issue
Block a user