Skip to content

Commit

Permalink
feat: ui changes
Browse files Browse the repository at this point in the history
  • Loading branch information
kasin-it committed Oct 22, 2024
1 parent ce07a9e commit 1fbc230
Show file tree
Hide file tree
Showing 52 changed files with 540 additions and 491 deletions.
57 changes: 35 additions & 22 deletions starters/shopify-meilisearch/app/home/[bucket]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,57 @@
import { Suspense } from "react"
import { BUCKETS } from "constants/index"
import { BestOffersSection } from "views/homepage/best-offers-skeleton"
import { CarouselSectionSkeleton } from "views/homepage/carousel-section"
import { CategoriesSection, CategoriesSectionSkeleton } from "views/homepage/categories-section"
import { EverythingUnderSection } from "views/homepage/everything-under-section"
import { AnnouncementBar } from "components/announcement-bar"
import { HeroSection } from "views/homepage/hero-section"
import { meilisearch } from "clients/search"
import { CommerceProduct } from "types"
import { env } from "env.mjs"
import type { Hits } from "meilisearch"
import { CategoriesSection } from "views/homepage/categories-section"
import { FeaturedProductsSection } from "views/homepage/featured-products-section"
import { PlatformCollection } from "lib/shopify/types"

export const revalidate = 86400

export const dynamic = "force-static"

export const dynamicParams = true

export default function Homepage({ params: { bucket } }: { params: { bucket: string } }) {
export default async function Homepage({ params: { bucket } }: { params: { bucket: string } }) {
const heroTitles = {
a: "Your daily trendsetting deals",
b: "Spring into Savings! Up to 60% Off",
a: "Discover Your Next Favorite Thing",
b: "Shop the best Deals on Top Brands & Unique Finds",
}

const { products, categories } = await fetchFeaturedData()

return (
<div className="flex w-full flex-col">
<HeroSection className="-order-1 md:-order-2" title={heroTitles[bucket as keyof typeof heroTitles]} />
<AnnouncementBar className="-order-2 md:-order-1" />

<Suspense fallback={<CategoriesSectionSkeleton />}>
<CategoriesSection />
</Suspense>

<Suspense fallback={<CarouselSectionSkeleton />}>
<BestOffersSection />
</Suspense>

<Suspense fallback={<CarouselSectionSkeleton />}>
<EverythingUnderSection />
</Suspense>
<AnnouncementBar className="-order-2" />
<HeroSection className="-order-1 self-center md:-order-2" title={heroTitles[bucket]} />
<FeaturedProductsSection products={products} />
<CategoriesSection categories={categories} />
</div>
)
}

export async function generateStaticParams() {
return BUCKETS.HOME.map((bucket) => ({ bucket }))
}

const fetchFeaturedData = async () => {
const results = await meilisearch?.multiSearch({
queries: [
{
indexUid: env.MEILISEARCH_FEATURED_PRODUCTS_INDEX,
q: "",
limit: 6,
attributesToRetrieve: ["id", "title", "featuredImage", "minPrice", "variants", "avgRating", "totalReviews", "vendor", "handle"],
},
{ indexUid: env.MEILISEARCH_CATEGORIES_INDEX, q: "", limit: 4, attributesToRetrieve: ["id", "title", "handle"] },
],
})

return {
products: results[0].hits as Hits<CommerceProduct>,
categories: results[1].hits as Hits<PlatformCollection>,
}
}
2 changes: 0 additions & 2 deletions starters/shopify-meilisearch/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { CartView } from "views/cart/cart-view"
import type { NavItem } from "components/navigation-bar/types"
import { NavigationBar } from "components/navigation-bar/navigation-bar"
import { mobileInlineScript } from "components/navigation-bar/mobile-inline-script"
import { CallToAction } from "components/call-to-action"
import { Footer } from "components/footer"
import { Modals } from "components/modals/modals"

Expand Down Expand Up @@ -245,7 +244,6 @@ export default async function RootLayout({ children }: { children: React.ReactNo

{children}

<CallToAction />
<Footer />
<Modals />

Expand Down
8 changes: 5 additions & 3 deletions starters/shopify-meilisearch/app/product/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,13 @@ export default async function Product({ params: { slug } }: ProductProps) {
return (
<div className="relative mx-auto max-w-container-md px-4 xl:px-0">
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(generateJsonLd(product, slug)) }}></script>
<div className="mb:pb-8 relative w-fit py-4 md:pt-12">
<BackButton className="mb-8 hidden md:block" />
<div className="mb:pb-8 relative flex w-full items-center justify-center gap-10 py-4 md:pt-12">
<BackButton className="left-2 mb-8 hidden md:block xl:absolute" />
<div className="mx-auto w-full max-w-container-sm">
<Breadcrumbs className="mb-8" items={makeBreadcrumbs(product)} />
</div>
</div>
<main className="mx-auto max-w-container-sm">
<Breadcrumbs className="mb-8" items={makeBreadcrumbs(product)} />
<div className="grid grid-cols-1 gap-4 md:mx-auto md:max-w-screen-xl md:grid-cols-12 md:gap-8">
<ProductTitle
className="md:hidden"
Expand Down
4 changes: 2 additions & 2 deletions starters/shopify-meilisearch/components/breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ export function Breadcrumbs({ items, className }: BreadcrumbsProps) {
<BreadcrumbLink
prefetch={false}
aria-current={isLast ? "page" : undefined}
className={cn("text-neutral-500 hover:underline", isLast && "font-medium underline")}
className={cn("text-sm text-neutral-500 hover:underline", isLast && "font-medium underline")}
href={href}
>
{title}
</BreadcrumbLink>
</BreadcrumbItem>
{!isLast && <BreadcrumbSeparator />}
{!isLast && <BreadcrumbSeparator className="text-transparent [&>svg]:size-2 [&>svg]:fill-black" />}
</React.Fragment>
)
})}
Expand Down
32 changes: 0 additions & 32 deletions starters/shopify-meilisearch/components/call-to-action.tsx

