From 16f6c9af46b8ad476c5a68796539160a4518be52 Mon Sep 17 00:00:00 2001 From: hta218 Date: Tue, 10 Dec 2024 08:39:14 +0700 Subject: [PATCH 1/3] Update checkbox, update collection filters options --- app/components/checkbox.tsx | 23 +++++++-------------- app/sections/collection-filters/filters.tsx | 17 +++++++++++---- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/app/components/checkbox.tsx b/app/components/checkbox.tsx index 72f8d18d..ad3b4f9e 100644 --- a/app/components/checkbox.tsx +++ b/app/components/checkbox.tsx @@ -1,34 +1,27 @@ +import { Check } from "@phosphor-icons/react"; import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; import * as React from "react"; import { cn } from "~/lib/cn"; -import { IconCheck } from "./icons"; interface CheckboxProps extends React.ComponentPropsWithoutRef { - label?: string; + label?: React.ReactNode; } -const Checkbox = React.forwardRef< +export let Checkbox = React.forwardRef< React.ElementRef, CheckboxProps >(({ className, label, ...props }, ref) => ( -
+
- - + + - {label ? {label} : null} + {label ? typeof label === "string" ? {label} : label : null}
)); -Checkbox.displayName = CheckboxPrimitive.Root.displayName; - -export { Checkbox }; diff --git a/app/sections/collection-filters/filters.tsx b/app/sections/collection-filters/filters.tsx index b62bff55..c61e407e 100644 --- a/app/sections/collection-filters/filters.tsx +++ b/app/sections/collection-filters/filters.tsx @@ -119,28 +119,37 @@ function ListItemFilter({ let navigate = useNavigate(); let [params] = useSearchParams(); let location = useLocation(); + let filter = appliedFilters.find( (filter) => JSON.stringify(filter.filter) === option.input, ); + let [checked, setChecked] = useState(!!filter); - let handleCheckedChange = (checked: boolean) => { + function handleCheckedChange(checked: boolean) { setChecked(checked); if (checked) { - const link = getFilterLink(option.input as string, params, location); + let link = getFilterLink(option.input as string, params, location); navigate(link); } else if (filter) { let link = getAppliedFilterLink(filter, params, location); navigate(link); } - }; + } return (
+ {option.label}{" "} + ({option.count}) + + ) : ( + option.label + ) } />
From f7b8ac40d157d2b29b76e86a132817138d94dfd8 Mon Sep 17 00:00:00 2001 From: hta218 Date: Tue, 10 Dec 2024 11:48:35 +0700 Subject: [PATCH 2/3] Update animation for tooltips --- app/components/tooltip.tsx | 10 ++++++++-- tailwind.config.js | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/components/tooltip.tsx b/app/components/tooltip.tsx index 59080c3a..1e711623 100644 --- a/app/components/tooltip.tsx +++ b/app/components/tooltip.tsx @@ -24,19 +24,25 @@ export let TooltipTrigger = ({ }: TooltipTriggerProps) => ; export let TooltipContent = forwardRef( - ({ children, className, sideOffset = 4, ...rest }, ref) => { + ({ children, className, sideOffset = 4, style, ...rest }, ref) => { return ( diff --git a/tailwind.config.js b/tailwind.config.js index e5340e24..b023c22e 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -31,6 +31,13 @@ export default { }, to: { opacity: 1, transform: "translateX(0)" }, }, + "slide-down-and-fade": { + from: { + opacity: 0, + transform: "translateY(var(--bottom-distance, 6px))", + }, + to: { opacity: 1, transform: "translateY(0)" }, + }, "enter-from-left": { from: { transform: "translateX(-100%)" }, to: { transform: "translateX(0)" }, @@ -75,6 +82,8 @@ export default { "slide-up var(--slide-up-duration, .3s) cubic-bezier(0.87, 0, 0.13, 1) forwards", "slide-left-and-fade": "slide-left-and-fade var(--slide-left-and-fade-duration, .5s) cubic-bezier(.165,.84,.44,1) forwards", + "slide-down-and-fade": + "slide-down-and-fade var(--slide-down-and-fade-duration, .5s) cubic-bezier(.165,.84,.44,1) forwards", "enter-from-left": "enter-from-left var(--enter-from-left-duration, .3s) ease-out forwards", "enter-from-right": From 5903680a8bf18b5210a11eb15a2ead6db346fc34 Mon Sep 17 00:00:00 2001 From: hta218 Date: Tue, 10 Dec 2024 11:48:54 +0700 Subject: [PATCH 3/3] Allow colors filter to display as swatches --- app/modules/product-form/options.tsx | 63 +++--- app/sections/collection-filters/filters.tsx | 218 +++++++++++++------- app/sections/collection-filters/index.tsx | 5 + 3 files changed, 182 insertions(+), 104 deletions(-) diff --git a/app/modules/product-form/options.tsx b/app/modules/product-form/options.tsx index 69371a9a..898bd933 100644 --- a/app/modules/product-form/options.tsx +++ b/app/modules/product-form/options.tsx @@ -6,38 +6,41 @@ import type { ProductVariantFragmentFragment } from "storefrontapi.generated"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/components/tooltip"; import { cn } from "~/lib/cn"; -let variants = cva("border border-line hover:border-body cursor-pointer", { - variants: { - colorSize: { - sm: "w-8 h-8", - md: "w-10 h-10", - lg: "w-12 h-12", - }, - buttonSize: { - sm: "min-w-8 h-8", - md: "min-w-10 h-10", - lg: "min-w-12 h-12", - }, - imageSize: { - sm: "w-12 h-auto", - md: "w-16 h-auto", - lg: "w-20 h-auto", - }, - shape: { - square: "", - circle: "rounded-full", - round: "rounded-md", - }, - selected: { - true: "border-body", - false: "", - }, - disabled: { - true: "diagonal", - false: "", +export let variants = cva( + "border border-line hover:border-body cursor-pointer", + { + variants: { + colorSize: { + sm: "w-8 h-8", + md: "w-10 h-10", + lg: "w-12 h-12", + }, + buttonSize: { + sm: "min-w-8 h-8", + md: "min-w-10 h-10", + lg: "min-w-12 h-12", + }, + imageSize: { + sm: "w-12 h-auto", + md: "w-16 h-auto", + lg: "w-20 h-auto", + }, + shape: { + square: "", + circle: "rounded-full", + round: "rounded-md", + }, + selected: { + true: "border-body", + false: "", + }, + disabled: { + true: "diagonal", + false: "", + }, }, }, -}); +); interface VariantOptionProps { selectedOptionValue: string; diff --git a/app/sections/collection-filters/filters.tsx b/app/sections/collection-filters/filters.tsx index c61e407e..c2282417 100644 --- a/app/sections/collection-filters/filters.tsx +++ b/app/sections/collection-filters/filters.tsx @@ -22,11 +22,21 @@ import { getAppliedFilterLink, getFilterLink } from "~/lib/filter"; import type { CollectionFiltersData } from "."; import { Input } from "../../modules/input"; import { cn } from "~/lib/cn"; +import { Tooltip, TooltipContent, TooltipTrigger } from "~/components/tooltip"; +import { type SwatchesConfigs, useThemeSettings } from "@weaverse/hydrogen"; +import { variants as productOptionsVariants } from "~/modules/product-form/options"; + +const COLORS_FILTERS = ["Color", "Colors", "Colour", "Colours"]; export function Filters({ className }: { className?: string }) { let parentInstance = useClosestWeaverseItem(".filters-list"); let parentData = parentInstance.data as unknown as CollectionFiltersData; - let { expandFilters, showFiltersCount } = parentData; + let { + expandFilters, + showFiltersCount, + enableColorSwatch, + displayAsButtonFor, + } = parentData; let [params] = useSearchParams(); let { collection, appliedFilters } = useLoaderData< CollectionDetailsQuery & { @@ -36,33 +46,6 @@ export function Filters({ className }: { className?: string }) { >(); let filters = collection.products.filters as Filter[]; - let filterMarkup = (filter: Filter, option: Filter["values"][0]) => { - switch (filter.type) { - case "PRICE_RANGE": { - let priceFilter = params.get(`${FILTER_URL_PREFIX}price`); - let price = priceFilter - ? (JSON.parse(priceFilter) as ProductFilter["price"]) - : undefined; - let min = Number.isNaN(Number(price?.min)) - ? undefined - : Number(price?.min); - let max = Number.isNaN(Number(price?.max)) - ? undefined - : Number(price?.max); - return ; - } - - default: - return ( - - ); - } - }; - return ( filter.id) : []} > - {filters.map((filter: Filter) => ( - - - {filter.label} - - - { + let asColorSwatch = + enableColorSwatch && COLORS_FILTERS.includes(filter.label); + + return ( + -
    - {filter.values?.map((option) => { - return
  • {filterMarkup(filter, option)}
  • ; - })} -
-
-
- ))} + + {filter.label} + + + +
+ {filter.values?.map((option) => { + switch (filter.type) { + case "PRICE_RANGE": { + let priceFilter = params.get(`${FILTER_URL_PREFIX}price`); + let price = priceFilter + ? (JSON.parse(priceFilter) as ProductFilter["price"]) + : undefined; + let min = Number.isNaN(Number(price?.min)) + ? undefined + : Number(price?.min); + let max = Number.isNaN(Number(price?.max)) + ? undefined + : Number(price?.max); + return ( + + ); + } + default: + return ( + + ); + } + })} +
+
+ + ); + })}
); } function ListItemFilter({ + asColorSwatch, option, appliedFilters, showFiltersCount, }: { + asColorSwatch?: boolean; option: Filter["values"][0]; appliedFilters: AppliedFilter[]; showFiltersCount: boolean; @@ -119,6 +141,8 @@ function ListItemFilter({ let navigate = useNavigate(); let [params] = useSearchParams(); let location = useLocation(); + let themeSettings = useThemeSettings(); + let { options, swatches }: SwatchesConfigs = themeSettings.productSwatches; let filter = appliedFilters.find( (filter) => JSON.stringify(filter.filter) === option.input, @@ -130,29 +154,75 @@ function ListItemFilter({ setChecked(checked); if (checked) { let link = getFilterLink(option.input as string, params, location); - navigate(link); + navigate(link, { preventScrollReset: true }); } else if (filter) { let link = getAppliedFilterLink(filter, params, location); - navigate(link); + navigate(link, { preventScrollReset: true }); } } - return ( -
- name === option.label); + let optionConf = options.find(({ name }) => { + return name.toLowerCase() === option.label.toLowerCase(); + }); + + let { shape = "square", size = "md" } = optionConf || {}; + return ( + + + + + + {showFiltersCount ? ( {option.label}{" "} - ({option.count}) + ({option.count}) ) : ( option.label - ) - } - /> -
+ )} + + + ); + } + + return ( + + {option.label}{" "} + ({option.count}) + + ) : ( + option.label + ) + } + /> ); } diff --git a/app/sections/collection-filters/index.tsx b/app/sections/collection-filters/index.tsx index d7781e2c..588a53c3 100644 --- a/app/sections/collection-filters/index.tsx +++ b/app/sections/collection-filters/index.tsx @@ -15,6 +15,8 @@ export interface CollectionFiltersData { filtersPosition: "sidebar" | "drawer"; expandFilters: boolean; showFiltersCount: boolean; + enableColorSwatch: boolean; + displayAsButtonFor: string; productsPerRowDesktop: number; productsPerRowMobile: number; loadPrevText: string; @@ -32,6 +34,8 @@ let CollectionFilters = forwardRef( filtersPosition, expandFilters, showProductsCount, + enableColorSwatch, + displayAsButtonFor, productsPerRowDesktop, productsPerRowMobile, loadPrevText, @@ -180,6 +184,7 @@ export let schema: HydrogenComponentSchema = { label: "Display as button for:", defaultValue: "Size, More filters", condition: "enableFilter.eq.true", + helpText: "Comma-separated list of filters to display as buttons", }, ], },