diff --git a/app/components/Cart.tsx b/app/components/Cart.tsx index 01dbe37..83a9cc2 100644 --- a/app/components/Cart.tsx +++ b/app/components/Cart.tsx @@ -166,19 +166,33 @@ function CartLines({ ])} > - {layout === 'page' && - - - - - - - - - } + {layout === 'page' && ( + + + + + + + + + + + )} {currentLines.map((line) => ( - + ))}
ProductPriceQuantityTotal
+ Product + + Price + + Quantity + + Total +
@@ -247,12 +261,18 @@ type OptimisticData = { quantity?: number; }; -function CartLineItem({line, layout}: {line: CartLine, layout: 'drawer' | 'page'}) { +function CartLineItem({ + line, + layout, +}: { + line: CartLine; + layout: 'drawer' | 'page'; +}) { const optimisticData = useOptimisticData(line?.id); let styles = { - page: "grid lg:table-row gap-2 grid-rows-2 grid-cols-[100px_1fr_64px]", - drawer: "grid gap-2 grid-rows-2 grid-cols-[100px_1fr_64px]" - } + page: 'grid lg:table-row gap-2 grid-rows-2 grid-cols-[100px_1fr_64px]', + drawer: 'grid gap-2 grid-rows-2 grid-cols-[100px_1fr_64px]', + }; if (!line?.id) return null; const {id, quantity, merchandise, cost} = line; @@ -262,11 +282,7 @@ function CartLineItem({line, layout}: {line: CartLine, layout: 'drawer' | 'page' // Do not remove the form from the DOM let style = optimisticData?.action === 'remove' ? {display: 'none'} : {}; return ( - + {merchandise.image && (
- {
- -
} + { +
+ +
+ }
- {layout === 'page' && - - } + {layout === 'page' && ( + + + + )} - + ); diff --git a/app/components/Icon.tsx b/app/components/Icon.tsx index be9114e..96a4bf1 100644 --- a/app/components/Icon.tsx +++ b/app/components/Icon.tsx @@ -313,3 +313,10 @@ export function IconFacebook(props: IconProps) { ); } +export function IconMapBlank(props: IconProps) { + return( + + + + ); +} diff --git a/app/components/Input.tsx b/app/components/Input.tsx index 6ecbe27..1ea78f7 100644 --- a/app/components/Input.tsx +++ b/app/components/Input.tsx @@ -1,6 +1,6 @@ import clsx from 'clsx'; import {useState} from 'react'; -import { IconClose, IconSearch } from '.'; +import {IconClose} from '.'; const variants = { default: '', @@ -30,16 +30,16 @@ export function Input({ let commonClasses = clsx( 'w-full rounded-sm border px-3 py-2.5', focused ? 'border-bar/50' : 'border-bar/10', - className + className, ); - let handleClear = (e) => { + let handleClear = (e: any) => { e.preventDefault(); e.stopPropagation(); e.currentTarget.previousSibling.value = ''; - } + }; if (type === 'search') { - suffix = + suffix = ; } let hasChild = Boolean(prefix || suffix); diff --git a/app/root.tsx b/app/root.tsx index 1e741df..228e005 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -253,7 +253,7 @@ async function getLayoutData({storefront, env}: AppLoadContext) { - /blog/news/blog-post -> /news/blog-post - /collections/all -> /products */ - const customPrefixes = {BLOG: 'blogs', CATALOG: 'products'}; + const customPrefixes = {BLOG: '', CATALOG: 'products'}; const headerMenu = data?.headerMenu ? parseMenu( diff --git a/app/routes/($locale)._index.tsx b/app/routes/($locale)._index.tsx index b4c09c1..81860f6 100644 --- a/app/routes/($locale)._index.tsx +++ b/app/routes/($locale)._index.tsx @@ -17,7 +17,7 @@ export async function loader(args: RouteLoaderArgs) { params.locale.toLowerCase() !== `${language}-${country}`.toLowerCase() ) { // If the locale URL param is defined, yet we still are on `EN-US` - // then the locale param must be invalid, send to the 404 page + // the the locale param must be invalid, send to the 404 page throw new Response(null, {status: 404}); } diff --git a/app/routes/($locale).account.login.tsx b/app/routes/($locale).account.login.tsx index 5f8f2b9..fe9849b 100644 --- a/app/routes/($locale).account.login.tsx +++ b/app/routes/($locale).account.login.tsx @@ -11,7 +11,7 @@ import { useLoaderData, type V2_MetaFunction, } from '@remix-run/react'; -import {useState} from 'react'; +import {MouseEvent, useState} from 'react'; import {getInputStyleClasses} from '~/lib/utils'; import {Input, Link, Button} from '~/components'; @@ -106,17 +106,13 @@ export default function Login() {

Login

{/* TODO: Add onSubmit to validate _before_ submission with native? */} -
+ {actionData?.formError && (

{actionData.formError}

)} -
+
{ + onBlur={(event: MouseEvent) => { setNativeEmailError( event.currentTarget.value.length && !event.currentTarget.validity.valid @@ -156,7 +152,7 @@ export default function Login() { required // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus - onBlur={(event) => { + onBlur={(event: MouseEvent) => { if ( event.currentTarget.validity.valid || !event.currentTarget.value.length @@ -194,7 +190,10 @@ export default function Login() { > Sign in - + Create an account
diff --git a/app/routes/($locale).account.recover.tsx b/app/routes/($locale).account.recover.tsx index b3d0903..f5d0e56 100644 --- a/app/routes/($locale).account.recover.tsx +++ b/app/routes/($locale).account.recover.tsx @@ -5,10 +5,9 @@ import { type LoaderArgs, } from '@shopify/remix-oxygen'; import {Form, useActionData, type V2_MetaFunction} from '@remix-run/react'; -import {useState} from 'react'; +import {useState, type MouseEvent} from 'react'; import {Button, Input, Link} from '~/components'; -import {getInputStyleClasses} from '~/lib/utils'; export async function loader({context, params}: LoaderArgs) { const customerAccessToken = await context.session.get('customerAccessToken'); @@ -74,13 +73,11 @@ export default function Recover() { ) : ( <>

Reset your password

-

Enter your email to reset your password

+

+ Enter your email to reset your password +

{/* TODO: Add onSubmit to validate _before_ submission with native? */} - + {actionData?.formError && (

@@ -99,7 +96,7 @@ export default function Recover() { aria-label="Email address" // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus - onBlur={(event) => { + onBlur={(event: MouseEvent) => { setNativeEmailError( event.currentTarget.value.length && !event.currentTarget.validity.valid diff --git a/app/routes/($locale).account.register.tsx b/app/routes/($locale).account.register.tsx index 118d8f6..d8754d0 100644 --- a/app/routes/($locale).account.register.tsx +++ b/app/routes/($locale).account.register.tsx @@ -5,7 +5,7 @@ import { type LoaderArgs, } from '@shopify/remix-oxygen'; import {Form, useActionData, type V2_MetaFunction} from '@remix-run/react'; -import {useState} from 'react'; +import {useState, type MouseEvent} from 'react'; import {getInputStyleClasses} from '~/lib/utils'; import {Button, Input, Link} from '~/components'; @@ -120,7 +120,7 @@ export default function Register() { aria-label="Email" // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus - onBlur={(event) => { + onBlur={(event: MouseEvent) => { setNativeEmailError( event.currentTarget.value.length && !event.currentTarget.validity.valid @@ -147,7 +147,7 @@ export default function Register() { required // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus - onBlur={(event) => { + onBlur={(event: MouseEvent) => { if ( event.currentTarget.validity.valid || !event.currentTarget.value.length diff --git a/app/sections/column-with-text/item.tsx b/app/sections/column-with-text/item.tsx index 626d814..0b19ea8 100644 --- a/app/sections/column-with-text/item.tsx +++ b/app/sections/column-with-text/item.tsx @@ -2,11 +2,10 @@ import type { HydrogenComponentProps, HydrogenComponentSchema, } from '@weaverse/hydrogen'; -import { forwardRef } from 'react'; -import { Image } from '@shopify/hydrogen'; +import {forwardRef} from 'react'; +import {Image} from '@shopify/hydrogen'; import clsx from 'clsx'; -import { CSSProperties } from 'react'; - +import {CSSProperties} from 'react'; interface ContentColumnItemProps extends HydrogenComponentProps { imageSrc: { @@ -23,27 +22,56 @@ interface ContentColumnItemProps extends HydrogenComponentProps { hideOnMobile: boolean; } -let ContentColumnItem = forwardRef((props, ref) => { - let { imageSrc, titleText, contentAlignment, descriptionText, buttonLabel, buttonLink, hideOnMobile, ...rest } = props; - let contentStyle: CSSProperties = { - textAlign: `${contentAlignment}`, - } as CSSProperties; - return ( -

-
- -
-
- {titleText &&

{titleText}

} - {descriptionText &&

} - {buttonLabel && {buttonLabel}} +let ContentColumnItem = forwardRef( + (props, ref) => { + let { + imageSrc, + titleText, + contentAlignment, + descriptionText, + buttonLabel, + buttonLink, + hideOnMobile, + ...rest + } = props; + let contentStyle: CSSProperties = { + textAlign: `${contentAlignment}`, + } as CSSProperties; + return ( +
+
+ +
+
+ {titleText && ( +

{titleText}

+ )} + {descriptionText && ( +

+ )} + {buttonLabel && ( + + {buttonLabel} + + )} +
-
- ); -}); + ); + }, +); export default ContentColumnItem; @@ -61,7 +89,7 @@ export let schema: HydrogenComponentSchema = { defaultValue: { id: 'image-placeholder', url: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/pilot-image-placeholder.svg', - alt: 'Image index', + altText: 'Image index', width: 0, height: 0, }, @@ -79,9 +107,9 @@ export let schema: HydrogenComponentSchema = { name: 'contentAlignment', configs: { options: [ - { label: 'Left', value: 'left' }, - { label: 'Center', value: 'center' }, - { label: 'Right', value: 'right' }, + {label: 'Left', value: 'left'}, + {label: 'Center', value: 'center'}, + {label: 'Right', value: 'right'}, ], }, defaultValue: 'center', diff --git a/app/sections/header-image/description-text-item.tsx b/app/sections/header-image/description-text-item.tsx index b569103..db9ef63 100644 --- a/app/sections/header-image/description-text-item.tsx +++ b/app/sections/header-image/description-text-item.tsx @@ -2,21 +2,25 @@ import type { HydrogenComponentProps, HydrogenComponentSchema, } from '@weaverse/hydrogen'; -import { forwardRef } from 'react'; - +import {forwardRef} from 'react'; interface DescriptionTextItemProps extends HydrogenComponentProps { descriptionText: string; } -let DescriptionTextItem = forwardRef((props, ref) => { - let { descriptionText, ...rest } = props; - return ( -
-

-
- ); -}); +let DescriptionTextItem = forwardRef( + (props, ref) => { + let {descriptionText, ...rest} = props; + return ( +
+

+
+ ); + }, +); export default DescriptionTextItem; @@ -28,7 +32,7 @@ export let schema: HydrogenComponentSchema = { group: 'Description text', inputs: [ { - type: 'text-editor', + type: 'richtext', label: 'Text', name: 'descriptionText', defaultValue: 'Pair large text with an image to tell a story.', @@ -36,4 +40,4 @@ export let schema: HydrogenComponentSchema = { ], }, ], -} +}; diff --git a/app/sections/image-gallery/image.tsx b/app/sections/image-gallery/image.tsx index a3f899b..85bef37 100644 --- a/app/sections/image-gallery/image.tsx +++ b/app/sections/image-gallery/image.tsx @@ -1,19 +1,14 @@ +import {Image} from '@shopify/hydrogen'; import type { HydrogenComponentProps, HydrogenComponentSchema, + WeaverseImage, } from '@weaverse/hydrogen'; import clsx from 'clsx'; import {forwardRef} from 'react'; -import {Image} from '@shopify/hydrogen'; interface ImageGalleryItemProps extends HydrogenComponentProps { - // TODO: change src to imageData - src: { - url: string; - altText: string; - width?: number; - height?: number; - }; + src: WeaverseImage; columnSpan: number; borderRadius: number; hideOnMobile: boolean; @@ -66,18 +61,11 @@ export let schema: HydrogenComponentSchema = { inputs: [ { type: 'image', - // TODO: change src to imageData object name: 'src', label: 'Image', defaultValue: 'https://cdn.shopify.com/s/files/1/0728/0410/6547/files/pilot-image-placeholder.svg', }, - // { - // type: 'text', - // label: 'Alt Text', - // name: 'altText', - // defaultValue: 'Pilot Image', - // }, { type: 'range', label: 'Column Span', diff --git a/app/sections/image-with-text.tsx b/app/sections/image-with-text.tsx index c4b4b5f..9ac64d4 100644 --- a/app/sections/image-with-text.tsx +++ b/app/sections/image-with-text.tsx @@ -2,24 +2,23 @@ import type { HydrogenComponentProps, HydrogenComponentSchema, } from '@weaverse/hydrogen'; -import { forwardRef } from 'react'; -import { CSSProperties } from 'react'; -import { Image } from '@shopify/hydrogen'; - +import {forwardRef} from 'react'; +import {CSSProperties} from 'react'; +import {Image} from '@shopify/hydrogen'; interface ImageWithTextProps extends HydrogenComponentProps { - imageFisrt: { + imageFirst: { url: string; altText: string; width?: number; height?: number; - } + }; imageSecond: { url: string; altText: string; width?: number; height?: number; - } + }; heading: string; subHeading: string; subHeadingSize: string; @@ -31,38 +30,86 @@ interface ImageWithTextProps extends HydrogenComponentProps { loading: HTMLImageElement['loading']; } -let ImageWithText = forwardRef((props, ref) => { - let { imageFisrt, imageSecond, heading, subHeading, subHeadingSize, headingSize, descriptionText, textAlignment, buttonLabel, buttonLink, loading, ...rest } = props; - let styleSection: CSSProperties = { - '--height-section': '410px', - '--font-size-display': `${headingSize}`, - '--font-size-heading': `${subHeadingSize}`, - textAlign: `${textAlignment}`, - } as CSSProperties; - const isDescriptionEmpty = /^


<\/p>$/i.test(descriptionText); - return ( -

-
-
-
- {subHeading &&

{subHeading}

} - {heading &&

{heading}

} - {!isDescriptionEmpty && (

)} - {buttonLabel && {buttonLabel}} -
-
-
- +let ImageWithText = forwardRef( + (props, ref) => { + let { + imageFirst, + imageSecond, + heading, + subHeading, + subHeadingSize, + headingSize, + descriptionText, + textAlignment, + buttonLabel, + buttonLink, + loading, + ...rest + } = props; + let styleSection: CSSProperties = { + '--height-section': '410px', + '--font-size-display': `${headingSize}`, + '--font-size-heading': `${subHeadingSize}`, + textAlign: `${textAlignment}`, + } as CSSProperties; + const isDescriptionEmpty = /^


<\/p>$/i.test(descriptionText); + return ( +

+
+
+
+ {subHeading && ( +

+ {subHeading} +

+ )} + {heading && ( +

+ {heading} +

+ )} + {!isDescriptionEmpty && ( +

+ )} + {buttonLabel && ( + + {buttonLabel} + + )}
-
- +
+
+ +
+
+ +
-
-
- ); -}); +
+ ); + }, +); export default ImageWithText; @@ -76,20 +123,21 @@ export let schema: HydrogenComponentSchema = { inputs: [ { type: 'image', - name: 'imageFisrt', + name: 'imageFirst', label: 'Image 1', - defaultValue:{ + defaultValue: { url: 'https://thang-weaverse-test-shop.myshopify.com/cdn/shop/files/gift-card-envelopes.jpg?v=1696497046&width=1100', altText: 'imageIndex', - } - }, { + }, + }, + { type: 'image', name: 'imageSecond', label: 'Image 2', - defaultValue:{ + defaultValue: { url: 'https://thang-weaverse-test-shop.myshopify.com/cdn/shop/files/gift-card.jpg?v=1696497401&width=1100', altText: 'imageIndex', - } + }, }, { type: 'text', @@ -104,11 +152,11 @@ export let schema: HydrogenComponentSchema = { name: 'subHeadingSize', configs: { options: [ - { label: 'XS', value: '14px' }, - { label: 'S', value: '16px' }, - { label: 'M', value: '18px' }, - { label: 'L', value: '20px' }, - { label: 'XL', value: '22px' }, + {label: 'XS', value: '14px'}, + {label: 'S', value: '16px'}, + {label: 'M', value: '18px'}, + {label: 'L', value: '20px'}, + {label: 'XL', value: '22px'}, ], }, defaultValue: '16px', @@ -126,20 +174,21 @@ export let schema: HydrogenComponentSchema = { name: 'headingSize', configs: { options: [ - { label: 'XS', value: '22px' }, - { label: 'S', value: '24px' }, - { label: 'M', value: '26px' }, - { label: 'L', value: '28px' }, - { label: 'XL', value: '30px' }, + {label: 'XS', value: '22px'}, + {label: 'S', value: '24px'}, + {label: 'M', value: '26px'}, + {label: 'L', value: '28px'}, + {label: 'XL', value: '30px'}, ], }, defaultValue: '24px', }, { - type: 'text-editor', + type: 'richtext', label: 'Text', name: 'descriptionText', - defaultValue: 'Pair large text with an image to tell a story, explain a detail about your product, or describe a new promotion.', + defaultValue: + 'Pair large text with an image to tell a story, explain a detail about your product, or describe a new promotion.', }, { type: 'toggle-group', @@ -147,9 +196,9 @@ export let schema: HydrogenComponentSchema = { name: 'textAlignment', configs: { options: [ - { label: 'Left', value: 'left' }, - { label: 'Center', value: 'center' }, - { label: 'Right', value: 'right' }, + {label: 'Left', value: 'left'}, + {label: 'Center', value: 'center'}, + {label: 'Right', value: 'right'}, ], }, defaultValue: 'left', @@ -164,7 +213,7 @@ export let schema: HydrogenComponentSchema = { type: 'text', name: 'buttonLink', label: 'Button link', - placeholder: 'https://' + placeholder: 'https://', }, { type: 'toggle-group', @@ -173,7 +222,7 @@ export let schema: HydrogenComponentSchema = { defaultValue: 'eager', configs: { options: [ - { label: 'Eager', value: 'eager', icon: 'Lightning' }, + {label: 'Eager', value: 'eager', icon: 'Lightning'}, { label: 'Lazy', value: 'lazy', diff --git a/app/sections/map.tsx b/app/sections/map.tsx new file mode 100644 index 0000000..21cd963 --- /dev/null +++ b/app/sections/map.tsx @@ -0,0 +1,145 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import { forwardRef } from 'react'; +import { CSSProperties } from 'react'; +import {IconMapBlank} from '~/components'; +import clsx from 'clsx'; + + +interface MapProps extends HydrogenComponentProps { + heading: string; + textColor: string; + contentAlignment: string; + descriptionText: string; + address: string; + buttonLabel: string; + buttonLink: string; + openInNewTab: boolean; + sectionHeight: string; + buttonStyle: string; +} + +let Map = forwardRef((props, ref) => { + let { heading, textColor, contentAlignment, descriptionText, address, buttonLabel, buttonLink, openInNewTab, sectionHeight, buttonStyle, ...rest } = props; + let sectionStyle: CSSProperties = { + '--section-height': `${sectionHeight}px`, + justifyContent: `${contentAlignment}`, + } as CSSProperties; + + return ( +
+
+ {address ? : +
+ +
} +
+
+
+ {heading &&

{heading}

} + {address &&

{address}

} + {descriptionText &&

{descriptionText}

} + {buttonLabel && {buttonLabel}} +
+
+
+ ); +}); + +export default Map; + +export let schema: HydrogenComponentSchema = { + type: 'map', + title: 'Map', + toolbar: ['general-settings', ['duplicate', 'delete']], + inspector: [ + { + group: 'Map', + inputs: [ + { + type: 'text', + name: 'heading', + label: 'Heading', + defaultValue: 'Our store address', + }, + { + type: 'color', + name: 'textColor', + label: 'Text color', + defaultValue: '#333333', + }, + { + 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: 'map-autocomplete', + name: 'address', + label: 'Map address', + defaultValue: 'San Francisco, CA', + }, + { + type: 'textarea', + label: 'Description text', + name: 'descriptionText', + defaultValue: 'Pair large text with an image to tell a story, explain a detail about your product, or describe a new promotion.', + }, + { + 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 bg-white border-2 border-solid border-gray-900 text-black hover:bg-black hover:text-white', + }, + { + type: 'range', + name: 'sectionHeight', + label: 'Section height', + defaultValue: 500, + configs: { + min: 400, + max: 900, + step: 10, + unit: 'px', + }, + }, + ], + }, + ], +}; diff --git a/app/sections/single-product.tsx b/app/sections/single-product.tsx index 376a170..fec05af 100644 --- a/app/sections/single-product.tsx +++ b/app/sections/single-product.tsx @@ -96,7 +96,7 @@ export let schema: HydrogenComponentSchema = { { label: 'Choose product', type: 'product', - defaultValue: '', + name: 'product', }, ], }, diff --git a/app/sections/video-with-text/video-button-item.tsx b/app/sections/video-with-text/video-button-item.tsx new file mode 100644 index 0000000..6f963cc --- /dev/null +++ b/app/sections/video-with-text/video-button-item.tsx @@ -0,0 +1,66 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import { forwardRef } from 'react'; + +interface VideoButtonProps extends HydrogenComponentProps { + buttonLabel: string; + buttonLink: string; + enableNewtab: boolean; +} + +let VideoButtonItem = forwardRef((props, ref) => { + let {buttonLabel, buttonLink, enableNewtab, ...rest} = props; + return ( + + ); +}); + +export default VideoButtonItem; + +export let schema: HydrogenComponentSchema = { + type: 'video-button--item', + title: 'Button item', + limit: 1, + inspector: [ + { + group: 'Button', + inputs: [ + { + type: 'text', + name: 'buttonLabel', + label: 'Button label', + defaultValue: 'Button', + }, + { + type: 'text', + name: 'buttonLink', + label: 'Button link', + placeholder: 'https://', + }, + { + type: 'switch', + name: 'enableNewtab', + label: 'Open in new tab', + defaultValue: true, + }, + { + type: 'toggle-group', + label: 'Button style', + name: 'buttonStyle', + configs: { + options: [ + { label: '1', value: '1' }, + { label: '2', value: '2' }, + { label: '3', value: '3' }, + ], + }, + defaultValue: '1', + }, + ], + }, + ], +} diff --git a/app/sections/video-with-text/video-description-item.tsx b/app/sections/video-with-text/video-description-item.tsx new file mode 100644 index 0000000..0f731c2 --- /dev/null +++ b/app/sections/video-with-text/video-description-item.tsx @@ -0,0 +1,62 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import { forwardRef } from 'react'; + +interface VideoDescriptionProps extends HydrogenComponentProps { + descriptionText: string; + descriptionSize: string; + descriptionColor: string; +} + +let VideoDescriptionItem = forwardRef((props, ref) => { + let {descriptionText, descriptionSize, descriptionColor, ...rest} = props; + return ( +
+

{descriptionText}

+
+ ); +}); + +export default VideoDescriptionItem; + +export let schema: HydrogenComponentSchema = { + type: 'video-description--item', + title: 'Description item', + limit: 1, + inspector: [ + { + group: 'Description', + inputs: [ + { + type: 'textarea', + label: 'Text', + name: 'descriptionText', + defaultValue: 'Pair large text with an video to tell a story.', + }, + { + 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', + }, + ], + }, + ], +} diff --git a/app/sections/video-with-text/video-heading-item.tsx b/app/sections/video-with-text/video-heading-item.tsx new file mode 100644 index 0000000..77aabac --- /dev/null +++ b/app/sections/video-with-text/video-heading-item.tsx @@ -0,0 +1,63 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import { forwardRef } from 'react'; + +interface VideoHeadingProps extends HydrogenComponentProps { + heading: string; + headingSize: string; + headingColor: string; +} + +let VideoHeadingItem = forwardRef((props, ref) => { + let {heading, headingSize, headingColor, ...rest} = props; + return ( +
+

{heading}

+
+ ); +}); + +export default VideoHeadingItem; + +export let schema: HydrogenComponentSchema = { + type: 'video-heading--item', + title: 'Heading item', + limit: 1, + inspector: [ + { + group: 'Heading', + inputs: [ + { + type: 'text', + name: 'heading', + label: 'Heading', + defaultValue: 'Heading for Video', + placeholder: 'Heading for video section', + }, + { + type: 'toggle-group', + label: 'Heading size', + name: 'headingSize', + configs: { + options: [ + { label: 'XS', value: '22px' }, + { label: 'S', value: '24px' }, + { label: 'M', value: '26px' }, + { label: 'L', value: '28px' }, + { label: 'XL', value: '30px' }, + ], + }, + defaultValue: '24px', + }, + { + type: 'color', + name: 'headingColor', + label: 'Heading color', + defaultValue: '#333333', + }, + ], + }, + ], +} diff --git a/app/sections/video-with-text/video-subheading-item.tsx b/app/sections/video-with-text/video-subheading-item.tsx new file mode 100644 index 0000000..9812ad0 --- /dev/null +++ b/app/sections/video-with-text/video-subheading-item.tsx @@ -0,0 +1,63 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import { forwardRef } from 'react'; + +interface VideoSubheadingProps extends HydrogenComponentProps { + subHeading: string; + subHeadingSize: string; + subHeadingColor: string; +} + +let VideoSubheadingItem = forwardRef((props, ref) => { + let {subHeading, subHeadingSize, subHeadingColor, ...rest} = props; + return ( +
+

{subHeading}

+
+ ); +}); + +export default VideoSubheadingItem; + +export let schema: HydrogenComponentSchema = { + type: 'video-subheading--item', + title: 'Subheading item', + limit: 1, + inspector: [ + { + group: 'Subheading', + inputs: [ + { + 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', + }, + ], + }, + ], +} diff --git a/app/sections/video-with-text/video-with-text.tsx b/app/sections/video-with-text/video-with-text.tsx new file mode 100644 index 0000000..2e15258 --- /dev/null +++ b/app/sections/video-with-text/video-with-text.tsx @@ -0,0 +1,173 @@ +import type { + HydrogenComponentProps, + HydrogenComponentSchema, +} from '@weaverse/hydrogen'; +import { forwardRef } from 'react'; +import { CSSProperties } from 'react'; +import ReactPlayer from 'react-player/youtube'; + +interface VideoWithTextProps extends HydrogenComponentProps { + videoLink: string; + enableOverlay: boolean; + overlayColor: string; + overlayOpacity: number; + sectionHeightDesktop: number; + sectionHeightMobile: number; + enableAutoPlay: boolean; + enableLoop: boolean; + enableMuted: boolean; + contentAlignment: string; +} + +let VideoWithText = 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}`, + } as CSSProperties; + + return ( +
+ {videoLink ? : +
+ + + + +
} + {enableOverlay &&
} +
+ {children} +
+
+ ); +}); + +export default VideoWithText; + +export let schema: HydrogenComponentSchema = { + type: 'video-with-text', + title: 'Video with text', + 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: ['video-subheading--item', 'video-heading--item', 'video-description--item', 'video-button--item'], + presets: { + children: [ + { + type: 'video-heading--item', + }, + { + type: 'video-subheading--item', + }, + { + type: 'video-description--item', + }, + { + type: 'video-button--item', + } + ], + }, +}; diff --git a/app/weaverse/components.ts b/app/weaverse/components.ts index 8ad12e5..75e76d0 100644 --- a/app/weaverse/components.ts +++ b/app/weaverse/components.ts @@ -36,6 +36,12 @@ import * as RichText from '~/sections/rich-text/index'; import * as RichTextHeadingItem from '~/sections/rich-text/headings-item'; import * as RichTextDescriptionItem from '~/sections/rich-text/descriptions-item'; import * as RichTextButtonItem from '~/sections/rich-text/buttons-item'; +import * as VideoWithText from '~/sections/video-with-text/video-with-text'; +import * as VideoSubheadingItem from '~/sections/video-with-text/video-subheading-item'; +import * as VideoHeadingItem from '~/sections/video-with-text/video-heading-item'; +import * as VideoDescriptionItem from '~/sections/video-with-text/video-description-item'; +import * as VideoButtonItem from '~/sections/video-with-text/video-button-item'; +import * as Map from '~/sections/map'; export let components: HydrogenComponent[] = [ Main, @@ -60,6 +66,12 @@ export let components: HydrogenComponent[] = [ RichTextHeadingItem, RichTextDescriptionItem, RichTextButtonItem, + VideoWithText, + VideoSubheadingItem, + VideoHeadingItem, + VideoDescriptionItem, + VideoButtonItem, + Map, Blogs, BlogPost, AllProducts, diff --git a/app/weaverse/schema.server.ts b/app/weaverse/schema.server.ts index 39a97b8..c8d6d6a 100644 --- a/app/weaverse/schema.server.ts +++ b/app/weaverse/schema.server.ts @@ -7,7 +7,7 @@ export let themeSchema: HydrogenThemeSchema = { author: 'Weaverse', name: 'Pilot', authorProfilePhoto: - 'https://ucarecdn.com/174c3d08-fc53-4088-8d12-8eaf7090cdec/', + 'https://cdn.shopify.com/s/files/1/0838/0052/3057/files/Weaverse_logo_-_3000x_e2fa8c13-dac2-4dcb-a2c2-f7aaf7a58169.png?v=1698245759', documentationUrl: 'https://weaverse.io/docs', supportUrl: 'https://help.weaverse.io/', },