index.tsx raw

   1  import { Button } from '@/components/ui/button'
   2  import { Label } from '@/components/ui/label'
   3  import { Switch } from '@/components/ui/switch'
   4  import { useSocialGraphFilter } from '@/providers/SocialGraphFilterProvider'
   5  import { Loader2, Minus, Plus } from 'lucide-react'
   6  import { useTranslation } from 'react-i18next'
   7  
   8  const DEPTH_LABELS: Record<number, string> = {
   9    1: 'Direct follows',
  10    2: 'Follows of follows'
  11  }
  12  
  13  interface SocialGraphFilterProps {
  14    temporaryProximity: number | null
  15    temporaryIncludeMode: boolean
  16    onTemporaryProximityChange: (level: number | null) => void
  17    onTemporaryIncludeModeChange: (include: boolean) => void
  18  }
  19  
  20  export default function SocialGraphFilter({
  21    temporaryProximity,
  22    temporaryIncludeMode,
  23    onTemporaryProximityChange,
  24    onTemporaryIncludeModeChange
  25  }: SocialGraphFilterProps) {
  26    const { t } = useTranslation()
  27    const { graphPubkeyCount, isLoading } = useSocialGraphFilter()
  28  
  29    const isEnabled = temporaryProximity !== null
  30    const depth = temporaryProximity ?? 1
  31  
  32    const handleToggle = (enabled: boolean) => {
  33      onTemporaryProximityChange(enabled ? 1 : null)
  34    }
  35  
  36    const handleIncrease = () => {
  37      if (depth < 2) {
  38        onTemporaryProximityChange(depth + 1)
  39      }
  40    }
  41  
  42    const handleDecrease = () => {
  43      if (depth > 1) {
  44        onTemporaryProximityChange(depth - 1)
  45      }
  46    }
  47  
  48    return (
  49      <div className="space-y-3">
  50        <div className="flex items-center justify-between">
  51          <Label htmlFor="social-graph-filter" className="font-medium">
  52            {t('Social graph filter')}
  53          </Label>
  54          <Switch id="social-graph-filter" checked={isEnabled} onCheckedChange={handleToggle} />
  55        </div>
  56  
  57        {isEnabled && (
  58          <>
  59            {/* Include/Exclude toggle */}
  60            <div className="flex items-center gap-2">
  61              <Button
  62                variant={temporaryIncludeMode ? 'default' : 'outline'}
  63                size="sm"
  64                className="flex-1"
  65                onClick={() => onTemporaryIncludeModeChange(true)}
  66              >
  67                {t('Include')}
  68              </Button>
  69              <Button
  70                variant={!temporaryIncludeMode ? 'default' : 'outline'}
  71                size="sm"
  72                className="flex-1"
  73                onClick={() => onTemporaryIncludeModeChange(false)}
  74              >
  75                {t('Exclude')}
  76              </Button>
  77            </div>
  78  
  79            {/* Depth stepper */}
  80            <div className="flex items-center justify-between rounded-lg border px-3 py-2">
  81              <div className="flex-1">
  82                <p className="text-sm font-medium">{t(DEPTH_LABELS[depth])}</p>
  83                <p className="text-xs text-muted-foreground">
  84                  {isLoading ? (
  85                    <span className="flex items-center gap-1">
  86                      <Loader2 className="h-3 w-3 animate-spin" />
  87                      {t('Loading...')}
  88                    </span>
  89                  ) : (
  90                    t('{{count}} users', { count: graphPubkeyCount })
  91                  )}
  92                </p>
  93              </div>
  94              <div className="flex items-center gap-1">
  95                <Button
  96                  variant="outline"
  97                  size="icon"
  98                  className="h-8 w-8"
  99                  onClick={handleDecrease}
 100                  disabled={depth <= 1}
 101                >
 102                  <Minus className="h-4 w-4" />
 103                </Button>
 104                <span className="w-6 text-center text-sm font-medium">{depth}</span>
 105                <Button
 106                  variant="outline"
 107                  size="icon"
 108                  className="h-8 w-8"
 109                  onClick={handleIncrease}
 110                  disabled={depth >= 2}
 111                >
 112                  <Plus className="h-4 w-4" />
 113                </Button>
 114              </div>
 115            </div>
 116  
 117            {/* Mode description */}
 118            <p className="text-xs text-muted-foreground">
 119              {temporaryIncludeMode
 120                ? t('Only show notes from users in your social graph')
 121                : t('Hide notes from users in your social graph')}
 122            </p>
 123          </>
 124        )}
 125      </div>
 126    )
 127  }
 128