mirror of
https://github.com/vercel/commerce.git
synced 2025-05-20 16:36:59 +00:00
Add categories into all products page and complete translation of that page
This commit is contained in:
parent
59f6c63ce3
commit
c211bff2ad
84
site/components/common/Category/CategoryListItem.tsx
Normal file
84
site/components/common/Category/CategoryListItem.tsx
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Flex,
|
||||||
|
Text,
|
||||||
|
IconButton,
|
||||||
|
Button,
|
||||||
|
Stack,
|
||||||
|
Collapse,
|
||||||
|
Icon,
|
||||||
|
Link,
|
||||||
|
Popover,
|
||||||
|
PopoverTrigger,
|
||||||
|
PopoverContent,
|
||||||
|
useColorModeValue,
|
||||||
|
useBreakpointValue,
|
||||||
|
useDisclosure,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import {
|
||||||
|
HamburgerIcon,
|
||||||
|
CloseIcon,
|
||||||
|
ChevronDownIcon,
|
||||||
|
ChevronRightIcon,
|
||||||
|
} from '@chakra-ui/icons';
|
||||||
|
|
||||||
|
const CategoryListItem = ({ label, children, href, enabled }: CategoryItem) => {
|
||||||
|
const { isOpen, onToggle } = useDisclosure();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack spacing={4} onClick={children && onToggle} className={"block text-sm leading-5 text-accent-4 hover:bg-accent-1 lg:hover:bg-transparent hover:text-accent-8 focus:outline-none focus:bg-accent-1 focus:text-accent-8"}>
|
||||||
|
<Flex
|
||||||
|
py={2}
|
||||||
|
as={Link}
|
||||||
|
className={"block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4"}
|
||||||
|
href={enabled ? href : '#'}
|
||||||
|
justify={'space-between'}
|
||||||
|
align={'center'}
|
||||||
|
_hover={{
|
||||||
|
textDecoration: 'none',
|
||||||
|
}}>
|
||||||
|
<Text
|
||||||
|
fontWeight={600}
|
||||||
|
color={useColorModeValue('gray.600', 'gray.200')}>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
{children && (
|
||||||
|
<Icon
|
||||||
|
as={ChevronDownIcon}
|
||||||
|
transition={'all .25s ease-in-out'}
|
||||||
|
transform={isOpen ? 'rotate(180deg)' : ''}
|
||||||
|
w={6}
|
||||||
|
h={6}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Collapse in={isOpen} animateOpacity style={{ marginTop: '0!important' }}>
|
||||||
|
<Stack
|
||||||
|
mt={2}
|
||||||
|
pl={4}
|
||||||
|
borderLeft={1}
|
||||||
|
borderStyle={'solid'}
|
||||||
|
borderColor={useColorModeValue('gray.200', 'gray.700')}
|
||||||
|
align={'start'}>
|
||||||
|
{children &&
|
||||||
|
children.map((child) => (
|
||||||
|
<Link key={child.label} py={2} href={enabled ? child.href : '#'}>
|
||||||
|
{child.label}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Collapse>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface CategoryItem {
|
||||||
|
label: string;
|
||||||
|
subLabel?: string;
|
||||||
|
children?: Array<CategoryItem>;
|
||||||
|
href?: string;
|
||||||
|
enabled: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CategoryListItem;
|
@ -18,20 +18,11 @@ interface NavbarProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Navbar: FC<NavbarProps> = ({ links }) => {
|
const Navbar: FC<NavbarProps> = ({ links }) => {
|
||||||
const {
|
|
||||||
isOpen: isOpenDrawer,
|
|
||||||
onOpen: onOpenDrawer,
|
|
||||||
onClose: onCloseDrawer,
|
|
||||||
} = useDisclosure()
|
|
||||||
|
|
||||||
const { locale, pathname } = useRouter()
|
const { locale, pathname } = useRouter()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NavBarFiltersDrawer
|
|
||||||
onClose={onCloseDrawer}
|
|
||||||
isOpen={isOpenDrawer}
|
|
||||||
></NavBarFiltersDrawer>
|
|
||||||
<NavbarRoot>
|
<NavbarRoot>
|
||||||
<Container clean className="mx-auto max-w-8xl px-6">
|
<Container clean className="mx-auto max-w-8xl px-6">
|
||||||
<div className={s.nav}>
|
<div className={s.nav}>
|
||||||
@ -49,13 +40,7 @@ const Navbar: FC<NavbarProps> = ({ links }) => {
|
|||||||
</Link>
|
</Link>
|
||||||
{links?.map((l) => (
|
{links?.map((l) => (
|
||||||
<Link href={l.href} key={l.href}>
|
<Link href={l.href} key={l.href}>
|
||||||
{l.label === 'Categories' || l.label === 'Categorie' ? (
|
<a className={s.link}>{l.label}</a>
|
||||||
<a onClick={onOpenDrawer} className={s.link}>
|
|
||||||
{l.label}
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<a className={s.link}>{l.label}</a>
|
|
||||||
)}
|
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -43,7 +43,7 @@ const ProductCard: FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={`/product/${product.slug}`}>
|
<Link href={`/product/${product.slug}`}>
|
||||||
<a className={rootClassName} aria-label={product.name} onMouseLeave={() => setIsHover(false)} onMouseEnter={() => setIsHover(true)}>
|
<a className={rootClassName} aria-label={product.name} onMouseOut={() => setIsHover(false)} onMouseOver={() => setIsHover(true)}>
|
||||||
{variant === 'slim' && !isHover && (
|
{variant === 'slim' && !isHover && (
|
||||||
<>
|
<>
|
||||||
<div className={s.header}>
|
<div className={s.header}>
|
||||||
@ -128,9 +128,6 @@ const ProductCard: FC<Props> = ({
|
|||||||
p={6}
|
p={6}
|
||||||
w={'full'}
|
w={'full'}
|
||||||
bg={useColorModeValue('white', 'gray.800')}
|
bg={useColorModeValue('white', 'gray.800')}
|
||||||
boxShadow={'2xl'}
|
|
||||||
rounded={'lg'}
|
|
||||||
pos={'relative'}
|
|
||||||
zIndex={1}>
|
zIndex={1}>
|
||||||
{process.env.COMMERCE_WISHLIST_ENABLED && (
|
{process.env.COMMERCE_WISHLIST_ENABLED && (
|
||||||
<WishlistButton
|
<WishlistButton
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
import {
|
|
||||||
Flex,
|
|
||||||
Box,
|
|
||||||
Image,
|
|
||||||
useColorModeValue,
|
|
||||||
Stack,
|
|
||||||
Heading,
|
|
||||||
Text,
|
|
||||||
Center
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import usePrice from '@framework/product/use-price'
|
|
||||||
|
|
||||||
import type { Product } from '@commerce/types/product'
|
|
||||||
import { ImageProps } from 'next/image'
|
|
||||||
import ProductTag from '../ProductTag'
|
|
||||||
import { FC } from 'react';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
product: Product
|
|
||||||
imgProps?: Omit<ImageProps, 'src' | 'layout' | 'placeholder' | 'blurDataURL'>
|
|
||||||
}
|
|
||||||
|
|
||||||
const ProductCardExtended: FC<Props> =({
|
|
||||||
product,
|
|
||||||
imgProps
|
|
||||||
}) => {
|
|
||||||
|
|
||||||
const { price } = usePrice({
|
|
||||||
amount: product.price.value,
|
|
||||||
baseAmount: product.price.retailPrice,
|
|
||||||
currencyCode: product.price.currencyCode!,
|
|
||||||
})
|
|
||||||
|
|
||||||
const placeholderImg = '/product-img-placeholder.svg';
|
|
||||||
const IMAGE = product.images[0]?.url || placeholderImg
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Center>
|
|
||||||
<Box
|
|
||||||
role={'group'}
|
|
||||||
p={6}
|
|
||||||
maxW={'330px'}
|
|
||||||
w={'full'}
|
|
||||||
bg={useColorModeValue('white', 'gray.800')}
|
|
||||||
boxShadow={'2xl'}
|
|
||||||
rounded={'lg'}
|
|
||||||
pos={'relative'}
|
|
||||||
zIndex={1}>
|
|
||||||
<Box
|
|
||||||
rounded={'lg'}
|
|
||||||
mt={-12}
|
|
||||||
pos={'relative'}
|
|
||||||
height={'230px'}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
rounded={'lg'}
|
|
||||||
height={230}
|
|
||||||
width={282}
|
|
||||||
objectFit={'cover'}
|
|
||||||
src={IMAGE}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Stack pt={10} align={'center'}>
|
|
||||||
<Text color={'gray.500'} fontSize={'sm'} textTransform={'uppercase'}>
|
|
||||||
Brand
|
|
||||||
</Text>
|
|
||||||
<Heading fontSize={'2xl'} fontFamily={'body'} fontWeight={500}>
|
|
||||||
Nice Chair, pink
|
|
||||||
</Heading>
|
|
||||||
<Stack direction={'row'} align={'center'}>
|
|
||||||
<Text fontWeight={800} fontSize={'xl'}>
|
|
||||||
$57
|
|
||||||
</Text>
|
|
||||||
<Text textDecoration={'line-through'} color={'gray.600'}>
|
|
||||||
$199
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
</Center>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ProductCardExtended;
|
|
@ -9,18 +9,11 @@ import type { Product } from '@commerce/types/product'
|
|||||||
|
|
||||||
import { Layout } from '@components/common'
|
import { Layout } from '@components/common'
|
||||||
import { ProductCard } from '@components/product'
|
import { ProductCard } from '@components/product'
|
||||||
import { Container, Skeleton } from '@components/ui'
|
import { Collapse, Container, Skeleton } from '@components/ui'
|
||||||
|
|
||||||
import useSearch from '@framework/product/use-search'
|
import useSearch from '@framework/product/use-search'
|
||||||
import rangeMap from '@lib/range-map'
|
import rangeMap from '@lib/range-map'
|
||||||
|
|
||||||
const SORT = {
|
|
||||||
'trending-desc': 'Trending',
|
|
||||||
'latest-desc': 'Latest arrivals',
|
|
||||||
'price-asc': 'Price: Low to high',
|
|
||||||
'price-desc': 'Price: High to low',
|
|
||||||
}
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
filterQuery,
|
filterQuery,
|
||||||
getCategoryPath,
|
getCategoryPath,
|
||||||
@ -28,6 +21,11 @@ import {
|
|||||||
useSearchMeta,
|
useSearchMeta,
|
||||||
} from '@lib/search'
|
} from '@lib/search'
|
||||||
import ErrorMessage from './ui/ErrorMessage'
|
import ErrorMessage from './ui/ErrorMessage'
|
||||||
|
import NavBarFiltersItem from './common/Navbar/NavBarFiltersItem'
|
||||||
|
import filtersData from '../static_data/navBarMenuData.json'
|
||||||
|
import { Stack } from '@chakra-ui/react'
|
||||||
|
import random from 'lodash.random'
|
||||||
|
import CategoryListItem from './common/Category/CategoryListItem'
|
||||||
|
|
||||||
export default function Search({ categories, brands }: SearchPropsType) {
|
export default function Search({ categories, brands }: SearchPropsType) {
|
||||||
const [activeFilter, setActiveFilter] = useState('')
|
const [activeFilter, setActiveFilter] = useState('')
|
||||||
@ -54,6 +52,15 @@ export default function Search({ categories, brands }: SearchPropsType) {
|
|||||||
locale,
|
locale,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const categoriesItems = filtersData.categories[locale as keyof typeof filtersData.categories]
|
||||||
|
|
||||||
|
const SORT = {
|
||||||
|
'trending-desc': locale === "it" ? "Tendenza" :'Trending',
|
||||||
|
'latest-desc': locale === "it" ? "Ultimi Arrivi" : 'Latest arrivals',
|
||||||
|
'price-asc': locale === "it" ? "Prezzo Crescente" : 'Price: Low to high',
|
||||||
|
'price-desc': locale === "it" ? "Prezzo Decrescente" :'Price: High to low',
|
||||||
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return <ErrorMessage error={error} />
|
return <ErrorMessage error={error} />
|
||||||
}
|
}
|
||||||
@ -132,36 +139,12 @@ export default function Search({ categories, brands }: SearchPropsType) {
|
|||||||
'block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4'
|
'block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
All Categories
|
{locale == "it" ? "Tutte le Categorie" : "All Categories"}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
{categories.map((cat: any) => (
|
{categoriesItems.map((category: any) => (
|
||||||
<li
|
<CategoryListItem key={category.label} {...category} />
|
||||||
key={cat.path}
|
|
||||||
className={cn(
|
|
||||||
'block text-sm leading-5 text-accent-4 hover:bg-accent-1 lg:hover:bg-transparent hover:text-accent-8 focus:outline-none focus:bg-accent-1 focus:text-accent-8',
|
|
||||||
{
|
|
||||||
underline: activeCategory?.id === cat.id,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
href={{
|
|
||||||
pathname: getCategoryPath(cat.path, brand),
|
|
||||||
query,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
onClick={(e) => handleClick(e, 'categories')}
|
|
||||||
className={
|
|
||||||
'block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{cat.name}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -253,7 +236,7 @@ export default function Search({ categories, brands }: SearchPropsType) {
|
|||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
aria-expanded="true"
|
aria-expanded="true"
|
||||||
>
|
>
|
||||||
{sort ? SORT[sort as keyof typeof SORT] : 'Relevance'}
|
{sort ? SORT[sort as keyof typeof SORT] : locale === "it" ? "Rilevanza" : "Relevance"}
|
||||||
<svg
|
<svg
|
||||||
className="-mr-1 ml-2 h-5 w-5"
|
className="-mr-1 ml-2 h-5 w-5"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@ -296,7 +279,7 @@ export default function Search({ categories, brands }: SearchPropsType) {
|
|||||||
'block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4'
|
'block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Relevance
|
{locale === "it" ? "Rilevanza" : "Relevance"}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
|
@ -28,7 +28,7 @@ export default function WhereWeAre() {
|
|||||||
</Box>
|
</Box>
|
||||||
<Box mt={10}>
|
<Box mt={10}>
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table variant="striped" colorScheme="teal">
|
<Table colorScheme="teal">
|
||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr>
|
||||||
<Th>{locale == 'it' ? 'Giorno' : 'Day of Week'}</Th>
|
<Th>{locale == 'it' ? 'Giorno' : 'Day of Week'}</Th>
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
{
|
{
|
||||||
"it": [
|
"it": [
|
||||||
{
|
|
||||||
"label": "Categorie",
|
|
||||||
"href": "#"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"label": "Chi Siamo",
|
"label": "Chi Siamo",
|
||||||
"href": "/about"
|
"href": "/about"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"label": "News",
|
|
||||||
"href": "/news"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"label": "Contatti",
|
"label": "Contatti",
|
||||||
"href": "/contact"
|
"href": "/contact"
|
||||||
@ -19,25 +11,25 @@
|
|||||||
{
|
{
|
||||||
"label": "Dove Siamo",
|
"label": "Dove Siamo",
|
||||||
"href": "/where-we-are"
|
"href": "/where-we-are"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "News",
|
||||||
|
"href": "/news"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"en": [
|
"en": [
|
||||||
{
|
|
||||||
"label": "Categories",
|
|
||||||
"href": "#"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"label": "About",
|
"label": "About",
|
||||||
"href": "/about"
|
"href": "/about"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"label": "News",
|
|
||||||
"href": "/news"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"label": "Contact",
|
"label": "Contact",
|
||||||
"href": "/contact"
|
"href": "/contact"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "News",
|
||||||
|
"href": "/news"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "Where we are",
|
"label": "Where we are",
|
||||||
"href": "/where-we-are"
|
"href": "/where-we-are"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user