From 5251d9992389fdb576d5bce3548489325d591313 Mon Sep 17 00:00:00 2001
From: Sylfr Serenity Tan <98162476+NekoDrone@users.noreply.github.com>
Date: Thu, 8 May 2025 06:21:13 +0800
Subject: [PATCH] feat: link to website for handles (#43)
---
src/screens/Profile/Header/Handle.tsx | 22 +++++++--
src/screens/Settings/DeerSettings.tsx | 22 +++++++++
src/state/persisted/schema.ts | 2 +
src/state/preferences/index.tsx | 49 ++++++++++---------
src/state/preferences/show-link-in-handle.tsx | 47 ++++++++++++++++++
5 files changed, 116 insertions(+), 26 deletions(-)
create mode 100644 src/state/preferences/show-link-in-handle.tsx
diff --git a/src/screens/Profile/Header/Handle.tsx b/src/screens/Profile/Header/Handle.tsx
index 27b73da70..6b9686de5 100644
--- a/src/screens/Profile/Header/Handle.tsx
+++ b/src/screens/Profile/Header/Handle.tsx
@@ -1,12 +1,14 @@
import {View} from 'react-native'
-import {AppBskyActorDefs} from '@atproto/api'
+import {type AppBskyActorDefs} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {isInvalidHandle} from '#/lib/strings/handles'
import {isIOS} from '#/platform/detection'
-import {Shadow} from '#/state/cache/types'
+import {type Shadow} from '#/state/cache/types'
+import {useShowLinkInHandle} from '#/state/preferences/show-link-in-handle.tsx'
import {atoms as a, useTheme, web} from '#/alf'
+import {InlineLinkText} from '#/components/Link.tsx'
import {NewskieDialog} from '#/components/NewskieDialog'
import {Text} from '#/components/Typography'
@@ -21,6 +23,8 @@ export function ProfileHeaderHandle({
const {_} = useLingui()
const invalidHandle = isInvalidHandle(profile.handle)
const blockHide = profile.viewer?.blocking || profile.viewer?.blockedBy
+ const isBskySocialHandle = profile.handle.endsWith('.bsky.social')
+ const showProfileInHandle = useShowLinkInHandle()
return (
- {invalidHandle ? _(msg`⚠Invalid Handle`) : `@${profile.handle}`}
+ {invalidHandle ? (
+ _(msg`⚠Invalid Handle`)
+ ) : showProfileInHandle && !isBskySocialHandle ? (
+
+
+ @{profile.handle}
+
+
+ ) : (
+ `@${profile.handle}`
+ )}
)
diff --git a/src/screens/Settings/DeerSettings.tsx b/src/screens/Settings/DeerSettings.tsx
index c3f9a11ed..f04cb5955 100644
--- a/src/screens/Settings/DeerSettings.tsx
+++ b/src/screens/Settings/DeerSettings.tsx
@@ -51,6 +51,10 @@ import {
useRepostCarouselEnabled,
useSetRepostCarouselEnabled,
} from '#/state/preferences/repost-carousel-enabled'
+import {
+ useSetShowLinkInHandle,
+ useShowLinkInHandle,
+} from '#/state/preferences/show-link-in-handle.tsx'
import {useProfilesQuery} from '#/state/queries/profile'
import * as SettingsList from '#/screens/Settings/components/SettingsList'
import {atoms as a, useBreakpoints} from '#/alf'
@@ -271,6 +275,9 @@ export function DeerSettingsScreen({}: Props) {
const repostCarouselEnabled = useRepostCarouselEnabled()
const setRepostCarouselEnabled = useSetRepostCarouselEnabled()
+ const showLinkInHandle = useShowLinkInHandle()
+ const setShowLinkInHandle = useSetShowLinkInHandle()
+
const [gates, setGatesView] = useState(Object.fromEntries(useGatesCache()))
const dangerousSetGate = useDangerousSetGate()
const setGate = (gate: Gate, value: boolean) => {
@@ -499,6 +506,21 @@ export function DeerSettingsScreen({}: Props) {
+ setShowLinkInHandle(value)}
+ style={[a.w_full]}>
+
+
+ On non-bsky.social handles, show a link to that URL
+
+
+
+
diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts
index 1f00cd69a..df03cfd73 100644
--- a/src/state/persisted/schema.ts
+++ b/src/state/persisted/schema.ts
@@ -133,6 +133,7 @@ const schema = z.object({
repostCarouselEnabled: z.boolean().optional(),
hideFollowNotifications: z.boolean().optional(),
constellationInstance: z.string().optional(),
+ showLinkInHandle: z.boolean().optional(),
deerVerification: z
.object({
enabled: z.boolean(),
@@ -201,6 +202,7 @@ export const defaults: Schema = {
repostCarouselEnabled: false,
hideFollowNotifications: false,
constellationInstance: 'https://constellation.microcosm.blue/',
+ showLinkInHandle: false,
deerVerification: {
enabled: false,
// https://deer.social/profile/did:plc:p2cp5gopk7mgjegy6wadk3ep/post/3lndyqyyr4k2k
diff --git a/src/state/preferences/index.tsx b/src/state/preferences/index.tsx
index decafd964..f7a00d62e 100644
--- a/src/state/preferences/index.tsx
+++ b/src/state/preferences/index.tsx
@@ -18,6 +18,7 @@ import {Provider as LargeAltBadgeProvider} from './large-alt-badge'
import {Provider as NoAppLabelersProvider} from './no-app-labelers'
import {Provider as NoDiscoverProvider} from './no-discover-fallback'
import {Provider as RepostCarouselProvider} from './repost-carousel-enabled'
+import {Provider as ShowLinkInHandleProvider} from './show-link-in-handle'
import {Provider as SubtitlesProvider} from './subtitles'
import {Provider as TrendingSettingsProvider} from './trending'
import {Provider as UsedStarterPacksProvider} from './used-starter-packs'
@@ -50,29 +51,31 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
-
-
-
-
-
-
-
-
-
-
-
- {children}
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/state/preferences/show-link-in-handle.tsx b/src/state/preferences/show-link-in-handle.tsx
new file mode 100644
index 000000000..74cbd130f
--- /dev/null
+++ b/src/state/preferences/show-link-in-handle.tsx
@@ -0,0 +1,47 @@
+import React from 'react'
+
+import * as persisted from '#/state/persisted'
+
+type StateContext = persisted.Schema['showLinkInHandle']
+type SetContext = (v: persisted.Schema['showLinkInHandle']) => void
+
+const stateContext = React.createContext(
+ persisted.defaults.showLinkInHandle,
+)
+const setContext = React.createContext(
+ (_: persisted.Schema['showLinkInHandle']) => {},
+)
+
+export function Provider({children}: React.PropsWithChildren<{}>) {
+ const [state, setState] = React.useState(persisted.get('showLinkInHandle'))
+
+ const setStateWrapped = React.useCallback(
+ (showLinkInHandle: persisted.Schema['showLinkInHandle']) => {
+ setState(showLinkInHandle)
+ persisted.write('showLinkInHandle', showLinkInHandle)
+ },
+ [setState],
+ )
+
+ React.useEffect(() => {
+ return persisted.onUpdate('showLinkInHandle', nextShowLinkInHandle => {
+ setState(nextShowLinkInHandle)
+ })
+ }, [setStateWrapped])
+
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+export function useShowLinkInHandle() {
+ return React.useContext(stateContext)
+}
+
+export function useSetShowLinkInHandle() {
+ return React.useContext(setContext)
+}
--
2.51.2