diff options
| author | Miqdad <ahmadmiqdad27@gmail.com> | 2025-10-08 11:56:00 +0700 |
|---|---|---|
| committer | Miqdad <ahmadmiqdad27@gmail.com> | 2025-10-08 11:56:00 +0700 |
| commit | fdf788bd65061e7003cbdef1f934a72f4382f346 (patch) | |
| tree | bffc59cae9c6f375c4dd86c8a2bb9c1fe64da4d5 | |
| parent | d70ac2945e8755cbb63c60ad260d442e8f71ca74 (diff) | |
<Miqdad> Fix breadcrumb
| -rw-r--r-- | src/lib/category/components/Breadcrumb.jsx | 221 |
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; |
