Skip to content

Commit

Permalink
Merge pull request Weaverse#232 from Weaverse/dev
Browse files Browse the repository at this point in the history
Add clear filters functionlity, update filters styles
  • Loading branch information
hta218 authored Dec 10, 2024
2 parents 7e1f9dc + e47364b commit bbdf99a
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 76 deletions.
2 changes: 0 additions & 2 deletions app/components/header/desktop-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { useThemeSettings } from "@weaverse/hydrogen";
import { cva } from "class-variance-authority";
import { Suspense } from "react";
import useWindowScroll from "react-use/esm/useWindowScroll";
import { DialogDemo } from "~/components/drawer";
import { IconUser } from "~/components/icons";
import { Logo } from "~/components/logo";
import { cn } from "~/lib/cn";
Expand Down Expand Up @@ -73,7 +72,6 @@ export function DesktopHeader() {
<div className="flex items-center gap-1 z-1">
<PredictiveSearchButton />
<AccountLink className="relative flex items-center justify-center w-8 h-8" />
{/* <DialogDemo openFrom="right" /> */}
<CartCount
isHome={isHome}
openCart={() => {}}
Expand Down
2 changes: 1 addition & 1 deletion app/components/tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export let TooltipContent = forwardRef<HTMLDivElement, TooltipContentProps>(
ref={ref}
className={cn(
"animate-slide-down-and-fade",
"z-50 px-4 rounded py-1 shadow-sm text-background bg-body",
"z-50 px-3 py-1 shadow-sm text-background bg-body",
className,
)}
align="center"
Expand Down
81 changes: 56 additions & 25 deletions app/sections/collection-filters/filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,22 @@ export function Filters({ className }: { className?: string }) {
appliedFilters: AppliedFilter[];
}
>();
let appliedFiltersKeys = appliedFilters
.map((filter) => filter.label)
.join("-");
let filters = collection.products.filters as Filter[];

return (
<Accordion.Root
type="multiple"
className={cn("filters-list divide-y divide-line-subtle", className)}
key={expandFilters.toString() + showFiltersCount}
key={appliedFiltersKeys + expandFilters.toString() + showFiltersCount}
defaultValue={expandFilters ? filters.map((filter) => filter.id) : []}
>
{filters.map((filter: Filter) => {
let asColorSwatch =
enableColorSwatch && COLORS_FILTERS.includes(filter.label);
let asButton = displayAsButtonFor.includes(filter.label);

return (
<Accordion.Item
Expand Down Expand Up @@ -83,10 +87,11 @@ export function Filters({ className }: { className?: string }) {
])}
>
<div
key={filter.id}
className={clsx(
"flex pt-8",
asColorSwatch ? "gap-1.5 flex-wrap" : "flex-col gap-5",
asColorSwatch || asButton
? "gap-1.5 flex-wrap"
: "flex-col gap-5",
)}
>
{filter.values?.map((option) => {
Expand All @@ -108,9 +113,15 @@ export function Filters({ className }: { className?: string }) {
}
default:
return (
<ListItemFilter
<FilterItem
key={option.id}
asColorSwatch={asColorSwatch}
displayAs={
asColorSwatch
? "color-swatch"
: asButton
? "button"
: "list-item"
}
appliedFilters={appliedFilters as AppliedFilter[]}
option={option}
showFiltersCount={showFiltersCount}
Expand All @@ -127,13 +138,13 @@ export function Filters({ className }: { className?: string }) {
);
}

function ListItemFilter({
asColorSwatch,
function FilterItem({
displayAs,
option,
appliedFilters,
showFiltersCount,
}: {
asColorSwatch?: boolean;
displayAs: "color-swatch" | "button" | "list-item";
option: Filter["values"][0];
appliedFilters: AppliedFilter[];
showFiltersCount: boolean;
Expand Down Expand Up @@ -161,7 +172,7 @@ function ListItemFilter({
}
}

if (asColorSwatch) {
if (displayAs === "color-swatch") {
let swatchColor = swatches.colors.find(({ name }) => name === option.label);
let optionConf = options.find(({ name }) => {
return name.toLowerCase() === option.label.toLowerCase();
Expand All @@ -179,6 +190,7 @@ function ListItemFilter({
shape,
}),
checked ? "p-1 border-line" : "border-line-subtle",
option.count === 0 && "diagonal",
)}
onClick={() => handleCheckedChange(!checked)}
>
Expand All @@ -195,37 +207,56 @@ function ListItemFilter({
</button>
</TooltipTrigger>
<TooltipContent>
{showFiltersCount ? (
<span>
{option.label}{" "}
<span className="text-gray-100">({option.count})</span>
</span>
) : (
option.label
)}
<FilterLabel option={option} showFiltersCount={showFiltersCount} />
</TooltipContent>
</Tooltip>
);
}

if (displayAs === "button") {
return (
<button
type="button"
className={cn(
"px-3 py-1.5 border text-center",
option.count === 0 && "diagonal text-body-subtle",
checked
? "border-line bg-body text-background"
: "border-line-subtle hover:border-line",
)}
onClick={() => handleCheckedChange(!checked)}
>
<FilterLabel option={option} showFiltersCount={showFiltersCount} />
</button>
);
}

return (
<Checkbox
checked={checked}
onCheckedChange={handleCheckedChange}
label={
showFiltersCount ? (
<span>
{option.label}{" "}
<span className="text-gray-700">({option.count})</span>
</span>
) : (
option.label
)
<FilterLabel option={option} showFiltersCount={showFiltersCount} />
}
className={clsx(option.count === 0 && "line-through text-body-subtle")}
/>
);
}

function FilterLabel({
option,
showFiltersCount,
}: { option: Filter["values"][0]; showFiltersCount: boolean }) {
if (showFiltersCount) {
return (
<span>
{option.label} <span>({option.count})</span>
</span>
);
}
return option.label;
}

// const PRICE_RANGE_FILTER_DEBOUNCE = 500;

function PriceRangeFilter({ max, min }: { max?: number; min?: number }) {
Expand Down
126 changes: 81 additions & 45 deletions app/sections/collection-filters/products-pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { useLoaderData, useNavigate } from "@remix-run/react";
import { X } from "@phosphor-icons/react";
import {
useLoaderData,
useLocation,
useNavigate,
useSearchParams,
} from "@remix-run/react";
import { Pagination } from "@shopify/hydrogen";
import clsx from "clsx";
import { useEffect } from "react";
import { useInView } from "react-intersection-observer";
import type { CollectionDetailsQuery } from "storefrontapi.generated";
import Link from "~/components/link";
import { getImageLoadingPriority } from "~/lib/const";
import { getAppliedFilterLink, type AppliedFilter } from "~/lib/filter";
import { ProductCard } from "~/modules/product-card";

export function ProductsPagination({
Expand All @@ -19,58 +26,87 @@ export function ProductsPagination({
loadPrevText: string;
loadMoreText: string;
}) {
let { collection } = useLoaderData<
let { collection, appliedFilters } = useLoaderData<
CollectionDetailsQuery & {
collections: Array<{ handle: string; title: string }>;
appliedFilters: AppliedFilter[];
}
>();
let [params] = useSearchParams();
let location = useLocation();
let { pathname } = location;
let { ref, inView } = useInView();

return (
<Pagination connection={collection.products}>
{({
nodes,
isLoading,
nextPageUrl,
previousPageUrl,
hasNextPage,
hasPreviousPage,
state,
}) => (
<div
className="flex w-full flex-col gap-8 items-center"
style={
{
"--cols-mobile": `repeat(${gridSizeMobile || 1}, minmax(0, 1fr))`,
"--cols-desktop": `repeat(${gridSizeDesktop || 3}, minmax(0, 1fr))`,
} as React.CSSProperties
}
>
{hasPreviousPage && (
<Link to={previousPageUrl} variant="outline" className="mx-auto">
{isLoading ? "Loading..." : loadPrevText}
</Link>
)}
<ProductsLoadedOnScroll
nodes={nodes}
inView={inView}
nextPageUrl={nextPageUrl}
hasNextPage={hasNextPage}
state={state}
/>
{hasNextPage && (
<Link
ref={ref}
to={nextPageUrl}
variant="outline"
className="mx-auto"
>
{isLoading ? "Loading..." : loadMoreText}
</Link>
)}
<div className="space-y-6">
{appliedFilters.length > 0 ? (
<div className="flex items-center flex-wrap gap-6">
<div className="flex items-center gap-2">
{appliedFilters.map((filter: AppliedFilter) => {
let { label } = filter;
return (
<Link
key={label}
to={getAppliedFilterLink(filter, params, location)}
className="px-2 py-1 border border-line-subtle hover:border-line items-center gap-2"
variant="custom"
>
<span>{label}</span>
<X className="w-4 h-4" />
</Link>
);
})}
</div>
<Link to={pathname} variant="underline">
Clear all filters
</Link>
</div>
)}
</Pagination>
) : null}
<Pagination connection={collection.products}>
{({
nodes,
isLoading,
nextPageUrl,
previousPageUrl,
hasNextPage,
hasPreviousPage,
state,
}) => (
<div
className="flex w-full flex-col gap-8 items-center"
style={
{
"--cols-mobile": `repeat(${gridSizeMobile || 1}, minmax(0, 1fr))`,
"--cols-desktop": `repeat(${gridSizeDesktop || 3}, minmax(0, 1fr))`,
} as React.CSSProperties
}
>
{hasPreviousPage && (
<Link to={previousPageUrl} variant="outline" className="mx-auto">
{isLoading ? "Loading..." : loadPrevText}
</Link>
)}
<ProductsLoadedOnScroll
nodes={nodes}
inView={inView}
nextPageUrl={nextPageUrl}
hasNextPage={hasNextPage}
state={state}
/>
{hasNextPage && (
<Link
ref={ref}
to={nextPageUrl}
variant="outline"
className="mx-auto"
>
{isLoading ? "Loading..." : loadMoreText}
</Link>
)}
</div>
)}
</Pagination>
</div>
);
}

Expand Down
7 changes: 4 additions & 3 deletions app/sections/collection-filters/sort.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CaretDown } from "@phosphor-icons/react";
import { CaretDown, CheckCircle } from "@phosphor-icons/react";
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import { Link, useLocation, useSearchParams } from "@remix-run/react";
import { useLocation, useSearchParams } from "@remix-run/react";
import Link from "~/components/link";
import { cn } from "~/lib/cn";
import type { SortParam } from "~/lib/filter";

Expand Down Expand Up @@ -68,7 +69,7 @@ export function Sort() {
to={sortUrl}
className={cn(
"hover:underline underline-offset-[6px] hover:outline-none",
currentSortValue === key && "underline",
currentSortValue === key && "font-bold",
)}
>
{label}
Expand Down

0 comments on commit bbdf99a

Please sign in to comment.