feat: add website field to profile editor

This commit is contained in:
codytseng
2025-07-01 22:17:44 +08:00
parent 78f2011d23
commit f8572d0795
14 changed files with 55 additions and 24 deletions

View File

@@ -278,6 +278,7 @@ export default {
'No pubkeys found from {url}': 'لم يتم العثور على مفاتيح عامة من {{url}}', 'No pubkeys found from {url}': 'لم يتم العثور على مفاتيح عامة من {{url}}',
'Translating...': 'جارٍ الترجمة...', 'Translating...': 'جارٍ الترجمة...',
Translate: 'ترجمة', Translate: 'ترجمة',
'Show original': 'عرض الأصل' 'Show original': 'عرض الأصل',
Website: 'الموقع الإلكتروني'
} }
} }

View File

@@ -285,6 +285,7 @@ export default {
'No pubkeys found from {url}': 'Keine Pubkeys von {{url}} gefunden', 'No pubkeys found from {url}': 'Keine Pubkeys von {{url}} gefunden',
'Translating...': 'Übersetze...', 'Translating...': 'Übersetze...',
Translate: 'Übersetzen', Translate: 'Übersetzen',
'Show original': 'Original anzeigen' 'Show original': 'Original anzeigen',
Website: 'Website'
} }
} }

View File

@@ -278,6 +278,7 @@ export default {
'No pubkeys found from {url}': 'No pubkeys found from {{url}}', 'No pubkeys found from {url}': 'No pubkeys found from {{url}}',
'Translating...': 'Translating...', 'Translating...': 'Translating...',
Translate: 'Translate', Translate: 'Translate',
'Show original': 'Show original' 'Show original': 'Show original',
Website: 'Website'
} }
} }

View File

@@ -283,6 +283,7 @@ export default {
'No pubkeys found from {url}': 'No se encontraron pubkeys desde {{url}}', 'No pubkeys found from {url}': 'No se encontraron pubkeys desde {{url}}',
'Translating...': 'Traduciendo...', 'Translating...': 'Traduciendo...',
Translate: 'Traducir', Translate: 'Traducir',
'Show original': 'Mostrar original' 'Show original': 'Mostrar original',
Website: 'Sitio web'
} }
} }

View File

@@ -283,6 +283,7 @@ export default {
'No pubkeys found from {url}': 'Aucun pubkey trouvé à partir de {{url}}', 'No pubkeys found from {url}': 'Aucun pubkey trouvé à partir de {{url}}',
'Translating...': 'Traduction en cours...', 'Translating...': 'Traduction en cours...',
Translate: 'Traduire', Translate: 'Traduire',
'Show original': 'Afficher loriginal' 'Show original': 'Afficher loriginal',
Website: 'Site Web'
} }
} }

View File

@@ -282,6 +282,7 @@ export default {
'No pubkeys found from {url}': 'Nessun pubkey trovato da {{url}}', 'No pubkeys found from {url}': 'Nessun pubkey trovato da {{url}}',
'Translating...': 'Traduzione in corso...', 'Translating...': 'Traduzione in corso...',
Translate: 'Traduci', Translate: 'Traduci',
'Show original': 'Mostra originale' 'Show original': 'Mostra originale',
Website: 'Sito web'
} }
} }

View File

@@ -280,6 +280,7 @@ export default {
'No pubkeys found from {url}': 'URL {{url}} からのpubkeyは見つかりませんでした', 'No pubkeys found from {url}': 'URL {{url}} からのpubkeyは見つかりませんでした',
'Translating...': '翻訳中...', 'Translating...': '翻訳中...',
Translate: '翻訳', Translate: '翻訳',
'Show original': '原文を表示' 'Show original': '原文を表示',
Website: 'ウェブサイト'
} }
} }

View File

@@ -281,6 +281,7 @@ export default {
'No pubkeys found from {url}': 'Nie znaleziono kluczy publicznych z {{url}}', 'No pubkeys found from {url}': 'Nie znaleziono kluczy publicznych z {{url}}',
'Translating...': 'Tłumaczenie...', 'Translating...': 'Tłumaczenie...',
Translate: 'Przetłumacz', Translate: 'Przetłumacz',
'Show original': 'Pokaż oryginał' 'Show original': 'Pokaż oryginał',
Website: 'Strona internetowa'
} }
} }

