grand commit
This commit is contained in:
@@ -15,13 +15,6 @@ type MenuProps = {
|
||||
}
|
||||
|
||||
export default async function Header() {
|
||||
/*{
|
||||
searchParams
|
||||
}: {
|
||||
searchParams: Promise<{query?: string}>
|
||||
}*/
|
||||
//const query = (await searchParams).query
|
||||
|
||||
return (
|
||||
<header className='w-full border-none bg-background text-white'>
|
||||
<div className='container flex'>
|
||||
|
||||
@@ -1,34 +1,22 @@
|
||||
import Image from 'next/image'
|
||||
import * as React from 'react'
|
||||
|
||||
import {cards} from '@/lib/data'
|
||||
import {Card, CardContent} from '@/ui/card'
|
||||
import FeatureCardFront from '@/components/shared/store/feature-card-front'
|
||||
import {CategoryPageSqlSchema} from '@/lib/data/models/sqlSchemas'
|
||||
import {Carousel, CarouselContent, CarouselItem} from '@/ui/carousel'
|
||||
|
||||
export default function FeatureCards() {
|
||||
export default function FeatureCards({
|
||||
items
|
||||
}: {
|
||||
items: CategoryPageSqlSchema[]
|
||||
}) {
|
||||
return (
|
||||
<Carousel className='mx-auto w-full'>
|
||||
<CarouselContent className='-ml-2 md:-ml-4'>
|
||||
{cards.map((card: any) => (
|
||||
{items.map((card: any) => (
|
||||
<CarouselItem
|
||||
key={card.title}
|
||||
className='pl-3 md:basis-1/3 lg:basis-1/4 xl:basis-1/5'
|
||||
className='py-4 pl-3 md:basis-1/3 lg:basis-1/4'
|
||||
>
|
||||
<div className='p-1'>
|
||||
<Card className='border-[2px] border-brand-violet'>
|
||||
<CardContent className='aspect-card flex items-center justify-center p-1'>
|
||||
<CarouselItem>
|
||||
<Image
|
||||
src={card.image}
|
||||
width={256}
|
||||
height={256}
|
||||
className='object-scale-down'
|
||||
priority
|
||||
alt={''}
|
||||
/>
|
||||
</CarouselItem>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<FeatureCardFront card={card} />
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
|
||||
@@ -1,39 +1,37 @@
|
||||
'use client'
|
||||
|
||||
import cookies from 'js-cookie'
|
||||
import {useLocale} from 'next-intl'
|
||||
import {redirect} from 'next/navigation'
|
||||
|
||||
import {Link, usePathname, useRouter} from '@/i18n/routing'
|
||||
import {useRouter} from '@/i18n/routing'
|
||||
import {Link} from '@/i18n/routing'
|
||||
import {Label} from '@/ui/label'
|
||||
import {Switch} from '@/ui/switch'
|
||||
|
||||
export default function LocaleSwitcher() {
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const locale = useLocale()
|
||||
const initialState = locale !== 'uk'
|
||||
//const [localeState, setLocaleState] = useState(initialState)
|
||||
|
||||
const handler = (state: boolean) => {
|
||||
const newPath = `/${locale}${pathname}`
|
||||
//window.history.replaceState(null, '', newPath)
|
||||
const link = document.getElementById('lang-switch')
|
||||
if (link) {
|
||||
link.innerText = `${state ? '/ru' : ''}${pathname}`
|
||||
link.setAttribute('href', `${state ? '/ru' : ''}${pathname}`)
|
||||
link.click()
|
||||
}
|
||||
const handleLocaleChange = (state: boolean) => {
|
||||
const locale = cookies.get('NEXT_LOCALE') === 'ru' ? 'uk' : 'ru'
|
||||
cookies.set('NEXT_LOCALE', locale, {
|
||||
expires: 7,
|
||||
path: '/',
|
||||
sameSite: 'Lax'
|
||||
})
|
||||
router.replace(window.location.pathname.replace(/^\/ru/, ''), {locale})
|
||||
}
|
||||
// router.replace('/cabinet', {locale: checked ? 'ru' : 'uk'}
|
||||
|
||||
return (
|
||||
<div className='flex items-center space-x-2'>
|
||||
<Link id='lang-switch' href='/' locale='uk'>
|
||||
LA
|
||||
</Link>
|
||||
<Label htmlFor='locale-switcher'>Укр</Label>
|
||||
<Switch
|
||||
className='bg-brand-violet-900'
|
||||
id='locale-switcher'
|
||||
defaultChecked={initialState}
|
||||
onCheckedChange={handler}
|
||||
onCheckedChange={handleLocaleChange}
|
||||
/>
|
||||
<Label htmlFor='locale-switcher'>Рус</Label>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
'use client'
|
||||
|
||||
import {Menu as MenuIcon, X} from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import {useState} from 'react'
|
||||
|
||||
import {Link} from '@/i18n/routing'
|
||||
import {data} from '@/lib/data'
|
||||
import {Button} from '@/ui/button'
|
||||
|
||||
@@ -21,7 +20,7 @@ export default function NavbarMenu() {
|
||||
<div className={`hidden ${bp}:block w-full`}>
|
||||
<div className='flex items-center justify-between'>
|
||||
{data.headerMenus.map(item => (
|
||||
<Link href={item.href + item.slug} className='' key={item.name}>
|
||||
<Link href='/about-us' className='' key={item.name}>
|
||||
{item.name}
|
||||
</Link>
|
||||
))}
|
||||
|
||||
@@ -12,18 +12,20 @@ export default function AppCatalogRender(data: {items: Category[]}) {
|
||||
return (
|
||||
<div className='flex w-full justify-center'>
|
||||
<div className='bw-dd-menu group inline-block w-full'>
|
||||
<Button className='py-13 flex h-10 w-full items-center rounded-sm border-none bg-brand-yellow-300 px-3 outline-none focus:outline-none'>
|
||||
<span className='flex-1 pr-1 font-semibold'>Каталог</span>
|
||||
<span>
|
||||
<svg
|
||||
className='h-4 w-4 transform fill-current transition duration-300 ease-in-out group-hover:-rotate-180'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
viewBox='0 0 20 20'
|
||||
>
|
||||
<path d='M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z' />
|
||||
</svg>
|
||||
</span>
|
||||
</Button>
|
||||
<Link href='/catalog'>
|
||||
<Button className='py-13 flex h-10 w-full items-center rounded-sm border-none bg-brand-yellow-300 px-3 outline-none focus:outline-none'>
|
||||
<span className='flex-1 pr-1 font-semibold'>Каталог</span>
|
||||
<span>
|
||||
<svg
|
||||
className='h-4 w-4 transform fill-current transition duration-300 ease-in-out group-hover:-rotate-180'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
viewBox='0 0 20 20'
|
||||
>
|
||||
<path d='M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z' />
|
||||
</svg>
|
||||
</span>
|
||||
</Button>
|
||||
</Link>
|
||||
<ul className='-bw-app-catalog-collapse mt-2 w-full min-w-32 origin-top transform rounded-sm border bg-white shadow-xl transition duration-300 ease-in-out group-hover:scale-100 hover:shadow-2xl'>
|
||||
{data?.items.map((item: any) => (
|
||||
<li
|
||||
@@ -33,7 +35,7 @@ export default function AppCatalogRender(data: {items: Category[]}) {
|
||||
<button className='flex w-full items-center text-left outline-none focus:outline-none'>
|
||||
<Link
|
||||
className='flex-1 pr-1 leading-none xl:leading-[1.3]'
|
||||
href={`/category/${item.id}-${item.locales[locale === 'uk' ? 0 : 1].slug}`}
|
||||
href={`/category/${item.locales[locale === 'uk' ? 0 : 1].slug}`}
|
||||
>
|
||||
{item.locales[locale === 'uk' ? 0 : 1].title}
|
||||
</Link>
|
||||
|
||||
33
components/shared/store/add-cart-button.tsx
Normal file
33
components/shared/store/add-cart-button.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
'use client'
|
||||
|
||||
import {ShoppingCartIcon} from 'lucide-react'
|
||||
import {useTranslations} from 'next-intl'
|
||||
|
||||
import {dump} from '@/lib/utils'
|
||||
import useCartStore, {CartItem} from '@/store/cart-store'
|
||||
import {Button} from '@/ui/button'
|
||||
|
||||
export default function AddCartButton({product}: {product: CartItem}) {
|
||||
const t = useTranslations('cart')
|
||||
const addItemToCart = useCartStore(state => state.addItemToCart)
|
||||
const {cartItems} = useCartStore(state => state)
|
||||
|
||||
return (
|
||||
<>
|
||||
{/*<Button
|
||||
className='bw-cart-btn flex flex-col items-center border-0 shadow-none'
|
||||
variant='outline'
|
||||
title={t('basket')}
|
||||
onClick={() => addItemToCart(product)}
|
||||
>
|
||||
|
||||
</Button>*/}
|
||||
|
||||
<ShoppingCartIcon
|
||||
role='button'
|
||||
className='bw-cart-btn h-[24px] w-[24px]'
|
||||
onClick={() => addItemToCart(product)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
31
components/shared/store/card-buy-button.tsx
Normal file
31
components/shared/store/card-buy-button.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
'use client'
|
||||
|
||||
import {ShoppingCartIcon} from 'lucide-react'
|
||||
import {useTranslations} from 'next-intl'
|
||||
|
||||
import useCartStore, {CartItem} from '@/store/cart-store'
|
||||
import {Button} from '@/ui/button'
|
||||
|
||||
export default function CardBuyButton({
|
||||
item,
|
||||
isIcon
|
||||
}: {
|
||||
item: CartItem
|
||||
isIcon?: boolean
|
||||
}) {
|
||||
const t = useTranslations('cart')
|
||||
const addItemToCart = useCartStore(state => state.addItemToCart)
|
||||
|
||||
return (
|
||||
<Button
|
||||
className={`mr-2 ${isIcon ? '' : 'w-[80px]'} grow-0 shadow-white hover:shadow-md hover:shadow-brand-violet/50`}
|
||||
onClick={() => addItemToCart(item)}
|
||||
>
|
||||
{isIcon ? (
|
||||
<ShoppingCartIcon role='button' className='bw-cart-btn p-1' />
|
||||
) : (
|
||||
t('buy')
|
||||
)}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
71
components/shared/store/feature-card-front.tsx
Normal file
71
components/shared/store/feature-card-front.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import {ProductResource} from '@prisma/client'
|
||||
import {Star, StarHalf} from 'lucide-react'
|
||||
import Image from 'next/image'
|
||||
|
||||
import CardBuyButton from '@/components/shared/store/card-buy-button'
|
||||
import RateStars from '@/components/shared/store/stars'
|
||||
import {Link} from '@/i18n/routing'
|
||||
import {CategoryPageSqlSchema} from '@/lib/data/models/sqlSchemas'
|
||||
import {Button} from '@/ui/button'
|
||||
import {Card, CardContent, CardFooter} from '@/ui/card'
|
||||
import {CarouselItem} from '@/ui/carousel'
|
||||
|
||||
export default function FeatureCardFront({
|
||||
card
|
||||
}: {
|
||||
card: CategoryPageSqlSchema
|
||||
}) {
|
||||
return (
|
||||
<Card className='relative aspect-card overflow-hidden border-[2px] border-brand-violet transition duration-300 hover:shadow-lg hover:shadow-brand-violet/50'>
|
||||
<Link href={`/product/${card.productId}-${card.slug}`}>
|
||||
<CardContent className='relative flex h-[81%] flex-col justify-between overflow-hidden pt-4'>
|
||||
{/*<CarouselItem>*/}
|
||||
<Image
|
||||
className='transition duration-300 hover:scale-110'
|
||||
src={card?.image || ''}
|
||||
width={card.imageWidth || 100}
|
||||
height={card.imageHeight || 100}
|
||||
/*className='object-scale-down'*/
|
||||
priority
|
||||
alt={''}
|
||||
sizes='100vw'
|
||||
style={{
|
||||
objectFit: 'contain',
|
||||
width: '100%',
|
||||
height: 'calc(100% - 24px)'
|
||||
}}
|
||||
/>
|
||||
<RateStars />
|
||||
{/*</CarouselItem>*/}
|
||||
</CardContent>
|
||||
</Link>
|
||||
<div className='bw-card-footer flex h-[19%] items-center justify-between border-t-[2px] border-brand-violet px-4'>
|
||||
<div className=''>
|
||||
<p className='ml-2 border-b border-b-brand-violet pl-2 pr-6 text-[16px]'>
|
||||
{card.title}
|
||||
</p>
|
||||
<p className='pl-4 text-[16px] font-bold text-brand-violet'>
|
||||
{parseFloat(card.price as string).toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
<CardBuyButton
|
||||
item={{
|
||||
id: card.productId,
|
||||
quantity: 1,
|
||||
title: card.title,
|
||||
price: parseFloat(card.price as string).toFixed(2)
|
||||
}}
|
||||
isIcon={true}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
// id: number
|
||||
// quantity: number
|
||||
// title: string
|
||||
// price: string | any
|
||||
// image?: string | null
|
||||
// imageWidth?: number | null
|
||||
// imageHeight?: number | null
|
||||
65
components/shared/store/feature-card.tsx
Normal file
65
components/shared/store/feature-card.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import {Star, StarHalf} from 'lucide-react'
|
||||
import Image from 'next/image'
|
||||
|
||||
import CardBuyButton from '@/components/shared/store/card-buy-button'
|
||||
import RateStars from '@/components/shared/store/stars'
|
||||
import {Link} from '@/i18n/routing'
|
||||
import {Button} from '@/ui/button'
|
||||
import {Card, CardContent, CardFooter} from '@/ui/card'
|
||||
|
||||
//import {CarouselItem} from '@/ui/carousel'
|
||||
|
||||
export default function FeatureCard({card}: {card: any}) {
|
||||
return (
|
||||
<Card className='relative aspect-card overflow-hidden border-[2px] border-brand-violet transition duration-300 hover:shadow-lg hover:shadow-brand-violet/50'>
|
||||
<Link href={`/product/${card.productId}-${card.slug}`}>
|
||||
<CardContent className='relative flex h-[81%] flex-col justify-between overflow-hidden pt-4'>
|
||||
{/*<CarouselItem>*/}
|
||||
<Image
|
||||
className='transition duration-300 hover:scale-110'
|
||||
src={card.image}
|
||||
width={card.imageWidth}
|
||||
height={card.imageHeight}
|
||||
/*className='object-scale-down'*/
|
||||
priority
|
||||
alt={''}
|
||||
sizes='100vw'
|
||||
style={{
|
||||
objectFit: 'contain',
|
||||
width: '100%',
|
||||
height: 'calc(100% - 24px)'
|
||||
}}
|
||||
/>
|
||||
<RateStars />
|
||||
</CardContent>
|
||||
</Link>
|
||||
<div className='bw-card-footer flex h-[19%] items-center justify-between border-t-[2px] border-brand-violet px-4'>
|
||||
<div className=''>
|
||||
<p className='ml-2 border-b border-b-brand-violet pl-2 pr-6'>
|
||||
{card.title}
|
||||
</p>
|
||||
<p className='pl-4 text-[18px] font-bold text-brand-violet'>
|
||||
{parseFloat(card.price).toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
<CardBuyButton
|
||||
item={{
|
||||
id: card.productId,
|
||||
quantity: 1,
|
||||
title: card.title,
|
||||
price: parseFloat(card.price).toFixed(2),
|
||||
image: card.image
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
// id: number
|
||||
// quantity: number
|
||||
// title: string
|
||||
// price: string | any
|
||||
// image?: string | null
|
||||
// imageWidth?: number | null
|
||||
// imageHeight?: number | null
|
||||
16
components/shared/store/stars.tsx
Normal file
16
components/shared/store/stars.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import {Star} from 'lucide-react'
|
||||
|
||||
const startStroke = 1.5
|
||||
const color = '#ffd139'
|
||||
|
||||
export default function RateStars() {
|
||||
return (
|
||||
<div className='bw-rating absolute bottom-2 left-4 inline-flex h-[32px] items-center gap-1'>
|
||||
<Star strokeWidth={startStroke} color={color} fill={color} />
|
||||
<Star strokeWidth={startStroke} color={color} fill={color} />
|
||||
<Star strokeWidth={startStroke} color={color} fill={color} />
|
||||
<Star strokeWidth={startStroke} color={color} />
|
||||
<Star strokeWidth={startStroke} color={color} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user