15 changed files with 503 additions and 25 deletions
@ -0,0 +1,62 @@
@@ -0,0 +1,62 @@
|
||||
import { Event } from 'nostr-tools' |
||||
import dayjs from 'dayjs' |
||||
import storage from '@/services/local-storage.service' |
||||
|
||||
/** |
||||
* Check if an event has expired based on its expiration tag |
||||
*/ |
||||
export function isEventExpired(event: Event): boolean { |
||||
const expirationTag = event.tags.find(tag => tag[0] === 'expiration') |
||||
if (!expirationTag || !expirationTag[1]) { |
||||
return false |
||||
} |
||||
|
||||
const expirationTime = parseInt(expirationTag[1]) |
||||
if (isNaN(expirationTime)) { |
||||
return false |
||||
} |
||||
|
||||
return dayjs().unix() > expirationTime |
||||
} |
||||
|
||||
/** |
||||
* Check if an event is in quiet mode based on its quiet tag |
||||
*/ |
||||
export function isEventInQuietMode(event: Event): boolean { |
||||
const quietTag = event.tags.find(tag => tag[0] === 'quiet') |
||||
if (!quietTag || !quietTag[1]) { |
||||
return false |
||||
} |
||||
|
||||
const quietEndTime = parseInt(quietTag[1]) |
||||
if (isNaN(quietEndTime)) { |
||||
return false |
||||
} |
||||
|
||||
return dayjs().unix() < quietEndTime |
||||
} |
||||
|
||||
/** |
||||
* Check if interactions should be hidden for an event based on quiet settings |
||||
*/ |
||||
export function shouldHideInteractions(event: Event): boolean { |
||||
// Check global quiet mode first
|
||||
if (storage.getGlobalQuietMode()) { |
||||
return true |
||||
} |
||||
|
||||
// Check if we should respect quiet tags
|
||||
if (!storage.getRespectQuietTags()) { |
||||
return false |
||||
} |
||||
|
||||
// Check if the event is in quiet mode
|
||||
return isEventInQuietMode(event) |
||||
} |
||||
|
||||
/** |
||||
* Check if an event should be filtered out completely (expired) |
||||
*/ |
||||
export function shouldFilterEvent(event: Event): boolean { |
||||
return isEventExpired(event) |
||||
} |
||||
@ -0,0 +1,66 @@
@@ -0,0 +1,66 @@
|
||||
import { Label } from '@/components/ui/label' |
||||
import { Switch } from '@/components/ui/switch' |
||||
import { Input } from '@/components/ui/input' |
||||
import storage from '@/services/local-storage.service' |
||||
import { useEffect, useState } from 'react' |
||||
import { useTranslation } from 'react-i18next' |
||||
|
||||
export default function ExpirationSettings() { |
||||
const { t } = useTranslation() |
||||
const [enabled, setEnabled] = useState(false) |
||||
const [months, setMonths] = useState(6) |
||||
|
||||
useEffect(() => { |
||||
setEnabled(storage.getDefaultExpirationEnabled()) |
||||
setMonths(storage.getDefaultExpirationMonths()) |
||||
}, []) |
||||
|
||||
const handleEnabledChange = (checked: boolean) => { |
||||
setEnabled(checked) |
||||
storage.setDefaultExpirationEnabled(checked) |
||||
} |
||||
|
||||
const handleMonthsChange = (value: string) => { |
||||
const num = parseInt(value) |
||||
if (!isNaN(num) && num >= 0 && Number.isInteger(num)) { |
||||
setMonths(num) |
||||
storage.setDefaultExpirationMonths(num) |
||||
} |
||||
} |
||||
|
||||
return ( |
||||
<div className="space-y-4"> |
||||
<div className="space-y-2"> |
||||
<div className="flex items-center space-x-2"> |
||||
<Label htmlFor="expiration-enabled">{t('Add expiration tags by default')}</Label> |
||||
<Switch |
||||
id="expiration-enabled" |
||||
checked={enabled} |
||||
onCheckedChange={handleEnabledChange} |
||||
/> |
||||
</div> |
||||
<div className="text-muted-foreground text-xs"> |
||||
{t('Posts will automatically include expiration tags')} |
||||
</div> |
||||
</div> |
||||
|
||||
{enabled && ( |
||||
<div className="space-y-2"> |
||||
<Label htmlFor="expiration-months">{t('Default expiration (months)')}</Label> |
||||
<Input |
||||
id="expiration-months" |
||||
type="number" |
||||
min="0" |
||||
step="1" |
||||
value={months} |
||||
onChange={(e) => handleMonthsChange(e.target.value)} |
||||
className="w-24" |
||||
/> |
||||
<div className="text-muted-foreground text-xs"> |
||||
{t('Posts will expire after this many months')} |
||||
</div> |
||||
</div> |
||||
)} |
||||
</div> |
||||
) |
||||
} |
||||
@ -0,0 +1,108 @@
@@ -0,0 +1,108 @@
|
||||
import { Label } from '@/components/ui/label' |
||||
import { Switch } from '@/components/ui/switch' |
||||
import { Input } from '@/components/ui/input' |
||||
import storage from '@/services/local-storage.service' |
||||
import { useEffect, useState } from 'react' |
||||
import { useTranslation } from 'react-i18next' |
||||
|
||||
export default function QuietSettings() { |
||||
const { t } = useTranslation() |
||||
const [enabled, setEnabled] = useState(false) |
||||
const [days, setDays] = useState(7) |
||||
const [respectQuietTags, setRespectQuietTags] = useState(true) |
||||
const [globalQuietMode, setGlobalQuietMode] = useState(false) |
||||
|
||||
useEffect(() => { |
||||
setEnabled(storage.getDefaultQuietEnabled()) |
||||
setDays(storage.getDefaultQuietDays()) |
||||
setRespectQuietTags(storage.getRespectQuietTags()) |
||||
setGlobalQuietMode(storage.getGlobalQuietMode()) |
||||
}, []) |
||||
|
||||
const handleEnabledChange = (checked: boolean) => { |
||||
setEnabled(checked) |
||||
storage.setDefaultQuietEnabled(checked) |
||||
} |
||||
|
||||
const handleDaysChange = (value: string) => { |
||||
const num = parseInt(value) |
||||
if (!isNaN(num) && num >= 0 && Number.isInteger(num)) { |
||||
setDays(num) |
||||
storage.setDefaultQuietDays(num) |
||||
} |
||||
} |
||||
|
||||
const handleRespectQuietTagsChange = (checked: boolean) => { |
||||
setRespectQuietTags(checked) |
||||
storage.setRespectQuietTags(checked) |
||||
} |
||||
|
||||
const handleGlobalQuietModeChange = (checked: boolean) => { |
||||
setGlobalQuietMode(checked) |
||||
storage.setGlobalQuietMode(checked) |
||||
} |
||||
|
||||
return ( |
||||
<div className="space-y-4"> |
||||
<div className="space-y-2"> |
||||
<div className="flex items-center space-x-2"> |
||||
<Label htmlFor="quiet-enabled">{t('Add quiet tags by default')}</Label> |
||||
<Switch |
||||
id="quiet-enabled" |
||||
checked={enabled} |
||||
onCheckedChange={handleEnabledChange} |
||||
/> |
||||
</div> |
||||
<div className="text-muted-foreground text-xs"> |
||||
{t('Posts will automatically include quiet tags')} |
||||
</div> |
||||
</div> |
||||
|
||||
{enabled && ( |
||||
<div className="space-y-2"> |
||||
<Label htmlFor="quiet-days">{t('Default quiet period (days)')}</Label> |
||||
<Input |
||||
id="quiet-days" |
||||
type="number" |
||||
min="0" |
||||
step="1" |
||||
value={days} |
||||
onChange={(e) => handleDaysChange(e.target.value)} |
||||
className="w-24" |
||||
/> |
||||
<div className="text-muted-foreground text-xs"> |
||||
{t('Posts will be quiet for this many days')} |
||||
</div> |
||||
</div> |
||||
)} |
||||
|
||||
<div className="space-y-2"> |
||||
<div className="flex items-center space-x-2"> |
||||
<Label htmlFor="respect-quiet-tags">{t('Respect quiet tags')}</Label> |
||||
<Switch |
||||
id="respect-quiet-tags" |
||||
checked={respectQuietTags} |
||||
onCheckedChange={handleRespectQuietTagsChange} |
||||
/> |
||||
</div> |
||||
<div className="text-muted-foreground text-xs"> |
||||
{t('Hide interactions on posts with quiet tags')} |
||||
</div> |
||||
</div> |
||||
|
||||
<div className="space-y-2"> |
||||
<div className="flex items-center space-x-2"> |
||||
<Label htmlFor="global-quiet-mode">{t('Global quiet mode')}</Label> |
||||
<Switch |
||||
id="global-quiet-mode" |
||||
checked={globalQuietMode} |
||||
onCheckedChange={handleGlobalQuietModeChange} |
||||
/> |
||||
</div> |
||||
<div className="text-muted-foreground text-xs"> |
||||
{t('Hide interactions on all posts')} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
Loading…
Reference in new issue