View File

@@ -281,6 +281,7 @@ export default {
'No pubkeys found from {url}': 'Nenhum pubkey encontrado em {{url}}', 'No pubkeys found from {url}': 'Nenhum pubkey encontrado em {{url}}',
'Translating...': 'Traduzindo...', 'Translating...': 'Traduzindo...',
Translate: 'Traduzir', Translate: 'Traduzir',
'Show original': 'Mostrar original' 'Show original': 'Mostrar original',
Website: 'Website'
} }
} }

View File

@@ -282,6 +282,7 @@ export default {
'No pubkeys found from {url}': 'Nenhum pubkey encontrado em {{url}}', 'No pubkeys found from {url}': 'Nenhum pubkey encontrado em {{url}}',
'Translating...': 'Traduzindo...', 'Translating...': 'Traduzindo...',
Translate: 'Traduzir', Translate: 'Traduzir',
'Show original': 'Mostrar original' 'Show original': 'Mostrar original',
Website: 'Website'
} }
} }

View File

@@ -283,6 +283,7 @@ export default {
'No pubkeys found from {url}': 'Не найдено pubkeys из {{url}}', 'No pubkeys found from {url}': 'Не найдено pubkeys из {{url}}',
'Translating...': 'Перевод...', 'Translating...': 'Перевод...',
Translate: 'Перевести', Translate: 'Перевести',
'Show original': 'Показать оригинал' 'Show original': 'Показать оригинал',
Website: 'Веб-сайт'
} }
} }

View File

@@ -277,6 +277,7 @@ export default {
'No pubkeys found from {url}': 'ไม่พบ pubkeys จาก {{url}}', 'No pubkeys found from {url}': 'ไม่พบ pubkeys จาก {{url}}',
'Translating...': 'กำลังแปล...', 'Translating...': 'กำลังแปล...',
Translate: 'แปล', Translate: 'แปล',
'Show original': 'แสดงต้นฉบับ' 'Show original': 'แสดงต้นฉบับ',
Website: 'เว็บไซต์'
} }
} }

View File

@@ -278,6 +278,7 @@ export default {
'No pubkeys found from {url}': '在 {{url}} 中未找到 pubkeys', 'No pubkeys found from {url}': '在 {{url}} 中未找到 pubkeys',
'Translating...': '翻译中...', 'Translating...': '翻译中...',
Translate: '翻译', Translate: '翻译',
'Show original': '显示原文' 'Show original': '显示原文',
Website: '网站'
} }
} }

View File

