feat: update for qsv pro v1

This commit is contained in:
rzmk 2024-09-04 08:28:23 -04:00
parent 1749f461bb
commit 386708c082
No known key found for this signature in database
18 changed files with 324 additions and 115 deletions

BIN
bun.lockb

Binary file not shown.

View file

@ -14,6 +14,8 @@
"@astrojs/tailwind": "^5.1.0",
"@fontsource/inter": "^5.0.18",
"astro": "^4.7.1",
"embla-carousel-autoplay": "^8.2.1",
"embla-carousel-react": "^8.2.0",
"framer-motion": "^11.1.7",
"npm-check-updates": "^16.14.20",
"tailwindcss": "^3.4.3"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View file

@ -0,0 +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 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

View file

@ -0,0 +1,21 @@
import React from 'react'
export const Thumb = (props) => {
const { selected, index, onClick } = props
return (
<div
className={'embla-thumbs__slide'.concat(
selected ? ' embla-thumbs__slide--selected' : ''
)}
>
<button
onClick={onClick}
type="button"
className="embla-thumbs__slide__number border-4 border-zinc-600 rounded hover:brightness-110"
>
<img alt="qsv pro feature demo GIF thumbnail" width={200} src={index.image.src} />
</button>
</div>
)
}

View file

@ -5,34 +5,24 @@ import generateCkanApiToken from "../assets/images/faq/generate-ckan-api-token.p
const FAQData = [
{
question: "What is qsv pro?",
answer: "qsv pro is a spreadsheet data wrangling desktop application to view, transform, and upload data to CKAN with a graphical user interface based on the qsv CLI tool. It features a suite of recipes (scripts) for common data wrangling tasks to perform on your spreadsheet, including sorting rows, removing duplicate rows, and removing Personally Identifiable Information (PII).",
},
{
question: 'What does "preview" mean?',
answer: "qsv pro is currently in preview, which means that it may contain bugs and does not include all of the features that are planned in a stable release (features may also be removed). If you encounter any bugs or have any feature/feedback requests, you may contact us on our support site by creating a ticket.",
answer: "qsv pro is a desktop application to view and transform spreadsheet data (for example Microsoft Excel data and CSV) with a graphical user interface based on the qsv CLI tool. It includes multiple features for data wrangling and is available on compatible Windows, macOS, and Linux devices.",
links: [
{
label: "Support site",
url: "https://support.dathere.com",
label: "About datHere",
url: "https://dathere.com",
},
],
},
{
question: 'What does "experimental" mean?',
answer: "qsv pro may include experimental features that may not be fully functional/tested or may not be included in a stable release. If you encounter any bugs or have any feature/feedback requests, you may contact us on our support site by creating a ticket.",
links: [
{
label: "Support site",
url: "https://support.dathere.com",
label: "Learn to use qsv",
url: "https://100.dathere.com",
},
],
},
{
question: "How do I get qsv pro?",
answer: "You may download the latest version of qsv pro with a 7-day free trial (no payment method required) from the top of this page. During or after the trial, you may purchase a license to continue using qsv pro. You may choose between any of the installers for Windows (.msi), macOS (.app.tar.gz), and Linux (.AppImage).",
answer: "You may download the latest version of qsv pro from the top of this page. Within the app you may continue with the free plan or you may purchase a license key from store.dathere.com to use paid features. You may choose between any of the installers for Windows (.msi), macOS (.app.tar.gz), and Linux (.AppImage).",
links: [
{
label: "Purchase a license",
label: "Purchase a license key",
url: "https://store.dathere.com/checkout/buy/41f919fd-2b68-40ea-a5ed-0f531b2efba5",
},
],
@ -42,7 +32,7 @@ const FAQData = [
answer: "You may provide feedback on our support site by creating a ticket.",
links: [
{
label: "Support site",
label: "Contact support",
url: "https://support.dathere.com",
},
],
@ -57,6 +47,20 @@ const FAQData = [
},
],
},
{
question: "How can I use qsv pro on more than one device?",
answer: "Each license key can only be activated for 1 device at a time. If you used your license key on a device and want to use it on a different device, you may deactivate your license key by navigating to your billing information page then deactivate your license. Then you may activate your license key on your other device. If you need more than 1 device to use qsv pro at one time, you may purchase an additional license key.",
links: [
{
label: "Manage billing information",
url: "https://store.dathere.com/billing",
},
{
label: "Purchase a license key",
url: "https://store.dathere.com/checkout/buy/41f919fd-2b68-40ea-a5ed-0f531b2efba5",
},
],
},
{
question: "Where can I manage my billing information?",
answer: "You may manage your billing information at store.dathere.com/billing.",
@ -69,7 +73,41 @@ const FAQData = [
},
{
question: "Is there a light theme?",
answer: "Yes, you may change the theme with the sun/moon icon on the top right of qsv pro.",
answer: "Yes, you may change the theme with the sun/moon icon on the navigation panel of qsv pro.",
},
{
question: "Can I change the zoom size?",
answer: "Yes, you may change the zoom size in the settings panel of qsv pro.",
},
{
question: "What is qsv pro's current status?",
answer: "qsv pro has reached version 1, but that does not mean it cannot contain errors and features may still be added and/or improved. If you encounter any bugs or have any feature/feedback requests, you may contact us on our support site by creating a ticket.",
links: [
{
label: "Contact support",
url: "https://support.dathere.com",
},
],
},
{
question: 'Why is "experimental" mentioned?',
answer: "qsv pro may include \"experimental\" features that may not be fully functional/tested and may be outdated. If you encounter any bugs or have any feature/feedback requests, you may contact us on our support site by creating a ticket.",
links: [
{
label: "Contact support",
url: "https://support.dathere.com",
},
],
},
{
question: 'What is CKAN?',
answer: "CKAN is an open-source data management system used around the world. You may learn more at ckan.org.",
links: [
{
label: "CKAN website",
url: "https://ckan.org",
},
],
},
];

View file

@ -0,0 +1,70 @@
import React from 'react'
import flowDemo from "../assets/images/v1/flow-demo.gif";
import apiDemo from "../assets/images/v1/api-demo.gif";
import configuratorDemo from "../assets/images/v1/configurator-demo.gif";
import workflowDemo from "../assets/images/v1/drag-and-drop.gif";
import commandDemo from "../assets/images/v1/qsv-pro-command-demo.gif";
import toolboxDemo from "../assets/images/v1/toolbox-demo.gif";
import EmblaCarousel from './EmblaCarousel';
import Autoplay from 'embla-carousel-autoplay'
const FeatureCarousel = () => {
const SLIDES = [
{
title: "Workflow - Explore your spreadsheet data with interactive data tables",
description:
"Drag and drop your spreadsheet data into the qsv pro Workflow. Once imported successfully, you may browse statistics, frequency, and metadata about your file. Run Polars SQL queries and recipes, view your file with csvlens on Windows, search your file (optionally by regex), export to multiple file formats, download/upload from/to compatible CKAN instances, and more.",
image: workflowDemo,
},
{
title: "Flow - Build custom node-based flows and data pipelines",
description:
"Engineer data pipelines using an interactive node-based UI. Access multiple qsv commands and pipe them together along with custom nodes to architect data pipelines. Share or import your pipelines with other qsv pro users.",
image: flowDemo,
},
{
title: "Toolbox - Run scripts on your data based on use cases",
description:
'Run tools in qsv pro\'s Toolbox including scripts such as Copy CSV to clipboard, Sort CSV rows, Get CSV row count, and more.',
image: toolboxDemo,
},
{
title: "API - Interact with qsv pro using external services",
description:
"Interact with the local qsv pro API server from other apps and services such as importing a file path into the qsv pro Workflow or on Windows launching an Alacritty terminal running csvlens on a provided file path. Explore the API's capabilities through locally served API documentation or through the qsv pro command available on the qsv command-line tool. qsv pro closes to the system tray so that you may continue to use the API with the window closed (some endpoints may have conditions to work properly such as having the Workflow open for the Workflow endpoint).",
image: apiDemo,
},
{
title: "qsv pro command - Interact with qsv pro using the qsv command-line tool",
description:
"Use the qsv pro command available from the qsv command-line tool to import local files by their file path into the qsv pro Workflow or on Windows launch an Alacritty terminal running csvlens on the file.",
image: commandDemo,
},
{
title: "Configurator (Experimental) - Run qsv commands in an interactive GUI",
description:
"Run qsv commands in a graphical user interface and explore its stdout and stderr as raw output. The command's elapsed time is also provided. Note: Not all commands are supported and this feature may be broken/outdated.",
image: configuratorDemo,
},
];
const OPTIONS = {}
const PLUGINS = [Autoplay({ delay: 30000 })]
return (
<EmblaCarousel slides={SLIDES} options={OPTIONS} plugins={PLUGINS} />
// <div className="embla" ref={emblaRef}>
// <div className="embla__container">
// <div className="embla__slide"><img src={flowDemo.src} /></div>
// <div className="embla__slide"><img src={workflowDemo.src} /></div>
// <div className="embla__slide"><img src={toolboxDemo.src} /></div>
// <div className="embla__slide"><img src={commandDemo.src} /></div>
// <div className="embla__slide"><img src={apiDemo.src} /></div>
// <div className="embla__slide"><img src={configuratorDemo.src} /></div>
// </div>
// </div>
)
}
export default FeatureCarousel;

View file

@ -6,8 +6,7 @@ import { CheckArrowIcon } from "../assets/icons/CheckArrowIcon";
export const Features0 = () => {
return (
<section
className="w-full bg-customDarkBg2 mt-20 mb-8 sm:mt-16 sm:mb-16 xl:mt-0 pt-[2rem] md:pt-[12vw] lg:pt-16"
id="features"
className="w-full bg-customDarkBg2 mt-20 mb-8 sm:mt-16 sm:mb-16 xl:mt-0"
>
<motion.div
initial={{ opacity: 0 }}
@ -40,15 +39,7 @@ export const Features0 = () => {
<li className="mb-4 flex">
<CheckArrowIcon />
<span>
File formats: .csv, .xlsx,{" "}
<span className="text-red-300">
.tsv, .tab, .xls, .ods, .xlsm, .xlsb
</span>
<br />
<span className="text-red-300">
*Experimental file formats, may not
work as expected.
</span>
File formats: .csv, .xlsx, .tsv, .tab, .xls, .ods, .xlsm, .xlsb
</span>
</li>
<li className="mb-4 flex">
@ -61,8 +52,8 @@ export const Features0 = () => {
<li className="mb-4 flex">
<CheckArrowIcon />
<span>
Begins scanning and analyzing your data
on import
Begins process to scan and analysis file data
after import
</span>
</li>
<li className="mb-4 flex">

View file

@ -4,6 +4,7 @@ import { motion } from "framer-motion";
import dashboard from "../assets/images/dashboard.png";
import qsvProLogo from "../assets/logos/qsv-pro-logo.png";
import Download from "../assets/icons/Download.jsx";
import FeatureCarousel from "./FeatureCarousel.jsx";
export const Hero = () => {
const [downloadData, setDownloadData] = useState();
@ -71,7 +72,7 @@ export const Hero = () => {
return (
<section
className="w-screen flex justify-center items-center bg-customDarkBg1 mb-[28vw] md:mb-[18vw] lg:mb-[10vw] xl:mb-[13vw] 2xl:mb-60 hero-bg-gradient pb-24 sm:pb-32 md:pb-44 lg:pb-0"
className="w-screen flex justify-center items-center bg-customDarkBg1 mb-40 hero-bg-gradient pb-24 sm:pb-32 md:pb-44 lg:pb-0"
id="home"
>
<div className="w-full md:w-[1100px] flex flex-col justify-center items-center pt-16 md:pt-16 lg:pt-20 text-center">
@ -104,24 +105,13 @@ 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 and upload spreadsheet data to{" "}
<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>{" "}
with our streamlined desktop app, featuring "recipes"
for common data wrangling tasks. Based on the{" "}
<a
href="https://github.com/jqnatividad/qsv"
target="_blank"
className="text-blue-300"
>
qsv
</a>{" "}
CLI tool.
</a> instances, and explore qsv pro.
</div>
</motion.div>
<motion.div
@ -133,8 +123,7 @@ export const Hero = () => {
{downloadData && OS !== "unknown" ? (
<>
<p className="text-white text-md text-center mx-auto mb-4">
Start your 7-day free trial,{" "}
<u>no payment required</u>.
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(
@ -182,8 +171,7 @@ export const Hero = () => {
</div>
</a>
<p className="text-white text-sm sm:text-base text-center mx-auto">
Start your 7-day free trial,{" "}
<u>no payment required</u>.
Download qsv pro and explore the free plan or unlock features with a paid plan.
</p>
</>
)}
@ -198,17 +186,20 @@ export const Hero = () => {
initial={{ opacity: 0, y: 10, zIndex: 20 }}
animate={{ opacity: 1, y: 0, zIndex: 20 }}
transition={{ duration: 0.5, delay: 0.15 }}
id="features"
className="w-full"
>
<div className="relative w-screen flex justify-center ">
<img
<div className="relative w-full flex justify-center">
<FeatureCarousel />
{/*<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"
/>
/>*/}
</div>
</motion.div>
<div className="relative w-screen flex justify-center ">
<div className="custom-shape-divider-bottom-1665343298 mt-4 sm:mt-16 md:mt-52 hidden lg:block">
<div className="custom-shape-divider-bottom-1665343298 hidden lg:block">
<svg
data-name="Layer 1"
xmlns="http://www.w3.org/2000/svg"

View file

@ -42,9 +42,9 @@ export const Navbar = () => {
alt="qsv pro logo"
className="h-8"
/>
<small className="text-white font-['Inter'] text-xs mb-1 rounded-full px-1 border">
{/* <small className="text-white font-['Inter'] text-xs mb-1 rounded-full px-1 border">
Download v1 now! Website update is planned.
</small>
</small> */}
</div>
</a>
</motion.div>

View file

@ -4,11 +4,25 @@ import { motion } from "framer-motion";
import { CheckArrowIcon } from "../assets/icons/CheckArrowIcon";
const pricingData = [
"Import local spreadsheet data",
"Transform data with recipes",
"Upload to CKAN instances",
"Interactive data table view",
"Configurator GUI (experimental)",
["Import spreadsheets up to 1MB",
"Transform data with free recipes",
"List 1 CKAN instance",
"Use free tools in Toolbox",
"Use qsv slice from Flow",
"Use qsv count and qsv slice in Configurator (experimental)",
"Export Workflow file data and various data table data to CSV, TSV, TAB, and SSV"
],
["Import spreadsheets larger than 1MB",
"View extra statistics in the Workflow based on your file",
"Transform data with Pro recipes",
"List more than 1 CKAN instance",
"Use Pro tools in Toolbox",
"Use more qsv commands other than qsv slice from Flow",
"Use more qsv commands other than qsv count and qsv slice in Configurator (experimental)",
"Export Workflow file data and various data table data to 16 formats",
"Run csvlens on a spreadsheet or data table in a new Alacritty terminal (Windows only)"
],
[]
];
export const Pricing = () => {
@ -29,7 +43,7 @@ export const Pricing = () => {
transition={{ duration: 0.5, delay: 0.2 }}
>
<div className="container mx-auto px-4">
<div className="max-w-2xl mx-auto text-center mb-16">
<div className="max-w-2xl mx-auto text-center">
<span className="custom-block-subtitle">
Pick a Plan
</span>
@ -37,10 +51,8 @@ export const Pricing = () => {
Choose your plan
</h2>
<p className="mb-6 text-customGrayText">
After you complete your 7-day free trial, you'll
need a license key to continue using qsv pro.
Select the subscription plan that suits your
needs and benefit from qsv pro.
To unlock paid features, you'll
need to purchase and activate a license key. USD pricing.
</p>
<label className="mx-auto bg-customDarkBg3 relative flex justify-between items-center group text-xl w-44 h-12 rounded-lg pr-36 pl-1 cursor-pointer">
<input
@ -68,61 +80,64 @@ export const Pricing = () => {
</div>
</label>
</div>
<div className="flex flex-wrap flex-col lg:flex-row -mx-4 items-center mt-20">
<div className="flex flex-wrap flex-col lg:flex-row -mx-4 items-center mt-6">
<div className="w-[350px] sm:w-[380px] lg:w-1/3 px-4 mb-8 lg:mb-0">
{/* <div className="p-8 bg-customDarkBg3 rounded-3xl">
<h4 className="mb-2 text-xl font-bold font-heading text-white text-left">
Beginner
<div className="px-8 py-8 bg-customDarkBg3 rounded-3xl">
<h4 className="mb-2 2xl:mb-4 text-2xl font-bold font-heading text-white text-left">
Free
</h4>
<div className="flex justify-start items-end">
<div className="text-4xl sm:text-5xl font-bold text-white text-left mt-4 mr-2">
$0
</div>
<div className="text-gray-500">
{isMonthly ? "/ month" : "/ year"}
</div>
</div>
<p className="mt-4 mb-6 2xl:mb-10 text-gray-500 leading-loose text-left">
The perfect way to get started and get
used to our tools.
<p className="my-4 text-gray-400 leading-loose text-left">
No license key required
</p>
<ul className="mb-2 2xl:mb-6 text-white">
{pricingData.map((text, index) => (
<ul className="mb-14 text-white">
{pricingData[0].map((text, index) => (
<li
className="mb-4 flex"
key={`${text}-${index}`}
>
<CheckArrowIcon />
<CheckArrowIcon
fillColor={
text.includes(
"(experimental)"
)
? "fill-red-300"
: ""
}
/>
<span>{text}</span>
</li>
))}
</ul>
<div
className="inline-block text-center py-2 px-4 w-full rounded-xl rounded-t-xl custom-button-colored font-bold leading-loose mt-16"
>
Get Started
</div>
</div> */}
<a href="#">
<div className="inline-block text-center py-2 px-4 w-full custom-button-colored leading-loose transition duration-200">
Download qsv pro
</div>
</a>
</div>
</div>
<div className="w-[350px] sm:w-[380px] lg:w-1/3 px-4 mb-8 lg:mb-0">
<div className="px-8 py-8 bg-customDarkBg3 rounded-3xl">
<h4 className="mb-2 2xl:mb-4 text-2xl font-bold font-heading text-white text-left">
qsv pro (preview)
<div className="px-8 py-8 bg-blue-950 rounded-3xl border-4 border-blue-600">
<h4 className="mb-2 2xl:mb-4 text-3xl font-bold font-heading text-white text-left">
Pro
</h4>
<div className="flex justify-start items-end">
<div className="text-4xl sm:text-5xl font-bold text-white text-left mt-4 mr-2">
{isMonthly ? "$99.99" : "$999.00"}
</div>
<div className="text-gray-500">
<div className="text-gray-400">
{isMonthly ? "/ month" : "/ year"}
</div>
</div>
<p className="mt-8 mb-8 2xl:mb-12 text-gray-500 leading-loose text-left">
1 license key
<p className="mt-8 mb-8 2xl:mb-12 text-gray-400 leading-loose text-left">
1 license key (1 device at a time)
</p>
<ul className="mb-14 text-white">
{pricingData.map((text, index) => (
{pricingData[1].map((text, index) => (
<li
className="mb-4 flex"
key={`${text}-${index}`}
@ -148,46 +163,50 @@ export const Pricing = () => {
}
target="_blank"
>
<div className="inline-block text-center py-2 px-4 w-full custom-button-colored leading-loose transition duration-200 mt-20">
<div className="inline-block text-center py-2 px-4 w-full custom-button-colored leading-loose transition duration-200">
Purchase a License Key
</div>
</a>
</div>
</div>
<div className="w-[350px] sm:w-[380px] lg:w-1/3 px-4 mb-8 lg:mb-0">
{/* <div className="p-8 bg-customDarkBg3 rounded-3xl">
<h4 className="mb-2 text-xl font-bold font-heading text-white text-left">
Premium
<div className="px-8 py-8 bg-customDarkBg3 rounded-3xl">
<h4 className="mb-2 2xl:mb-4 text-2xl font-bold font-heading text-white text-left">
Business / Enterprise
</h4>
<div className="flex justify-start items-end">
<div className="text-4xl sm:text-5xl font-bold text-white text-left mt-4 mr-2">
{isMonthly ? "$36" : "$390"}
</div>
<div className="text-gray-500">
{isMonthly ? "/ month" : "/ year"}
Contact us
</div>
</div>
<p className="mt-4 mb-6 2xl:mb-10 text-gray-500 leading-loose text-left">
Experience the full power of our
analytic platform
<p className="my-4 text-gray-400 leading-loose text-left">
License keys by approved request
</p>
<ul className="mb-2 2xl:mb-6 text-white">
{pricingData.map((text, index) => (
<ul className="mb-14 text-white">
{pricingData[2].map((text, index) => (
<li
className="mb-4 flex"
key={`${text}-${index}`}
>
<CheckArrowIcon />
<CheckArrowIcon
fillColor={
text.includes(
"(experimental)"
)
? "fill-red-300"
: ""
}
/>
<span>{text}</span>
</li>
))}
</ul>
<div
className="inline-block text-center py-2 px-4 w-full rounded-xl rounded-t-xl custom-button-colored font-bold leading-loose mt-16"
>
Get Started
</div>
</div> */}
<a href="https://dathere.com/contact">
<div className="inline-block text-center py-2 px-4 w-full custom-button-colored leading-loose transition duration-200">
Contact us
</div>
</a>
</div>
</div>
</div>
</div>

View file

@ -17,7 +17,6 @@ import "../styles/Theme.css";
import "../styles/Diagonals.css";
import { Features0 } from "../components/Features0";
import { Features3 } from "../components/Features3";
---
<Layout title="qsv pro">
@ -30,7 +29,7 @@ import { Features3 } from "../components/Features3";
<Features2 client:load />
<Features3 client:load />
<!-- <Testimonials client:load /> -->
<FeaturesDiagonal client:load />
<!-- <FeaturesDiagonal client:load /> -->
<Pricing client:load />
<!-- <Brands client:load /> -->
<Tech client:load />

View file

@ -16,6 +16,16 @@
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.embla {
overflow: hidden;
}
.embla__container {
display: flex;
}
.embla__slide {
flex: 0 0 100%;
min-width: 0;
}
/* Features Top */