|
|
|
@ -1,6 +1,6 @@ |
|
|
|
import { cn } from '@/lib/utils' |
|
|
|
import { cn } from '@/lib/utils' |
|
|
|
import { useDeepBrowsing } from '@/providers/DeepBrowsingProvider' |
|
|
|
import { useDeepBrowsing } from '@/providers/DeepBrowsingProvider' |
|
|
|
import { useEffect, useRef, useState } from 'react' |
|
|
|
import { useMemo } from 'react' |
|
|
|
import { useTranslation } from 'react-i18next' |
|
|
|
import { useTranslation } from 'react-i18next' |
|
|
|
|
|
|
|
|
|
|
|
type TabDefinition = { |
|
|
|
type TabDefinition = { |
|
|
|
@ -21,62 +21,38 @@ export default function Tabs({ |
|
|
|
}) { |
|
|
|
}) { |
|
|
|
const { t } = useTranslation() |
|
|
|
const { t } = useTranslation() |
|
|
|
const { deepBrowsing, lastScrollTop } = useDeepBrowsing() |
|
|
|
const { deepBrowsing, lastScrollTop } = useDeepBrowsing() |
|
|
|
const tabRefs = useRef<(HTMLDivElement | null)[]>([]) |
|
|
|
const activeIndex = useMemo(() => tabs.findIndex((tab) => tab.value === value), [value, tabs]) |
|
|
|
const [indicatorStyle, setIndicatorStyle] = useState({ width: 0, left: 0 }) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
const handleResize = () => { |
|
|
|
|
|
|
|
const activeIndex = tabs.findIndex((tab) => tab.value === value) |
|
|
|
|
|
|
|
if (tabs.length === 4) { |
|
|
|
|
|
|
|
console.log('notification tabs', activeIndex, value) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (activeIndex >= 0 && tabRefs.current[activeIndex]) { |
|
|
|
|
|
|
|
const activeTab = tabRefs.current[activeIndex] |
|
|
|
|
|
|
|
const { offsetWidth, offsetLeft } = activeTab |
|
|
|
|
|
|
|
const padding = 24 // 12px padding on each side
|
|
|
|
|
|
|
|
if (tabs.length === 4) { |
|
|
|
|
|
|
|
console.log('notification tabs', offsetWidth, offsetLeft, padding) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
setIndicatorStyle({ |
|
|
|
|
|
|
|
width: offsetWidth - padding, |
|
|
|
|
|
|
|
left: offsetLeft + padding / 2 |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
window.addEventListener('resize', handleResize) |
|
|
|
|
|
|
|
setTimeout(() => handleResize(), 20) // ensure tabs are rendered before calculating
|
|
|
|
|
|
|
|
return () => { |
|
|
|
|
|
|
|
window.removeEventListener('resize', handleResize) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, [value]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<div |
|
|
|
<div |
|
|
|
className={cn( |
|
|
|
className={cn( |
|
|
|
'sticky flex justify-around top-12 p-1 bg-background z-30 w-full transition-transform', |
|
|
|
'sticky flex top-12 p-1 bg-background z-30 w-full transition-transform', |
|
|
|
deepBrowsing && lastScrollTop > threshold ? '-translate-y-[calc(100%+12rem)]' : '' |
|
|
|
deepBrowsing && lastScrollTop > threshold ? '-translate-y-[calc(100%+12rem)]' : '' |
|
|
|
)} |
|
|
|
)} |
|
|
|
> |
|
|
|
> |
|
|
|
{tabs.map((tab, index) => ( |
|
|
|
{tabs.map((tab) => ( |
|
|
|
<div |
|
|
|
<div |
|
|
|
key={tab.value} |
|
|
|
key={tab.value} |
|
|
|
ref={(el) => (tabRefs.current[index] = el)} |
|
|
|
|
|
|
|
className={cn( |
|
|
|
className={cn( |
|
|
|
`text-center w-full py-2 font-semibold clickable cursor-pointer rounded-lg`, |
|
|
|
`flex-1 text-center py-2 font-semibold clickable cursor-pointer rounded-lg`, |
|
|
|
value === tab.value ? '' : 'text-muted-foreground' |
|
|
|
value === tab.value ? '' : 'text-muted-foreground' |
|
|
|
)} |
|
|
|
)} |
|
|
|
onClick={() => onTabChange?.(tab.value)} |
|
|
|
onClick={() => { |
|
|
|
|
|
|
|
onTabChange?.(tab.value) |
|
|
|
|
|
|
|
}} |
|
|
|
> |
|
|
|
> |
|
|
|
{t(tab.label)} |
|
|
|
{t(tab.label)} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
))} |
|
|
|
))} |
|
|
|
<div |
|
|
|
<div |
|
|
|
className="absolute bottom-0 h-1 bg-primary rounded-full transition-all duration-500" |
|
|
|
className="absolute bottom-0 px-4 transition-all duration-500" |
|
|
|
style={{ |
|
|
|
style={{ |
|
|
|
width: `${indicatorStyle.width}px`, |
|
|
|
width: `${100 / tabs.length}%`, |
|
|
|
left: `${indicatorStyle.left}px` |
|
|
|
left: `${activeIndex >= 0 ? activeIndex * (100 / tabs.length) : 0}%` |
|
|
|
}} |
|
|
|
}} |
|
|
|
/> |
|
|
|
> |
|
|
|
|
|
|
|
<div className="w-full h-1 bg-primary rounded-full" /> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|