From 7ef1aeb97a487320b3c90efd688fc2643ccf0043 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 3 Jan 2024 11:06:05 +0700 Subject: [PATCH] sync demo --- app/sections/CountDown/Timer.tsx | 19 +- app/sections/CountDown/actions.tsx | 62 +++++ app/sections/CountDown/index.tsx | 138 +++++++++++ app/sections/collection-banner.tsx | 161 +++++++++++++ app/sections/column-with-image/index.tsx | 138 +++++++++++ app/sections/column-with-image/item.tsx | 188 +++++++++++++++ app/sections/image-banner/index.tsx | 180 +++++++++++++++ app/sections/image-gallery/index.tsx | 76 ++---- app/sections/image-gallery/items.tsx | 87 +++++++ app/sections/image-with-text/content.tsx | 71 ++++++ app/sections/image-with-text/image.tsx | 67 ++++++ app/sections/image-with-text/index.tsx | 93 ++++++++ app/sections/promotion-grid/buttons.tsx | 62 +++++ app/sections/promotion-grid/index.tsx | 89 +++++++ app/sections/promotion-grid/item.tsx | 218 +++++------------- app/sections/shared/Description.tsx | 2 +- app/sections/shared/atoms.ts | 2 +- .../single-product/judgeme-review.tsx | 71 ++++++ app/sections/video-banner/index.tsx | 205 ++++++++++++++++ app/sections/video-embed/index.tsx | 44 ++++ app/sections/video-embed/video.tsx | 46 ++++ app/weaverse/components.ts | 78 +++---- package.json | 2 +- 23 files changed, 1821 insertions(+), 278 deletions(-) create mode 100644 app/sections/CountDown/actions.tsx create mode 100644 app/sections/CountDown/index.tsx create mode 100644 app/sections/collection-banner.tsx create mode 100644 app/sections/column-with-image/index.tsx create mode 100644 app/sections/column-with-image/item.tsx create mode 100644 app/sections/image-banner/index.tsx create mode 100644 app/sections/image-gallery/items.tsx create mode 100644 app/sections/image-with-text/content.tsx create mode 100644 app/sections/image-with-text/image.tsx create mode 100644 app/sections/image-with-text/index.tsx create mode 100644 app/sections/promotion-grid/buttons.tsx create mode 100644 app/sections/promotion-grid/index.tsx create mode 100644 app/sections/single-product/judgeme-review.tsx create mode 100644 app/sections/video-banner/index.tsx create mode 100644 app/sections/video-embed/index.tsx create mode 100644 app/sections/video-embed/video.tsx diff --git a/app/sections/CountDown/Timer.tsx b/app/sections/CountDown/Timer.tsx index 6f5e8d7..d8bd612 100644 --- a/app/sections/CountDown/Timer.tsx +++ b/app/sections/CountDown/Timer.tsx @@ -10,7 +10,7 @@ interface CountDownTimerProps extends HydrogenComponentProps { startDate: number; } -let CountDownTimer = forwardRef( +let CountdownTimer = forwardRef( (props, ref) => { let {textColor, startDate, ...rest} = props; const [timeRemaining, setTimeRemaining] = useState( @@ -33,8 +33,8 @@ let CountDownTimer = forwardRef( }, [startDate]); function calculateTimeRemaining(startTime: number) { - const now = new Date().getTime(); - const difference = startTime - now; + let now = new Date().getTime(); + let difference = startTime - now; if (difference <= 0) { return { days: 0, @@ -44,12 +44,12 @@ let CountDownTimer = forwardRef( }; } - const days = Math.floor(difference / (1000 * 60 * 60 * 24)); - const hours = Math.floor( + let days = Math.floor(difference / (1000 * 60 * 60 * 24)); + let hours = Math.floor( (difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60), ); - const minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)); - const seconds = Math.floor((difference % (1000 * 60)) / 1000); + let minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)); + let seconds = Math.floor((difference % (1000 * 60)) / 1000); return { days, hours, @@ -101,11 +101,12 @@ let CountDownTimer = forwardRef( }, ); -export default CountDownTimer; +export default CountdownTimer; export let schema: HydrogenComponentSchema = { - type: 'count-down--timer', + type: 'countdown--timer', title: 'Timer', + toolbar: ['general-settings', ['duplicate', 'delete']], inspector: [ { group: 'Timer', diff --git a/app/sections/CountDown/actions.tsx b/app/sections/CountDown/actions.tsx new file mode 100644 index 0000000..6a0e91d --- /dev/null +++ b/app/sections/CountDown/actions.tsx @@ -0,0 +1,62 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import type { CSSProperties } from 'react'; +import { forwardRef } from 'react'; + +interface ActionsProps extends HydrogenComponentProps { + gap: number; +} + +let Actions = forwardRef((props, ref) => { + let {gap, children, ...rest} = props; + let spacingStyle: CSSProperties = { + gap: `${gap}px`, + } as CSSProperties; + return ( +
+ {children} +
+ ); +}); + +export default Actions; + +export let schema: HydrogenComponentSchema = { + type: 'countdown--actions', + title: 'Actions', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Buttons', + inputs: [ + { + type: 'range', + name: 'gap', + label: 'Gap', + defaultValue: 12, + configs: { + min: 10, + max: 30, + step: 1, + unit: 'px', + }, + }, + ], + }, + ], + childTypes: ['button'], + presets: { + children: [ + { + type: 'button', + content: 'Button', + }, + { + type: 'button', + content: 'Button', + }, + ], + }, +}; diff --git a/app/sections/CountDown/index.tsx b/app/sections/CountDown/index.tsx new file mode 100644 index 0000000..d47b4eb --- /dev/null +++ b/app/sections/CountDown/index.tsx @@ -0,0 +1,138 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, + WeaverseImage, +} from '@weaverse/hydrogen'; +import type {CSSProperties} from 'react'; +import {forwardRef} from 'react'; +import {Image} from '@shopify/hydrogen'; + +interface CountdownProps extends HydrogenComponentProps { + backgroundColor: string; + backgroundImage: WeaverseImage; + overlayColor: string; + overlayOpacity: number; + sectionHeight: number; +} + +let Countdown = forwardRef((props, ref) => { + let { + backgroundColor, + backgroundImage, + overlayColor, + overlayOpacity, + sectionHeight, + children, + ...rest + } = props; + let sectionStyle: CSSProperties = { + '--section-height': `${sectionHeight}px`, + '--section-background-color': backgroundColor, + '--overlay-color': overlayColor, + '--overlay-opacity': `${overlayOpacity}%`, + } as CSSProperties; + + return ( +
+
+ {backgroundImage && ( + + )} + {backgroundImage && ( +
+ )} +
+
+ {children} +
+
+ ); +}); + +export default Countdown; + +export let schema: HydrogenComponentSchema = { + type: 'count-down', + title: 'Countdown', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Countdown', + inputs: [ + { + type: 'color', + name: 'backgroundColor', + label: 'Background color', + defaultValue: '#ffffff', + }, + { + type: 'image', + name: 'backgroundImage', + label: 'Background image', + }, + { + type: 'color', + name: 'overlayColor', + label: 'Overlay color', + }, + { + type: 'range', + name: 'overlayOpacity', + label: 'Overlay opacity', + defaultValue: 50, + configs: { + min: 10, + max: 100, + step: 10, + unit: '%', + }, + }, + { + type: 'range', + name: 'sectionHeight', + label: 'Section height', + defaultValue: 450, + configs: { + min: 400, + max: 700, + step: 10, + unit: 'px', + }, + }, + ], + }, + ], + childTypes: [ + 'heading', + 'subheading', + 'countdown--timer', + 'countdown--actions', + ], + presets: { + children: [ + { + type: 'heading', + content: 'Countdown heading', + }, + { + type: 'subheading', + content: 'Countdown to our upcoming event', + }, + { + type: 'countdown--timer', + }, + { + type: 'countdown--actions', + }, + ], + }, +}; diff --git a/app/sections/collection-banner.tsx b/app/sections/collection-banner.tsx new file mode 100644 index 0000000..95b69c4 --- /dev/null +++ b/app/sections/collection-banner.tsx @@ -0,0 +1,161 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import type {CSSProperties} from 'react'; +import {forwardRef} from 'react'; +import {useLoaderData} from '@remix-run/react'; +import type {CollectionDetailsQuery} from 'storefrontapi.generated'; +import clsx from 'clsx'; + +interface CollectionBannerProps extends HydrogenComponentProps { + sectionHeightDesktop: number; + sectionHeightMobile: number; + enableBackground: boolean; + overlayOpacity: number; + enableOverlay: boolean; + contentPosition: string; +} + +let CollectionBanner = forwardRef((props, ref) => { + let { + sectionHeightDesktop, + sectionHeightMobile, + enableBackground, + overlayOpacity, + enableOverlay, + contentPosition, + ...rest + } = props; + let {collection} = useLoaderData< + CollectionDetailsQuery & { + collections: Array<{handle: string; title: string}>; + } + >(); + let backgroundStyle: CSSProperties = { + '--header-height-desktop': `${sectionHeightDesktop}px`, + '--header-height-mobile': `${sectionHeightMobile}px`, + } as CSSProperties; + + if (enableBackground) { + backgroundStyle.backgroundImage = `url('${collection?.image?.url}')`; + } + let overlayStyle: CSSProperties = {}; + if (enableOverlay && enableBackground) { + overlayStyle = { + '--overlay-opacity': `${overlayOpacity}`, + } as CSSProperties; + } + let positionClass: {[key: string]: string} = { + 'top left': 'items-start justify-start', + 'top right': 'items-start justify-end', + 'top center': 'items-start justify-center', + 'center left': 'items-center justify-start', + 'center center': 'items-center justify-center', + 'center right': 'items-center justify-end', + 'bottom left': 'items-end justify-start', + 'bottom center': 'items-end justify-center', + 'bottom right': 'items-end justify-end', + }; + return ( +
+ {enableOverlay && enableBackground && ( +
+ )} +
+

{collection?.title}

+ {collection?.description && ( +

+ {collection.description} +

+ )} +
+
+ ); +}); + +export default CollectionBanner; + +export let schema: HydrogenComponentSchema = { + type: 'collection-banner', + title: 'Collection banner', + toolbar: ['general-settings', ['duplicate', 'delete']], + enabledOn: { + pages: ['COLLECTION'], + }, + inspector: [ + { + group: 'Header', + inputs: [ + { + type: 'switch', + name: 'enableBackground', + label: 'Enable background', + defaultValue: true, + }, + { + type: 'range', + name: 'sectionHeightDesktop', + label: 'Section height desktop', + defaultValue: 450, + configs: { + min: 350, + max: 550, + step: 10, + }, + }, + { + type: 'range', + name: 'sectionHeightMobile', + label: 'Section height mobile', + defaultValue: 450, + configs: { + min: 350, + max: 550, + step: 10, + }, + }, + { + type: 'switch', + name: 'enableOverlay', + label: 'Enable overlay', + defaultValue: true, + }, + { + type: 'range', + name: 'overlayOpacity', + label: 'Overlay opacity', + defaultValue: 0.5, + configs: { + min: 0.1, + max: 1, + step: 0.1, + }, + condition: `enableOverlay.eq.true`, + }, + { + type: 'position', + name: 'contentPosition', + label: 'Content position', + defaultValue: 'center center', + }, + ], + }, + ], +}; diff --git a/app/sections/column-with-image/index.tsx b/app/sections/column-with-image/index.tsx new file mode 100644 index 0000000..e4efa2a --- /dev/null +++ b/app/sections/column-with-image/index.tsx @@ -0,0 +1,138 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import type { CSSProperties } from 'react'; +import { forwardRef } from 'react'; + +interface ColumnWithImageProps extends HydrogenComponentProps { + heading: string; + textColor: string; + gap: number; + headingAlignment: string; + topPadding: number; + bottomPadding: number; +} + +let ColumnWithImage = forwardRef< + HTMLElement, + ColumnWithImageProps +>((props, ref) => { + let { + heading, + textColor, + headingAlignment, + gap, + topPadding, + bottomPadding, + children, + ...rest + } = props; + let headingStyle: CSSProperties = { + justifyContent: `${headingAlignment}`, + } as CSSProperties; + let sectionStyle: CSSProperties = { + paddingTop: `${topPadding}px`, + paddingBottom: `${bottomPadding}px`, + '--text-color': `${textColor}`, + '--gap-item': `${gap}px`, + } as CSSProperties; + + return ( +
+
+
+

{heading}

+
+
+ {children} +
+
+
+ ); +}); + +export default ColumnWithImage; + +export let schema: HydrogenComponentSchema = { + type: 'column-with-image', + title: 'Column with image', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Content', + inputs: [ + { + type: 'text', + name: 'heading', + label: 'Heading', + defaultValue: 'Heading for Image', + placeholder: 'Heading for Image section', + }, + { + type: 'color', + name: 'textColor', + label: 'Text color', + defaultValue: '#000000', + }, + { + type: 'toggle-group', + label: 'Heading alignment', + name: 'headingAlignment', + configs: { + options: [ + {label: 'Left', value: 'flex-start'}, + {label: 'Center', value: 'center'}, + {label: 'Right', value: 'flex-end'}, + ], + }, + defaultValue: 'center', + }, + { + type: 'range', + name: 'gap', + label: 'Gap', + defaultValue: 20, + configs: { + min: 10, + max: 50, + step: 1, + unit: 'px', + }, + }, + { + type: 'range', + name: 'topPadding', + label: 'Top padding', + defaultValue: 0, + configs: { + min: 0, + max: 100, + step: 5, + unit: 'px', + }, + }, + { + type: 'range', + name: 'bottomPadding', + label: 'Bottom padding', + defaultValue: 0, + configs: { + min: 0, + max: 100, + step: 5, + unit: 'px', + }, + }, + ], + }, + ], + childTypes: ['column-with-image--item'], + presets: { + children: [ + { + type: 'column-with-image--item', + }, + ], + }, +}; diff --git a/app/sections/column-with-image/item.tsx b/app/sections/column-with-image/item.tsx new file mode 100644 index 0000000..3b55592 --- /dev/null +++ b/app/sections/column-with-image/item.tsx @@ -0,0 +1,188 @@ +import { Image } from '@shopify/hydrogen'; +import type { + HydrogenComponentProps, + HydrogenComponentSchema, + WeaverseImage, +} from '@weaverse/hydrogen'; +import clsx from 'clsx'; +import type { CSSProperties } from 'react'; +import { forwardRef } from 'react'; +import { IconImageBlank } from '~/components'; + +interface ColumnWithImageItemProps extends HydrogenComponentProps { + imageSrc: WeaverseImage; + titleText: string; + contentAlignment: string; + descriptionText: string; + buttonLabel: string; + buttonLink: string; + openInNewTab: boolean; + buttonStyle: string; + hideOnMobile: boolean; +} + +let ColumnWithImageItem = forwardRef( + (props, ref) => { + let { + imageSrc, + titleText, + contentAlignment, + descriptionText, + buttonLabel, + buttonLink, + openInNewTab, + buttonStyle, + hideOnMobile, + ...rest + } = props; + let contentStyle: CSSProperties = { + textAlign: `${contentAlignment}`, + } as CSSProperties; + return ( +
+
+ {imageSrc ? ( + + ) : ( +
+ +
+ )} +
+
+ {titleText && ( +

+ {titleText} +

+ )} + {descriptionText && ( +

+ {descriptionText} +

+ )} + {buttonLabel && ( + + {buttonLabel} + + )} +
+
+ ); + }, +); + +export default ColumnWithImageItem; + +export let schema: HydrogenComponentSchema = { + type: 'column-with-image--item', + title: 'Column', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Column', + inputs: [ + { + type: 'image', + name: 'imageSrc', + label: 'Image', + }, + { + type: 'text', + name: 'titleText', + label: 'Title', + placeholder: 'Item title', + defaultValue: 'Item title', + }, + { + type: 'toggle-group', + label: 'Content alignment', + name: 'contentAlignment', + configs: { + options: [ + {label: 'Left', value: 'left'}, + {label: 'Center', value: 'center'}, + {label: 'Right', value: 'right'}, + ], + }, + defaultValue: 'center', + }, + { + type: 'textarea', + label: 'Text', + name: 'descriptionText', + placeholder: 'Brief description', + defaultValue: 'Brief description', + }, + { + type: 'text', + label: 'Button label', + name: 'buttonLabel', + placeholder: 'Button label', + defaultValue: 'Optional button', + }, + { + type: 'text', + label: 'Button link', + name: 'buttonLink', + placeholder: 'Button link', + }, + { + type: 'switch', + name: 'openInNewTab', + label: 'Open in new tab', + defaultValue: true, + }, + { + type: 'toggle-group', + label: 'Button style', + name: 'buttonStyle', + configs: { + options: [ + { + label: '1', + value: + 'transition hover:bg-white border-2 border-solid hover:border-gray-900 hover:text-black bg-black text-white', + }, + { + label: '2', + value: + 'transition bg-white border-2 border-solid border-gray-900 text-black hover:bg-black hover:text-white', + }, + { + label: '3', + value: + 'transition hover:bg-white border-2 border-solid border-white hover:text-black bg-gray-200 text-white', + }, + ], + }, + defaultValue: + 'transition hover:bg-white border-2 border-solid hover:border-gray-900 hover:text-black bg-black text-white', + }, + { + type: 'switch', + label: 'Hide on Mobile', + name: 'hideOnMobile', + defaultValue: false, + }, + ], + }, + ], +}; diff --git a/app/sections/image-banner/index.tsx b/app/sections/image-banner/index.tsx new file mode 100644 index 0000000..c92b0bf --- /dev/null +++ b/app/sections/image-banner/index.tsx @@ -0,0 +1,180 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, + WeaverseImage, +} from '@weaverse/hydrogen'; +import type {CSSProperties} from 'react'; +import {forwardRef} from 'react'; +import clsx from 'clsx'; +import {Image} from '@shopify/hydrogen'; +import {IconImageBlank} from '~/components'; + +interface HeaderImageProps extends HydrogenComponentProps { + backgroundImage: WeaverseImage; + contentAlignment: string; + enableOverlay: boolean; + overlayColor: string; + overlayOpacity: number; + sectionHeightDesktop: number; + sectionHeightMobile: number; +} + +let HeaderImage = forwardRef((props, ref) => { + let { + backgroundImage, + contentAlignment, + enableOverlay, + overlayColor, + overlayOpacity, + sectionHeightDesktop, + sectionHeightMobile, + children, + ...rest + } = props; + let sectionStyle: CSSProperties = { + justifyContent: `${contentAlignment}`, + '--section-height-desktop': `${sectionHeightDesktop}px`, + '--section-height-mobile': `${sectionHeightMobile}px`, + '--overlay-opacity': `${overlayOpacity}%`, + '--overlay-color': `${overlayColor}`, + '--max-width-content': '600px', + } as CSSProperties; + + return ( +
+
+ {backgroundImage ? ( + + ) : ( +
+ +
+ )} + {enableOverlay && ( +
+ )} +
+
+ {children} +
+
+ ); +}); + +export default HeaderImage; + +export let schema: HydrogenComponentSchema = { + type: 'image-banner', + title: 'Image banner', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Image', + inputs: [ + { + type: 'image', + name: 'backgroundImage', + label: 'Background image', + }, + { + type: 'toggle-group', + label: 'Content alignment', + name: 'contentAlignment', + configs: { + options: [ + {label: 'Left', value: 'flex-start'}, + {label: 'Center', value: 'center'}, + {label: 'Right', value: 'flex-end'}, + ], + }, + defaultValue: 'center', + }, + { + type: 'switch', + name: 'enableOverlay', + label: 'Enable overlay', + defaultValue: true, + }, + { + type: 'color', + name: 'overlayColor', + label: 'Overlay color', + defaultValue: '#333333', + condition: `enableOverlay.eq.true`, + }, + { + type: 'range', + name: 'overlayOpacity', + label: 'Overlay opacity', + defaultValue: 50, + configs: { + min: 10, + max: 100, + step: 10, + unit: '%', + }, + condition: `enableOverlay.eq.true`, + }, + { + type: 'range', + name: 'sectionHeightDesktop', + label: 'Section height desktop', + defaultValue: 450, + configs: { + min: 400, + max: 700, + step: 10, + unit: 'px', + }, + }, + { + type: 'range', + name: 'sectionHeightMobile', + label: 'Section height mobile', + defaultValue: 350, + configs: { + min: 300, + max: 600, + step: 10, + unit: 'px', + }, + }, + ], + }, + ], + childTypes: ['subheading', 'heading', 'description', 'button'], + presets: { + children: [ + { + type: 'subheading', + content: 'Subheading', + }, + { + type: 'heading', + content: 'Heading for Image', + }, + { + type: 'description', + content: 'Pair large text with an image to tell a story.', + }, + { + type: 'button', + content: 'Button section', + }, + ], + }, +}; diff --git a/app/sections/image-gallery/index.tsx b/app/sections/image-gallery/index.tsx index 4e9ab08..d86a7cc 100644 --- a/app/sections/image-gallery/index.tsx +++ b/app/sections/image-gallery/index.tsx @@ -3,28 +3,20 @@ import type { HydrogenComponentSchema, } from '@weaverse/hydrogen'; import {forwardRef} from 'react'; +import type {SectionProps} from '~/sections/shared/Section'; +import {Section, sectionConfigs} from '~/sections/shared/Section'; -interface ImageGalleryProps extends HydrogenComponentProps { +type ImageGalleryProps = SectionProps & { heading: string; description: string; -} +}; let ImageGallery = forwardRef((props, ref) => { let {heading, description, children, ...rest} = props; return ( -
-
-

- {heading} -

-

- {description} -

-
- {children} -
-
-
+
+ {children} +
); }); @@ -33,60 +25,22 @@ export default ImageGallery; export let schema: HydrogenComponentSchema = { type: 'image-gallery', title: 'Image Gallery', - childTypes: ['image-gallery--item'], - inspector: [ - { - group: 'Image Gallery', - inputs: [ - { - type: 'text', - name: 'heading', - label: 'Heading', - placeholder: 'Section heading', - defaultValue: 'Discover Our Latest Styles', - }, - { - type: 'text', - name: 'description', - label: 'Description', - placeholder: 'Section description', - defaultValue: `Stay on trend this season with our newest arrivals. We've curated the latest looks in women's fashion so you can refresh your wardrobe with ease. From flowy dresses and printed blouses perfect for summer, to cozy sweaters and tall boots for cooler months, our new collection has versatile pieces to take you from work to weekend. Shop cute and comfortable athleisure wear, chic handbags, and so much more.`, - }, - ], - }, - ], + childTypes: ['heading', 'description', 'image-gallery--items'], + inspector: [sectionConfigs], toolbar: ['general-settings', ['duplicate', 'delete']], presets: { children: [ { - type: 'image-gallery--item', - columnSpan: 2, - src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-hand-placed-on-the-iridescent-keys-of-a-small-piano.jpg?v=1694236467', - }, - { - type: 'image-gallery--item', - hideOnMobile: true, - src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-open-novel-with-a-hand-on-it-by-dried-flowers.jpg?v=1694236467', - }, - { - type: 'image-gallery--item', - hideOnMobile: true, - src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-creamy-cold-drink-sits-on-a-wooden-table.jpg?v=1694236467', - }, - { - type: 'image-gallery--item', - hideOnMobile: true, - src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-hands-reach-to-feed-a-flying-seagull.jpg?v=1694236467', + type: 'heading', + content: 'Hello World from Weaverse!', }, { - type: 'image-gallery--item', - hideOnMobile: true, - src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-nati-melnychuk-5ngCICAXiH0-unsplash.jpg?v=1694231122', + type: 'description', + content: + "Stay on trend this season with our newest arrivals. We've curated the latest looks in women's fashion so you can refresh your wardrobe with ease. From flowy dresses and printed blouses perfect for summer, to cozy sweaters and tall boots for cooler months, our new collection has versatile pieces to take you from work to weekend. Shop cute and comfortable athleisure wear, chic handbags, and so much more.", }, { - type: 'image-gallery--item', - columnSpan: 2, - src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-flatlay-of-a-coffee-mug-and-items-to-plan-travel.jpg?v=1694236467', + type: 'image-gallery--items', }, ], }, diff --git a/app/sections/image-gallery/items.tsx b/app/sections/image-gallery/items.tsx new file mode 100644 index 0000000..a918dc8 --- /dev/null +++ b/app/sections/image-gallery/items.tsx @@ -0,0 +1,87 @@ +import { + type HydrogenComponentProps, + type HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import {forwardRef} from 'react'; + +interface ImageGalleyItemsProps extends HydrogenComponentProps { + gap: number; +} + +let ImageGalleyItems = forwardRef( + (props, ref) => { + let {children, gap, ...rest} = props; + + return ( +
+ {children} +
+ ); + }, +); + +export default ImageGalleyItems; + +export let schema: HydrogenComponentSchema = { + type: 'image-gallery--items', + title: 'Items', + inspector: [ + { + group: 'Image', + inputs: [ + { + type: 'range', + label: 'Gap', + name: 'gap', + configs: { + min: 16, + max: 40, + step: 6, + }, + defaultValue: 16, + }, + ], + }, + ], + childTypes: ['image-gallery--item'], + toolbar: ['general-settings', ['duplicate', 'delete']], + presets: { + children: [ + { + type: 'image-gallery--item', + columnSpan: 2, + src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-hand-placed-on-the-iridescent-keys-of-a-small-piano.jpg?v=1694236467', + }, + { + type: 'image-gallery--item', + hideOnMobile: true, + src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-open-novel-with-a-hand-on-it-by-dried-flowers.jpg?v=1694236467', + }, + { + type: 'image-gallery--item', + hideOnMobile: true, + src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-creamy-cold-drink-sits-on-a-wooden-table.jpg?v=1694236467', + }, + { + type: 'image-gallery--item', + hideOnMobile: true, + src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-hands-reach-to-feed-a-flying-seagull.jpg?v=1694236467', + }, + { + type: 'image-gallery--item', + hideOnMobile: true, + src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-nati-melnychuk-5ngCICAXiH0-unsplash.jpg?v=1694231122', + }, + { + type: 'image-gallery--item', + columnSpan: 2, + src: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/wv-flatlay-of-a-coffee-mug-and-items-to-plan-travel.jpg?v=1694236467', + }, + ], + }, +}; diff --git a/app/sections/image-with-text/content.tsx b/app/sections/image-with-text/content.tsx new file mode 100644 index 0000000..028a30e --- /dev/null +++ b/app/sections/image-with-text/content.tsx @@ -0,0 +1,71 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import { forwardRef, CSSProperties } from 'react'; + +interface ContentItemsProps extends HydrogenComponentProps { + gap: number; +} + +let ContentItems = forwardRef((props, ref) => { + let { children, gap, ...rest } = props; + let style = { + gap: `${gap}px`, + textAlign: 'left', + } as CSSProperties; + return ( +
+ {children} +
+ ); +}); + +export default ContentItems; + +export let schema: HydrogenComponentSchema = { + type: 'image-with-text--content', + title: 'Content', + limit: 1, + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Content', + inputs: [ + { + type: 'range', + name: 'gap', + label: 'Items gap', + configs: { + min: 0, + max: 40, + step: 4, + unit: 'px', + }, + defaultValue: 20, + }, + ], + }, + ], + childTypes: ['subheading', 'heading', 'description', 'button'], + presets: { + children: [ + { + type: 'subheading', + content: 'Subheading', + }, + { + type: 'heading', + content: 'Heading for image', + }, + { + type: 'description', + content: 'Pair large text with an image to tell a story.', + }, + { + type: 'button', + content: 'Button section', + }, + ], + }, +}; diff --git a/app/sections/image-with-text/image.tsx b/app/sections/image-with-text/image.tsx new file mode 100644 index 0000000..e364ed2 --- /dev/null +++ b/app/sections/image-with-text/image.tsx @@ -0,0 +1,67 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, + WeaverseImage, +} from '@weaverse/hydrogen'; +import { forwardRef } from 'react'; +import { Image } from '@shopify/hydrogen'; +import { IconImageBlank } from '~/components'; + +interface ImageItemsProps extends HydrogenComponentProps { + image: WeaverseImage, + loading: HTMLImageElement['loading']; +} + +let ImageItems = forwardRef((props, ref) => { + let { image, loading, ...rest } = props; + + return ( +
+ {image ? : +
+ +
+ } +
+ ); +}); + +export default ImageItems; + +export let schema: HydrogenComponentSchema = { + type: 'image-with-text--image', + title: 'Image', + toolbar: ['general-settings', ['duplicate', 'delete']], + limit: 1, + inspector: [ + { + group: 'Image', + inputs: [ + { + type: 'image', + name: 'image', + label: 'Image', + }, + { + type: 'toggle-group', + name: 'loading', + label: 'Image loading', + defaultValue: 'eager', + configs: { + options: [ + { label: 'Eager', value: 'eager', icon: 'Lightning' }, + { + label: 'Lazy', + value: 'lazy', + icon: 'SpinnerGap', + weight: 'light', + }, + ], + }, + helpText: + 'Learn more about image loading strategies.', + }, + ], + }, + ], +}; diff --git a/app/sections/image-with-text/index.tsx b/app/sections/image-with-text/index.tsx new file mode 100644 index 0000000..6b5d8b2 --- /dev/null +++ b/app/sections/image-with-text/index.tsx @@ -0,0 +1,93 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import type { CSSProperties } from 'react'; +import { forwardRef } from 'react'; +import { clsx } from 'clsx'; + +type AlignImage = 'left' | 'right'; +interface ImageWithTextProps extends HydrogenComponentProps { + sectionHeight: number; + backgroundColor: string; + imageAlignment?: AlignImage; +} + +let AlignImageClasses: Record = { + left: 'flex-row-reverse', + right: 'flex-row', +}; + +let ImageWithText = forwardRef((props, ref) => { + let { imageAlignment, sectionHeight, backgroundColor, children, ...rest } = props; + let styleSection: CSSProperties = { + '--section-height': `${sectionHeight}px`, + backgroundColor: backgroundColor, + } as CSSProperties; + + return ( +
+
+
+ {children} +
+
+
+ ); +}); + +export default ImageWithText; + +export let schema: HydrogenComponentSchema = { + type: 'image-with-text', + title: 'Image with text', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Image', + inputs: [ + { + type: 'toggle-group', + label: 'Image alignment', + name: 'imageAlignment', + configs: { + options: [ + { label: 'Left', value: 'left', icon: 'AlignLeft' }, + { label: 'Right', value: 'right', icon: 'AlignRight' }, + ], + }, + defaultValue: 'left', + }, + { + type: 'range', + name: 'sectionHeight', + label: 'Section height', + defaultValue: 450, + configs: { + min: 400, + max: 700, + step: 10, + unit: 'px', + }, + }, + { + type: 'color', + name: 'backgroundColor', + label: 'Background color', + defaultValue: '#f4f4f4', + }, + ], + }, + ], + childTypes: ['content-items', 'image-items'], + presets: { + children: [ + { + type: 'image-with-text--content', + }, + { + type: 'image-with-text--image', + }, + ], + }, +}; diff --git a/app/sections/promotion-grid/buttons.tsx b/app/sections/promotion-grid/buttons.tsx new file mode 100644 index 0000000..8fd30d2 --- /dev/null +++ b/app/sections/promotion-grid/buttons.tsx @@ -0,0 +1,62 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import type { CSSProperties } from 'react'; +import { forwardRef } from 'react'; + +interface ButtonItemsProps extends HydrogenComponentProps { + gap: number; +} + +let PromotionItemButtons = forwardRef((props, ref) => { + let {gap, children, ...rest} = props; + let spacingStyle: CSSProperties = { + gap: `${gap}px`, + } as CSSProperties; + return ( +
+ {children} +
+ ); +}); + +export default PromotionItemButtons; + +export let schema: HydrogenComponentSchema = { + type: 'promotion-item--buttons', + title: 'Buttons', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Buttons', + inputs: [ + { + type: 'range', + name: 'gap', + label: 'Gap', + defaultValue: 12, + configs: { + min: 10, + max: 30, + step: 1, + unit: 'px', + }, + }, + ], + }, + ], + childTypes: ['button'], + presets: { + children: [ + { + type: 'button', + content: 'Button', + }, + { + type: 'button', + content: 'Button', + }, + ], + }, +}; diff --git a/app/sections/promotion-grid/index.tsx b/app/sections/promotion-grid/index.tsx new file mode 100644 index 0000000..824d299 --- /dev/null +++ b/app/sections/promotion-grid/index.tsx @@ -0,0 +1,89 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import type {CSSProperties} from 'react'; +import {forwardRef} from 'react'; + +interface PromotionProps extends HydrogenComponentProps { + gap: number; + topPadding: number; + bottomPadding: number; +} + +let PromotionGrid = forwardRef((props, ref) => { + let {gap, topPadding, bottomPadding, children, ...rest} = props; + let spacingStyle: CSSProperties = { + gap: `${gap}px`, + paddingTop: `${topPadding}px`, + paddingBottom: `${bottomPadding}px`, + } as CSSProperties; + return ( +
+
+
+ {children} +
+
+
+ ); +}); + +export default PromotionGrid; + +export let schema: HydrogenComponentSchema = { + type: 'promotion-grid', + title: 'Promotion grid', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Promotion', + inputs: [ + { + type: 'range', + name: 'gap', + label: 'Gap', + defaultValue: 30, + configs: { + min: 20, + max: 50, + step: 10, + unit: 'px', + }, + }, + { + type: 'range', + name: 'topPadding', + label: 'Top padding', + defaultValue: 40, + configs: { + min: 10, + max: 100, + step: 10, + unit: 'px', + }, + }, + { + type: 'range', + name: 'bottomPadding', + label: 'Bottom padding', + defaultValue: 40, + configs: { + min: 10, + max: 100, + step: 10, + unit: 'px', + }, + }, + ], + }, + ], + childTypes: ['promotion-item'], + presets: { + children: [ + { + type: 'promotion-item', + }, + ], + }, +}; diff --git a/app/sections/promotion-grid/item.tsx b/app/sections/promotion-grid/item.tsx index 1cae73a..a8e7798 100644 --- a/app/sections/promotion-grid/item.tsx +++ b/app/sections/promotion-grid/item.tsx @@ -3,194 +3,82 @@ import type { HydrogenComponentSchema, WeaverseImage, } from '@weaverse/hydrogen'; -import { forwardRef } from 'react'; -import { Image } from '@shopify/hydrogen'; +import {forwardRef} from 'react'; +import {Image} from '@shopify/hydrogen'; import {IconImageBlank} from '~/components'; -import clsx from 'clsx'; interface PromotionItemProps extends HydrogenComponentProps { backgroundImage: WeaverseImage; - subHeading: string; - subHeadingSize: string; - subHeadingColor: string; - heading: string; - headingColor: string; - descriptionText: string; - descriptionSize: string; - descriptionColor: string; - buttonLabel1: string; - buttonLink1: string; - buttonLabel2: string; - buttonLink2: string; - openInNewTab: boolean; - buttonStyle1: string; - buttonStyle2: string; } -let PromotionGridItem = forwardRef((props, ref) => { - let { backgroundImage, subHeading, subHeadingSize, subHeadingColor, heading, headingColor, descriptionText, descriptionSize, descriptionColor, buttonLabel1, buttonLink1, buttonLabel2, buttonLink2, openInNewTab, buttonStyle1, buttonStyle2, ...rest } = props; - return ( -
-
- {backgroundImage ? : -
- -
} -
-
-
- {subHeading &&

{subHeading}

} - {heading &&

{heading}

} - {descriptionText &&

{descriptionText}

} -
- {buttonLabel1 && {buttonLabel1}} - {buttonLabel2 && {buttonLabel2}} +let PromotionGridItem = forwardRef( + (props, ref) => { + let {backgroundImage, children, ...rest} = props; + return ( +
+
+ {backgroundImage ? ( + + ) : ( +
+ +
+ )} +
+
+
+ {children}
-
- ); -}); + ); + }, +); export default PromotionGridItem; export let schema: HydrogenComponentSchema = { type: 'promotion-item', - title: 'Promotion item', + title: 'Promotion', + toolbar: ['general-settings', ['duplicate', 'delete']], inspector: [ { - group: 'Promotion item', + group: 'Promotion', inputs: [ { type: 'image', name: 'backgroundImage', label: 'Background image', }, - { - type: 'text', - name: 'subHeading', - label: 'Subheading', - defaultValue: 'Subheading', - placeholder: 'Subheading', - }, - { - type: 'toggle-group', - label: 'Subheading size', - name: 'subHeadingSize', - configs: { - options: [ - { label: 'XS', value: '14px' }, - { label: 'S', value: '16px' }, - { label: 'M', value: '18px' }, - { label: 'L', value: '20px' }, - { label: 'XL', value: '22px' }, - ], - }, - defaultValue: '16px', - }, - { - type: 'color', - name: 'subHeadingColor', - label: 'Subheading color', - defaultValue: '#333333', - }, - { - type: 'text', - name: 'heading', - label: 'Heading', - defaultValue: 'Heading for Image', - placeholder: 'Heading for image section', - }, - { - type: 'color', - name: 'headingColor', - label: 'Heading color', - defaultValue: '#333333', - }, - { - type: 'textarea', - name: 'descriptionText', - label: 'Text', - defaultValue: 'Include the smaller details of your promotion in text below the title.', - }, - { - type: 'toggle-group', - label: 'Description size', - name: 'descriptionSize', - configs: { - options: [ - { label: 'XS', value: '14px' }, - { label: 'S', value: '16px' }, - { label: 'M', value: '18px' }, - { label: 'L', value: '20px' }, - { label: 'XL', value: '22px' }, - ], - }, - defaultValue: '16px', - }, - { - type: 'color', - name: 'descriptionColor', - label: 'Description color', - defaultValue: '#333333', - }, - { - type: 'text', - name: 'buttonLabel1', - label: 'Button label 1', - defaultValue: 'Button', - }, - { - type: 'text', - name: 'buttonLink1', - label: 'Button #1 link', - placeholder: 'https://', - }, - { - type: 'text', - name: 'buttonLabel2', - label: 'Button label 2', - defaultValue: 'Button', - }, - { - type: 'text', - name: 'buttonLink2', - label: 'Button #2 link', - placeholder: 'https://', - }, - { - type: 'switch', - name: 'openInNewTab', - label: 'Open in new tab', - defaultValue: true, - }, - { - type: 'toggle-group', - label: 'Button style #1', - name: 'buttonStyle1', - configs: { - options: [ - { label: '1', value: 'transition hover:bg-white border-2 border-solid hover:border-gray-900 hover:text-black bg-black text-white' }, - { label: '2', value: 'transition bg-white border-2 border-solid border-gray-900 text-black hover:bg-black hover:text-white' }, - { label: '3', value: 'transition hover:bg-white border-2 border-solid border-white hover:text-black bg-gray-200 text-white' }, - ], - }, - defaultValue: 'transition hover:bg-white border-2 border-solid hover:border-gray-900 hover:text-black bg-black text-white', - }, - { - type: 'toggle-group', - label: 'Button style #2', - name: 'buttonStyle2', - configs: { - options: [ - { label: '1', value: 'transition hover:bg-white border-2 border-solid hover:border-gray-900 hover:text-black bg-black text-white' }, - { label: '2', value: 'transition bg-white border-2 border-solid border-gray-900 text-black hover:bg-black hover:text-white' }, - { label: '3', value: 'transition hover:bg-white border-2 border-solid border-white hover:text-black bg-gray-200 text-white' }, - ], - }, - defaultValue: 'transition hover:bg-white border-2 border-solid hover:border-gray-900 hover:text-black bg-black text-white', - }, ], }, ], + childTypes: ['subheading', 'heading', 'description', 'promotion-item--buttons'], + presets: { + children: [ + { + type: 'subheading', + content: 'Subheading', + }, + { + type: 'heading', + content: 'Heading for Image', + }, + { + type: 'description', + content: + 'Include the smaller details of your promotion in text below the title.', + }, + { + type: 'promotion-item--buttons', + }, + ], + }, }; diff --git a/app/sections/shared/Description.tsx b/app/sections/shared/Description.tsx index bcf215d..73ebc82 100644 --- a/app/sections/shared/Description.tsx +++ b/app/sections/shared/Description.tsx @@ -80,7 +80,7 @@ export let schema: HydrogenComponentSchema = { defaultValue: 'p', }, { - type: 'textarea', + type: 'richtext', name: 'content', label: 'Content', defaultValue: diff --git a/app/sections/shared/atoms.ts b/app/sections/shared/atoms.ts index dfe19da..691162e 100644 --- a/app/sections/shared/atoms.ts +++ b/app/sections/shared/atoms.ts @@ -4,7 +4,7 @@ import * as SubHeading from './SubHeading'; import * as Description from './Description'; import * as Button from './Button'; -export let atoms: HydrogenComponent[] = [ +export let commonComponents: HydrogenComponent[] = [ SubHeading, Heading, Description, diff --git a/app/sections/single-product/judgeme-review.tsx b/app/sections/single-product/judgeme-review.tsx new file mode 100644 index 0000000..320fb0f --- /dev/null +++ b/app/sections/single-product/judgeme-review.tsx @@ -0,0 +1,71 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import StarsRating from 'react-star-rate'; +import {useParentInstance} from '@weaverse/hydrogen'; +import {useFetcher} from '@remix-run/react'; +import {forwardRef, useEffect} from 'react'; +import {usePrefixPathWithLocale} from '~/lib/utils'; + +let JudgemeReview = forwardRef( + (props, ref) => { + let {load, data} = useFetcher<{ + rating: number; + reviewNumber: number; + error?: string; + }>(); + + let context = useParentInstance(); + let handle = context?.data?.product?.handle!; + let api = usePrefixPathWithLocale(`/api/review/${handle}`); + + useEffect(() => { + if (handle) { + load(api); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [handle, api]); + + if (!data) return null; + if (data.error) { + return ( +
+ {data.error} +
+ ); + } + + let rating = Math.round((data.rating || 0) * 100) / 100; + let reviewNumber = data.reviewNumber || 0; + + return ( +
+ {' '} + ({reviewNumber}) +
+ ); + }, +); + +export default JudgemeReview; + +export let schema: HydrogenComponentSchema = { + type: 'judgeme', + title: 'Judgeme review', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Judgeme', + inputs: [], + }, + ], +}; diff --git a/app/sections/video-banner/index.tsx b/app/sections/video-banner/index.tsx new file mode 100644 index 0000000..07795b4 --- /dev/null +++ b/app/sections/video-banner/index.tsx @@ -0,0 +1,205 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import type {CSSProperties} from 'react'; +import {forwardRef} from 'react'; +import ReactPlayer from 'react-player/youtube'; +import {IconVideoBlank} from '~/components'; + +interface VideoBannerProps extends HydrogenComponentProps { + videoLink: string; + enableOverlay: boolean; + overlayColor: string; + overlayOpacity: number; + sectionHeightDesktop: number; + sectionHeightMobile: number; + enableAutoPlay: boolean; + enableLoop: boolean; + enableMuted: boolean; + contentAlignment: string; +} + +let VideoBanner = forwardRef( + (props, ref) => { + let { + videoLink, + enableOverlay, + overlayColor, + overlayOpacity, + sectionHeightDesktop, + sectionHeightMobile, + enableAutoPlay, + enableLoop, + enableMuted, + contentAlignment, + children, + ...rest + } = props; + let sectionStyle: CSSProperties = { + justifyContent: `${contentAlignment}`, + '--section-height-desktop': `${sectionHeightDesktop}px`, + '--section-height-mobile': `${sectionHeightMobile}px`, + '--overlay-opacity': `${overlayOpacity}%`, + '--overlay-color': `${overlayColor}`, + '--max-width-content': '600px', + } as CSSProperties; + + return ( +
+ {videoLink ? ( + + ) : ( +
+ +
+ )} + {enableOverlay && ( +
+ )} +
+ {children} +
+
+ ); + }, +); + +export default VideoBanner; + +export let schema: HydrogenComponentSchema = { + type: 'video-banner', + title: 'Video banner', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Video', + inputs: [ + { + type: 'text', + name: 'videoLink', + label: 'Video link', + defaultValue: 'https://www.youtube.com/embed/_9VUPq3SxOc', + placeholder: 'https://', + }, + { + type: 'switch', + name: 'enableOverlay', + label: 'Enable overlay', + defaultValue: true, + }, + { + type: 'color', + name: 'overlayColor', + label: 'Overlay color', + defaultValue: '#333333', + condition: `enableOverlay.eq.true`, + }, + { + type: 'range', + name: 'overlayOpacity', + label: 'Overlay opacity', + defaultValue: 50, + configs: { + min: 10, + max: 100, + step: 10, + unit: '%', + }, + condition: `enableOverlay.eq.true`, + }, + { + type: 'toggle-group', + label: 'Content alignment', + name: 'contentAlignment', + configs: { + options: [ + {label: 'Left', value: 'flex-start'}, + {label: 'Center', value: 'center'}, + {label: 'Right', value: 'flex-end'}, + ], + }, + defaultValue: 'center', + }, + { + type: 'range', + name: 'sectionHeightDesktop', + label: 'Section height desktop', + defaultValue: 450, + configs: { + min: 400, + max: 500, + step: 10, + unit: 'px', + }, + }, + { + type: 'range', + name: 'sectionHeightMobile', + label: 'Section height mobile', + defaultValue: 250, + configs: { + min: 200, + max: 300, + step: 10, + unit: 'px', + }, + }, + { + type: 'switch', + name: 'enableAutoPlay', + label: 'Auto play', + defaultValue: true, + }, + { + type: 'switch', + name: 'enableLoop', + label: 'Loop', + defaultValue: true, + }, + { + type: 'switch', + name: 'enableMuted', + label: 'Muted', + defaultValue: true, + }, + ], + }, + ], + childTypes: ['subheading', 'heading', 'description', 'button'], + presets: { + children: [ + { + type: 'subheading', + content: 'Subheading', + }, + { + type: 'heading', + content: 'Heading for Video', + }, + { + type: 'description', + content: 'Pair large text with an image to tell a story.', + }, + { + type: 'button', + content: 'Button section', + }, + ], + }, +}; diff --git a/app/sections/video-embed/index.tsx b/app/sections/video-embed/index.tsx new file mode 100644 index 0000000..106cf5e --- /dev/null +++ b/app/sections/video-embed/index.tsx @@ -0,0 +1,44 @@ +import type {HydrogenComponentSchema} from '@weaverse/hydrogen'; +import {forwardRef} from 'react'; +import type {SectionProps} from '~/sections/shared/Section'; +import {Section, sectionConfigs} from '~/sections/shared/Section'; + +type VideoEmbedProps = SectionProps & { + heading: string; + description: string; +}; + +let VideoEmbed = forwardRef((props, ref) => { + let {children, ...rest} = props; + return ( +
+ {children} +
+ ); +}); + +export default VideoEmbed; + +export let schema: HydrogenComponentSchema = { + type: 'video', + title: 'Video embed', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [sectionConfigs], + childTypes: ['heading', 'description', 'video-embed--item'], + presets: { + children: [ + { + type: 'heading', + content: 'This is how Shopify Headless done right!', + }, + { + type: 'description', + content: + 'Our Hydrogen store is set up by Shopify Experts and can be customized with Weaverse. It can be easily published to Oxygen and then handed over to the merchants. The Hydrogen store offers the ability to connect to any data source from the server side, eliminating the need for developers to create custom apps. Weaverse provides a user-friendly way for merchants to edit their storefront, similar to the Liquid theme customizer. It also offers developers a powerful toolset and a reusable bootstrap theme, which can save up to 70% of their time when building a headless storefront.', + }, + { + type: 'video-embed--item', + }, + ], + }, +}; diff --git a/app/sections/video-embed/video.tsx b/app/sections/video-embed/video.tsx new file mode 100644 index 0000000..2d25592 --- /dev/null +++ b/app/sections/video-embed/video.tsx @@ -0,0 +1,46 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import {forwardRef} from 'react'; + +interface VideoItemProps extends HydrogenComponentProps { + videoUrl: string; +} + +let VideoItem = forwardRef((props, ref) => { + let {videoUrl, ...rest} = props; + return ( +