feat: add protected badge for NIP-70 events

Display a subtle green "Protected" badge next to the username for
events with the `-` tag (NIP-70), indicating restricted distribution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
codytseng 2026-03-19 22:27:11 +08:00
parent 67f308e47f
commit bd6340bbc7
20 changed files with 78 additions and 18 deletions

View file

@ -11,6 +11,7 @@ import AudioPlayer from '../AudioPlayer'
import ClientTag from '../ClientTag'
import Content from '../Content'
import FollowingBadge from '../FollowingBadge'
import ProtectedBadge from '../ProtectedBadge'
import { FormattedTimestamp } from '../FormattedTimestamp'
import Nip05 from '../Nip05'
import NoteOptions from '../NoteOptions'
@ -134,6 +135,7 @@ export default function Note({
/>
<FollowingBadge pubkey={event.pubkey} />
<TrustScoreBadge pubkey={event.pubkey} />
<ProtectedBadge event={event} />
<ClientTag event={event} />
</div>
<div className="flex items-center gap-1 text-sm text-muted-foreground">

View file

@ -0,0 +1,22 @@
import { isProtectedEvent } from '@/lib/event'
import { Event } from 'nostr-tools'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
export default function ProtectedBadge({ event }: { event: Event }) {
const { t } = useTranslation()
const isProtected = useMemo(() => isProtectedEvent(event), [event])
if (!isProtected) return null
return (
<div
className="flex items-center rounded-full bg-green-500/10 px-2 py-0.5"
title={t('Protected event (NIP-70)')}
>
<span className="text-xs leading-none text-green-600 dark:text-green-400">
{t('Protected')}
</span>
</div>
)
}

View file

@ -671,6 +671,8 @@ export default {
'Copy note content': 'نسخ محتوى الملاحظة',
'Video loop': 'تكرار الفيديو',
'Automatically replay videos when they end': 'إعادة تشغيل مقاطع الفيديو تلقائيًا عند انتهائها',
'Relays used for searching notes (NIP-50)': 'الريلايات المستخدمة للبحث عن الملاحظات (NIP-50)'
'Relays used for searching notes (NIP-50)': 'الريلايات المستخدمة للبحث عن الملاحظات (NIP-50)',
'Protected event (NIP-70)': 'حدث محمي (NIP-70)',
'Protected': 'محمي'
}
}

View file

@ -695,6 +695,8 @@ export default {
'Copy note content': 'Notizinhalt kopieren',
'Video loop': 'Video-Schleife',
'Automatically replay videos when they end': 'Videos automatisch wiederholen, wenn sie enden',
'Relays used for searching notes (NIP-50)': 'Relays für die Notizsuche (NIP-50)'
'Relays used for searching notes (NIP-50)': 'Relays für die Notizsuche (NIP-50)',
'Protected event (NIP-70)': 'Geschütztes Ereignis (NIP-70)',
'Protected': 'Geschützt'
}
}

View file

@ -677,6 +677,8 @@ export default {
'Copy note content': 'Copy note content',
'Video loop': 'Video loop',
'Automatically replay videos when they end': 'Automatically replay videos when they end',
'Relays used for searching notes (NIP-50)': 'Relays used for searching notes (NIP-50)'
'Relays used for searching notes (NIP-50)': 'Relays used for searching notes (NIP-50)',
'Protected event (NIP-70)': 'Protected event (NIP-70)',
'Protected': 'Protected'
}
}

View file

@ -688,6 +688,8 @@ export default {
'Copy note content': 'Copiar contenido de la nota',
'Video loop': 'Repetir video',
'Automatically replay videos when they end': 'Reproducir automáticamente los videos cuando terminen',
'Relays used for searching notes (NIP-50)': 'Relés utilizados para buscar notas (NIP-50)'
'Relays used for searching notes (NIP-50)': 'Relés utilizados para buscar notas (NIP-50)',
'Protected event (NIP-70)': 'Evento protegido (NIP-70)',
'Protected': 'Protegido'
}
}

View file

