grand commit

This commit is contained in:
2025-02-07 08:34:42 +02:00
parent f594f001f6
commit c6c34f0453
53 changed files with 1283 additions and 625 deletions

View File

@@ -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'>

View File

@@ -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>
))}

View File

@@ -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>

View File

@@ -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>
))}

View File

@@ -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>

View 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)}
/>
</>
)
}

View 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>
)
}

View 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

View 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

View 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>
)
}