feat: add NSFW display policy setting

This commit is contained in:
codytseng
2025-12-11 23:37:05 +08:00
parent c2b0e6f666
commit f6f974adc6
24 changed files with 185 additions and 53 deletions

View File

@@ -1,5 +1,5 @@
import { useSecondaryPage } from '@/PageManager'
import { ExtendedKind, SUPPORTED_KINDS } from '@/constants'
import { ExtendedKind, NSFW_DISPLAY_POLICY, SUPPORTED_KINDS } from '@/constants'
import { getParentStuff, isNsfwEvent } from '@/lib/event'
import { toExternalContent, toNote } from '@/lib/link'
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
@@ -55,10 +55,14 @@ export default function Note({
const { parentEventId, parentExternalContent } = useMemo(() => {
return getParentStuff(event)
}, [event])
const { defaultShowNsfw } = useContentPolicy()
const { nsfwDisplayPolicy } = useContentPolicy()
const [showNsfw, setShowNsfw] = useState(false)
const { mutePubkeySet } = useMuteList()
const [showMuted, setShowMuted] = useState(false)
const isNsfw = useMemo(
() => (nsfwDisplayPolicy === NSFW_DISPLAY_POLICY.SHOW ? false : isNsfwEvent(event)),
[event, nsfwDisplayPolicy]
)
let content: React.ReactNode
if (
@@ -72,7 +76,7 @@ export default function Note({
content = <UnknownNote className="mt-2" event={event} />
} else if (mutePubkeySet.has(event.pubkey) && !showMuted) {
content = <MutedNote show={() => setShowMuted(true)} />
} else if (!defaultShowNsfw && isNsfwEvent(event) && !showNsfw) {
} else if (isNsfw && !showNsfw) {
content = <NsfwNote show={() => setShowNsfw(true)} />
} else if (event.kind === kinds.Highlights) {
content = <Highlight className="mt-2" event={event} />

View File

@@ -1,5 +1,6 @@
import { Skeleton } from '@/components/ui/skeleton'
import { isMentioningMutedUsers } from '@/lib/event'
import { NSFW_DISPLAY_POLICY } from '@/constants'
import { isMentioningMutedUsers, isNsfwEvent } from '@/lib/event'
import { cn } from '@/lib/utils'
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import { useMuteList } from '@/providers/MuteListProvider'
@@ -22,7 +23,7 @@ export default function NoteCard({
reposters?: string[]
}) {
const { mutePubkeySet } = useMuteList()
const { hideContentMentioningMutedUsers } = useContentPolicy()
const { hideContentMentioningMutedUsers, nsfwDisplayPolicy } = useContentPolicy()
const shouldHide = useMemo(() => {
if (filterMutedNotes && mutePubkeySet.has(event.pubkey)) {
return true
@@ -30,8 +31,11 @@ export default function NoteCard({
if (hideContentMentioningMutedUsers && isMentioningMutedUsers(event, mutePubkeySet)) {
return true
}
if (nsfwDisplayPolicy === NSFW_DISPLAY_POLICY.HIDE && isNsfwEvent(event)) {
return true
}
return false
}, [event, filterMutedNotes, mutePubkeySet])
}, [event, filterMutedNotes, mutePubkeySet, nsfwDisplayPolicy])
if (shouldHide) return null
if (event.kind === kinds.Repost || event.kind === kinds.GenericRepost) {

View File

@@ -28,7 +28,6 @@ export const StorageKey = {
TRANSLATION_SERVICE_CONFIG_MAP: 'translationServiceConfigMap',
MEDIA_UPLOAD_SERVICE_CONFIG_MAP: 'mediaUploadServiceConfigMap',
HIDE_UNTRUSTED_NOTES: 'hideUntrustedNotes',
DEFAULT_SHOW_NSFW: 'defaultShowNsfw',
DISMISSED_TOO_MANY_RELAYS_ALERT: 'dismissedTooManyRelaysAlert',
SHOW_KINDS: 'showKinds',
SHOW_KINDS_VERSION: 'showKindsVersion',
@@ -43,6 +42,8 @@ export const StorageKey = {
FILTER_OUT_ONION_RELAYS: 'filterOutOnionRelays',
QUICK_REACTION: 'quickReaction',
QUICK_REACTION_EMOJI: 'quickReactionEmoji',
NSFW_DISPLAY_POLICY: 'nsfwDisplayPolicy',
DEFAULT_SHOW_NSFW: 'defaultShowNsfw', // deprecated
PINNED_PUBKEYS: 'pinnedPubkeys', // deprecated
MEDIA_UPLOAD_SERVICE: 'mediaUploadService', // deprecated
HIDE_UNTRUSTED_EVENTS: 'hideUntrustedEvents', // deprecated
@@ -170,6 +171,12 @@ export const MEDIA_AUTO_LOAD_POLICY = {
NEVER: 'never'
} as const
export const NSFW_DISPLAY_POLICY = {
HIDE: 'hide',
HIDE_CONTENT: 'hide_content',
SHOW: 'show'
} as const
export const MAX_PINNED_NOTES = 10
export const PRIMARY_COLORS = {

View File

@@ -571,6 +571,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'إذا تم التمكين، يمكنك التفاعل بنقرة واحدة. اضغط مع الاستمرار للمزيد من الخيارات',
'Quick reaction emoji': 'رمز تعبيري للرد السريع',
'Select emoji': 'اختر رمز تعبيري'
'Select emoji': 'اختر رمز تعبيري',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -587,6 +587,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'Wenn aktiviert, können Sie mit einem Klick reagieren. Klicken und halten Sie für weitere Optionen',
'Quick reaction emoji': 'Schnellreaktions-Emoji',
'Select emoji': 'Emoji auswählen'
'Select emoji': 'Emoji auswählen',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -574,6 +574,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'If enabled, you can react with a single click. Click and hold for more options',
'Quick reaction emoji': 'Quick reaction emoji',
'Select emoji': 'Select emoji'
'Select emoji': 'Select emoji',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -583,6 +583,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'Si está habilitado, puedes reaccionar con un solo clic. Mantén presionado para más opciones',
'Quick reaction emoji': 'Emoji de reacción rápida',
'Select emoji': 'Seleccionar emoji'
'Select emoji': 'Seleccionar emoji',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -577,6 +577,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'اگر فعال باشد، می‌توانید با یک کلیک واکنش نشان دهید. برای گزینه‌های بیشتر کلیک کنید و نگه دارید',
'Quick reaction emoji': 'ایموجی واکنش سریع',
'Select emoji': 'انتخاب ایموجی'
'Select emoji': 'انتخاب ایموجی',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -584,8 +584,13 @@ export default {
notes: 'notes',
'Quick reaction': 'Réaction rapide',
'If enabled, you can react with a single click. Click and hold for more options':
'Si activé, vous pouvez réagir en un seul clic. Maintenez enfoncé pour plus d\'options',
"Si activé, vous pouvez réagir en un seul clic. Maintenez enfoncé pour plus d'options",
'Quick reaction emoji': 'Emoji de réaction rapide',
'Select emoji': 'Sélectionner un emoji'
'Select emoji': 'Sélectionner un emoji',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -578,6 +578,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'यदि सक्षम है, तो आप एक क्लिक से प्रतिक्रिया दे सकते हैं। अधिक विकल्पों के लिए क्लिक करें और रोकें',
'Quick reaction emoji': 'त्वरित प्रतिक्रिया इमोजी',
'Select emoji': 'इमोजी चुनें'
'Select emoji': 'इमोजी चुनें',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -572,6 +572,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'Ha engedélyezve van, egy kattintással reagálhat. Tartsa lenyomva további lehetőségekért',
'Quick reaction emoji': 'Gyors reakció emoji',
'Select emoji': 'Emoji kiválasztása'
'Select emoji': 'Emoji kiválasztása',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -582,6 +582,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'Se abilitato, puoi reagire con un solo clic. Fai clic e tieni premuto per altre opzioni',
'Quick reaction emoji': 'Emoji reazione rapida',
'Select emoji': 'Seleziona emoji'
'Select emoji': 'Seleziona emoji',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -577,6 +577,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'有効にすると、ワンクリックでリアクションできます。長押しで他のオプションを表示',
'Quick reaction emoji': 'クイックリアクション絵文字',
'Select emoji': '絵文字を選択'
'Select emoji': '絵文字を選択',
'NSFW content display': 'NSFWコンテンツの表示',
'Hide completely': '完全に非表示',
'Show but hide content': '表示するがコンテンツを非表示',
'Show directly': '直接表示',
'Click to view': 'クリックして表示'
}
}

View File

@@ -576,6 +576,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'활성화하면 한 번의 클릭으로 반응할 수 있습니다. 더 많은 옵션을 보려면 길게 누르세요',
'Quick reaction emoji': '빠른 반응 이모지',
'Select emoji': '이모지 선택'
'Select emoji': '이모지 선택',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -583,6 +583,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'Jeśli włączone, możesz zareagować jednym kliknięciem. Kliknij i przytrzymaj, aby uzyskać więcej opcji',
'Quick reaction emoji': 'Emoji szybkiej reakcji',
'Select emoji': 'Wybierz emoji'
'Select emoji': 'Wybierz emoji',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -578,6 +578,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'Se ativado, você pode reagir com um único clique. Clique e segure para mais opções',
'Quick reaction emoji': 'Emoji de reação rápida',
'Select emoji': 'Selecionar emoji'
'Select emoji': 'Selecionar emoji',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -581,6 +581,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'Se ativado, pode reagir com um único clique. Clique e mantenha premido para mais opções',
'Quick reaction emoji': 'Emoji de reação rápida',
'Select emoji': 'Selecionar emoji'
'Select emoji': 'Selecionar emoji',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -583,6 +583,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'Если включено, вы можете реагировать одним щелчком. Нажмите и удерживайте для дополнительных параметров',
'Quick reaction emoji': 'Эмодзи быстрой реакции',
'Select emoji': 'Выбрать эмодзи'
'Select emoji': 'Выбрать эмодзи',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -570,6 +570,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'หากเปิดใช้งาน คุณสามารถรีแอคได้ด้วยคลิกเดียว คลิกค้างไว้สำหรับตัวเลือกเพิ่มเติม',
'Quick reaction emoji': 'อีโมจิรีแอคชั่นด่วน',
'Select emoji': 'เลือกอีโมจิ'
'Select emoji': 'เลือกอีโมจิ',
'NSFW content display': 'NSFW content display',
'Hide completely': 'Hide completely',
'Show but hide content': 'Show but hide content',
'Show directly': 'Show directly',
'Click to view': 'Click to view'
}
}

View File

@@ -563,6 +563,11 @@ export default {
'If enabled, you can react with a single click. Click and hold for more options':
'启用后,您可以通过单击进行点赞。长按以获取更多选项',
'Quick reaction emoji': '快速点赞表情',
'Select emoji': '选择表情'
'Select emoji': '选择表情',
'NSFW content display': 'NSFW 内容显示',
'Hide completely': '完全隐藏',
'Show but hide content': '显示但隐藏内容',
'Show directly': '直接显示',
'Click to view': '点击查看'
}
}

View File

@@ -4,14 +4,14 @@ import { Button } from '@/components/ui/button'
import { Label } from '@/components/ui/label'
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select'
import { Switch } from '@/components/ui/switch'
import { MEDIA_AUTO_LOAD_POLICY } from '@/constants'
import { MEDIA_AUTO_LOAD_POLICY, NSFW_DISPLAY_POLICY } from '@/constants'
import { LocalizedLanguageNames, TLanguage } from '@/i18n'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { cn, isSupportCheckConnectionType } from '@/lib/utils'
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
import { useUserTrust } from '@/providers/UserTrustProvider'
import { TMediaAutoLoadPolicy } from '@/types'
import { TMediaAutoLoadPolicy, TNsfwDisplayPolicy } from '@/types'
import { SelectValue } from '@radix-ui/react-select'
import { RotateCcw } from 'lucide-react'
import { forwardRef, HTMLProps, useState } from 'react'
@@ -23,8 +23,8 @@ const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
const {
autoplay,
setAutoplay,
defaultShowNsfw,
setDefaultShowNsfw,
nsfwDisplayPolicy,
setNsfwDisplayPolicy,
hideContentMentioningMutedUsers,
setHideContentMentioningMutedUsers,
mediaAutoLoadPolicy,
@@ -110,10 +110,24 @@ const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
/>
</SettingItem>
<SettingItem>
<Label htmlFor="show-nsfw" className="text-base font-normal">
{t('Show NSFW content by default')}
<Label htmlFor="nsfw-display-policy" className="text-base font-normal">
{t('NSFW content display')}
</Label>
<Switch id="show-nsfw" checked={defaultShowNsfw} onCheckedChange={setDefaultShowNsfw} />
<Select
value={nsfwDisplayPolicy}
onValueChange={(value: TNsfwDisplayPolicy) => setNsfwDisplayPolicy(value)}
>
<SelectTrigger id="nsfw-display-policy" className="w-48">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value={NSFW_DISPLAY_POLICY.HIDE}>{t('Hide completely')}</SelectItem>
<SelectItem value={NSFW_DISPLAY_POLICY.HIDE_CONTENT}>
{t('Show but hide content')}
</SelectItem>
<SelectItem value={NSFW_DISPLAY_POLICY.SHOW}>{t('Show directly')}</SelectItem>
</SelectContent>
</Select>
</SettingItem>
<SettingItem>
<Label htmlFor="quick-reaction" className="text-base font-normal">

View File

@@ -1,14 +1,14 @@
import { MEDIA_AUTO_LOAD_POLICY } from '@/constants'
import storage from '@/services/local-storage.service'
import { TMediaAutoLoadPolicy } from '@/types'
import { TMediaAutoLoadPolicy, TNsfwDisplayPolicy } from '@/types'
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
type TContentPolicyContext = {
autoplay: boolean
setAutoplay: (autoplay: boolean) => void
defaultShowNsfw: boolean
setDefaultShowNsfw: (showNsfw: boolean) => void
nsfwDisplayPolicy: TNsfwDisplayPolicy
setNsfwDisplayPolicy: (policy: TNsfwDisplayPolicy) => void
hideContentMentioningMutedUsers?: boolean
setHideContentMentioningMutedUsers?: (hide: boolean) => void
@@ -33,7 +33,7 @@ export const useContentPolicy = () => {
export function ContentPolicyProvider({ children }: { children: React.ReactNode }) {
const [autoplay, setAutoplay] = useState(storage.getAutoplay())
const [defaultShowNsfw, setDefaultShowNsfw] = useState(storage.getDefaultShowNsfw())
const [nsfwDisplayPolicy, setNsfwDisplayPolicy] = useState(storage.getNsfwDisplayPolicy())
const [hideContentMentioningMutedUsers, setHideContentMentioningMutedUsers] = useState(
storage.getHideContentMentioningMutedUsers()
)
@@ -72,9 +72,9 @@ export function ContentPolicyProvider({ children }: { children: React.ReactNode
setAutoplay(autoplay)
}
const updateDefaultShowNsfw = (defaultShowNsfw: boolean) => {
storage.setDefaultShowNsfw(defaultShowNsfw)
setDefaultShowNsfw(defaultShowNsfw)
const updateNsfwDisplayPolicy = (policy: TNsfwDisplayPolicy) => {
storage.setNsfwDisplayPolicy(policy)
setNsfwDisplayPolicy(policy)
}
const updateHideContentMentioningMutedUsers = (hide: boolean) => {
@@ -97,8 +97,8 @@ export function ContentPolicyProvider({ children }: { children: React.ReactNode
value={{
autoplay,
setAutoplay: updateAutoplay,
defaultShowNsfw,
setDefaultShowNsfw: updateDefaultShowNsfw,
nsfwDisplayPolicy,
setNsfwDisplayPolicy: updateNsfwDisplayPolicy,
hideContentMentioningMutedUsers,
setHideContentMentioningMutedUsers: updateHideContentMentioningMutedUsers,
autoLoadMedia,

View File

@@ -5,6 +5,7 @@ import {
ExtendedKind,
MEDIA_AUTO_LOAD_POLICY,
NOTIFICATION_LIST_STYLE,
NSFW_DISPLAY_POLICY,
StorageKey,
TPrimaryColor
} from '@/constants'
@@ -19,6 +20,7 @@ import {
TMediaAutoLoadPolicy,
TMediaUploadServiceConfig,
TNoteListMode,
TNsfwDisplayPolicy,
TNotificationStyle,
TRelaySet,
TThemeSetting,
@@ -46,7 +48,6 @@ class LocalStorageService {
private hideUntrustedNotes: boolean = false
private translationServiceConfigMap: Record<string, TTranslationServiceConfig> = {}
private mediaUploadServiceConfigMap: Record<string, TMediaUploadServiceConfig> = {}
private defaultShowNsfw: boolean = false
private dismissedTooManyRelaysAlert: boolean = false
private showKinds: number[] = []
private hideContentMentioningMutedUsers: boolean = false
@@ -60,6 +61,7 @@ class LocalStorageService {
private filterOutOnionRelays: boolean = !isTorBrowser()
private quickReaction: boolean = false
private quickReactionEmoji: string | TEmoji = '+'
private nsfwDisplayPolicy: TNsfwDisplayPolicy = NSFW_DISPLAY_POLICY.HIDE_CONTENT
constructor() {
if (!LocalStorageService.instance) {
@@ -161,7 +163,20 @@ class LocalStorageService {
this.mediaUploadServiceConfigMap = JSON.parse(mediaUploadServiceConfigMapStr)
}
this.defaultShowNsfw = window.localStorage.getItem(StorageKey.DEFAULT_SHOW_NSFW) === 'true'
// Migrate old boolean setting to new policy
const nsfwDisplayPolicyStr = window.localStorage.getItem(StorageKey.NSFW_DISPLAY_POLICY)
if (
nsfwDisplayPolicyStr &&
Object.values(NSFW_DISPLAY_POLICY).includes(nsfwDisplayPolicyStr as TNsfwDisplayPolicy)
) {
this.nsfwDisplayPolicy = nsfwDisplayPolicyStr as TNsfwDisplayPolicy
} else {
// Migration: convert old boolean to new policy
const defaultShowNsfwStr = window.localStorage.getItem(StorageKey.DEFAULT_SHOW_NSFW)
this.nsfwDisplayPolicy =
defaultShowNsfwStr === 'true' ? NSFW_DISPLAY_POLICY.SHOW : NSFW_DISPLAY_POLICY.HIDE_CONTENT
window.localStorage.setItem(StorageKey.NSFW_DISPLAY_POLICY, this.nsfwDisplayPolicy)
}
this.dismissedTooManyRelaysAlert =
window.localStorage.getItem(StorageKey.DISMISSED_TOO_MANY_RELAYS_ALERT) === 'true'
@@ -458,15 +473,6 @@ class LocalStorageService {
return config
}
getDefaultShowNsfw() {
return this.defaultShowNsfw
}
setDefaultShowNsfw(defaultShowNsfw: boolean) {
this.defaultShowNsfw = defaultShowNsfw
window.localStorage.setItem(StorageKey.DEFAULT_SHOW_NSFW, defaultShowNsfw.toString())
}
getDismissedTooManyRelaysAlert() {
return this.dismissedTooManyRelaysAlert
}
@@ -592,6 +598,15 @@ class LocalStorageService {
typeof emoji === 'string' ? emoji : JSON.stringify(emoji)
)
}
getNsfwDisplayPolicy() {
return this.nsfwDisplayPolicy
}
setNsfwDisplayPolicy(policy: TNsfwDisplayPolicy) {
this.nsfwDisplayPolicy = policy
window.localStorage.setItem(StorageKey.NSFW_DISPLAY_POLICY, policy)
}
}
const instance = new LocalStorageService()

View File

@@ -1,5 +1,5 @@
import { Event, Filter, VerifiedEvent } from 'nostr-tools'
import { MEDIA_AUTO_LOAD_POLICY, NOTIFICATION_LIST_STYLE, POLL_TYPE } from '../constants'
import { MEDIA_AUTO_LOAD_POLICY, NOTIFICATION_LIST_STYLE, NSFW_DISPLAY_POLICY, POLL_TYPE } from '../constants'
export type TSubRequestFilter = Omit<Filter, 'since' | 'until'> & { limit: number }
@@ -205,3 +205,6 @@ export type TAwesomeRelayCollection = {
export type TMediaAutoLoadPolicy =
(typeof MEDIA_AUTO_LOAD_POLICY)[keyof typeof MEDIA_AUTO_LOAD_POLICY]
export type TNsfwDisplayPolicy =
(typeof NSFW_DISPLAY_POLICY)[keyof typeof NSFW_DISPLAY_POLICY]