@ -683,6 +683,8 @@ export default {
'Copy note content': 'کپی محتوای یادداشت',
'Video loop': 'تکرار ویدیو',
'Automatically replay videos when they end': 'پخش خودکار ویدیوها پس از پایان',
'Relays used for searching notes (NIP-50)': 'رله‌هایی که برای جستجوی یادداشت‌ها استفاده می‌شوند (NIP-50)'
'Relays used for searching notes (NIP-50)': 'رله‌هایی که برای جستجوی یادداشت‌ها استفاده می‌شوند (NIP-50)',
'Protected event (NIP-70)': 'رویداد محافظت‌شده (NIP-70)',
'Protected': 'محافظت‌شده'
}
}

View file

@ -692,6 +692,8 @@ export default {
'Copy note content': 'Copier le contenu de la note',
'Video loop': 'Boucle vidéo',
'Automatically replay videos when they end': 'Rejouer automatiquement les vidéos à la fin',
'Relays used for searching notes (NIP-50)': 'Relais utilisés pour rechercher des notes (NIP-50)'
'Relays used for searching notes (NIP-50)': 'Relais utilisés pour rechercher des notes (NIP-50)',
'Protected event (NIP-70)': 'Événement protégé (NIP-70)',
'Protected': 'Protégé'
}
}

View file

@ -683,6 +683,8 @@ export default {
'Copy note content': 'नोट सामग्री कॉपी करें',
'Video loop': 'वीडियो लूप',
'Automatically replay videos when they end': 'वीडियो समाप्त होने पर स्वचालित रूप से दोबारा चलाएं',
'Relays used for searching notes (NIP-50)': 'नोट्स खोजने के लिए उपयोग किए जाने वाले रिले (NIP-50)'
'Relays used for searching notes (NIP-50)': 'नोट्स खोजने के लिए उपयोग किए जाने वाले रिले (NIP-50)',
'Protected event (NIP-70)': 'संरक्षित इवेंट (NIP-70)',
'Protected': 'संरक्षित'
}
}

View file

@ -677,6 +677,8 @@ export default {
'Copy note content': 'Jegyzet tartalmának másolása',
'Video loop': 'Videó ismétlése',
'Automatically replay videos when they end': 'Videók automatikus újrajátszása, amikor véget érnek',
'Relays used for searching notes (NIP-50)': 'Jegyzetek kereséséhez használt csomópontok (NIP-50)'
'Relays used for searching notes (NIP-50)': 'Jegyzetek kereséséhez használt csomópontok (NIP-50)',
'Protected event (NIP-70)': 'Védett esemény (NIP-70)',
'Protected': 'Védett'
}
}

View file

@ -688,6 +688,8 @@ export default {
'Copy note content': 'Copia contenuto della nota',
'Video loop': 'Ripetizione video',
'Automatically replay videos when they end': 'Riprodurre automaticamente i video quando terminano',
'Relays used for searching notes (NIP-50)': 'Relay utilizzati per cercare le note (NIP-50)'
'Relays used for searching notes (NIP-50)': 'Relay utilizzati per cercare le note (NIP-50)',
'Protected event (NIP-70)': 'Evento protetto (NIP-70)',
'Protected': 'Protetto'
}
}

View file

@ -683,6 +683,8 @@ export default {
'Copy note content': 'ノート内容をコピー',
'Video loop': 'ビデオループ',
'Automatically replay videos when they end': 'ビデオ終了時に自動的にリプレイする',
'Relays used for searching notes (NIP-50)': 'ノート検索に使用するリレー (NIP-50)'
'Relays used for searching notes (NIP-50)': 'ノート検索に使用するリレー (NIP-50)',
'Protected event (NIP-70)': '保護されたイベント (NIP-70)',
'Protected': '保護'
}
}

View file

@ -677,6 +677,8 @@ export default {
'Copy note content': '노트 내용 복사',
'Video loop': '비디오 반복',
'Automatically replay videos when they end': '비디오가 끝나면 자동으로 다시 재생',
'Relays used for searching notes (NIP-50)': '노트 검색에 사용되는 릴레이 (NIP-50)'
'Relays used for searching notes (NIP-50)': '노트 검색에 사용되는 릴레이 (NIP-50)',
'Protected event (NIP-70)': '보호된 이벤트 (NIP-70)',
'Protected': '보호됨'
}
}

View file

