Skip to content

Commit

Permalink
Merge pull request Weaverse#142 from Weaverse/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
paul-phan authored Jun 17, 2024
2 parents 00bb8be + ba6ef14 commit 7a014d3
Show file tree
Hide file tree
Showing 47 changed files with 6,804 additions and 7,756 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ _Pilot is an innovative Shopify theme, powered by Hydrogen, Remix, and Weaverse,
![demo](https://cdn.shopify.com/s/files/1/0693/8201/3220/files/Home.png?v=1695816170)

## What's included

- Remix
- Hydrogen
- Oxygen
Expand Down
45 changes: 22 additions & 23 deletions app/components/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as React from 'react';
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
import {Check} from 'lucide-react';
import { cn } from '~/lib/cn';

import * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { Check } from "lucide-react";
import { cn } from "~/lib/cn";

interface CheckboxProps
extends React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> {
Expand All @@ -12,24 +11,24 @@ interface CheckboxProps
const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>,
CheckboxProps
>(({className, label, ...props}, ref) => (
<div className={cn(`flex items-center space-x-2.5`, className)}>
<CheckboxPrimitive.Root
ref={ref}
className={cn(
'peer w-5 h-5 shrink-0 rounded border-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
)}
{...props}
>(({ className, label, ...props }, ref) => (
<div className={cn(`flex items-center space-x-2.5`, className)}>
<CheckboxPrimitive.Root
ref={ref}
className={cn(
"peer w-5 h-5 shrink-0 rounded border-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
)}
{...props}
>
<CheckboxPrimitive.Indicator
className={cn("flex items-center justify-center text-current")}
>
<CheckboxPrimitive.Indicator
className={cn('flex items-center justify-center text-current')}
>
<Check className="h-4 w-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
{label ? <span>{label}</span> : null}
</div>
));
<Check className="h-4 w-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
{label ? <span>{label}</span> : null}
</div>
));
Checkbox.displayName = CheckboxPrimitive.Root.displayName;

export {Checkbox};
export { Checkbox };
11 changes: 6 additions & 5 deletions app/components/predictive-search/PredictiveSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import { IconSearch, Input } from '~/modules';
import {PredictiveSearchResults} from './PredictiveSearchResults';
import {PredictiveSearchForm} from './SearchForm';
import { IconSearch, Input } from "~/modules";
import { PredictiveSearchResults } from "./PredictiveSearchResults";
import { PredictiveSearchForm } from "./SearchForm";

interface PredictiveSearchProps {
// Predictive search props
isOpen?: boolean;
}

export function PredictiveSearch(props: PredictiveSearchProps) {
let {isOpen} = props;
let { isOpen } = props;
return (
<div className="relative border-t border-bar-subtle">
<PredictiveSearchForm>
{({fetchResults, inputRef}) => (
{({ fetchResults, inputRef }) => (
<div className="mx-auto w-full max-w-[560px] p-6">
<Input
name="q"
type="search"
onChange={fetchResults}
onFocus={fetchResults}
onClear={fetchResults}
Expand Down
57 changes: 33 additions & 24 deletions app/components/predictive-search/PredictiveSearchResult.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {Link} from '@remix-run/react';
import {SearchResultItem} from './ResultItem';
import {
import { Link } from "@remix-run/react";
import { SearchResultItem } from "./ResultItem";
import type {
NormalizedPredictiveSearchResultItem,
NormalizedPredictiveSearchResults,
SearchResultTypeProps,
} from './types';
} from "./types";
import clsx from "clsx";

export function PredictiveSearchResult({
Expand All @@ -13,7 +13,7 @@ export function PredictiveSearchResult({
searchTerm,
type,
}: SearchResultTypeProps) {
const isSuggestions = type === 'queries';
const isSuggestions = type === "queries";
const categoryUrl = `/search?q=${
searchTerm.current
}&type=${pluralToSingularSearchType(type)}`;
Expand All @@ -24,17 +24,26 @@ export function PredictiveSearchResult({
key={type}
>
<Link prefetch="intent" to={categoryUrl} onClick={goToSearchResult}>
<h5 className="uppercase font-semibold">{isSuggestions ? 'Suggestions' : type}</h5>
<h5 className="uppercase font-semibold">
{isSuggestions ? "Suggestions" : type}
</h5>
</Link>
<ul className={clsx("pt-5", type === "products" ? 'space-y-4' : 'space-y-1')}>
{items.map((item: NormalizedPredictiveSearchResultItem) => (
<SearchResultItem
goToSearchResult={goToSearchResult}
item={item}
key={item.id}
/>
))}
</ul>
{items?.length && (
<ul
className={clsx(
"pt-5",
type === "products" ? "space-y-4" : "space-y-1",
)}
>
{items.map((item: NormalizedPredictiveSearchResultItem) => (
<SearchResultItem
goToSearchResult={goToSearchResult}
item={item}
key={item.id}
/>
))}
</ul>
)}
</div>
);
}
Expand All @@ -50,20 +59,20 @@ export function PredictiveSearchResult({
*/
function pluralToSingularSearchType(
type:
| NormalizedPredictiveSearchResults[number]['type']
| Array<NormalizedPredictiveSearchResults[number]['type']>,
| NormalizedPredictiveSearchResults[number]["type"]
| Array<NormalizedPredictiveSearchResults[number]["type"]>,
) {
const plural = {
articles: 'ARTICLE',
collections: 'COLLECTION',
pages: 'PAGE',
products: 'PRODUCT',
queries: 'QUERY',
articles: "ARTICLE",
collections: "COLLECTION",
pages: "PAGE",
products: "PRODUCT",
queries: "QUERY",
};

if (typeof type === 'string') {
if (typeof type === "string") {
return plural[type];
}

return type.map((t) => plural[t]).join(',');
return type.map((t) => plural[t]).join(",");
}
90 changes: 40 additions & 50 deletions app/components/predictive-search/PredictiveSearchResults.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import {Link} from '@remix-run/react';
import {PredictiveSearchResult} from './PredictiveSearchResult';
import {usePredictiveSearch} from './usePredictiveSearch';
import { Link } from "@remix-run/react";
import { PredictiveSearchResult } from "./PredictiveSearchResult";
import { usePredictiveSearch } from "./usePredictiveSearch";

export function PredictiveSearchResults() {
const {results, totalResults, searchTerm, searchInputRef} =
const { results, totalResults, searchTerm, searchInputRef } =
usePredictiveSearch();

let queries = results?.find((result) => result.type === 'queries');
let articles = results?.find((result) => result.type === 'articles');
let products = results?.find((result) => result.type === 'products');
let queries = results?.find((result) => result.type === "queries");
let articles = results?.find((result) => result.type === "articles");
let products = results?.find((result) => result.type === "products");
function goToSearchResult(event: React.MouseEvent<HTMLAnchorElement>) {
let type = event.currentTarget.dataset.type;
if (!searchInputRef.current) return;
if (type === 'SearchQuerySuggestion') {
if (type === "SearchQuerySuggestion") {
searchInputRef.current.value = event.currentTarget.innerText;
// dispatch event onchange for the search
searchInputRef.current.focus();
} else {
searchInputRef.current.blur();
searchInputRef.current.value = '';
searchInputRef.current.value = "";
// close the aside
window.location.href = event.currentTarget.href;
}
Expand All @@ -35,49 +34,40 @@ export function PredictiveSearchResults() {
<div className="absolute left-1/2 top-20 z-10 flex w-fit -translate-x-1/2 items-center justify-center">
<div className="grid w-screen min-w-[430px] max-w-[720px] grid-cols-1 gap-6 border bg-white p-6 lg:grid-cols-[1fr_2fr] max-h-[80vh] overflow-y-auto">
<div className="space-y-8">
{queries && (
<div className="flex flex-col gap-4 divide-y divide-bar-subtle">
<PredictiveSearchResult
goToSearchResult={goToSearchResult}
items={queries.items}
key={queries.type}
searchTerm={searchTerm}
type={queries.type}
/>
</div>
)}
{articles && (
<div className="flex flex-col gap-4">
<PredictiveSearchResult
goToSearchResult={goToSearchResult}
items={articles.items}
key={articles.type}
searchTerm={searchTerm}
type={articles.type}
/>
</div>
)}
</div>
{products && (
<div>
<div className="flex flex-col gap-4 divide-y divide-bar-subtle">
<PredictiveSearchResult
goToSearchResult={goToSearchResult}
items={products.items}
key={products.type}
items={queries?.items}
searchTerm={searchTerm}
type={products.type}
type="queries"
/>
{/* view all results /search?q=term */}
{searchTerm.current && (
<Link
onClick={goToSearchResult}
to={`/search?q=${searchTerm.current}`}
>
<p className="mt-6 underline">View all products</p>
</Link>
)}
</div>
)}
<div className="flex flex-col gap-4">
<PredictiveSearchResult
goToSearchResult={goToSearchResult}
items={articles?.items}
searchTerm={searchTerm}
type="articles"
/>
</div>
</div>
<div>
<PredictiveSearchResult
goToSearchResult={goToSearchResult}
items={products?.items?.slice(0, 5)}
searchTerm={searchTerm}
type="products"
/>
{/* view all results /search?q=term */}
{searchTerm.current && (
<Link
onClick={goToSearchResult}
to={`/search?q=${searchTerm.current}`}
>
<p className="mt-6 underline">View all products</p>
</Link>
)}
</div>
</div>
</div>
);
Expand All @@ -92,8 +82,8 @@ function NoPredictiveSearchResults({
return null;
}
return (
<p className="w-[640px] border bg-background-subtle-1 p-6">
<p className="w-[640px] border bg-primary p-6">
No results found for <q>{searchTerm.current}</q>
</p>
);
}
}
19 changes: 12 additions & 7 deletions app/components/predictive-search/ResultItem.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import {Link} from '@remix-run/react';
import {Image, Money, Pagination} from '@shopify/hydrogen';
import {SearchResultItemProps} from './types';
import { Link } from "@remix-run/react";
import { Image, Money, Pagination } from "@shopify/hydrogen";
import { SearchResultItemProps } from "./types";

export function SearchResultItem({
goToSearchResult,
item,
}: SearchResultItemProps) {
return (
<li key={item.id}>
<Link className="flex gap-4" onClick={goToSearchResult} to={item.url} data-type={item.__typename}>
{item.__typename === 'Product' && (
<Link
className="flex gap-4"
onClick={goToSearchResult}
to={item.url}
data-type={item.__typename}
>
{item.__typename === "Product" && (
<div className="h-20 w-20 shrink-0">
{item.image?.url && (
<Image
alt={item.image.altText ?? ''}
alt={item.image.altText ?? ""}
src={item.image.url}
width={80}
height={80}
Expand All @@ -37,7 +42,7 @@ export function SearchResultItem({
) : (
<div
className={
item.__typename === 'Product' ? 'line-clamp-1' : 'line-clamp-2'
item.__typename === "Product" ? "line-clamp-1" : "line-clamp-2"
}
>
{item.title}
Expand Down
Loading

0 comments on commit 7a014d3

Please sign in to comment.