@@ -3,6 +3,7 @@ import ProfileBanner from '@/components/ProfileBanner'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Textarea } from '@/components/ui/textarea' import { Textarea } from '@/components/ui/textarea'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { isEmail } from '@/lib/common' import { isEmail } from '@/lib/common'
@@ -22,6 +23,7 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
const [avatar, setAvatar] = useState<string>('') const [avatar, setAvatar] = useState<string>('')
const [username, setUsername] = useState<string>('') const [username, setUsername] = useState<string>('')
const [about, setAbout] = useState<string>('') const [about, setAbout] = useState<string>('')
const [website, setWebsite] = useState<string>('')
const [nip05, setNip05] = useState<string>('') const [nip05, setNip05] = useState<string>('')
const [nip05Error, setNip05Error] = useState<string>('') const [nip05Error, setNip05Error] = useState<string>('')
const [lightningAddress, setLightningAddress] = useState<string>('') const [lightningAddress, setLightningAddress] = useState<string>('')
@@ -41,6 +43,7 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
setAvatar(profile.avatar ?? '') setAvatar(profile.avatar ?? '')
setUsername(profile.original_username ?? '') setUsername(profile.original_username ?? '')
setAbout(profile.about ?? '') setAbout(profile.about ?? '')
setWebsite(profile.website ?? '')
setNip05(profile.nip05 ?? '') setNip05(profile.nip05 ?? '')
setLightningAddress(profile.lightningAddress || '') setLightningAddress(profile.lightningAddress || '')
} else { } else {
@@ -48,6 +51,7 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
setAvatar('') setAvatar('')
setUsername('') setUsername('')
setAbout('') setAbout('')
setWebsite('')
setNip05('') setNip05('')
setLightningAddress('') setLightningAddress('')
} }
@@ -83,6 +87,7 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
displayName: username, displayName: username,
name: oldProfileContent.name ?? username, name: oldProfileContent.name ?? username,
about, about,
website,
nip05, nip05,
banner, banner,
picture: avatar, picture: avatar,
@@ -129,7 +134,7 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
<ProfileBanner <ProfileBanner
banner={banner} banner={banner}
pubkey={account.pubkey} pubkey={account.pubkey}
className="w-full aspect-video object-cover rounded-lg" className="w-full aspect-[3/1] object-cover rounded-lg"
/> />
<div className="absolute top-0 bg-muted/30 w-full h-full rounded-lg flex flex-col justify-center items-center"> <div className="absolute top-0 bg-muted/30 w-full h-full rounded-lg flex flex-col justify-center items-center">
{uploadingBanner ? ( {uploadingBanner ? (
@@ -155,10 +160,11 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
</div> </div>
</Uploader> </Uploader>
</div> </div>
<div className="pt-14 space-y-4"> <div className="pt-14 flex flex-col gap-4">
<Item> <Item>
<ItemTitle>{t('Display Name')}</ItemTitle> <Label htmlFor="profile-username-input">{t('Display Name')}</Label>
<Input <Input
id="profile-username-input"
value={username} value={username}
onChange={(e) => { onChange={(e) => {
setUsername(e.target.value) setUsername(e.target.value)
@@ -167,8 +173,9 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
/> />
</Item> </Item>
<Item> <Item>
<ItemTitle>{t('Bio')}</ItemTitle> <Label htmlFor="profile-about-textarea">{t('Bio')}</Label>
<Textarea <Textarea
id="profile-about-textarea"
className="h-44" className="h-44"
value={about} value={about}
onChange={(e) => { onChange={(e) => {
@@ -178,8 +185,20 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
/> />
</Item> </Item>
<Item> <Item>
<ItemTitle>{t('Nostr Address (NIP-05)')}</ItemTitle> <Label htmlFor="profile-website-input">{t('Website')}</Label>
<Input <Input
id="profile-website-input"
value={website}
onChange={(e) => {
setWebsite(e.target.value)
setHasChanged(true)
}}
/>
</Item>
<Item>
<Label htmlFor="profile-nip05-input">{t('Nostr Address (NIP-05)')}</Label>
<Input
id="profile-nip05-input"
value={nip05} value={nip05}
onChange={(e) => { onChange={(e) => {
setNip05Error('') setNip05Error('')
@@ -191,8 +210,11 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
{nip05Error && <div className="text-xs text-destructive pl-3">{nip05Error}</div>} {nip05Error && <div className="text-xs text-destructive pl-3">{nip05Error}</div>}
</Item> </Item>
<Item> <Item>
<ItemTitle>{t('Lightning Address (or LNURL)')}</ItemTitle> <Label htmlFor="profile-lightning-address-input">
{t('Lightning Address (or LNURL)')}
</Label>
<Input <Input
id="profile-lightning-address-input"
value={lightningAddress} value={lightningAddress}
onChange={(e) => { onChange={(e) => {
setLightningAddressError('') setLightningAddressError('')
@@ -213,10 +235,6 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
ProfileEditorPage.displayName = 'ProfileEditorPage' ProfileEditorPage.displayName = 'ProfileEditorPage'
export default ProfileEditorPage export default ProfileEditorPage
function ItemTitle({ children }: { children: React.ReactNode }) {
return <div className="text-sm font-semibold text-muted-foreground">{children}</div>
}
function Item({ children }: { children: React.ReactNode }) { function Item({ children }: { children: React.ReactNode }) {
return <div className="space-y-1">{children}</div> return <div className="grid gap-2">{children}</div>
} }