mirror of
https://github.com/dathere/qsvpro.dathere.com.git
synced 2025-12-18 21:59:24 +00:00
chore: lazy load images and hide download button on vertical mobile view
This commit is contained in:
parent
6d0f0d2177
commit
e65a720026
2 changed files with 133 additions and 123 deletions
|
|
@ -1,68 +1,68 @@
|
|||
import React, { useState, useEffect, useCallback } from 'react'
|
||||
import useEmblaCarousel from 'embla-carousel-react'
|
||||
import { Thumb } from './EmblaCarouselThumbsButton'
|
||||
|
||||
const EmblaCarousel = (props) => {
|
||||
const { slides, options, plugins } = props
|
||||
const [selectedIndex, setSelectedIndex] = useState(0)
|
||||
const [emblaMainRef, emblaMainApi] = useEmblaCarousel(options, plugins)
|
||||
const [emblaThumbsRef, emblaThumbsApi] = useEmblaCarousel({
|
||||
containScroll: 'keepSnaps',
|
||||
dragFree: true,
|
||||
}
|
||||
)
|
||||
|
||||
const onThumbClick = useCallback(
|
||||
(index) => {
|
||||
if (!emblaMainApi || !emblaThumbsApi) return
|
||||
emblaMainApi.scrollTo(index)
|
||||
},
|
||||
[emblaMainApi, emblaThumbsApi]
|
||||
)
|
||||
|
||||
const onSelect = useCallback(() => {
|
||||
if (!emblaMainApi || !emblaThumbsApi) return
|
||||
setSelectedIndex(emblaMainApi.selectedScrollSnap())
|
||||
emblaThumbsApi.scrollTo(emblaMainApi.selectedScrollSnap())
|
||||
}, [emblaMainApi, emblaThumbsApi, setSelectedIndex])
|
||||
|
||||
useEffect(() => {
|
||||
if (!emblaMainApi) return
|
||||
onSelect()
|
||||
|
||||
emblaMainApi.on('select', onSelect).on('reInit', onSelect)
|
||||
}, [emblaMainApi, onSelect])
|
||||
|
||||
return (
|
||||
<div className="embla">
|
||||
<div className="embla__viewport lg:mb-4" ref={emblaMainRef}>
|
||||
<div className="embla__container">
|
||||
{slides.map((slide, index) => (
|
||||
<div key={index} className="embla__slide space-y-2">
|
||||
<img src={slide.image.src} alt="qsv pro feature demo GIF" className={index === slides.length - 1 ? `border-4 rounded h-[35rem] mx-auto border-zinc-600` : `border-4 rounded border-zinc-600`} />
|
||||
<h2 className="text-2xl font-bold pt-4 text-[#F2F2F2]">{slide.title}</h2>
|
||||
<p className="text-lg text-center text-[#F2F2F2]">{slide.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="embla-thumbs">
|
||||
<div className="embla-thumbs__viewport" ref={emblaThumbsRef}>
|
||||
<div className="embla-thumbs__container flex gap-2 w-full justify-evenly">
|
||||
{slides.map((slide, index) => (
|
||||
<Thumb
|
||||
key={index}
|
||||
onClick={() => onThumbClick(index)}
|
||||
selected={index === selectedIndex}
|
||||
index={slide}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default EmblaCarousel
|
||||
import React, { useState, useEffect, useCallback } from 'react'
|
||||
import useEmblaCarousel from 'embla-carousel-react'
|
||||
import { Thumb } from './EmblaCarouselThumbsButton'
|
||||
|
||||
const EmblaCarousel = (props) => {
|
||||
const { slides, options, plugins } = props
|
||||
const [selectedIndex, setSelectedIndex] = useState(0)
|
||||
const [emblaMainRef, emblaMainApi] = useEmblaCarousel(options, plugins)
|
||||
const [emblaThumbsRef, emblaThumbsApi] = useEmblaCarousel({
|
||||
containScroll: 'keepSnaps',
|
||||
dragFree: true,
|
||||
}
|
||||
)
|
||||
|
||||
const onThumbClick = useCallback(
|
||||
(index) => {
|
||||
if (!emblaMainApi || !emblaThumbsApi) return
|
||||
emblaMainApi.scrollTo(index)
|
||||
},
|
||||
[emblaMainApi, emblaThumbsApi]
|
||||
)
|
||||
|
||||
const onSelect = useCallback(() => {
|
||||
if (!emblaMainApi || !emblaThumbsApi) return
|
||||
setSelectedIndex(emblaMainApi.selectedScrollSnap())
|
||||
emblaThumbsApi.scrollTo(emblaMainApi.selectedScrollSnap())
|
||||
}, [emblaMainApi, emblaThumbsApi, setSelectedIndex])
|
||||
|
||||
useEffect(() => {
|
||||
if (!emblaMainApi) return
|
||||
onSelect()
|
||||
|
||||
emblaMainApi.on('select', onSelect).on('reInit', onSelect)
|
||||
}, [emblaMainApi, onSelect])
|
||||
|
||||
return (
|
||||
<div className="embla">
|
||||
<div className="embla__viewport lg:mb-4" ref={emblaMainRef}>
|
||||
<div className="embla__container">
|
||||
{slides.map((slide, index) => (
|
||||
<div key={index} className="embla__slide space-y-2">
|
||||
<img decoding="async" loading="lazy" src={slide.image.src} alt="qsv pro feature demo GIF" className={index === slides.length - 1 ? `border-4 rounded h-[35rem] mx-auto border-zinc-600` : `border-4 rounded border-zinc-600`} />
|
||||
<h2 className="text-2xl font-bold pt-4 text-[#F2F2F2]">{slide.title}</h2>
|
||||
<p className="text-lg text-center text-[#F2F2F2]">{slide.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="embla-thumbs">
|
||||
<div className="embla-thumbs__viewport" ref={emblaThumbsRef}>
|
||||
<div className="embla-thumbs__container flex gap-2 w-full justify-evenly">
|
||||
{slides.map((slide, index) => (
|
||||
<Thumb
|
||||
key={index}
|
||||
onClick={() => onThumbClick(index)}
|
||||
selected={index === selectedIndex}
|
||||
index={slide}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default EmblaCarousel
|
||||
|
|
|
|||
|
|
@ -105,13 +105,17 @@ export const Hero = () => {
|
|||
transition={{ duration: 0.5, delay: 0.1 }}
|
||||
>
|
||||
<div className="text-customGrayText text-sm lg:text-base xl:text-lg sm:text-base mt-10 px-12 sm:px-48 ">
|
||||
Transform spreadsheet data and view statistics in interactive data tables, download/upload from/to compatible <a
|
||||
Transform spreadsheet data and view statistics in
|
||||
interactive data tables, download/upload from/to
|
||||
compatible{" "}
|
||||
<a
|
||||
href="https://ckan.org"
|
||||
target="_blank"
|
||||
className="text-blue-300"
|
||||
>
|
||||
CKAN
|
||||
</a> instances, and explore qsv pro.
|
||||
</a>{" "}
|
||||
instances, and explore qsv pro.
|
||||
</div>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
|
|
@ -121,62 +125,63 @@ export const Hero = () => {
|
|||
>
|
||||
<div className="grid grid-cols-1 place-items-center gap-2 sm:flex-row mt-14 mb-24 sm:mb-40 justify-center">
|
||||
{downloadData && OS !== "unknown" ? (
|
||||
<>
|
||||
<p className="text-white text-md text-center mx-auto mb-4">
|
||||
Download qsv pro and explore the free plan
|
||||
or unlock features with a paid plan.
|
||||
</p>
|
||||
<div className="flex justify-center">
|
||||
{Object.keys(downloadData).map(
|
||||
(platform) => (
|
||||
<div
|
||||
key={platform}
|
||||
className={`mx-4 ${
|
||||
platform === OS
|
||||
? "text-white text-xl font-bold"
|
||||
: "text-white"
|
||||
}`}
|
||||
>
|
||||
{downloadData[platform].map(
|
||||
(download, index) => (
|
||||
<>
|
||||
{platform ===
|
||||
"windows" && (
|
||||
<div className="flex justify-center">
|
||||
<a href="https://apps.microsoft.com/detail/xpffdj3f1jsztf?mode=full">
|
||||
<img
|
||||
src="https://get.microsoft.com/images/en-us%20light.svg"
|
||||
width="200"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<a
|
||||
key={index}
|
||||
href={`https://github.com/dathere/qsv-pro-releases/releases/download/${name}/${download[1]}`} // Replace with actual download path
|
||||
className={`block lg:min-w-96 text-white font-bold py-2 px-4 rounded mt-4 ${
|
||||
platform ===
|
||||
OS
|
||||
? " bg-teal-600 hover:bg-teal-700"
|
||||
: " bg-blue-500 hover:bg-blue-700"
|
||||
}`}
|
||||
download
|
||||
>
|
||||
{download[0]}
|
||||
</a>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
<>
|
||||
<p className="text-white text-md text-center mx-auto mb-4">
|
||||
Download qsv pro and explore the free plan
|
||||
or unlock features with a paid plan.
|
||||
</p>
|
||||
<div className="flex justify-center">
|
||||
{Object.keys(downloadData).map(
|
||||
(platform) => (
|
||||
<div
|
||||
key={platform}
|
||||
className={`mx-4 ${
|
||||
platform === OS
|
||||
? "text-white text-xl font-bold"
|
||||
: "text-white"
|
||||
}`}
|
||||
>
|
||||
{downloadData[platform].map(
|
||||
(download, index) => (
|
||||
<>
|
||||
{platform ===
|
||||
"windows" && (
|
||||
<div className="flex justify-center">
|
||||
<a href="https://apps.microsoft.com/detail/xpffdj3f1jsztf?mode=full">
|
||||
<img
|
||||
src="https://get.microsoft.com/images/en-us%20light.svg"
|
||||
width="200"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<a
|
||||
key={index}
|
||||
href={`https://github.com/dathere/qsv-pro-releases/releases/download/${name}/${download[1]}`} // Replace with actual download path
|
||||
className={`block lg:min-w-96 text-white font-bold py-2 px-4 rounded mt-4 ${
|
||||
platform ===
|
||||
OS
|
||||
? " bg-teal-600 hover:bg-teal-700"
|
||||
: " bg-blue-500 hover:bg-blue-700"
|
||||
}`}
|
||||
download
|
||||
>
|
||||
{download[0]}
|
||||
</a>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<a
|
||||
href="https://github.com/dathere/qsv-pro-releases/releases/latest"
|
||||
target="_blank"
|
||||
className="hidden md:block"
|
||||
>
|
||||
<div className="custom-button-colored w-64 h-12 mb-2 sm:mb-0">
|
||||
<Download />
|
||||
|
|
@ -185,8 +190,13 @@ export const Hero = () => {
|
|||
</span>
|
||||
</div>
|
||||
</a>
|
||||
<p className="md:hidden text-white sm:text-base text-sm text-center mx-auto">
|
||||
You may access download links here on a
|
||||
desktop device.
|
||||
</p>
|
||||
<p className="text-white text-sm sm:text-base text-center mx-auto">
|
||||
Download qsv pro and explore the free plan or unlock features with a paid plan.
|
||||
Download qsv pro and explore the free plan
|
||||
or unlock features with a paid plan.
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
|
|
@ -206,7 +216,7 @@ export const Hero = () => {
|
|||
>
|
||||
<div className="relative w-full flex justify-center">
|
||||
<FeatureCarousel />
|
||||
{/*<img
|
||||
{/*<img
|
||||
src={dashboard.src}
|
||||
alt="123"
|
||||
className="w-4/5 2xl:w-[1200px] mx-auto absolute z-10 rounded-xl custom-border-gray hero-dashboard-border-gradient lg:top-6 xl:top-0"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue