feat: muted words

This commit is contained in:
codytseng 2026-01-08 22:53:11 +08:00
parent 3c74c8c5db
commit 603bd35b4a
25 changed files with 282 additions and 87 deletions

View file

@ -0,0 +1,78 @@
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import { Plus, X } from 'lucide-react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import SettingItem from './SettingItem'
export default function MutedWords() {
const { t } = useTranslation()
const { mutedWords, setMutedWords } = useContentPolicy()
const [newMutedWord, setNewMutedWord] = useState('')
const handleAddMutedWord = () => {
const word = newMutedWord.trim().toLowerCase()
if (word && !mutedWords.includes(word)) {
setMutedWords([...mutedWords, word])
setNewMutedWord('')
}
}
const handleRemoveMutedWord = (word: string) => {
setMutedWords(mutedWords.filter((w) => w !== word))
}
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
e.preventDefault()
handleAddMutedWord()
}
}
return (
<SettingItem className="flex-col items-start gap-2">
<Label className="text-base font-normal">{t('Muted words')}</Label>
<div className="w-full space-y-2">
<div className="flex gap-2">
<Input
placeholder={t('Add muted word')}
value={newMutedWord}
onChange={(e) => setNewMutedWord(e.target.value)}
onKeyDown={handleKeyDown}
className="flex-1"
/>
<Button
variant="ghost"
size="icon"
onClick={handleAddMutedWord}
disabled={!newMutedWord.trim() || mutedWords.includes(newMutedWord.trim())}
>
<Plus />
</Button>
</div>
{mutedWords.length > 0 && (
<div className="flex flex-wrap gap-2">
{mutedWords.map((word) => (
<div
key={word}
className="flex items-center gap-1 bg-muted px-2 py-1 rounded-md text-sm"
>
<span>{word}</span>
<Button
variant="ghost"
size="icon"
className="h-4 w-4 hover:bg-transparent"
onClick={() => handleRemoveMutedWord(word)}
>
<X className="h-3 w-3" />
</Button>
</div>
))}
</div>
)}
</div>
</SettingItem>
)
}

View file

@ -0,0 +1,21 @@
import { cn } from '@/lib/utils'
import { forwardRef, HTMLProps } from 'react'
const SettingItem = forwardRef<HTMLDivElement, HTMLProps<HTMLDivElement>>(
({ children, className, ...props }, ref) => {
return (
<div
className={cn(
'flex justify-between select-none items-center px-4 min-h-9 [&_svg]:size-4 [&_svg]:shrink-0',
className
)}
{...props}
ref={ref}
>
{children}
</div>
)
}
)
SettingItem.displayName = 'SettingItem'
export default SettingItem

View file

@ -11,14 +11,16 @@ import {
} from '@/constants'
import { LocalizedLanguageNames, TLanguage } from '@/i18n'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { cn, isSupportCheckConnectionType } from '@/lib/utils'
import { isSupportCheckConnectionType } from '@/lib/utils'
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
import { TMediaAutoLoadPolicy, TNsfwDisplayPolicy, TProfilePictureAutoLoadPolicy } from '@/types'
import { SelectValue } from '@radix-ui/react-select'
import { RotateCcw } from 'lucide-react'
import { forwardRef, HTMLProps, useState } from 'react'
import { forwardRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import MutedWords from './MutedWords'
import SettingItem from './SettingItem'
const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
const { t, i18n } = useTranslation()
@ -188,27 +190,10 @@ const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
</div>
</SettingItem>
)}
<MutedWords />
</div>
</SecondaryPageLayout>
)
})
GeneralSettingsPage.displayName = 'GeneralSettingsPage'
export default GeneralSettingsPage
const SettingItem = forwardRef<HTMLDivElement, HTMLProps<HTMLDivElement>>(
({ children, className, ...props }, ref) => {
return (
<div
className={cn(
'flex justify-between select-none items-center px-4 min-h-9 [&_svg]:size-4 [&_svg]:shrink-0',
className
)}
{...props}
ref={ref}
>
{children}
</div>
)
}
)
SettingItem.displayName = 'SettingItem'