mirror of
https://github.com/vercel/commerce.git
synced 2025-05-18 07:26:59 +00:00
New productTag
This commit is contained in:
parent
e752555e02
commit
9c647b856f
@ -6,7 +6,7 @@ import s from './ProductCard.module.css'
|
|||||||
import Image, { ImageProps } from 'next/image'
|
import Image, { ImageProps } from 'next/image'
|
||||||
import WishlistButton from '@components/wishlist/WishlistButton'
|
import WishlistButton from '@components/wishlist/WishlistButton'
|
||||||
import usePrice from '@framework/product/use-price'
|
import usePrice from '@framework/product/use-price'
|
||||||
|
import ProductTag from '../ProductTag'
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
product: Product
|
product: Product
|
||||||
@ -104,14 +104,10 @@ const ProductCard: FC<Props> = ({
|
|||||||
variant={product.variants[0] as any}
|
variant={product.variants[0] as any}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className={s.header}>
|
<ProductTag
|
||||||
<h3 className={s.name}>
|
name={product.name}
|
||||||
<span>{product.name}</span>
|
price={`${price} ${product.price?.currencyCode}`}
|
||||||
</h3>
|
/>
|
||||||
<div className={s.price}>
|
|
||||||
{`${price} ${product.price?.currencyCode}`}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={s.imageContainer}>
|
<div className={s.imageContainer}>
|
||||||
{product?.images && (
|
{product?.images && (
|
||||||
<Image
|
<Image
|
||||||
|
@ -12,7 +12,15 @@ import { a } from '@react-spring/web'
|
|||||||
import s from './ProductSlider.module.css'
|
import s from './ProductSlider.module.css'
|
||||||
import ProductSliderControl from '../ProductSliderControl'
|
import ProductSliderControl from '../ProductSliderControl'
|
||||||
|
|
||||||
const ProductSlider: FC = ({ children }) => {
|
interface ProductSliderProps {
|
||||||
|
children: React.ReactNode[]
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProductSlider: React.FC<ProductSliderProps> = ({
|
||||||
|
children,
|
||||||
|
className = '',
|
||||||
|
}) => {
|
||||||
const [currentSlide, setCurrentSlide] = useState(0)
|
const [currentSlide, setCurrentSlide] = useState(0)
|
||||||
const [isMounted, setIsMounted] = useState(false)
|
const [isMounted, setIsMounted] = useState(false)
|
||||||
const sliderContainerRef = useRef<HTMLDivElement>(null)
|
const sliderContainerRef = useRef<HTMLDivElement>(null)
|
||||||
@ -77,7 +85,7 @@ const ProductSlider: FC = ({ children }) => {
|
|||||||
const onNext = React.useCallback(() => slider.next(), [slider])
|
const onNext = React.useCallback(() => slider.next(), [slider])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={s.root} ref={sliderContainerRef}>
|
<div className={cn(s.root, className)} ref={sliderContainerRef}>
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(s.slider, { [s.show]: isMounted }, 'keen-slider')}
|
className={cn(s.slider, { [s.show]: isMounted }, 'keen-slider')}
|
||||||
|
30
components/product/ProductTag/ProductTag.module.css
Normal file
30
components/product/ProductTag/ProductTag.module.css
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
.root {
|
||||||
|
@apply transition-colors ease-in-out duration-500
|
||||||
|
absolute top-0 left-0 z-20 pr-16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root .name {
|
||||||
|
@apply pt-0 max-w-full w-full leading-extra-loose;
|
||||||
|
font-size: 2rem;
|
||||||
|
letter-spacing: 0.4px;
|
||||||
|
line-height: 2.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root .name span {
|
||||||
|
@apply py-4 px-6 bg-primary text-primary font-bold;
|
||||||
|
min-height: 70px;
|
||||||
|
font-size: inherit;
|
||||||
|
letter-spacing: inherit;
|
||||||
|
box-decoration-break: clone;
|
||||||
|
-webkit-box-decoration-break: clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root .name span.fontsizing {
|
||||||
|
display: flex;
|
||||||
|
padding-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root .price {
|
||||||
|
@apply pt-2 px-6 pb-4 text-sm bg-primary text-accent-9
|
||||||
|
font-semibold inline-block tracking-wide;
|
||||||
|
}
|
36
components/product/ProductTag/ProductTag.tsx
Normal file
36
components/product/ProductTag/ProductTag.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import cn from 'classnames'
|
||||||
|
import { inherits } from 'util'
|
||||||
|
import s from './ProductTag.module.css'
|
||||||
|
|
||||||
|
interface ProductTagProps {
|
||||||
|
className?: string
|
||||||
|
name: string
|
||||||
|
price: string
|
||||||
|
fontSize?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProductTag: React.FC<ProductTagProps> = ({
|
||||||
|
name,
|
||||||
|
price,
|
||||||
|
className = '',
|
||||||
|
fontSize = 32,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className={cn(s.root, className)}>
|
||||||
|
<h3 className={s.name}>
|
||||||
|
<span
|
||||||
|
className={cn({ [s.fontsizing]: fontSize < 32 })}
|
||||||
|
style={{
|
||||||
|
fontSize: `${fontSize}px`,
|
||||||
|
lineHeight: `${fontSize}px`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
|
<div className={s.price}>{price}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProductTag
|
1
components/product/ProductTag/index.ts
Normal file
1
components/product/ProductTag/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './ProductTag'
|
@ -8,30 +8,6 @@
|
|||||||
min-height: 500px;
|
min-height: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
|
||||||
@apply transition-colors ease-in-out duration-500
|
|
||||||
absolute top-0 left-0 z-20 pr-16;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header .name {
|
|
||||||
@apply pt-0 max-w-full w-full leading-extra-loose;
|
|
||||||
font-size: 2rem;
|
|
||||||
letter-spacing: 0.4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header .name span {
|
|
||||||
@apply py-4 px-6 bg-primary text-primary font-bold;
|
|
||||||
font-size: inherit;
|
|
||||||
letter-spacing: inherit;
|
|
||||||
box-decoration-break: clone;
|
|
||||||
-webkit-box-decoration-break: clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header .price {
|
|
||||||
@apply pt-2 px-6 pb-4 text-sm bg-primary text-accent-9
|
|
||||||
font-semibold inline-block tracking-wide;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
@apply flex flex-col col-span-1 mx-auto max-w-8xl px-6 py-6 w-full h-full;
|
@apply flex flex-col col-span-1 mx-auto max-w-8xl px-6 py-6 w-full h-full;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import { WishlistButton } from '@components/wishlist'
|
|||||||
import { ProductSlider, ProductCard } from '@components/product'
|
import { ProductSlider, ProductCard } from '@components/product'
|
||||||
import { Container, Text } from '@components/ui'
|
import { Container, Text } from '@components/ui'
|
||||||
import ProductSidebar from '../ProductSidebar'
|
import ProductSidebar from '../ProductSidebar'
|
||||||
|
import ProductTag from '../ProductTag'
|
||||||
interface ProductViewProps {
|
interface ProductViewProps {
|
||||||
product: Product
|
product: Product
|
||||||
relatedProducts: Product[]
|
relatedProducts: Product[]
|
||||||
@ -23,35 +24,14 @@ const ProductView: FC<ProductViewProps> = ({ product, relatedProducts }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NextSeo
|
|
||||||
title={product.name}
|
|
||||||
description={product.description}
|
|
||||||
openGraph={{
|
|
||||||
type: 'website',
|
|
||||||
title: product.name,
|
|
||||||
description: product.description,
|
|
||||||
images: [
|
|
||||||
{
|
|
||||||
url: product.images[0]?.url!,
|
|
||||||
width: 800,
|
|
||||||
height: 600,
|
|
||||||
alt: product.name,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Container className="max-w-none w-full" clean>
|
<Container className="max-w-none w-full" clean>
|
||||||
<div className={cn(s.root, 'fit')}>
|
<div className={cn(s.root, 'fit')}>
|
||||||
<div className={cn(s.main, 'fit')}>
|
<div className={cn(s.main, 'fit')}>
|
||||||
<div className={s.header}>
|
<ProductTag
|
||||||
<h3 className={s.name}>
|
name={product.name}
|
||||||
<span>{product.name}</span>
|
price={`${price} ${product.price?.currencyCode}`}
|
||||||
</h3>
|
fontSize={32}
|
||||||
<div className={s.price}>
|
/>
|
||||||
{`${price} ${product.price?.currencyCode}`}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={s.sliderContainer}>
|
<div className={s.sliderContainer}>
|
||||||
<ProductSlider key={product.id}>
|
<ProductSlider key={product.id}>
|
||||||
{product.images.map((image, i) => (
|
{product.images.map((image, i) => (
|
||||||
@ -105,6 +85,23 @@ const ProductView: FC<ProductViewProps> = ({ product, relatedProducts }) => {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</Container>
|
</Container>
|
||||||
|
<NextSeo
|
||||||
|
title={product.name}
|
||||||
|
description={product.description}
|
||||||
|
openGraph={{
|
||||||
|
type: 'website',
|
||||||
|
title: product.name,
|
||||||
|
description: product.description,
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: product.images[0]?.url!,
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
alt: product.name,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user