summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/category/components/Breadcrumb.jsx221
1 files changed, 161 insertions, 60 deletions
diff --git a/src/lib/category/components/Breadcrumb.jsx b/src/lib/category/components/Breadcrumb.jsx
index e691e379..50557c3e 100644
--- a/src/lib/category/components/Breadcrumb.jsx
+++ b/src/lib/category/components/Breadcrumb.jsx
@@ -9,6 +9,7 @@ import {
import Link from 'next/link';
import React from 'react';
import { useQuery } from 'react-query';
+import useDevice from '@/core/hooks/useDevice';
const Breadcrumb = ({ categoryId }) => {
const breadcrumbs = useQuery(
@@ -16,72 +17,172 @@ const Breadcrumb = ({ categoryId }) => {
async () =>
await odooApi('GET', `/api/v1/category/${categoryId}/category-breadcrumb`)
);
+ const { isDesktop, isMobile } = useDevice();
const items = breadcrumbs.data ?? [];
const lastIdx = items.length - 1;
- return (
- <div className='container mx-auto py-4 md:py-6'>
- <Skeleton isLoaded={!breadcrumbs.isLoading} className='w-2/3'>
- <ChakraBreadcrumb
- spacing='8px'
- sx={{
- // mobile boleh wrap; desktop tetap 1 baris
- '& ol': {
- display: 'flex',
- flexWrap: { base: 'wrap', md: 'nowrap' },
- alignItems: 'center',
- },
- '& li': { display: 'inline-flex', alignItems: 'center' },
- // semua item sebelum terakhir: jangan pernah wrap (tetap di baris atas)
- '& li:not(:last-of-type)': {
- flex: '0 0 auto',
- whiteSpace: 'nowrap',
- },
- // item terakhir: boleh ambil sisa lebar & wrap jika perlu
- '& li:last-of-type': {
- flex: '1 1 auto',
- minWidth: 0,
- },
- }}
- >
- {/* Home */}
- <BreadcrumbItem>
- <BreadcrumbLink as={Link} href='/' className='!text-danger-500'>
- Home
- </BreadcrumbLink>
- </BreadcrumbItem>
+ if (isDesktop) {
+ return (
+ <div className='container mx-auto py-4 md:py-6'>
+ <Skeleton isLoaded={!breadcrumbs.isLoading} className='w-2/3'>
+ <ChakraBreadcrumb
+ spacing='8px'
+ sx={{
+ '& ol': {
+ display: 'flex',
+ flexWrap: { base: 'wrap', md: 'nowrap' },
+ alignItems: 'center',
+ },
+ '& li': { display: 'inline-flex', alignItems: 'center' },
+ '& li:not(:last-of-type)': {
+ flex: '0 0 auto',
+ whiteSpace: 'nowrap',
+ },
+ '& li:last-of-type': {
+ flex: '1 1 auto',
+ minWidth: 0,
+ },
+ }}
+ >
+ {/* Home */}
+ <BreadcrumbItem>
+ <BreadcrumbLink as={Link} href='/' className='!text-danger-500'>
+ Home
+ </BreadcrumbLink>
+ </BreadcrumbItem>
- {/* Categories */}
- {items.map((category, index) => {
- const isLast = index === lastIdx;
- return (
- <BreadcrumbItem key={index} isCurrentPage={isLast}>
- {isLast ? (
- // HANYA yang terakhir boleh turun/wrap di mobile
- <BreadcrumbLink className='block whitespace-normal break-words md:whitespace-nowrap'>
- {category.name}
- </BreadcrumbLink>
- ) : (
- <BreadcrumbLink
- as={Link}
- href={createSlug(
- '/shop/category/',
- category.name,
- category.id
- )}
- className='!text-danger-500'
- >
- {category.name}
- </BreadcrumbLink>
- )}
+ {/* Categories */}
+ {items.map((category, index) => {
+ const isLast = index === lastIdx;
+ return (
+ <BreadcrumbItem key={index} isCurrentPage={isLast}>
+ {isLast ? (
+ <BreadcrumbLink className='block whitespace-normal break-words md:whitespace-nowrap'>
+ {category.name}
+ </BreadcrumbLink>
+ ) : (
+ <BreadcrumbLink
+ as={Link}
+ href={createSlug(
+ '/shop/category/',
+ category.name,
+ category.id
+ )}
+ className='!text-danger-500'
+ >
+ {category.name}
+ </BreadcrumbLink>
+ )}
+ </BreadcrumbItem>
+ );
+ })}
+ </ChakraBreadcrumb>
+ </Skeleton>
+ </div>
+ );
+ }
+
+ if (isMobile) {
+ const items = breadcrumbs.data ?? [];
+ const n = items.length;
+ const lastCat = n >= 1 ? items[n - 1] : null; // terakhir (current)
+ const secondLast = n >= 2 ? items[n - 2] : null; // sebelum current
+ const beforeSecond = n >= 3 ? items[n - 3] : null; // sebelum secondLast
+ const hiddenText =
+ n >= 3
+ ? items
+ .slice(0, n - 2)
+ .map((c) => c.name)
+ .join(' / ')
+ : '';
+
+ return (
+ <div className='container mx-auto py-2 mt-2'>
+ <Skeleton isLoaded={!breadcrumbs.isLoading} className='w-full'>
+ <ChakraBreadcrumb
+ separator={<span className='mx-1'>/</span>} // lebih rapat
+ spacing='4px'
+ sx={{
+ '& ol': {
+ display: 'flex',
+ alignItems: 'center',
+ overflow: 'hidden', // untuk ellipsis
+ whiteSpace: 'nowrap', // untuk ellipsis
+ gap: '0', // no extra gap
+ },
+ '& li': { display: 'inline-flex', alignItems: 'center' },
+ '& li:not(:last-of-type)': {
+ flex: '0 0 auto',
+ whiteSpace: 'nowrap',
+ },
+ '& li:last-of-type': {
+ flex: '0 1 auto', // jangan ambil full space biar gak keliatan “space kosong”
+ minWidth: 0,
+ },
+ }}
+ className='text-caption-2 p-0'
+ >
+ {/* Home */}
+ <BreadcrumbItem>
+ <BreadcrumbLink as={Link} href='/' className='!text-danger-500'>
+ Home
+ </BreadcrumbLink>
+ </BreadcrumbItem>
+
+ {/* Jika ada kategori sebelum secondLast, tampilkan '..' (link ke beforeSecond) */}
+ {beforeSecond && (
+ <BreadcrumbItem>
+ <BreadcrumbLink
+ as={Link}
+ href={createSlug(
+ '/shop/category/',
+ beforeSecond.name,
+ beforeSecond.id
+ )}
+ title={hiddenText}
+ aria-label={`Kembali ke ${beforeSecond.name}`}
+ className='!text-danger-500'
+ >
+ ..
+ </BreadcrumbLink>
</BreadcrumbItem>
- );
- })}
- </ChakraBreadcrumb>
- </Skeleton>
- </div>
- );
+ )}
+
+ {/* secondLast sebagai link (kalau ada) */}
+ {secondLast && (
+ <BreadcrumbItem>
+ <BreadcrumbLink
+ as={Link}
+ href={createSlug(
+ '/shop/category/',
+ secondLast.name,
+ secondLast.id
+ )}
+ className='!text-danger-500'
+ >
+ {secondLast.name}
+ </BreadcrumbLink>
+ </BreadcrumbItem>
+ )}
+
+ {/* lastCat (current) dengan truncate & lebar dibatasi */}
+ {lastCat && (
+ <BreadcrumbItem isCurrentPage>
+ <span
+ className='inline-block truncate align-bottom'
+ style={{ maxWidth: '60vw' }} // batasi lebar supaya gak “makan” baris & keliatan space kosong
+ title={lastCat.name}
+ >
+ {lastCat.name}
+ </span>
+ </BreadcrumbItem>
+ )}
+ </ChakraBreadcrumb>
+ </Skeleton>
+ </div>
+ );
+ }
};
export default Breadcrumb;