Files
AFFiNE/packages/frontend/admin/src/components/shared/feature-toggle-list.tsx
2026-02-17 17:40:29 +08:00

88 lines
2.6 KiB
TypeScript

import { Checkbox } from '@affine/admin/components/ui/checkbox';
import { Label } from '@affine/admin/components/ui/label';
import { Separator } from '@affine/admin/components/ui/separator';
import { Switch } from '@affine/admin/components/ui/switch';
import type { FeatureType } from '@affine/graphql';
import { useCallback } from 'react';
import { cn } from '../../utils';
type FeatureToggleListProps = {
features: FeatureType[];
selected: FeatureType[];
onChange: (features: FeatureType[]) => void;
control?: 'checkbox' | 'switch';
controlPosition?: 'left' | 'right';
showSeparators?: boolean;
className?: string;
};
export const FeatureToggleList = ({
features,
selected,
onChange,
control = 'checkbox',
controlPosition = 'left',
showSeparators = false,
className,
}: FeatureToggleListProps) => {
const Control = control === 'switch' ? Switch : Checkbox;
const handleToggle = useCallback(
(feature: FeatureType, checked: boolean) => {
if (checked) {
onChange([...new Set([...selected, feature])]);
} else {
onChange(selected.filter(item => item !== feature));
}
},
[onChange, selected]
);
if (!features.length) {
return (
<div className={cn(className, 'px-3 py-2 text-xs text-muted-foreground')}>
No configurable features.
</div>
);
}
return (
<div className={className}>
{features.map((feature, index) => (
<div key={feature}>
<Label
className={cn(
'cursor-pointer transition-colors duration-100',
controlPosition === 'right'
? 'flex items-center justify-between p-3 text-sm gap-2 font-medium leading-6 overflow-hidden hover:bg-muted/40'
: 'flex items-center gap-2 px-3 py-2 text-sm hover:bg-muted/40'
)}
>
{controlPosition === 'left' ? (
<>
<Control
checked={selected.includes(feature)}
onCheckedChange={checked => handleToggle(feature, !!checked)}
/>
<span className="truncate">{feature}</span>
</>
) : (
<>
<span className="overflow-hidden text-ellipsis" title={feature}>
{feature}
</span>
<Control
checked={selected.includes(feature)}
onCheckedChange={checked => handleToggle(feature, !!checked)}
/>
</>
)}
</Label>
{showSeparators && index < features.length - 1 && <Separator />}
</div>
))}
</div>
);
};