Search fixes

This commit is contained in:
Henrik Larsson 2023-08-11 11:54:50 +02:00
parent 70b869739f
commit 86f2475aad
17 changed files with 172 additions and 59 deletions

View File

@ -9,7 +9,7 @@ export default function OpenCart({
quantity?: number;
}) {
return (
<div className="relative flex h-10 w-10 items-center justify-center text-high-contrast">
<div className="relative flex h-8 w-8 items-center justify-center text-high-contrast lg:h-11 lg:w-11">
<ShoppingBagIcon
className={clsx(
'h-5 stroke-current transition-all ease-in-out hover:scale-110 ',

View File

@ -25,7 +25,7 @@ export default async function Header({ locale }: HeaderProps) {
<HeaderRoot>
<div className="relative flex flex-col border-b border-ui-border bg-app">
<div className="relative flex h-14 w-full items-center justify-between px-4 py-2 lg:h-16 lg:px-8 lg:py-3 2xl:px-16">
<div className="-translate-x-3 transform md:hidden">
<div className="-translate-x-2 transform md:hidden">
<Suspense fallback={<OpenMobileMenu />}>
<MobileMenuModal items={mainMenu} />
</Suspense>
@ -47,7 +47,7 @@ export default async function Header({ locale }: HeaderProps) {
{mainMenu.map((item: { title: string; slug: string }, i: number) => {
return (
<li key={i}>
<Link className="font-medium" href={`/category/${item.slug}`}>
<Link className="font-medium" href={`${locale}/category/${item.slug}`}>
{item.title}
</Link>
</li>

View File

@ -3,10 +3,10 @@ import clsx from 'clsx';
export default function OpenMobileMenu({ className }: { className?: string }) {
return (
<div className="relative flex h-11 w-11 items-center justify-center text-high-contrast">
<div className="relative flex h-8 w-8 items-center justify-center text-high-contrast">
<Bars3Icon
className={clsx(
'h-5 stroke-current transition-all ease-in-out hover:scale-110 ',
'h-6 w-6 translate-y-px transform stroke-current transition-all ease-in-out hover:scale-110 ',
className
)}
/>

View File

@ -3,7 +3,7 @@ import clsx from 'clsx';
export default function OpenSearch({ className }: { className?: string }) {
return (
<div className="relative flex h-10 w-10 items-center justify-center text-high-contrast">
<div className="relative flex h-8 w-8 items-center justify-center text-high-contrast lg:h-11 lg:w-11">
<MagnifyingGlassIcon
className={clsx('h-5 transition-all ease-in-out hover:scale-110 ', className)}
/>

View File

@ -3,7 +3,7 @@ import clsx from 'clsx';
export default function OpenUserMenu({ className }: { className?: string }) {
return (
<div className="relative flex h-10 w-10 items-center justify-center text-high-contrast">
<div className="relative flex h-8 w-8 items-center justify-center text-high-contrast lg:h-11 lg:w-11">
<UserCircleIcon
className={clsx(
'h-5 stroke-current transition-all ease-in-out hover:scale-110 ',

View File

@ -3,7 +3,7 @@ import clsx from 'clsx';
const Price = ({
amount,
className,
currencyCode = 'USD',
currencyCode = 'SEK',
currencyCodeClassName
}: {
amount: string;

View File

@ -27,7 +27,7 @@ export function Gallery({ images }: { images: { src: string; alt: string }[] })
return (
<>
<div className="relative aspect-square h-full w-full overflow-hidden">
<div className="relative aspect-square h-full w-full">
{images[imageIndex] && (
<Image
className="h-full w-full object-cover"

View File

@ -6,7 +6,7 @@ export function Grid({
images: { src: string; alt: string; width: number | undefined; height: number | undefined }[];
}) {
return (
<div className="grid grid-cols-2 gap-4">
<div className="grid w-full grid-cols-2 gap-4">
{images.map(
(
image: {
@ -19,7 +19,7 @@ export function Grid({
) => {
return (
<Image
className="aspect-square h-full w-full object-contain first:col-span-2"
className="aspect-square h-full w-full bg-neutral-300 object-cover first:col-span-2"
src={image.src}
height={image.height}
width={image.width}

View File

@ -1,22 +0,0 @@
const Price = ({
className,
amount,
currencyCode,
...props
}: {
amount: string;
currencyCode: string | 'SEK' | 'GPB';
className?: string;
} & React.ComponentProps<'p'>) => (
<p className={className} suppressHydrationWarning={true} {...props}>
{`${new Intl.NumberFormat(undefined, {
style: 'currency',
currency: currencyCode,
currencyDisplay: 'narrowSymbol'
}).format(parseFloat(amount))} ${currencyCode}`}
</p>
);
export default Price;

View File

@ -1,14 +1,20 @@
'use client';
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger
} from '@/components/ui/accordion';
import { Product } from '@/lib/storm/product';
import { Image } from '@/lib/storm/types';
import Text from 'components/ui/text/text';
import { cn } from 'lib/utils';
import { useTranslations } from 'next-intl';
import { Suspense } from 'react';
import Price from '../price';
import { Gallery } from './gallery';
import { Grid } from './grid';
import Price from './price';
interface ProductViewProps {
product: Product;
@ -43,21 +49,10 @@ export default function ProductView({ product, relatedProducts }: ProductViewPro
width: image.width
}))}
/>
{/* {images.map((image: Image, index: number) => (
<div key={index} className="first:col-span-2">
<SanityImage
image={image}
alt={image.alt}
priority={index === 0 ? true : false}
sizes="(max-width: 1024px) 100vw, 70vw"
/>
</div>
))} */}
</div>
</div>
<div className="col-span-1 mx-auto flex h-auto w-full flex-col p-4 lg:sticky lg:top-8 lg:col-span-5 lg:px-8 lg:py-0 lg:pr-0 2xl:top-16 2xl:px-16 2xl:pr-0">
<div className="col-span-1 mx-auto flex h-auto w-full flex-col p-4 lg:col-span-5 lg:px-8 lg:py-0 lg:pr-0 2xl:top-16 2xl:px-16 2xl:pr-0">
<Text variant={'productHeading'}>{name}</Text>
<Price
@ -66,9 +61,23 @@ export default function ProductView({ product, relatedProducts }: ProductViewPro
currencyCode={price.currencyCode ? price.currencyCode : 'SEK'}
/>
{description && (
<Accordion
className="mt-8"
type="single"
collapsible
defaultValue="product-description"
>
<AccordionItem value="product-description">
<AccordionTrigger>{t('description')}</AccordionTrigger>
<AccordionContent>
<Text className="mt-2" variant="paragraph">
{description}
</Text>
</AccordionContent>
</AccordionItem>
</Accordion>
)}
</div>
</div>

View File

@ -1,4 +1,6 @@
import algoliasearch from 'algoliasearch/lite';
// import { useLocale } from 'next-intl';
import Text from '@/components/ui/text';
import { Highlight, Hits, InstantSearch, SearchBox } from 'react-instantsearch';
const searchClient = algoliasearch(
@ -7,6 +9,7 @@ const searchClient = algoliasearch(
);
export default function Search() {
// const locale = useLocale();
// Hit.
function Hit(props: any) {
return (
@ -14,10 +17,13 @@ export default function Search() {
<a href={`/product/${props.hit.handle}`} className="flex gap-4">
<div className="relative aspect-square h-16 w-16 bg-neutral-300" />
<div>
<h3 className="mt-2 flex text-lg font-bold text-gray-900">
<Text className="!text-sm text-low-contrast" variant="label">
Brand
</Text>
<h3 className="flex text-sm font-bold text-high-contrast">
<Highlight attribute="title" hit={props.hit} />
</h3>
<p className="text-gray-700">{props.hit.price} SEK</p>
<p className="text-sm font-bold ">{props.hit.price} SEK</p>
</div>
</a>
</li>
@ -33,16 +39,20 @@ export default function Search() {
root: 'mt-4',
form: 'relative',
input:
'block w-full appearance-none rounded-none h-11 pl-9 pr-3 py-2 bg-white border border-ui-border',
'block w-full outline-offset-0 appearance-none rounded-none h-11 px-11 pr-3 py-2 bg-white border border-ui-border',
submit: 'absolute flex items-center justify-center top-0 left-0 bottom-0 w-11 h-11',
submitIcon: 'w-4 h-4'
submitIcon: 'w-4 h-4',
reset: 'absolute items-center justify-center top-0 right-0 bottom-0 w-11 h-11',
resetIcon: 'w-3 h-3 mx-auto bg-app'
}}
/>
{/* <Configure filters={`locale:${locale}`} /> */}
<Hits
classNames={{
root: 'flex flex-col mt-4',
list: 'grid grid-cols-1 gap-4 overflow-auto'
root: 'flex flex-col mt-4 overflow-auto max-h-full',
list: 'grid grid-cols-1 gap-12 overflow-auto'
}}
hitComponent={Hit}
/>

View File

@ -0,0 +1,56 @@
'use client';
import { ChevronDownIcon } from '@heroicons/react/24/outline';
import * as AccordionPrimitive from '@radix-ui/react-accordion';
import * as React from 'react';
import { cn } from '@/lib/utils';
const Accordion = AccordionPrimitive.Root;
const AccordionItem = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
<AccordionPrimitive.Item ref={ref} className={cn('border-b', className)} {...props} />
));
AccordionItem.displayName = 'AccordionItem';
const AccordionTrigger = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
'flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline data-[state=open]:font-bold [&[data-state=open]>svg]:rotate-180',
className
)}
{...props}
>
{children}
<ChevronDownIcon className="h-4 w-4 shrink-0 transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
const AccordionContent = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className={cn(
'overflow-hidden transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down',
className
)}
{...props}
>
<div className="pb-4 pt-0">{children}</div>
</AccordionPrimitive.Content>
));
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };

View File

@ -47,7 +47,7 @@ const DropdownMenuSubContent = React.forwardRef<
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'z-50 min-w-[8rem] overflow-hidden border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className
)}
{...props}
@ -64,7 +64,7 @@ const DropdownMenuContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'z-50 min-w-[8rem] overflow-hidden border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className
)}
{...props}

View File

@ -52,7 +52,7 @@ export default function LocaleSwitcher() {
<>
<DropdownMenu open={isOpen} onOpenChange={() => setIsOpen(!isOpen)}>
<DropdownMenuTrigger
className="relative flex h-11 w-11 items-center justify-center rounded-md border border-neutral-200 text-black transition-colors"
className="relative flex h-11 w-11 items-center justify-center text-black transition-colors"
aria-label={t('languageSelector')}
>
<LanguageIcon className="h-6 w-6" />

View File

@ -2,7 +2,7 @@
import SanityImage from '@/components/ui/sanity-image/sanity-image';
import type { Product } from '@/lib/storm/product';
import Price from 'components/product/price';
import Price from 'components/price';
import Text from 'components/ui/text';
import { cn } from 'lib/utils';
import Link from 'next/link';

View File

@ -21,6 +21,7 @@
"dependencies": {
"@heroicons/react": "^2.0.18",
"@portabletext/react": "^3.0.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.4",
"@radix-ui/react-navigation-menu": "^1.1.2",

59
pnpm-lock.yaml generated
View File

@ -5,6 +5,7 @@ specifiers:
'@next/bundle-analyzer': ^13.4.13
'@playwright/test': ^1.34.1
'@portabletext/react': ^3.0.0
'@radix-ui/react-accordion': ^1.1.2
'@radix-ui/react-dialog': ^1.0.4
'@radix-ui/react-dropdown-menu': ^2.0.4
'@radix-ui/react-navigation-menu': ^1.1.2
@ -56,6 +57,7 @@ specifiers:
dependencies:
'@heroicons/react': 2.0.18_react@18.2.0
'@portabletext/react': 3.0.4_react@18.2.0
'@radix-ui/react-accordion': 1.1.2_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-dialog': 1.0.4_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-dropdown-menu': 2.0.5_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-navigation-menu': 1.1.3_ml6diaeoljuxdq7psn5bilsrme
@ -1181,6 +1183,35 @@ packages:
'@babel/runtime': 7.22.10
dev: false
/@radix-ui/react-accordion/1.1.2_ml6diaeoljuxdq7psn5bilsrme:
resolution: {integrity: sha512-fDG7jcoNKVjSK6yfmuAs0EnPDro0WMXIhMtXdTBWqEioVW206ku+4Lw07e+13lUkFkpoEQ2PdeMIAGpdqEAmDg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.10
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-collapsible': 1.0.3_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-collection': 1.0.3_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-compose-refs': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@radix-ui/react-context': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@radix-ui/react-direction': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@radix-ui/react-id': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@radix-ui/react-primitive': 1.0.3_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-use-controllable-state': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@types/react': 18.2.19
'@types/react-dom': 18.2.7
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: false
/@radix-ui/react-arrow/1.0.3_ml6diaeoljuxdq7psn5bilsrme:
resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==}
peerDependencies:
@ -1202,6 +1233,34 @@ packages:
react-dom: 18.2.0_react@18.2.0
dev: false
/@radix-ui/react-collapsible/1.0.3_ml6diaeoljuxdq7psn5bilsrme:
resolution: {integrity: sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.10
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-compose-refs': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@radix-ui/react-context': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@radix-ui/react-id': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@radix-ui/react-presence': 1.0.1_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-primitive': 1.0.3_ml6diaeoljuxdq7psn5bilsrme
'@radix-ui/react-use-controllable-state': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@radix-ui/react-use-layout-effect': 1.0.1_6kgymidexis2l23kiss4by6rqm
'@types/react': 18.2.19
'@types/react-dom': 18.2.7
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: false
/@radix-ui/react-collection/1.0.3_ml6diaeoljuxdq7psn5bilsrme:
resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==}
peerDependencies: