stuff done

This commit is contained in:
2025-03-11 02:54:09 +02:00
parent 58e7ed2f06
commit 516b45fad9
90 changed files with 2950 additions and 9458 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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