@ -689,6 +689,8 @@ export default {
'Copy note content': 'Kopiuj treść notatki',
'Video loop': 'Zapętlanie wideo',
'Automatically replay videos when they end': 'Automatycznie powtarzaj filmy po zakończeniu',
'Relays used for searching notes (NIP-50)': 'Przekaźniki używane do wyszukiwania notatek (NIP-50)'
'Relays used for searching notes (NIP-50)': 'Przekaźniki używane do wyszukiwania notatek (NIP-50)',
'Protected event (NIP-70)': 'Chronione zdarzenie (NIP-70)',
'Protected': 'Chronione'
}
}

View file

@ -686,6 +686,8 @@ export default {
'Copy note content': 'Copiar conteúdo da nota',
'Video loop': 'Repetir vídeo',
'Automatically replay videos when they end': 'Reproduzir automaticamente os vídeos quando terminarem',
'Relays used for searching notes (NIP-50)': 'Relays usados para buscar notas (NIP-50)'
'Relays used for searching notes (NIP-50)': 'Relays usados para buscar notas (NIP-50)',
'Protected event (NIP-70)': 'Evento protegido (NIP-70)',
'Protected': 'Protegido'
}
}

View file

@ -689,6 +689,8 @@ export default {
'Copy note content': 'Copiar conteúdo da nota',
'Video loop': 'Repetir vídeo',
'Automatically replay videos when they end': 'Reproduzir automaticamente os vídeos quando terminarem',
'Relays used for searching notes (NIP-50)': 'Relés usados para pesquisar notas (NIP-50)'
'Relays used for searching notes (NIP-50)': 'Relés usados para pesquisar notas (NIP-50)',
'Protected event (NIP-70)': 'Evento protegido (NIP-70)',
'Protected': 'Protegido'
}
}

View file

@ -688,6 +688,8 @@ export default {
'Copy note content': 'Скопировать содержимое заметки',
'Video loop': 'Зацикливание видео',
'Automatically replay videos when they end': 'Автоматически воспроизводить видео заново после окончания',
'Relays used for searching notes (NIP-50)': 'Ретрансляторы для поиска заметок (NIP-50)'
'Relays used for searching notes (NIP-50)': 'Ретрансляторы для поиска заметок (NIP-50)',
'Protected event (NIP-70)': 'Защищённое событие (NIP-70)',
'Protected': 'Защищённый'
}
}

View file

@ -673,6 +673,8 @@ export default {
'Copy note content': 'คัดลอกเนื้อหาโน้ต',
'Video loop': 'เล่นวิดีโอซ้ำ',
'Automatically replay videos when they end': 'เล่นวิดีโอซ้ำอัตโนมัติเมื่อจบ',
'Relays used for searching notes (NIP-50)': 'รีเลย์ที่ใช้สำหรับค้นหาโน้ต (NIP-50)'
'Relays used for searching notes (NIP-50)': 'รีเลย์ที่ใช้สำหรับค้นหาโน้ต (NIP-50)',
'Protected event (NIP-70)': 'เหตุการณ์ที่ได้รับการป้องกัน (NIP-70)',
'Protected': 'ป้องกัน'
}
}

View file

@ -655,6 +655,8 @@ export default {
'Copy note content': '複製筆記內容',
'Video loop': '影片循環',
'Automatically replay videos when they end': '影片播放結束後自動重新播放',
'Relays used for searching notes (NIP-50)': '用於搜尋筆記的伺服器 (NIP-50)'
'Relays used for searching notes (NIP-50)': '用於搜尋筆記的伺服器 (NIP-50)',
'Protected event (NIP-70)': '受保護的事件 (NIP-70)',
'Protected': '受保護'
}
}

View file

@ -660,6 +660,8 @@ export default {
'Copy note content': '复制笔记内容',
'Video loop': '视频循环',
'Automatically replay videos when they end': '视频播放结束后自动重新播放',
'Relays used for searching notes (NIP-50)': '用于搜索笔记的服务器 (NIP-50)'
'Relays used for searching notes (NIP-50)': '用于搜索笔记的服务器 (NIP-50)',
'Protected event (NIP-70)': '受保护的事件 (NIP-70)',
'Protected': '受保护'
}
}