Skip to content

Commit

Permalink
feat: enhance UI components and add new features
Browse files Browse the repository at this point in the history
- Updated package.json to include new Radix UI components: dropdown menu and tooltip.
- Refactored layout.tsx to integrate Footer and improve structure.
- Added LoadingProductPage component for better user experience during product loading.
- Implemented NoProductsFound component for improved handling of empty search results.
- Introduced CategorySelector for better category filtering in product views.
- Enhanced Header component with an announcement banner for promotions.
- Added ButtonScrollTop for improved navigation.
- Updated various components for better styling and responsiveness.
  • Loading branch information
Lostovayne committed Dec 30, 2024
1 parent 4406578 commit 3d0f6c0
Show file tree
Hide file tree
Showing 25 changed files with 1,095 additions and 52 deletions.
2 changes: 1 addition & 1 deletion app/(store)/basket/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const BasketPage: FC = () => {
};

return (
<div className="container mx-auto p-4 max-w-6xl">
<div className="container mx-auto p-4 max-w-6xl mb-32 md:mb-48">
<h1 className="text-sm font-medium mb-4">
Envíos gratis por pedidos superiores a $800.00
</h1>
Expand Down
13 changes: 3 additions & 10 deletions app/(store)/categories/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,9 @@ const CategoryPage: FC<CategoryPageProps> = async ({
const categories = await getAllCategories();

return (
<div className="flex flex-col items-center justify-start min-h-screen bg-gray-100 p-4">
<div className=" bg-white p-8 rounded-lg shadow-md w-full ">
<div className="container mx-auto">
<h1 className="text-3xl font-bold mb-6 text-center">
Catálogo de{" "}
{slug
.split("-")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ")}{" "}
</h1>
<div className="flex flex-col items-center justify-start min-h-screen bg-gray-100">
<div className="w-full ">
<div className="container mt-24 mx-auto">
<ProductsView products={products} categories={categories} />
</div>
</div>
Expand Down
14 changes: 7 additions & 7 deletions app/(store)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import Header from "@/components/Header";
import { DisableDraftMode } from "@/components/DisableDraftMode";
import { Footer } from "@/components/Footer";
import { Header } from "@/components/header/Header";
import HeaderDiscount from "@/components/HeaderDiscount";
import { SanityLive } from "@/sanity/lib/live";
import { ClerkProvider } from "@clerk/nextjs";
import type { Metadata } from "next";
import "../globals.css";
import HeaderDiscount from "@/components/HeaderDiscount";
import SliderImages from "@/components/SliderImages";
import { draftMode } from "next/headers";
import { DisableDraftMode } from "@/components/DisableDraftMode";
import { VisualEditing } from "next-sanity";
import { draftMode } from "next/headers";
import "../globals.css";

export const metadata: Metadata = {
title: "Ropa online - Tienda de ropa para hombre y mujer",
Expand Down Expand Up @@ -74,9 +74,9 @@ export default async function RootLayout({
</>
)}
<main>
<HeaderDiscount />
<Header />
{children}
<Footer />
</main>
<SanityLive />
</body>
Expand Down
2 changes: 1 addition & 1 deletion app/(store)/product/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const ProductPage = async ({
const isOutOfStock = product.stock != null && product.stock <= 0;

return (
<div className="container mx-auto px-4 py-8 mt-6">
<div className="container mx-auto px-4 py-8 mt-6 mb-32 md:mb-44">
<div className="grid grid-cols-1 md:grid-cols-2 mx-auto max-w-7xl gap-8">
<div
className={`relative h-[680px] max-w-xl overflow-hidden rounded-lg ${isOutOfStock ? "opacity-50" : ""}`}
Expand Down
33 changes: 33 additions & 0 deletions app/(store)/product/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Skeleton } from "@/components/ui/skeleton";

const LoadingProductPage = () => {
return (
<div className="container mx-auto px-4 py-8 mt-6 mb-32 md:mb-44">
<div className="grid grid-cols-1 md:grid-cols-2 mx-auto max-w-7xl gap-8">
<div className="relative h-[680px] max-w-xl overflow-hidden rounded-lg">
<Skeleton className="h-full w-full" />
</div>
<div className="flex flex-col justify-between">
<div>
<h1 className="text-3xl font-bold mb-4">
<Skeleton className="h-8 w-3/4" />
</h1>
<div className="text-2xl font-semibold mb-4">
<Skeleton className="h-6 w-1/3" />
</div>
<div className="prose max-w-none mb-6">
<Skeleton className="h-4 w-full mb-2" />
<Skeleton className="h-4 w-5/6 mb-2" />
<Skeleton className="h-4 w-4/6 mb-2" />
</div>
</div>
<div className="mt-6">
<Skeleton className="h-10 w-1/2" />
</div>
</div>
</div>
</div>
);
};

export default LoadingProductPage;
15 changes: 3 additions & 12 deletions app/(store)/search/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import NoProductsFound from "@/components/NoProductsFound";
import ProductGrid from "@/components/ProductGrid";
import { searchProductsByName } from "@/sanity/lib/products/searchProductsByName";
import type React from "react";
import type { FC } from "react";

interface SearchParams {
Expand All @@ -15,18 +17,7 @@ const SearchPage: FC<SearchParams> = async ({
const products = await searchProductsByName(query);

if (!products.length) {
return (
<div className="flex flex-col items-center justify-start min-h-screen bg-gray-100 p-4">
<div className="bg-white p-8 rounded-lg shadow-md w-full max-w-4xl">
<h1 className="text-3xl font-semibold text-gray-800 mb-6 text-center">
No products for {query}
</h1>
<p className="text-gray-600 text-center">
Try searching with a different keywords
</p>
</div>
</div>
);
return <NoProductsFound />;
}

return (
Expand Down
Binary file modified bun.lockb
Binary file not shown.
37 changes: 37 additions & 0 deletions components/ButtonScrollTop.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use client";
import { cn } from "@/lib/utils";
import { ArrowUp } from "lucide-react";
import { ReactElement, useEffect, useState } from "react";

const ButtonScrollTop = ({}): ReactElement => {
const [isTop, setIsTop] = useState(false);

useEffect(() => {
window.addEventListener("scroll", () => {
if (window.scrollY > 20) {
setIsTop(true);
} else {
setIsTop(false);
}
});
}, []);

const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: "smooth" });
};

return (
<button
onClick={scrollToTop}
className={cn(
" hidden fixed bottom-8 right-8 bg-white text-black p-3 rounded-full shadow-lg hover:bg-zinc-200 transition-colors",
isTop && "block",
)}
aria-label="Volver arriba"
>
<ArrowUp className="w-6 h-6" />
</button>
);
};

export default ButtonScrollTop;
82 changes: 82 additions & 0 deletions components/CategorySelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"use client";

import { ChevronDown } from "lucide-react";
import { cn } from "@/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import type { Category } from "@/sanity.types";
import { useParams, useRouter } from "next/navigation";
import React, { useState } from "react";

interface CategorySelectorProps {
categories: Category[];
}

export function CategoryFilter({ categories }: CategorySelectorProps) {
const slug = useParams().slug;
const router = useRouter();
const initialValue = categories.find(
(category) => category.slug?.current === slug,
);
const [selectedCategory, setSelectedCategory] = useState<
Category | undefined
>(initialValue);

const [isOpen, setIsOpen] = React.useState(false);
return (
<DropdownMenu open={isOpen} onOpenChange={setIsOpen}>
<DropdownMenuTrigger asChild>
<button
className={cn(
"group flex items-center gap-3 px-5 py-2.5 rounded-lg text-sm font-medium transition-all duration-200",
"bg-black text-white hover:bg-zinc-800",
"border border-zinc-800 hover:border-zinc-700",
"focus:outline-none focus:ring-2 focus:ring-zinc-500 focus:ring-offset-2",
isOpen && "bg-zinc-800 border-zinc-700",
)}
>
{selectedCategory !== undefined && <span>Filtrar por:</span>}
<div className="flex items-center gap-2">
<span className="text-white group-hover:text-white transition-colors">
{selectedCategory?.title || "Todas las categorías"}
</span>
<ChevronDown
className={cn(
"w-4 h-4 text-zinc-400 group-hover:text-white transition-all duration-200",
isOpen && "transform rotate-180",
)}
/>
</div>
</button>
</DropdownMenuTrigger>
<DropdownMenuContent
className="w-64 max-h-[400px] overflow-auto rounded-lg border border-zinc-200 bg-white p-1 shadow-lg"
align="start"
>
{categories.map((category) => (
<DropdownMenuItem
key={category._id}
className={cn(
"text-sm cursor-pointer rounded-md transition-colors px-3 py-2",
"text-zinc-600 hover:text-black hover:bg-zinc-100",
"focus:text-black focus:bg-zinc-100 focus:outline-none",
selectedCategory?._id === category._id &&
"bg-zinc-100 text-black font-medium",
)}
onClick={() => {
setSelectedCategory(category);
setIsOpen(false);
router.push(`/categories/${category.slug?.current}`);
}}
>
{category.title}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
);
}
Loading

0 comments on commit 3d0f6c0

Please sign in to comment.