update menu navigation

This commit is contained in:
Husni Ailatat 2025-12-06 11:41:41 +07:00
parent 62bc47672f
commit 3af6e2b531
6 changed files with 115 additions and 18 deletions

View File

@ -10,6 +10,8 @@
}, },
"dependencies": { "dependencies": {
"@ant-design/cssinjs": "^2.0.1", "@ant-design/cssinjs": "^2.0.1",
"@hugeicons/core-free-icons": "^2.0.0",
"@hugeicons/react": "^1.1.1",
"antd": "^6.0.1", "antd": "^6.0.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"embla-carousel": "^8.6.0", "embla-carousel": "^8.6.0",

20
pnpm-lock.yaml generated
View File

@ -11,6 +11,12 @@ importers:
'@ant-design/cssinjs': '@ant-design/cssinjs':
specifier: ^2.0.1 specifier: ^2.0.1
version: 2.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) version: 2.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@hugeicons/core-free-icons':
specifier: ^2.0.0
version: 2.0.0
'@hugeicons/react':
specifier: ^1.1.1
version: 1.1.1(react@19.2.0)
antd: antd:
specifier: ^6.0.1 specifier: ^6.0.1
version: 6.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) version: 6.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@ -243,6 +249,14 @@ packages:
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@hugeicons/core-free-icons@2.0.0':
resolution: {integrity: sha512-OSfv5k0iB0yG61dcfK7jcf00AIK8EXyQOgtcNJzSBFvm88n9VOelkxihZHJnNwDUFpO/jZI3vZSVp6i1dmRvJQ==}
'@hugeicons/react@1.1.1':
resolution: {integrity: sha512-BAbFVtx0XZ/yF2poPLFn0N9Ji6ebV/MpI5+WRqooFp3smQDwpL+72m+BBs4KAM5djgWUpg12weyc5SJtTsOwsw==}
peerDependencies:
react: '>=16.0.0'
'@humanfs/core@0.19.1': '@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'} engines: {node: '>=18.18.0'}
@ -2598,6 +2612,12 @@ snapshots:
'@eslint/core': 0.17.0 '@eslint/core': 0.17.0
levn: 0.4.1 levn: 0.4.1
'@hugeicons/core-free-icons@2.0.0': {}
'@hugeicons/react@1.1.1(react@19.2.0)':
dependencies:
react: 19.2.0
'@humanfs/core@0.19.1': {} '@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.7': '@humanfs/node@0.16.7':

View File

@ -1,21 +1,27 @@
import Box from "@/Components/Atoms/Box"; import Box from "@/Components/Atoms/Box";
import { useBreakpoints } from "@/Contexts/BreakPointContext"; import { useBreakpoints } from "@/Contexts/BreakPointContext";
import useClient from "@/Hooks/useClient"; import useClient from "@/Hooks/useClient";
import { HugeiconsIcon } from "@hugeicons/react";
import { Button, Radio, Space } from "antd"; import { Button, Radio, Space } from "antd";
import { Calendar, Compass, Map, MapPin, Menu, Store } from "lucide-react"; import { Calendar, Compass, Map, MapPin, Menu, Store } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { PropsWithChildren, useState } from "react"; import { PropsWithChildren, useState } from "react";
import { DiscoverSquareIcon, Home07Icon, UserSquareIcon } from '@hugeicons/core-free-icons'
import { usePathname } from "next/navigation";
import { cn } from "@/Functions/cn";
const PublicLayout: React.FC<PropsWithChildren> = ({ children }) => { const PublicLayout: React.FC<PropsWithChildren> = ({ children }) => {
const { isDesktop } = useBreakpoints(); const { isDesktop } = useBreakpoints();
const isClient = useClient(); const isClient = useClient();
const pathname = usePathname()
const [position, setPosition] = useState<'ID' | 'EN'>('ID'); const [position, setPosition] = useState<'ID' | 'EN'>('ID');
if (!isClient) return; if (!isClient) return;
return ( return (
<Box className="min-h-screen bg-gray-50"> <Box className="min-h-screen bg-gray-50 relative">
<nav className="bg-white shadow-sm sticky top-0 z-50"> <nav className="bg-white shadow-sm sticky top-0 z-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16"> <div className="flex justify-between items-center h-16">
@ -26,12 +32,16 @@ const PublicLayout: React.FC<PropsWithChildren> = ({ children }) => {
{/* Desktop Menu */} {/* Desktop Menu */}
<div className="items-center gap-6 flex"> <div className="items-center gap-6 flex">
<div className="hidden md:flex items-center gap-12"> <div className="hidden md:flex items-center gap-12">
<Link href="/" className="flex items-center text-gray-700 hover:text-primary transition"> <Link href="/" className={cn(
<Store className="size-6 mr-2" /> "flex items-center text-gray-700 hover:text-primary transition",
<span className="font-semibold">Product</span> pathname === "/" && "text-primary"
)}>
<span className="font-semibold">Home</span>
</Link> </Link>
<Link href="/explore" className="flex items-center text-gray-700 hover:text-primary transition"> <Link href="/explore" className={cn(
<Compass className="size-6 mr-2" /> "flex items-center text-gray-700 hover:text-primary transition",
pathname === "/explore" && "text-primary"
)}>
<span className="font-semibold">Explore</span> <span className="font-semibold">Explore</span>
</Link> </Link>
</div> </div>
@ -58,6 +68,31 @@ const PublicLayout: React.FC<PropsWithChildren> = ({ children }) => {
<div> <div>
{children} {children}
</div> </div>
<div className="md:hidden fixed bottom-0 left-0 right-0 bg-white shadow-md">
<div className="flex items-center justify-around py-2">
<Link href="/" className={cn(
"flex flex-col items-center gap-1 text-black text-sm",
pathname === "/" && "text-primary"
)}>
<HugeiconsIcon icon={Home07Icon} className="size-7" />
<span>Home</span>
</Link>
<Link href="/explore" className={cn(
"flex flex-col items-center gap-1 text-black text-sm",
pathname === "/explore" && "text-primary"
)}>
<HugeiconsIcon icon={DiscoverSquareIcon} className="size-7" />
<span>Explore</span>
</Link>
<Link href="/login" className={cn(
"flex flex-col items-center gap-1 text-black text-sm",
pathname === "/login" && "text-primary"
)}>
<HugeiconsIcon icon={UserSquareIcon} className="size-7" />
<span>Account</span>
</Link>
</div>
</div>
</Box> </Box>
) )
} }

View File

@ -1 +1 @@
export const publicRoutes = ['/', '/login', 'register']; export const publicRoutes = ['/', '/explore', '/login', 'register'];

View File

@ -1,5 +1,5 @@
import { Fragment, useRef, useState } from 'react'; import { Fragment, useMemo, useRef, useState } from 'react';
import { Button } from 'antd'; import { Button } from 'antd';
import { ChevronLeft, ChevronRight } from 'lucide-react'; import { ChevronLeft, ChevronRight } from 'lucide-react';
import useClient from '@/Hooks/useClient'; import useClient from '@/Hooks/useClient';
@ -7,10 +7,15 @@ import Slider from "react-slick";
import "slick-carousel/slick/slick.css"; import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css"; import "slick-carousel/slick/slick-theme.css";
import { useBreakpoints } from '@/Contexts/BreakPointContext';
export default function HomeBanner() { export default function HomeBanner() {
const isClient = useClient(); const isClient = useClient();
const { isMobile, isTablet, isDesktop } = useBreakpoints()
console.log({isMobile, isTablet, isDesktop});
const [activeIndex, setActiveIndex] = useState<number>(0); const [activeIndex, setActiveIndex] = useState<number>(0);
const sliderRef = useRef<Slider | null>(null); const sliderRef = useRef<Slider | null>(null);
@ -36,41 +41,76 @@ export default function HomeBanner() {
<div className='flex flex-col relative mt-5'> <div className='flex flex-col relative mt-5'>
<Slider <Slider
ref={sliderRef} ref={sliderRef}
className='center' // className='center'
centerMode centerMode
infinite infinite
beforeChange={(current, next) => setActiveIndex(next)} beforeChange={(current, next) => setActiveIndex(next)}
slidesToShow={3} slidesToShow={isMobile ? 1 : 3}
slidesToScroll={1} slidesToScroll={1}
arrows={false}
speed={500} speed={500}
responsive={[
{
breakpoint: 1024,
settings: {
slidesToShow: 2,
slidesToScroll: 1,
centerMode: true
}
},
{
breakpoint: 600,
settings: {
slidesToShow: 2,
slidesToScroll: 2,
centerMode: true
}
},
{
breakpoint: 480,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
centerMode: true
}
},
{
breakpoint: 300,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
centerMode: true
}
}
]}
> >
{banners.map((item, index) => ( {banners.map((item, index) => (
<Fragment key={index}> <Fragment key={index}>
<div className='mx-3'> <div className='mx-3'>
<img <img
src={item} src={item}
className='w-full md:h-[300px] h-[200px] object-cover rounded-2xl' className='w-full xl:h-[300px] lg:h-[200px] h-[150px] object-cover rounded-2xl'
/> />
</div> </div>
</Fragment> </Fragment>
))} ))}
</Slider> </Slider>
<div className="flex justify-center items-center gap-2 mt-6"> <div className="flex justify-center items-center gap-2 mt-2">
<Button variant='text' type='text' onClick={onPrevious}> <Button variant='text' type='text' onClick={onPrevious}>
<ChevronLeft/> <ChevronLeft />
</Button> </Button>
{banners.map((_, index) => ( {banners.map((_, index) => (
<button <button
key={index} key={index}
className={`transition-all duration-300 rounded-full ${index === activeIndex className={`transition-all duration-300 rounded-full ${index === activeIndex
? 'bg-primary w-8 h-3' ? 'bg-primary w-8 h-3'
: 'bg-gray-300 hover:bg-gray-400 w-3 h-3' : 'bg-gray-300 hover:bg-gray-400 w-3 h-3'
}`} }`}
aria-label={`Go to slide ${index + 1}`} aria-label={`Go to slide ${index + 1}`}
/> />
))} ))}
<Button variant='text' type='text' onClick={onNext}> <Button variant='text' type='text' onClick={onNext}>
<ChevronRight/> <ChevronRight />
</Button> </Button>
</div> </div>
</div> </div>

View File

@ -30,6 +30,6 @@
body { body {
background: var(--background); background: var(--background);
color: var(--foreground); color: #0a0a0a;
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;
} }