This file was deleted.

32 changes: 32 additions & 0 deletions starters/shopify-meilisearch/components/category-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { PlatformCollection } from "lib/shopify/types"
import Image from "next/image"
import Link from "next/link"
import { cn } from "utils/cn"

interface CategoryCardProps extends Pick<PlatformCollection, "title" | "image" | "handle"> {
index: number
className?: string
}

export const CategoryCard = ({ handle, image, title, index, className }: CategoryCardProps) => {
const href = `/category/${handle}`
return (
<Link href={href} className={cn("group relative overflow-hidden rounded-lg transition-all hover:shadow-md", className)} prefetch={false}>
<div className="relative aspect-video">
<Image
src={image?.url || `/category-placeholder-${index}.png`}
alt={image?.altText || `${title} category`}
className="transition-transform group-hover:scale-105"
style={{
objectFit: "contain",
}}
fill
/>
<div className="absolute left-0 top-0 z-10 size-full bg-gradient-to-b from-white/90 to-60%" />
</div>
<div className="absolute inset-x-4 top-0 z-20">
<h3 className="ml-3 mt-5 text-xl font-semibold text-black group-hover:text-orange-500">{title}</h3>
</div>
</Link>
)
}
79 changes: 79 additions & 0 deletions starters/shopify-meilisearch/components/compact-product-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import Image from "next/image"
import Link from "next/link"
import { cn } from "utils/cn"
import { type CurrencyType, mapCurrencyToSign } from "utils/map-currency-to-sign"
import type { CommerceProduct } from "types"
import { StarIcon } from "components/icons/star-icon"

interface ProductCardProps extends Pick<CommerceProduct, "variants" | "handle" | "images" | "title" | "featuredImage" | "minPrice" | "avgRating" | "totalReviews" | "vendor"> {
priority?: boolean
prefetch?: boolean
className?: string
}

