stuff done
This commit is contained in:
@@ -11,7 +11,7 @@ export default function Above() {
|
||||
const t = useTranslations('Banner.Above')
|
||||
|
||||
return (
|
||||
<div className='flex w-full items-end justify-center bg-brand-violet md:min-h-[43px] xl:min-h-[51px]'>
|
||||
<div className='bw-above flex h-[51px] w-full items-end justify-center bg-brand-violet'>
|
||||
<div className='mx-0 mb-0.5'>
|
||||
<Image
|
||||
width={72.79}
|
||||
|
||||
@@ -2,26 +2,40 @@
|
||||
|
||||
// 31:47
|
||||
import {ChevronUp} from 'lucide-react'
|
||||
import {useLocale} from 'next-intl'
|
||||
|
||||
import SocialMediaPanel from '@/components/shared/social-media-panel'
|
||||
import {Link} from '@/i18n/routing'
|
||||
import {Button} from '@/ui/button'
|
||||
|
||||
export default function Footer() {
|
||||
const locale = useLocale()
|
||||
|
||||
return (
|
||||
<footer className='bg-brand-violet w-full py-3 text-white'>
|
||||
<footer className='w-full bg-brand-violet py-3 text-white'>
|
||||
<div className='container flex items-center justify-between'>
|
||||
<div>Політика конфіденційності</div>
|
||||
<div>Договір оферти</div>
|
||||
<div>
|
||||
<Link href={'/privacy-policy'}>
|
||||
{locale === 'uk'
|
||||
? 'Політика конфіденційності'
|
||||
: 'Политика конфиденциальности'}
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={'/offer-contract'}>
|
||||
{locale === 'uk' ? 'Договір оферти' : 'Договор оферты'}
|
||||
</Link>
|
||||
</div>
|
||||
<div>Доставка і повернення</div>
|
||||
<div>Контакти</div>
|
||||
<SocialMediaPanel color='#fff' />
|
||||
<Button
|
||||
{/*<Button
|
||||
variant='ghost'
|
||||
className='bg-brand-violet rounded-none'
|
||||
className='rounded-none bg-brand-violet'
|
||||
onClick={() => window.scrollTo({top: 0, behavior: 'smooth'})}
|
||||
>
|
||||
<ChevronUp className='mr-2 h-4 w-4' />
|
||||
</Button>
|
||||
</Button>*/}
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
|
||||
@@ -9,13 +9,13 @@ export default function HeaderControls() {
|
||||
const t = useTranslations('cart')
|
||||
|
||||
return (
|
||||
<div className='flex w-full justify-end gap-x-6 text-brand-violet'>
|
||||
<div className='flex w-full items-center justify-end gap-x-2 text-brand-violet'>
|
||||
<CabinetButton />
|
||||
|
||||
<Link href={'#' as never} className='header-button' aria-label='Вибране'>
|
||||
<button className='flex flex-col items-center' role='button'>
|
||||
<Heart className='h-[21px] w-[21px]' />
|
||||
<span className='font1-bold text-sm'>{t('favorites')}</span>
|
||||
{/*<span className='font1-bold text-sm'>{t('favorites')}</span>*/}
|
||||
</button>
|
||||
</Link>
|
||||
|
||||
|
||||
@@ -4,21 +4,30 @@ import {ShoppingCartIcon} from 'lucide-react'
|
||||
import {useTranslations} from 'next-intl'
|
||||
|
||||
import {Link} from '@/i18n/routing'
|
||||
import useCartStore from '@/store/cart-store'
|
||||
import useCartStore, {CartItem} from '@/store/cart-store'
|
||||
|
||||
export default function HeaderShoppingCartIcon() {
|
||||
const t = useTranslations('cart')
|
||||
const t = useTranslations('Common')
|
||||
const {cartItems} = useCartStore()
|
||||
const cartCount = cartItems.length
|
||||
const cartCount = cartItems.reduce(
|
||||
(accumulator: number, item: CartItem) => accumulator + item.quantity,
|
||||
0
|
||||
)
|
||||
|
||||
return (
|
||||
<Link href={'/cart' as never} className='header-button' aria-label='Кошик'>
|
||||
<Link
|
||||
href={'/cart' as never}
|
||||
className='header-button relative'
|
||||
aria-label={t('basket')}
|
||||
>
|
||||
<button className='flex flex-col items-center' role='button'>
|
||||
<ShoppingCartIcon className='h-[21px] w-[21px]' />
|
||||
|
||||
<span className='font1-bold text-sm'>
|
||||
{t('basket')} [{cartCount}]
|
||||
</span>
|
||||
{cartCount > 0 && (
|
||||
<div className='absolute -right-1 -top-1 h-[20px] w-[20px] rounded-full border border-brand-violet bg-brand-yellow pl-0 pr-[1px] text-[0.625rem] font-bold leading-[18px]'>
|
||||
{cartCount}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
</Link>
|
||||
)
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
'use client'
|
||||
|
||||
import {useLocale, useTranslations} from 'next-intl'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
|
||||
// TODO: Link throwing no connection error in this component; React 19 Bug
|
||||
// import {Link} from '@/i18n/routing'
|
||||
import {APP_NAME} from '@/lib/constants'
|
||||
import logoImg from '@/public/images/logo.svg'
|
||||
|
||||
export default function Logo() {
|
||||
const t = useTranslations('Common')
|
||||
const locale = useLocale()
|
||||
const ar = 121 / 192
|
||||
const w = 112
|
||||
|
||||
return (
|
||||
<div className='mt-0.5 flex items-center justify-center'>
|
||||
<Link
|
||||
href='/'
|
||||
<a
|
||||
href={locale !== 'ru' ? '/' : '/ru'}
|
||||
className='m-1 flex cursor-pointer items-center pt-[7px] text-2xl font-extrabold outline-0'
|
||||
aria-label={t('home')}
|
||||
>
|
||||
<Image
|
||||
src={logoImg}
|
||||
@@ -23,7 +28,7 @@ export default function Logo() {
|
||||
alt={`${APP_NAME} logo`}
|
||||
className='w-[131]'
|
||||
/>
|
||||
</Link>
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ export default function LocaleSwitcher() {
|
||||
path: '/',
|
||||
sameSite: 'Lax'
|
||||
})
|
||||
router.replace(window.location.pathname.replace(/^\/ru/, ''), {locale})
|
||||
let path = window.location.pathname.replace(/^\/ru/, '')
|
||||
if (path === '') path = '/'
|
||||
router.replace(path, {locale})
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -22,7 +22,11 @@ export default function NavbarMenu() {
|
||||
<div className='flex items-center justify-between'>
|
||||
{data[locale === 'uk' ? 'headerMenus' : 'headerMenusRus'].map(
|
||||
item => (
|
||||
<Link href='/about-us' className='' key={item.name}>
|
||||
<Link
|
||||
href='/about-us'
|
||||
className='hover:[text-shadow:_0_1px_2px_rgb(99_102_241_/_0.6)]'
|
||||
key={item.name}
|
||||
>
|
||||
{item.name}
|
||||
</Link>
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ 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'>
|
||||
<div className='bw-dd-menu b group inline-block w-full'>
|
||||
<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>
|
||||
@@ -29,12 +29,12 @@ export default function AppCatalogRender(data: {items: Category[]}) {
|
||||
<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
|
||||
className='cursor-pointer rounded-none py-2.5 pl-3 pr-1.5 text-sm font-medium hover:bg-[#442d88]/10 xl:py-3'
|
||||
className='pay-2.5 cursor-pointer rounded-none pl-3 pr-1.5 text-sm font-medium hover:bg-[#442d88]/10 xl:py-2'
|
||||
key={item.id}
|
||||
>
|
||||
<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]'
|
||||
className='flex-1 pr-1 leading-none xl:leading-[1.275]'
|
||||
href={`/category/${item.locales[locale === 'uk' ? 0 : 1].slug}`}
|
||||
>
|
||||
{item.locales[locale === 'uk' ? 0 : 1].title}
|
||||
|
||||
@@ -18,7 +18,7 @@ export default function CardBuyButton({
|
||||
|
||||
return (
|
||||
<Button
|
||||
className={`mr-2 ${isIcon ? '' : 'w-[80px]'} grow-0 shadow-white hover:shadow-md hover:shadow-brand-violet/50`}
|
||||
className={`mr-1.5 ${isIcon ? '' : 'w-[80px]'} z-50 grow-0 shadow-white hover:shadow-md hover:shadow-brand-violet/50`}
|
||||
onClick={() => addItemToCart(item)}
|
||||
>
|
||||
{isIcon ? (
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
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
|
||||
@@ -18,7 +14,7 @@ export default function FeatureCardFront({
|
||||
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'>
|
||||
<CardContent className='relative flex h-[76%] flex-col justify-between overflow-hidden pt-4'>
|
||||
{/*<CarouselItem>*/}
|
||||
<Image
|
||||
className='transition duration-300 hover:scale-110'
|
||||
@@ -39,12 +35,12 @@ export default function FeatureCardFront({
|
||||
{/*</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='bw-card-footer flex h-[24%] items-center justify-between border-t-[2px] border-brand-violet px-2'>
|
||||
<div className=''>
|
||||
<p className='ml-2 border-b border-b-brand-violet pl-2 pr-6 text-[16px]'>
|
||||
<p className='font-heading ml-1 border-b border-b-brand-violet pb-0.5 pl-1 pr-3'>
|
||||
{card.title}
|
||||
</p>
|
||||
<p className='pl-4 text-[16px] font-bold text-brand-violet'>
|
||||
<p className='pl-2 text-[18px] font-bold text-brand-violet'>
|
||||
{parseFloat(card.price as string).toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
@@ -55,17 +51,9 @@ export default function FeatureCardFront({
|
||||
title: card.title,
|
||||
price: parseFloat(card.price as string).toFixed(2)
|
||||
}}
|
||||
isIcon={true}
|
||||
isIcon={false}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
// id: number
|
||||
// quantity: number
|
||||
// title: string
|
||||
// price: string | any
|
||||
// image?: string | null
|
||||
// imageWidth?: number | null
|
||||
// imageHeight?: number | null
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
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>*/}
|
||||
<CardContent className='relative flex h-[76%] flex-col justify-between overflow-hidden pt-4'>
|
||||
<Image
|
||||
className='transition duration-300 hover:scale-110'
|
||||
src={card.image}
|
||||
@@ -33,12 +28,12 @@ export default function FeatureCard({card}: {card: any}) {
|
||||
<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='bw-card-footer flex h-[24%] items-center justify-between border-t-[2px] border-brand-violet px-1'>
|
||||
<div className=''>
|
||||
<p className='ml-2 border-b border-b-brand-violet pl-2 pr-6'>
|
||||
<p className='font-heading ml-1 border-b border-b-brand-violet pb-0.5 pl-1 pr-3'>
|
||||
{card.title}
|
||||
</p>
|
||||
<p className='pl-4 text-[18px] font-bold text-brand-violet'>
|
||||
<p className='pl-2 text-[18px] font-bold text-brand-violet'>
|
||||
{parseFloat(card.price).toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -2,15 +2,16 @@ import {Star} from 'lucide-react'
|
||||
|
||||
const startStroke = 1.5
|
||||
const color = '#ffd139'
|
||||
const size = 16
|
||||
|
||||
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 className='bw-rating absolute bottom-1 left-3 inline-flex h-[32px] items-center gap-1'>
|
||||
<Star size={size} strokeWidth={startStroke} color={color} fill={color} />
|
||||
<Star size={size} strokeWidth={startStroke} color={color} fill={color} />
|
||||
<Star size={size} strokeWidth={startStroke} color={color} fill={color} />
|
||||
<Star size={size} strokeWidth={startStroke} color={color} />
|
||||
<Star size={size} strokeWidth={startStroke} color={color} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
55
components/shared/terms/index.tsx
Normal file
55
components/shared/terms/index.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import {Entity, EntityLocale, type Lang} from '@prisma/client'
|
||||
import {useLocale} from 'next-intl'
|
||||
|
||||
import {getBlockEntity} from '@/actions/admin/entity'
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger
|
||||
} from '@/components/ui/accordion'
|
||||
import {locales} from '@/i18n/routing'
|
||||
import {EntityTerm} from '@/lib/schemas/admin/entity'
|
||||
import {dump, thisLocale} from '@/lib/utils'
|
||||
|
||||
export default async function Terms() {
|
||||
const locale = useLocale()
|
||||
const terms = await getBlockEntity('terms')
|
||||
|
||||
return (
|
||||
<section className='container mb-4 mt-12'>
|
||||
{/*<pre>{dump(terms)}</pre>*/}
|
||||
<div className='bw-terms-section mx-auto max-w-[1080px]'>
|
||||
<Accordion
|
||||
type='single'
|
||||
collapsible
|
||||
className='flex w-full flex-wrap justify-between gap-y-4'
|
||||
>
|
||||
{terms.map(async (term: any, index: number) => {
|
||||
const {locales} = term
|
||||
const locale: EntityLocale = await thisLocale(locales)
|
||||
|
||||
const {title, body} = locale
|
||||
return (
|
||||
<AccordionItem
|
||||
key={index}
|
||||
value={`item-${index}`}
|
||||
className='bw-accordion-item'
|
||||
>
|
||||
<AccordionTrigger className='bw-accordion-trigger'>
|
||||
<div className='flex-grow'>{title}</div>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className='bw-accordion-content'>
|
||||
<span
|
||||
dangerouslySetInnerHTML={{__html: body as string}}
|
||||
></span>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
)
|
||||
})}
|
||||
{/*<div className='bw-accordion-item table-cell'></div>*/}
|
||||
</Accordion>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
28
components/shared/youtube-component.tsx
Normal file
28
components/shared/youtube-component.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
'use client'
|
||||
|
||||
import YouTube, {YouTubeProps} from 'react-youtube'
|
||||
|
||||
export default function YoutubeComponent({id}: {id: string}) {
|
||||
const onPlayerReady: YouTubeProps['onReady'] = e => {
|
||||
e.target.pauseVideo()
|
||||
}
|
||||
|
||||
const opts: YouTubeProps['opts'] = {
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
playerVars: {
|
||||
// https://developers.google.com/youtube/player_parameters
|
||||
autoplay: 0
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<YouTube
|
||||
id={`video-yt-${id}`}
|
||||
videoId={id}
|
||||
opts={opts}
|
||||
onReady={onPlayerReady}
|
||||
iframeClassName='bw-yt-video'
|
||||
/>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user