FeedButton.tsx raw

   1  import FeedSwitcher from '@/components/FeedSwitcher'
   2  import RelayIcon from '@/components/RelayIcon'
   3  import { Drawer, DrawerContent } from '@/components/ui/drawer'
   4  import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
   5  import { simplifyUrl } from '@/lib/url'
   6  import { cn } from '@/lib/utils'
   7  import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
   8  import { useFeed } from '@/providers/FeedProvider'
   9  import { useScreenSize } from '@/providers/ScreenSizeProvider'
  10  import { ChevronDown, Server, Star, UsersRound } from 'lucide-react'
  11  import { forwardRef, HTMLAttributes, useMemo, useState } from 'react'
  12  import { useTranslation } from 'react-i18next'
  13  
  14  export default function FeedButton({ className }: { className?: string }) {
  15    const { isSmallScreen } = useScreenSize()
  16    const [open, setOpen] = useState(false)
  17  
  18    if (isSmallScreen) {
  19      return (
  20        <>
  21          <FeedSwitcherTrigger className={className} onClick={() => setOpen(true)} />
  22          <Drawer open={open} onOpenChange={setOpen}>
  23            <DrawerContent className="max-h-[85vh]">
  24              <div
  25                className="flex-1 overflow-y-auto overscroll-contain py-3 px-4"
  26                style={{
  27                  touchAction: 'pan-y',
  28                  WebkitOverflowScrolling: 'touch'
  29                }}
  30              >
  31                <FeedSwitcher close={() => setOpen(false)} />
  32              </div>
  33            </DrawerContent>
  34          </Drawer>
  35        </>
  36      )
  37    }
  38  
  39    return (
  40      <Popover open={open} onOpenChange={setOpen}>
  41        <PopoverTrigger asChild>
  42          <FeedSwitcherTrigger className={className} />
  43        </PopoverTrigger>
  44        <PopoverContent sideOffset={0} side="bottom" className="w-[400px] p-0 overflow-hidden">
  45          <div
  46            className="max-h-[calc(100vh-16rem)] overflow-y-auto overscroll-contain py-3 px-4"
  47            onWheel={(e) => e.stopPropagation()}
  48            onTouchMove={(e) => e.stopPropagation()}
  49          >
  50            <FeedSwitcher close={() => setOpen(false)} />
  51          </div>
  52        </PopoverContent>
  53      </Popover>
  54    )
  55  }
  56  
  57  const FeedSwitcherTrigger = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
  58    ({ className, ...props }, ref) => {
  59      const { t } = useTranslation()
  60      const { feedInfo, relayUrls } = useFeed()
  61      const { relaySets } = useFavoriteRelays()
  62      const activeRelaySet = useMemo(() => {
  63        return feedInfo?.feedType === 'relays' && feedInfo.id
  64          ? relaySets.find((set) => set.id === feedInfo.id)
  65          : undefined
  66      }, [feedInfo, relaySets])
  67      const title = useMemo(() => {
  68        if (feedInfo?.feedType === 'following') {
  69          return t('Following')
  70        }
  71        if (feedInfo?.feedType === 'pinned') {
  72          return t('Special Follow')
  73        }
  74        if (relayUrls.length === 0) {
  75          return t('Choose a feed')
  76        }
  77        if (feedInfo?.feedType === 'relay') {
  78          return simplifyUrl(feedInfo?.id ?? '')
  79        }
  80        if (feedInfo?.feedType === 'relays') {
  81          return activeRelaySet?.name ?? activeRelaySet?.id
  82        }
  83      }, [feedInfo, activeRelaySet])
  84  
  85      const icon = useMemo(() => {
  86        if (feedInfo?.feedType === 'following') return <UsersRound />
  87        if (feedInfo?.feedType === 'pinned') return <Star />
  88        if (feedInfo?.feedType === 'relay' && feedInfo.id) {
  89          return <RelayIcon url={feedInfo.id} />
  90        }
  91  
  92        return <Server />
  93      }, [feedInfo])
  94  
  95      return (
  96        <div
  97          className={cn('flex items-center gap-2 clickable px-3 h-full rounded-xl', className)}
  98          ref={ref}
  99          {...props}
 100        >
 101          {icon}
 102          <div className="text-lg font-semibold truncate">{title}</div>
 103          <ChevronDown />
 104        </div>
 105      )
 106    }
 107  )
 108