From cdebcb446520db141b7fc306200fb18dcf313658 Mon Sep 17 00:00:00 2001 From: dangthang1903 Date: Thu, 25 Jul 2024 16:57:55 +0700 Subject: [PATCH 01/17] chore: refactor animate scroll --- tailwind.config.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tailwind.config.js b/tailwind.config.js index ce24f7e..4e21db4 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -74,11 +74,7 @@ module.exports = { from: {height: 'var(--radix-accordion-content-height)'}, to: {height: '0'}, }, - 'scrollText':{ - '0%': { transform: 'translateX(0)' }, - '100%': { transform: 'translateX(-100%)' }, - }, - 'scrollImage':{ + 'scrollContent':{ from: { transform: 'translateX(0)' }, to: { transform: 'translateX(-100%)' }, }, @@ -86,8 +82,7 @@ module.exports = { animation: { 'accordion-down': 'accordion-down 0.2s ease-out', 'accordion-up': 'accordion-up 0.2s ease-out', - 'scrollText': 'scrollText linear infinite', - 'scrollImage': 'scrollImage linear infinite', + 'scrollContent': 'scrollContent linear infinite', }, }, }, From f40e8511803d963accabc9b078c54ecfef70bd34 Mon Sep 17 00:00:00 2001 From: dangthang1903 Date: Thu, 25 Jul 2024 16:58:46 +0700 Subject: [PATCH 02/17] chore: update logic product swimlane --- app/components/ProductSwimlane.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/components/ProductSwimlane.tsx b/app/components/ProductSwimlane.tsx index a1f5baf..0517d87 100644 --- a/app/components/ProductSwimlane.tsx +++ b/app/components/ProductSwimlane.tsx @@ -1,21 +1,21 @@ -import type {HomepageFeaturedProductsQuery} from 'storefrontapi.generated'; +import type {FeaturedItemsQuery} from 'storefrontapi.generated'; import { Section} from '~/components/Text'; import {ProductCard} from '~/components/ProductCard'; import { IconArrowScrollLeft, IconArrowScrollRight } from './Icon'; -import React, { useRef } from 'react'; +import { useRef } from 'react'; const mockProducts = { nodes: new Array(12).fill(''), }; -type ProductSwimlaneProps = HomepageFeaturedProductsQuery & { +type ProductSwimlaneProps = Pick & { title?: string; count?: number; }; export function ProductSwimlane({ title = 'Featured Products', - products = mockProducts, + featuredProducts = mockProducts, count = 12, ...props }: ProductSwimlaneProps) { @@ -35,7 +35,7 @@ export function ProductSwimlane({ return (
- {products.nodes.slice(0, count).map((product) => ( + {featuredProducts.nodes.slice(0, count).map((product) => ( Date: Thu, 25 Jul 2024 16:59:52 +0700 Subject: [PATCH 03/17] chore: update layout container --- app/routes/($locale).search.tsx | 2 +- app/sections/collection-filters/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/routes/($locale).search.tsx b/app/routes/($locale).search.tsx index b315da3..71931aa 100644 --- a/app/routes/($locale).search.tsx +++ b/app/routes/($locale).search.tsx @@ -211,7 +211,7 @@ export default function Search() { productNumber={products.totalCount} filters={productfilters} /> -
+
{noResults ? ( ( appliedFilters={appliedFilters} collections={collections} /> -
+
{({ nodes, From 65684298089adbe3edc558d1533ea9a97ba1f126 Mon Sep 17 00:00:00 2001 From: dangthang1903 Date: Thu, 25 Jul 2024 17:00:51 +0700 Subject: [PATCH 04/17] chore: fix style drawer filter and quickview --- app/components/DrawerFilter.tsx | 2 +- app/components/QuickView.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/components/DrawerFilter.tsx b/app/components/DrawerFilter.tsx index 5b4e319..5e29325 100644 --- a/app/components/DrawerFilter.tsx +++ b/app/components/DrawerFilter.tsx @@ -313,7 +313,7 @@ export default function SortMenu({ items.find((item) => item.key === params.get('sort')) || items[0]; return ( - + Sort by diff --git a/app/components/QuickView.tsx b/app/components/QuickView.tsx index ed30404..79ebf16 100644 --- a/app/components/QuickView.tsx +++ b/app/components/QuickView.tsx @@ -182,7 +182,7 @@ export function QuickViewTrigger(props: {productHandle: string}) { }, [quickAddOpen, data, load, state]); return ( <> -
+
From 39bb22628e94d1fe4cdbbe654e61144615d53390 Mon Sep 17 00:00:00 2001 From: dangthang1903 Date: Thu, 25 Jul 2024 17:04:40 +0700 Subject: [PATCH 07/17] chore: refactor product infomation use swiper --- app/components/product-form/product-media.tsx | 197 +++++++----------- app/sections/product-information/index.tsx | 2 +- .../related-products/related-products.tsx | 2 +- 3 files changed, 77 insertions(+), 124 deletions(-) diff --git a/app/components/product-form/product-media.tsx b/app/components/product-form/product-media.tsx index 6fc8bf1..65ffb3d 100644 --- a/app/components/product-form/product-media.tsx +++ b/app/components/product-form/product-media.tsx @@ -1,8 +1,9 @@ -import {Image} from '@shopify/hydrogen'; -import clsx from 'clsx'; -import {useKeenSlider, KeenSliderPlugin} from 'keen-slider/react'; -import {useCallback, useEffect, useState} from 'react'; -import type {MediaFragment} from 'storefrontapi.generated'; +import { Image } from "@shopify/hydrogen"; +import clsx from "clsx"; +import { useState } from "react"; +import type { MediaFragment } from "storefrontapi.generated"; +import { FreeMode, Pagination, Thumbs } from "swiper/modules"; +import { Swiper, type SwiperClass, SwiperSlide } from "swiper/react"; interface ProductMediaProps { selectedVariant: any; @@ -12,129 +13,81 @@ interface ProductMediaProps { spacing: number; } - export function ProductMedia(props: ProductMediaProps) { - let { - selectedVariant, - media: _media, - showThumbnails, - numberOfThumbnails, - spacing, - } = props; - let media = _media.filter((med) => med.__typename === 'MediaImage'); - let slideOptions = { - initial: 0, - loop: true, - slides: { - perView: 1, - spacing: 0, - }, - }; - - let thumbnailOptions = { - initial: 0, - slides: { - perView: numberOfThumbnails, - spacing: spacing, - }, - }; - - let [activeInd, setActiveInd] = useState(0); - let [sliderRef, instanceRef] = useKeenSlider({ - ...slideOptions, - slideChanged: (slider) => { - let pos = slider.track.details.rel; - setActiveInd(pos); - let maxThumbnailIndex = - thumbnailInstance.current?.track.details.maxIdx || 0; - let thumbnailNext = Math.min( - Math.floor((pos + 1) / numberOfThumbnails), - maxThumbnailIndex, - ); - thumbnailInstance.current?.moveToIdx(thumbnailNext); - }, - }); - - - function moveToIdx(idx: number) { - setActiveInd(idx); - if (instanceRef.current) { - instanceRef.current.moveToIdx(idx); - } - } - - let [thumbnailRef, thumbnailInstance] = useKeenSlider(thumbnailOptions); - function handleClickThumbnail(idx: number) { - moveToIdx(idx); - } - - useEffect(() => { - // instanceRef.current?.update(slideOptions); - // thumbnailInstance.current?.update(thumbnailOptions); - let selectedInd = media.findIndex((med) => { - if (med.__typename !== 'MediaImage') return false; - return med.image?.url === selectedVariant?.image.url; - }); - moveToIdx(selectedInd); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedVariant?.id]); - + let { selectedVariant, showThumbnails, media: _media, numberOfThumbnails, spacing } = props; + let media = _media.filter((med) => med.__typename === "MediaImage"); + let [thumbsSwiper, setThumbsSwiper] = useState(null); + let [activeIndex, setActiveIndex] = useState(0); + return ( -
-
+
+ + {media.map((med, i) => { + let image = { ...med.image, altText: med.alt || "Product image" }; + return ( + + + + ); + })} + + { + setActiveIndex(swiper.activeIndex); + }} + className="vt-product-image max-w-full pb-14 md:pb-0 md:[&_.swiper-pagination-fraction]:hidden" + style={ + { + "--swiper-pagination-bottom": "20px", + } as React.CSSProperties + } + > {media.map((med, i) => { - let image = - med.__typename === 'MediaImage' - ? {...med.image, altText: med.alt || 'Product image'} - : null; + let image = { ...med.image, altText: med.alt || "Product image" }; return ( - image && ( -
- -
- ) + + + ); })} -
- {showThumbnails && ( -
- {media.map((med, i) => { - let image = - med.__typename === 'MediaImage' - ? {...med.image, altText: med.alt || 'Product image'} - : null; - return ( - image && ( -
handleClickThumbnail(i)} - > - -
- ) - ); - })} -
- )} +
); } diff --git a/app/sections/product-information/index.tsx b/app/sections/product-information/index.tsx index 3b95f97..a2183a2 100644 --- a/app/sections/product-information/index.tsx +++ b/app/sections/product-information/index.tsx @@ -188,7 +188,7 @@ let ProductInformation = forwardRef( /> )}

( )} From b1281a6649540cf35deceb6bad555237d3dde27b Mon Sep 17 00:00:00 2001 From: dangthang1903 Date: Thu, 25 Jul 2024 17:05:23 +0700 Subject: [PATCH 08/17] chore: refactor instargram section --- app/sections/instagram/index.tsx | 225 +++++++++++++++---------------- 1 file changed, 111 insertions(+), 114 deletions(-) diff --git a/app/sections/instagram/index.tsx b/app/sections/instagram/index.tsx index e02060c..c02df9d 100644 --- a/app/sections/instagram/index.tsx +++ b/app/sections/instagram/index.tsx @@ -15,6 +15,7 @@ import {Pagination} from 'swiper/modules'; type InstagramData = { instagramToken: string; backgroundColor: string; + width: string; imagesPerRow: number; speed: number; visibleOnMobile: boolean; @@ -27,6 +28,11 @@ type InstagramData = { }; }; +let widthClasses: {[item: string]: string} = { + full: '', + fixed: 'container', +}; + type InstagramProps = HydrogenComponentProps< Awaited> > & @@ -36,6 +42,7 @@ const Instagram = forwardRef((props, ref) => { let { instagramToken, backgroundColor, + width, imagesPerRow, speed, visibleOnMobile, @@ -60,54 +67,18 @@ const Instagram = forwardRef((props, ref) => { ); }; - let res = loaderData?.data; - if (!res) { - return ( -

-
-
{children}
- - {Array.from({length: 3}).map((idx, i) => { - return ( - -
- {imageItemBlank()} -
-
-
- ); - })} -
-
- {Array.from({length: 3}).map((idx, i) => ( -
- {imageItemBlank()} -
- ))} -
-
-
- ); - } + const defaultInstagramData = Array.from({length: 3}).map((_, i) => ({ + id: i, + media_url: null, + username: null, + })); + + let res = loaderData?.data ?? defaultInstagramData; let displayedImages = res?.slice(0, imagesPerRow); const imageItemRender = () => { return (
{displayedImages.map((item, index) => { @@ -116,25 +87,33 @@ const Instagram = forwardRef((props, ref) => { className="group relative aspect-square min-w-80 cursor-pointer" key={index} > - - -
+ {item.media_url ? ( + + ) : ( + imageItemBlank() + )} + {item.username && ( + <> + +
+ + )}
); })} @@ -149,61 +128,69 @@ const Instagram = forwardRef((props, ref) => { className={clsx('h-full w-full', !visibleOnMobile && 'hidden sm:block')} style={sectionStyle} > -
+
{children}
- {res.length === 0 ? ( -
-

Not found post

-
- ) : ( - <> - - {displayedImages.map((item, index) => { - return ( - -
+ <> + + {displayedImages.map((item, index) => { + return ( + +
+ {item.media_url ? ( - -
-
-
- - ); - })} - - {Array.from({length: 11}).map((idx, i) => ( -
{imageItemRender()}
- ))} - - )} + ) : ( + imageItemBlank() + )} + {item.username && ( + <> + +
+ + )} +
+
+ + ); + })} + + {Array.from({length: 11}).map((idx, i) => ( +
{imageItemRender()}
+ ))} +
@@ -235,8 +222,6 @@ export const schema: HydrogenComponentSchema = { type: 'text', name: 'instagramToken', label: 'Instagram api token', - defaultValue: - 'IGQWRPX3Eyc1RHd3padDVwRXZANdkp4ZAkE1bkxjRlNtd3V4WnBXZAXUxWWlvVjlTc2h3SU45NmZAVOHptcEswalkyTHYtckh6cnlUNTUtaHpDUjYxTE04X0RwVG5qRnJ0cDhxcnlBVjRib3BoYUxGa2xCTlFZAZAC1PMmMZD', placeholder: '@instagram', helpText: 'Learn more about how to get API token for Instagram section.', @@ -247,6 +232,18 @@ export const schema: HydrogenComponentSchema = { name: 'backgroundColor', defaultValue: '#F8F8F0', }, + { + type: 'select', + name: 'width', + label: 'Content width', + configs: { + options: [ + {value: 'full', label: 'Full page'}, + {value: 'fixed', label: 'Fixed'}, + ], + }, + defaultValue: 'fixed', + }, { type: 'range', name: 'imagesPerRow', From 4c29a4ed5d70c1097a1e198302592c38cb7f5a46 Mon Sep 17 00:00:00 2001 From: dangthang1903 Date: Thu, 25 Jul 2024 17:06:01 +0700 Subject: [PATCH 09/17] chore: update scroll animate for scrolling text section --- app/sections/scrolling-text/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/sections/scrolling-text/index.tsx b/app/sections/scrolling-text/index.tsx index 003f81e..53808d3 100644 --- a/app/sections/scrolling-text/index.tsx +++ b/app/sections/scrolling-text/index.tsx @@ -46,17 +46,17 @@ const ScrollingText = forwardRef((props, ref) => { !visibleOnMobile && 'hidden sm:block', )}>
-

{` ${content} `.repeat(15)}

-

{` ${content} `.repeat(15)}

-

{` ${content} `.repeat(15)} From e016e4d9c55d0c2d3cd826eab393b5372f0e95b2 Mon Sep 17 00:00:00 2001 From: dangthang1903 Date: Thu, 25 Jul 2024 17:06:34 +0700 Subject: [PATCH 10/17] chore: refactor slides show section --- app/sections/slides/index.tsx | 143 +++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 61 deletions(-) diff --git a/app/sections/slides/index.tsx b/app/sections/slides/index.tsx index 8614f02..51869c9 100644 --- a/app/sections/slides/index.tsx +++ b/app/sections/slides/index.tsx @@ -1,81 +1,102 @@ import type { - HydrogenComponentProps, - HydrogenComponentSchema, + HydrogenComponentProps, + HydrogenComponentSchema, } from '@weaverse/hydrogen'; -import { forwardRef, CSSProperties } from 'react'; -import { Swiper, SwiperSlide } from 'swiper/react'; -import { EffectFade } from 'swiper/modules'; +import {CSSProperties, forwardRef} from 'react'; +import {EffectFade} from 'swiper/modules'; +import {Swiper, SwiperSlide} from 'swiper/react'; import 'swiper/css'; import 'swiper/css/effect-fade'; +import clsx from 'clsx'; interface SlidesProps extends HydrogenComponentProps { - sectionHeight: number; + sectionHeight: number; + width: string; } +let widthClasses: {[item: string]: string} = { + full: '', + fixed: 'container', +}; + const Slides = forwardRef((props, ref) => { - let { - sectionHeight, - children, - ...rest - } = props; + let {sectionHeight, width, children, ...rest} = props; - let sectionStyle: CSSProperties = { - '--section-height': `${sectionHeight}px`, - } as CSSProperties; + let sectionStyle: CSSProperties = { + '--section-height': `${sectionHeight}px`, + } as CSSProperties; - return ( -
- - {children?.map((child, index) => ( - - {child} - - ))} - -
- ); + return ( +
+ + {children?.map((child, index) => ( + {child} + ))} + +
+ ); }); export default Slides; export let schema: HydrogenComponentSchema = { - type: 'slides-index', - title: 'Slides', - toolbar: ['general-settings', ['duplicate', 'delete']], - inspector: [ + type: 'slides-index', + title: 'Slides', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Slides', + inputs: [ + { + type: 'range', + name: 'sectionHeight', + label: 'Section height', + defaultValue: 450, + configs: { + min: 400, + max: 700, + step: 10, + unit: 'px', + }, + }, { - group: 'Slides', - inputs: [ - { - type: 'range', - name: 'sectionHeight', - label: 'Section height', - defaultValue: 450, - configs: { - min: 400, - max: 700, - step: 10, - unit: 'px', - }, - }, + type: 'select', + name: 'width', + label: 'Content width', + configs: { + options: [ + {value: 'full', label: 'Full page'}, + {value: 'fixed', label: 'Fixed'}, ], + }, + defaultValue: 'fixed', }, - ], - childTypes: ['slides-item'], - presets: { - children: [ - { - type: 'slides-item', - } - ], + ], }, -}; \ No newline at end of file + ], + childTypes: ['slides-item'], + presets: { + children: [ + { + type: 'slides-item', + }, + ], + }, +}; From 4cab93cde32480f62b63d2a2bb0de5fdd83a27a3 Mon Sep 17 00:00:00 2001 From: dangthang1903 Date: Tue, 30 Jul 2024 17:10:37 +0700 Subject: [PATCH 11/17] chore: update button component --- @/components/button.tsx | 4 +++- app/sections/atoms/button.tsx | 45 +++++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/@/components/button.tsx b/@/components/button.tsx index 52eb6b8..6dd5586 100644 --- a/@/components/button.tsx +++ b/@/components/button.tsx @@ -26,7 +26,7 @@ const buttonVariants = cva( }, shape: { default: 'rounded', - round: 'rounded-md' + round: 'rounded-md', } }, defaultVariants: { @@ -43,6 +43,7 @@ export interface ButtonProps asChild?: boolean; as?: React.ElementType; to?: string; + target?: string; } const Button = React.forwardRef( @@ -70,6 +71,7 @@ const Button = React.forwardRef( )} ref={ref} {...props} + target={props.to ? props?.target || '_self' : undefined} > {loading && (
diff --git a/app/sections/atoms/button.tsx b/app/sections/atoms/button.tsx index 8608f7d..5a20ec7 100644 --- a/app/sections/atoms/button.tsx +++ b/app/sections/atoms/button.tsx @@ -3,9 +3,15 @@ import type {HydrogenComponentSchema} from '@weaverse/hydrogen'; import {IconEllipse} from '~/components/Icon'; import {CSSProperties, forwardRef} from 'react'; -const WeaverseButton = forwardRef( +interface OriginalButtonProps extends ButtonProps { + href?: string; + target?: string; + textColor?: string; +} + +const WeaverseButton = forwardRef( (props, ref) => { - const {href, target, value, variant, textColor, ...rest} = props; + const {href, target, value, variant, shape, textColor, ...rest} = props; const Component = href ? 'a' : 'button'; let style = { color: textColor, @@ -14,8 +20,9 @@ const WeaverseButton = forwardRef( +
+ +
+ +
+ + )} + +

+ ); + }, +); + +export default CollectionListItem; + +export let schema: HydrogenComponentSchema = { + type: 'collection-list--item', + title: 'Collection list', + limit: 1, + toolbar: ['general-settings'], + inspector: [ + { + group: 'Collection list', + inputs: [ + { + type: 'range', + name: 'collectionsPerRow', + label: 'Collections per row', + defaultValue: 3, + configs: { + min: 1, + max: 4, + step: 1, + }, + }, + { + type: 'switch', + name: 'lazyLoadImage', + label: 'Lazy load image', + defaultValue: true, + }, + ], + }, + ], +}; diff --git a/app/sections/collection-list/index.tsx b/app/sections/collection-list/index.tsx index 3ef9dd8..1348e6e 100644 --- a/app/sections/collection-list/index.tsx +++ b/app/sections/collection-list/index.tsx @@ -1,84 +1,16 @@ -import { useLoaderData } from '@remix-run/react'; -import { Pagination } from '@shopify/hydrogen'; -import type { - HydrogenComponentProps, - HydrogenComponentSchema, -} from '@weaverse/hydrogen'; -import { forwardRef, CSSProperties, Children } from 'react'; -import type { StoreCollectionsQuery } from 'storefrontapi.generated'; -import { Section } from '~/components/Text'; -import { Button } from '@/components/button'; -import { CollectionsLoadedOnScroll } from './collection-loader-on-scroll'; -import { useInView } from 'react-intersection-observer'; -import clsx from 'clsx'; +import type {HydrogenComponentSchema} from '@weaverse/hydrogen'; +import {forwardRef} from 'react'; +import {layoutInputs, Section, SectionProps} from '../atoms/Section'; -type Alignment = 'left' | 'center' | 'right'; -interface CollectionListProps extends HydrogenComponentProps { - textColor: string; - contentAlignment: Alignment; - collectionsPerRow: number; - topPadding: number; - bottomPadding: number; - lazyLoadImage: boolean; -} - -let alignmentClasses: Record = { - left: 'text-left', - center: 'text-center', - right: 'text-right', -}; +type CollectionListProps = SectionProps; let CollectionList = forwardRef( - (props, sectionRef) => { - let {ref, inView} = useInView(); - let { collections } = useLoaderData(); - let { textColor, contentAlignment, collectionsPerRow, topPadding, bottomPadding, lazyLoadImage, children, ...rest } = - props; - let contentStyle: CSSProperties = { - '--top-padding': `${topPadding}px`, - '--bottom-padding': `${bottomPadding}px`, - color: textColor, - } as CSSProperties; + (props, ref) => { + let {children, ...rest} = props; return ( -
-
- {!!Children.count(children) && ( -
- {children} -
- )} -
- - {({ nodes, isLoading, PreviousLink, NextLink, nextPageUrl, hasNextPage, state, }) => ( - <> -
- -
- -
- -
- - )} -
-
-
-
+
+ {children} +
); }, ); @@ -95,75 +27,20 @@ export let schema: HydrogenComponentSchema = { toolbar: ['general-settings'], inspector: [ { - group: 'Collection list', - inputs: [ - { - type: 'color', - name: 'textColor', - label: 'Text color', - }, - { - type: 'toggle-group', - label: 'Content alignment', - name: 'contentAlignment', - configs: { - options: [ - { label: 'Left', value: 'left' }, - { label: 'Center', value: 'center' }, - { label: 'Right', value: 'right' }, - ], - }, - defaultValue: 'left', - }, - { - type: 'range', - name: 'collectionsPerRow', - label: 'Collections per row', - defaultValue: 3, - configs: { - min: 1, - max: 4, - step: 1, - }, - }, - { - type: 'range', - name: 'topPadding', - label: 'Top padding', - defaultValue: 0, - configs: { - min: 0, - max: 100, - step: 1, - }, - }, - { - type: 'range', - name: 'bottomPadding', - label: 'Bottom padding', - defaultValue: 0, - configs: { - min: 0, - max: 100, - step: 1, - }, - }, - { - type: 'switch', - name: 'lazyLoadImage', - label: 'Lazy load image', - defaultValue: true, - }, - ], + group: 'Layout', + inputs: layoutInputs.filter(({ name }) => name !== 'divider' && name !== 'borderRadius'), }, ], - childTypes: ['heading'], + childTypes: ['heading', 'collection-list--item'], presets: { - children: [ - { - type: 'heading', - content: "Collections", - }, - ], + children: [ + { + type: 'heading', + content: 'Collections', + }, + { + type: 'collection-list--item', + }, + ], }, }; From 40b9ada9e45ff34f3039e1313f8903d496c63190 Mon Sep 17 00:00:00 2001 From: dangthang1903 Date: Tue, 30 Jul 2024 17:16:59 +0700 Subject: [PATCH 16/17] chore: refactor feature product --- app/sections/feature-product/index.tsx | 302 +++--------------- .../feature-product/list-products.tsx | 224 +++++++++++++ app/weaverse/components.ts | 4 + 3 files changed, 267 insertions(+), 263 deletions(-) create mode 100644 app/sections/feature-product/list-products.tsx diff --git a/app/sections/feature-product/index.tsx b/app/sections/feature-product/index.tsx index 622e3db..6ff1e0e 100644 --- a/app/sections/feature-product/index.tsx +++ b/app/sections/feature-product/index.tsx @@ -1,272 +1,48 @@ import type { - HydrogenComponentProps, - HydrogenComponentSchema, - ComponentLoaderArgs, - WeaverseCollection, + HydrogenComponentSchema, } from '@weaverse/hydrogen'; -import { forwardRef, CSSProperties } from 'react'; -import { FEATURED_PRODUCTS_QUERY } from '~/data/queries'; -import { IconImageBlank } from '~/components/Icon'; -import { Swiper, SwiperSlide } from 'swiper/react'; -import 'swiper/swiper-bundle.css'; -import 'swiper/css/pagination'; -import { Pagination } from 'swiper/modules'; -import clsx from 'clsx'; -import { Button } from '@/components/button'; -import { ProductCard } from '~/components/ProductCard'; -import { getImageLoadingPriority } from '~/lib/const'; - -type FeaturedProductsData = { - products: WeaverseCollection; - textColor: string; - backgroundColor: string; - totalProduct: number; - productsPerRow: number; - showViewAllLink: boolean; - topPadding: number; - bottomPadding: number; - lazyLoadImage: boolean; -}; - -type FeaturedProductsProps = HydrogenComponentProps>> & FeaturedProductsData; - -let productPerRowClasses: { [item: number]: string } = { - 1: 'sm:grid-cols-1', - 2: 'sm:grid-cols-2', - 3: 'sm:grid-cols-3', - 4: 'sm:grid-cols-4', -}; - -const FeaturedProducts = forwardRef( - (props, ref) => { - let { products, textColor, backgroundColor, totalProduct, productsPerRow, showViewAllLink, topPadding, bottomPadding, lazyLoadImage, loaderData, children, ...rest } = props; - - let sectionStyle: CSSProperties = { - color: textColor, - '--background-color': backgroundColor, - '--top-padding-desktop': `${topPadding}px`, - '--bottom-padding-desktop': `${bottomPadding}px`, - '--top-padding-mobile': `${topPadding > 20 ? topPadding - 20 : topPadding}px`, - '--bottom-padding-mobile': `${bottomPadding > 20 ? bottomPadding - 20 : bottomPadding}px`, - '--swiper-theme-color': '#3D490B', - } as CSSProperties; - let res = loaderData?.collection?.products?.nodes; - let displayedProducts = res?.slice(0, totalProduct); - const productItemBlank = () => { - return ( -
-
- -
-
-

By vendor

-

Product title

-

Price

-
-
- ); - } - return ( -
-
- {children} - {loaderData === undefined || null ? ( - <> - - {Array.from({ length: 4 }).map((idx, i) => { - return ( - -
- {productItemBlank()} -
-
-
- ); - })} -
- - - ) : ( - <> - - {displayedProducts?.map((index: any, i: any) => { - return ( - - -
-
- ); - })} -
- - )} - {showViewAllLink && loaderData && loaderData.collection && ( -
- -
- )} -
-
- ); - }, +import {forwardRef} from 'react'; +import { Section, sectionInspector, SectionProps } from '../atoms/Section'; + +type FeaturedProductsData = SectionProps; + + +const FeaturedProducts = forwardRef( + (props, ref) => { + let { + children, + ...rest + } = props; + + return ( +
+ {children} +
+ ); + }, ); export default FeaturedProducts; -export let loader = async (args: ComponentLoaderArgs) => { - let { weaverse, data } = args; - let { language, country } = weaverse.storefront.i18n; - if (data.products) { - return await weaverse.storefront.query( - FEATURED_PRODUCTS_QUERY, - { - variables: { - handle: data.products.handle, - country, - language, - }, - }, - ); - } - return null; -}; export let schema: HydrogenComponentSchema = { - type: 'featured-products', - title: 'Featured products', - inspector: [ - { - group: 'Featured products', - inputs: [ - { - type: 'collection', - name: 'products', - label: 'Products', - }, - { - type: 'color', - name: 'textColor', - label: 'Text color', - }, - { - type: 'color', - name: 'backgroundColor', - label: 'Background color', - defaultValue: '#F8F8F0', - }, - { - type: 'range', - name: 'totalProduct', - label: 'Total products', - defaultValue: 4, - configs: { - min: 1, - max: 24, - step: 1, - }, - }, - { - type: 'range', - name: 'productsPerRow', - label: 'Products per row', - defaultValue: 4, - configs: { - min: 1, - max: 4, - step: 1, - }, - }, - { - type: 'switch', - name: 'showViewAllLink', - label: 'Show “View All” link', - defaultValue: true, - }, - { - type: 'range', - name: 'topPadding', - label: 'Top padding', - defaultValue: 40, - configs: { - min: 10, - max: 100, - step: 1, - }, - }, - { - type: 'range', - name: 'bottomPadding', - label: 'Bottom padding', - defaultValue: 40, - configs: { - min: 10, - max: 100, - step: 1, - }, - }, - { - type: 'switch', - name: 'lazyLoadImage', - label: 'Lazy load image', - defaultValue: true, - }, - ], - }, + type: 'featured-products', + title: 'Featured products', + inspector: sectionInspector, + toolbar: ['general-settings', ['duplicate', 'delete']], + childTypes: ['heading', 'featured-products--list'], + presets: { + children: [ + { + type: 'heading', + content: 'Best Sellers', + }, + { + type: 'featured-products--list', + } ], - toolbar: ['general-settings', ['duplicate', 'delete']], - childTypes: ['heading'], - presets: { - children: [ - { - type: 'heading', - content: 'Best Sellers', - } - ], - }, -}; \ No newline at end of file + }, +}; diff --git a/app/sections/feature-product/list-products.tsx b/app/sections/feature-product/list-products.tsx new file mode 100644 index 0000000..6cefe3c --- /dev/null +++ b/app/sections/feature-product/list-products.tsx @@ -0,0 +1,224 @@ +import type { + ComponentLoaderArgs, + HydrogenComponentProps, + HydrogenComponentSchema, + WeaverseCollection, +} from '@weaverse/hydrogen'; +import {IconImageBlank} from '~/components/Icon'; +import {FEATURED_PRODUCTS_QUERY} from '~/data/queries'; +import {CSSProperties, forwardRef} from 'react'; +import {Swiper, SwiperSlide} from 'swiper/react'; +import 'swiper/swiper-bundle.css'; +import 'swiper/css/pagination'; +import {Button} from '@/components/button'; +import {ProductCard} from '~/components/ProductCard'; +import {getImageLoadingPriority} from '~/lib/const'; +import clsx from 'clsx'; +import {Pagination} from 'swiper/modules'; + +type FeaturedProductsData = { + products: WeaverseCollection; + textColor: string; + totalProduct: number; + productsPerRow: number; + showViewAllLink: boolean; + lazyLoadImage: boolean; +}; + +type FeaturedProductsProps = HydrogenComponentProps< + Awaited> +> & + FeaturedProductsData; + +let productPerRowClasses: {[item: number]: string} = { + 1: 'sm:grid-cols-1', + 2: 'sm:grid-cols-2', + 3: 'sm:grid-cols-3', + 4: 'sm:grid-cols-4', +}; + +const ListProducts = forwardRef( + (props, ref) => { + let { + products, + textColor, + totalProduct, + productsPerRow, + showViewAllLink, + lazyLoadImage, + loaderData, + ...rest + } = props; + + let sectionStyle: CSSProperties = { + color: textColor, + '--swiper-theme-color': '#3D490B', + } as CSSProperties; + let res = loaderData?.collection?.products?.nodes; + let displayedProducts = res?.slice(0, totalProduct); + const productItemBlank = () => { + return ( +
+
+ +
+
+

By vendor

+

Product title

+

Price

+
+
+ ); + }; + const renderProducts = () => { + if (!loaderData || !displayedProducts) { + return Array.from({length: 4}).map((_, i) => ( +
+ {productItemBlank()} +
+ )); + } else { + return displayedProducts.map((product, i) => ( + + )); + } + }; + return ( +
+
+ <> +
+ + {renderProducts().map((product, i) => ( + + {product} +
+
+ ))} +
+
+
+ {renderProducts()} +
+ + {showViewAllLink && loaderData && loaderData.collection && ( +
+ +
+ )} +
+
+ ); + }, +); + +export default ListProducts; + +export let loader = async (args: ComponentLoaderArgs) => { + let {weaverse, data} = args; + let {language, country} = weaverse.storefront.i18n; + if (data.products) { + return await weaverse.storefront.query(FEATURED_PRODUCTS_QUERY, { + variables: { + handle: data.products.handle, + country, + language, + }, + }); + } + return null; +}; + +export let schema: HydrogenComponentSchema = { + type: 'featured-products--list', + title: 'Featured products list', + limit: 1, + inspector: [ + { + group: 'Featured products', + inputs: [ + { + type: 'collection', + name: 'products', + label: 'Products', + }, + { + type: 'color', + name: 'textColor', + label: 'Text color', + }, + { + type: 'range', + name: 'totalProduct', + label: 'Total products', + defaultValue: 4, + configs: { + min: 1, + max: 24, + step: 1, + }, + }, + { + type: 'range', + name: 'productsPerRow', + label: 'Products per row', + defaultValue: 4, + configs: { + min: 1, + max: 4, + step: 1, + }, + }, + { + type: 'switch', + name: 'showViewAllLink', + label: 'Show “View All” link', + defaultValue: true, + }, + { + type: 'switch', + name: 'lazyLoadImage', + label: 'Lazy load image', + defaultValue: true, + }, + ], + }, + ], + toolbar: ['general-settings', ['duplicate', 'delete']], +}; diff --git a/app/weaverse/components.ts b/app/weaverse/components.ts index 22c6d6d..0240333 100644 --- a/app/weaverse/components.ts +++ b/app/weaverse/components.ts @@ -19,7 +19,9 @@ import * as Instagram from '~/sections/instagram'; import * as BeforeAndAfter from '~/sections/before-and-after/index'; import * as BeforeAndAfterSlide from '~/sections/before-and-after/slider'; import * as FeaturedProducts from '~/sections/feature-product/index'; +import * as FeaturedProductsList from '~/sections/feature-product/list-products'; import * as CollectionList from '~/sections/collection-list/index'; +import * as CollectionListItem from '~/sections/collection-list/collection-list'; import * as AllProducts from '~/sections/all-products/index'; import * as ProductInformation from '~/sections/product-information/index'; import * as HeaderImage from '~/sections/image-banner/index'; @@ -63,7 +65,9 @@ export const components: HydrogenComponent[] = [ BeforeAndAfter, BeforeAndAfterSlide, FeaturedProducts, + FeaturedProductsList, CollectionList, + CollectionListItem, AllProducts, ProductInformation, HeaderImage, From 6ced6d3cb0a3844b335d40c7fd2a3515869ec081 Mon Sep 17 00:00:00 2001 From: "Tuan Anh (Leo) Huynh" Date: Tue, 30 Jul 2024 18:36:51 +0700 Subject: [PATCH 17/17] v2.0.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fa6eadf..492020f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "naturelle", "private": true, "sideEffects": false, - "version": "2.0.2", + "version": "2.0.3", "scripts": { "build": "shopify hydrogen build --codegen", "dev": "shopify hydrogen dev --port 3456 --codegen",