diff --git a/src/components/status-action-bar.tsx b/src/components/status-action-bar.tsx index edfa10396..4f2f0856f 100644 --- a/src/components/status-action-bar.tsx +++ b/src/components/status-action-bar.tsx @@ -464,11 +464,13 @@ const StatusActionBar: React.FC = ({ } if (features.federating && !account.local) { - const { hostname: domain } = new URL(status.uri); + const externalNostrUrl: string | undefined = status.ditto?.get('external_url'); + const { hostname: domain } = new URL(externalNostrUrl || status.uri); + menu.push({ text: intl.formatMessage(messages.external, { domain }), icon: require('@tabler/icons/outline/external-link.svg'), - href: status.uri, + href: externalNostrUrl || status.uri, target: '_blank', }); } diff --git a/src/features/account/components/header.tsx b/src/features/account/components/header.tsx index be74a5b65..786ce40c9 100644 --- a/src/features/account/components/header.tsx +++ b/src/features/account/components/header.tsx @@ -311,14 +311,19 @@ const Header: React.FC = ({ account }) => { }); } - if (features.federating && !account.local) { - const domain = account.fqn.split('@')[1]; + const externalNostrUrl = account.ditto.external_url ? new URL(account.ditto.external_url).host : undefined; + if (features.federating && (!account.local || externalNostrUrl)) { + const domain = externalNostrUrl || account.fqn.split('@')[1]; + const url = account.ditto.external_url || account.url; - menu.push({ - text: intl.formatMessage(messages.profileExternal, { domain }), - action: () => onProfileExternal(account.url), - icon: require('@tabler/icons/outline/external-link.svg'), - }); + if (domain && url) { + menu.push({ + text: intl.formatMessage(messages.profileExternal, { domain }), + action: () => onProfileExternal(url), + icon: require('@tabler/icons/outline/external-link.svg'), + href: url, + }); + } } menu.push({ diff --git a/src/normalizers/status.ts b/src/normalizers/status.ts index 1797feb2e..093069f4c 100644 --- a/src/normalizers/status.ts +++ b/src/normalizers/status.ts @@ -67,6 +67,7 @@ export const StatusRecord = ImmutableRecord({ muted: false, pinned: false, pleroma: ImmutableMap(), + ditto: ImmutableMap(), poll: null as EmbeddedEntity, quote: null as EmbeddedEntity, quotes_count: 0, diff --git a/src/schemas/account.ts b/src/schemas/account.ts index 966e03ef0..15ebc821e 100644 --- a/src/schemas/account.ts +++ b/src/schemas/account.ts @@ -43,6 +43,7 @@ const baseAccountSchema = z.object({ ditto: coerceObject({ accepts_zaps: z.boolean().catch(false), is_registered: z.boolean().catch(false), + external_url: z.string().optional().catch(undefined), }), emojis: filteredArray(customEmojiSchema), fields: filteredArray(fieldSchema), diff --git a/src/schemas/status.ts b/src/schemas/status.ts index 865b3a02e..7d41837f5 100644 --- a/src/schemas/status.ts +++ b/src/schemas/status.ts @@ -24,6 +24,10 @@ const statusPleromaSchema = z.object({ quote_visible: z.boolean().catch(true), }); +const statusDittoSchema = z.object({ + external_url: z.string().optional().catch(undefined), +}); + const baseStatusSchema = z.object({ account: accountSchema, application: z.object({ @@ -51,6 +55,7 @@ const baseStatusSchema = z.object({ muted: z.coerce.boolean(), pinned: z.coerce.boolean(), pleroma: statusPleromaSchema.optional().catch(undefined), + ditto: statusDittoSchema.optional().catch(undefined), reactions: filteredArray(emojiReactionSchema), poll: pollSchema.nullable().catch(null), quote: z.literal(null).catch(null), @@ -152,4 +157,4 @@ const statusSchema = baseStatusSchema.extend({ type Status = Resolve>; -export { statusSchema, type Status }; \ No newline at end of file +export { statusSchema, type Status };