export const CompactProductCard = ({
variants,
handle,
title,
featuredImage,
minPrice,
avgRating,
totalReviews,
className,
priority,
vendor,
prefetch = false,
}: ProductCardProps) => {
const noOfVariants = variants?.length
const href = `/product/${handle}`
const linkAria = `Visit product: ${title}`
const variantPrice = variants?.find(Boolean)?.price

return (
<Link
className={cn("group relative flex flex-col overflow-hidden rounded-lg border border-gray-100 transition-all", className)}
aria-label={linkAria}
href={href}
prefetch={prefetch}
>
<div className="relative aspect-square overflow-hidden">
<Image
priority={priority}
className="object-cover transition-transform group-hover:scale-105"
src={featuredImage?.url || "/default-product-image.svg"}
alt={featuredImage?.altText || title}
fill
/>
</div>
<div className="absolute bottom-0 flex w-full shrink-0 grow translate-y-full flex-col overflow-hidden bg-gradient-to-t from-gray-100 to-transparent p-4 transition-transform group-hover:translate-y-0">
{/* remove first word from the title as it includes vendor (this just needs feed update and then can be removed) */}
<h3 className="line-clamp-2 text-lg font-semibold">{title.split(" ").slice(1).join(" ")}</h3>
<div className="mt-auto flex flex-col gap-1">
{!!variantPrice && <span>From {mapCurrencyToSign((variantPrice.currencyCode as CurrencyType) || "USD") + minPrice.toFixed(2)}</span>}

{!!vendor && <p className="text-sm text-gray-500">{vendor}</p>}

<div className="flex items-center gap-1">
{!!avgRating && !!totalReviews && (
<>
<div className="flex items-center space-x-1">
<StarIcon className="size-4 fill-gray-400 stroke-gray-500" />
<span className="text-sm">{avgRating.toFixed(2)}</span>
<span className="text-xs">
({totalReviews} review{totalReviews !== 1 && "s"})
</span>
</div>
</>
)}
{noOfVariants > 0 && (
<p className="text-sm text-gray-500">
{noOfVariants} variant{noOfVariants > 1 ? "s" : ""}
</p>
)}
</div>
</div>
</div>
</Link>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const ExpandableContent = ({ children, className, lines = 2 }: Expandable
{children}
</div>
{isClamped && (
<button className={cn("flex items-center gap-1 bg-transparent text-sm underline")} onClick={() => setIsExpanded((prev) => !prev)}>
<button className={cn("mx-auto flex items-center gap-1 bg-transparent text-sm underline")} onClick={() => setIsExpanded((prev) => !prev)}>
{isExpanded ? "Read less" : "Read more"}
<ChevronIcon className={isExpanded ? "rotate-180" : "rotate-0"} />
</button>
Expand Down
76 changes: 76 additions & 0 deletions starters/shopify-meilisearch/components/featured-product-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import Image from "next/image"
import Link from "next/link"
import { cn } from "utils/cn"
import { type CurrencyType, mapCurrencyToSign } from "utils/map-currency-to-sign"
import type { CommerceProduct } from "types"
import { StarIcon } from "components/icons/star-icon"

interface ProductCardProps extends Pick<CommerceProduct, "variants" | "handle" | "images" | "title" | "featuredImage" | "minPrice" | "avgRating" | "totalReviews" | "vendor"> {
priority?: boolean
prefetch?: boolean
className?: string
}

export const FeaturedProductCard = ({
variants,
handle,
title,
featuredImage,
minPrice,
avgRating,
totalReviews,
className,
priority,
vendor,
prefetch = false,
}: ProductCardProps) => {
const noOfVariants = variants?.length
const href = `/product/${handle}`
const linkAria = `Visit product: ${title}`
const variantPrice = variants?.find(Boolean)?.price

return (
<Link className={cn("group flex flex-col overflow-hidden rounded-lg border border-gray-100 transition-all", className)} aria-label={linkAria} href={href} prefetch={prefetch}>
<div className="relative aspect-square overflow-hidden">
<Image
priority={priority}
className="object-cover transition-transform group-hover:scale-105"
src={featuredImage?.url || "/default-product-image.svg"}
alt={featuredImage?.altText || title}
fill
/>
</div>
<div className="flex shrink-0 grow items-start justify-between p-4 transition-colors group-hover:bg-gradient-to-t group-hover:from-gray-100 group-hover:to-transparent">
<div className="flex flex-col gap-1">
{/* remove first word from the title as it includes vendor (this just needs feed update and then can be removed) */}
<h3 className="line-clamp-2 text-lg font-semibold">{title.split(" ").slice(1).join(" ")}</h3>
{!!variantPrice && <span className="block sm:hidden">From {mapCurrencyToSign((variantPrice.currencyCode as CurrencyType) || "USD") + minPrice.toFixed(2)}</span>}

<div className="mt-auto flex flex-col gap-1">
{!!vendor && <p className="text-sm text-gray-500">{vendor}</p>}
<div className="flex items-center gap-1">
{!!avgRating && !!totalReviews && (
<>
<div className="flex items-center space-x-1">
<StarIcon className="size-4 fill-gray-400 stroke-gray-500" />
<span className="text-sm">{avgRating.toFixed(2)}</span>
<span className="text-xs">
({totalReviews} review{totalReviews !== 1 && "s"})
</span>
</div>
</>
)}
{noOfVariants > 0 && (
<p className="text-sm text-gray-500">
{noOfVariants} variant{noOfVariants > 1 ? "s" : ""}
</p>
)}
</div>
</div>
</div>
{!!variantPrice && <span className="hidden sm:block">From {mapCurrencyToSign((variantPrice.currencyCode as CurrencyType) || "USD") + minPrice.toFixed(2)}</span>}
</div>
</Link>
)
}
Loading

0 comments on commit 1fbc230

Please sign in to comment.