Skip to content

Commit

Permalink
style: Searchbar layout modified
Browse files Browse the repository at this point in the history
  • Loading branch information
yuriassuncx committed Jul 22, 2024
1 parent 31ff9ed commit 394a477
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 39 deletions.
5 changes: 4 additions & 1 deletion components/header/Drawers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,19 @@ export interface Props {
}

const Aside = (
{ title, onClose, children, isMenu = false }: {
{ title, onClose, children, isMenu = false, isSearchbar = false }: {
title: string;
onClose?: () => void;
children: ComponentChildren;
isMenu?: boolean;
isSearchbar?: boolean;
},
) => (
<div
class={clx(
"bg-base-100 grid grid-rows-[auto_1fr] h-full divide-y max-w-[100vw]",
isMenu && "w-[75%]",
isSearchbar && "overflow-auto",
)}
>
<div class="flex justify-between items-center">
Expand Down Expand Up @@ -77,6 +79,7 @@ function Drawers({ menu, searchbar, children, platform }: Props) {
}}
title={displayMenu.value ? "Menu" : "Buscar"}
isMenu={displayMenu.value}
isSearchbar={displaySearchDrawer.value}
>
{displayMenu.value && <Menu {...menu} />}
{searchbar && displaySearchDrawer.value && (
Expand Down
232 changes: 194 additions & 38 deletions components/search/Searchbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/

import Icon from "$store/components/ui/Icon.tsx";
import Image from "apps/website/components/Image.tsx";
import Slider from "$store/components/ui/Slider.tsx";
import { sendEvent } from "$store/sdk/analytics.tsx";
import { useId } from "$store/sdk/useId.ts";
import { useUI } from "$store/sdk/useUI.ts";
Expand All @@ -19,6 +19,16 @@ import { Resolved } from "deco/engine/core/resolver.ts";
import { Suggestion } from "apps/commerce/types.ts";
import { useEffect, useRef } from "preact/compat";
import Button from "deco-sites/maconequiio/components/ui/Button.tsx";
import Image from "apps/website/components/Image.tsx";
import { relative } from "deco-sites/maconequiio/sdk/url.ts";
import {
formatInstallments,
formatPrice,
} from "deco-sites/maconequiio/sdk/format.ts";
import { useOffer } from "deco-sites/maconequiio/sdk/useOffer.ts";
import { SendEventOnClick } from "$store/components/Analytics.tsx";
import { mapProductToAnalyticsItem } from "apps/commerce/utils/productToAnalyticsItem.ts";
import Spinner from "deco-sites/maconequiio/components/ui/Spinner.tsx";

// Editable props
export interface Props {
Expand Down Expand Up @@ -57,13 +67,14 @@ function Searchbar({
const id = useId();
const { displaySearchPopup } = useUI();
const searchInputRef = useRef<HTMLInputElement>(null);
const { setQuery, payload } = useSuggestions(loader);
const { setQuery, payload, loading } = useSuggestions(loader);
const { products = [], searches = [] } = payload.value ?? {};
const hasProducts = Boolean(products.length);
const hasTerms = Boolean(searches.length);
const notFound = !hasProducts && !hasTerms;

useEffect(() => {
if (displaySearchPopup.value === true) {
if (displaySearchPopup.value) {
searchInputRef.current?.focus();
}
}, [displaySearchPopup.value]);
Expand Down Expand Up @@ -138,41 +149,186 @@ function Searchbar({
</button>
</div>

<div
class={`${!hasProducts && !hasTerms ? "hidden" : "pb-12 h-full"}`}
>
<div class="gap-4 grid grid-cols-1 px-2 h-full">
<div class="flex flex-col gap-2 overflow-y-auto max-h-[50%] h-full">
{products?.map(({ isVariantOf, image: images, url }) => {
const [front] = images ?? [];

return (
<a
href={url || "#"}
class="flex items-center w-full h-full gap-3"
>
<Image
src={front.url?.replace("-25-25", "-60-60") || ""}
alt={front.alternateName}
width={60}
height={60}
loading="lazy"
decoding="async"
preload={false}
/>

<h2
class="truncate text-black uppercase font-semibold text-xs pt-1.5"
dangerouslySetInnerHTML={{
__html: isVariantOf?.name ?? name ??
"",
}}
/>
</a>
);
})}
</div>
</div>
<div class="flex flex-col gap-6 divide-y divide-base-200 mt-6 empty:mt-0 md:flex-row md:divide-y-0">
{notFound
? (
<div class="py-16 md:py-6! flex flex-col gap-4 w-full">
<span
class="font-medium text-xl text-center"
role="heading"
aria-level={3}
>
Nenhum resultado encontrado
</span>
<span class="text-center text-black-neutral">
Vamos tentar de outro jeito? Verifique a ortografia ou use um
termo diferente
</span>
</div>
)
: (
<>
<div class="flex flex-col gap-6 md:w-[15.25rem] md:max-w-[15.25rem]\">
<div class="flex gap-2 items-center">
<span
class="font-medium text-xl"
role="heading"
aria-level={3}
>
Sugestões
</span>
{loading.value && <Spinner />}
</div>
<ul id="search-suggestion" class="flex flex-col gap-6">
{searches?.map(({ term }) => (
<li>
<a href={`/s?q=${term}`} class="flex gap-4 items-center">
<span>
<Icon
id="MagnifyingGlass"
size={27}
strokeWidth={0.01}
/>
</span>
<span>
{term}
</span>
</a>
</li>
))}
</ul>
</div>
<div class="flex flex-col pt-6 md:pt-0 gap-6 overflow-x-hidden flex-1">
<div class="flex gap-2 items-center">
<span
class="font-medium text-xl"
role="heading"
aria-level={3}
>
Produtos sugeridos
</span>
{loading.value && <Spinner />}
</div>
<Slider class="carousel gap-4 ">
{products?.map((product, index) => {
const { isVariantOf, image: images, url, offers } = product;
const [front] = images ?? [];

const WIDTH = 200;
const HEIGHT = 150;

const { listPrice, price, installments, availability } =
useOffer(
offers,
);

const inStock =
availability === "https://schema.org/InStock";

return (
<Slider.Item
index={index}
class="carousel-item first:ml-4 last:mr-4 min-w-[200px] max-w-[200px]"
>
<div
class="card card-compact group w-full h-full"
data-deco="view-product"
>
<SendEventOnClick
id={id}
event={{
name: "select_item" as const,
params: {
item_list_name: "suggestions",
items: [
mapProductToAnalyticsItem({
product,
price,
listPrice,
index,
}),
],
},
}}
/>
<figure
class="relative"
style={{ aspectRatio: WIDTH / HEIGHT }}
>
<a
href={url && relative(url)}
aria-label="view product"
class="contents"
>
<Image
src={front.url!}
alt={front.alternateName}
width={WIDTH}
height={HEIGHT}
class="col-span-full row-span-full rounded w-full h-[150px] object-contain"
sizes="(max-width: 640px) 50vw, 20vw"
loading="lazy"
decoding="async"
/>
</a>
</figure>

<div class="flex-auto flex flex-col p-2 gap-3 lg:gap-4">
<div class="flex flex-col mb-2 h-full">
<h2 class="line-clamp-2 text-sm text-black-neutral uppercase font-medium leading-4">
{isVariantOf?.name ?? name}
</h2>
</div>

{inStock &&
(
<div class="flex flex-col gap-2">
<div class="flex flex-col gap-0 lg:flex-row lg:gap-2">
{(listPrice ?? 0) > (price ?? 0) && (
<div class="line-through text-gray-base text-xs leading-3">
de: {formatPrice(
listPrice,
offers?.priceCurrency,
)}
</div>
)}

<div class="text-base">
{formatPrice(
price,
offers!.priceCurrency!,
)}
</div>
</div>

{!installments
? ""
: (
<div class="text-neutral text-sm lg:text-base">
ou {formatInstallments(installments)}
</div>
)}
</div>
)}

<div class="flex-auto flex items-end">
<a
href={url && relative(url)}
aria-label="view product"
class="btn btn-block bg-red text-white-normal hover:bg-red/90"
>
{inStock ? "Ver produto" : "Indisponível"}
</a>
</div>
</div>
</div>
</Slider.Item>
);
})}
</Slider>
</div>
</>
)}
</div>
</div>
);
Expand Down
8 changes: 8 additions & 0 deletions sdk/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,11 @@ export const formatPrice = (
currency = "BRL",
locale = "pt-BR",
) => price ? formatter(currency, locale).format(price) : null;

export const formatInstallments = (str: string | null) => {
if (!str) return "";
const value = str.split("R$ ")[1].split(" ")[0];
const newValue = `${formatPrice(parseFloat(value))}`;
str = str.replace(`R$ ${value}`, newValue);
return str;
};

0 comments on commit 394a477

Please sign in to comment.