Skip to content

Commit 3fc2d9e

Browse files
committed
feat: mf-6673 lens v3 follow/unfollow
1 parent 7123622 commit 3fc2d9e

30 files changed

+1070
-1586
lines changed

eslint.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,12 @@ const codeStyleRules = {
447447
// 'unicorn/no-unused-properties': 'warn',
448448
// '@typescript-eslint/no-unused-expressions': 'warn',
449449
// '@typescript-eslint/no-unused-vars': 'warn',
450+
'react-hooks/exhaustive-deps': [
451+
'warn',
452+
{
453+
additionalHooks: '(useAsync|useAsyncFn)\\b',
454+
},
455+
],
450456
}
451457
const moduleSystemRules = {
452458
'@typescript-eslint/no-restricted-imports': [

packages/mask/shared-ui/initialization/fetch.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const { fetch: original_fetch } = globalThis
88
function contentFetch(input: RequestInfo | URL, init?: RequestInit) {
99
const request = new Request(input, init)
1010

11-
if (canAccessAsContent(request.url)) {
11+
if (shouldAccessViaContent(request.url)) {
1212
if (
1313
navigator.userAgent.includes('Firefox') &&
1414
browser.runtime.getManifest().manifest_version === 2 &&
@@ -48,14 +48,15 @@ function fetchingTwitterResource(target: URL) {
4848

4949
function fetchingInsResource(target: URL) {
5050
// cspell:disable-next-line
51-
return location.origin.endsWith('instagram.com') && target.origin.match(/(fbcdn\.net|cdninstagram\.com)$/)
51+
if (location.origin.endsWith('instagram.com') && target.origin.match(/(fbcdn\.net|cdninstagram\.com)$/)) return true
52+
return target.host === 'api.lens.xyz'
5253
}
5354

5455
function fetchingGoogleDriveResource(target: URL) {
5556
return target.origin === 'https://www.googleapis.com'
5657
}
5758

58-
function canAccessAsContent(url: string) {
59+
function shouldAccessViaContent(url: string) {
5960
const target = new URL(url, location.href)
6061
if (fetchingTwitterResource(target) || fetchingInsResource(target) || fetchingGoogleDriveResource(target))
6162
return true

packages/plugins/Web3Profile/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
}
1717
},
1818
"dependencies": {
19+
"@lens-protocol/client": "0.0.0-canary-20250408064617",
1920
"@masknet/icons": "workspace:^",
2021
"@masknet/plugin-infra": "workspace:^",
2122
"@masknet/shared": "workspace:^",

packages/plugins/Web3Profile/src/SiteAdaptor/Web3ProfileGlobalInjection.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@ export const Web3ProfileGlobalInjection = memo(function Web3ProfileGlobalInjecti
1919
const { open: lensOpen, closeDialog: closeLensDialog } = useRemoteControlledDialog(
2020
CrossIsolationMessages.events.followLensDialogEvent,
2121
(ev) => {
22-
if (!ev.open) {
23-
setHandle('')
24-
}
25-
setHandle(ev.handle)
22+
setHandle(ev.open ? ev.handle : '')
2623
},
2724
)
2825

packages/plugins/Web3Profile/src/SiteAdaptor/components/Lens/FollowLensDialog.tsx

Lines changed: 109 additions & 241 deletions
Large diffs are not rendered by default.

packages/plugins/Web3Profile/src/SiteAdaptor/components/Lens/HandlerDescription.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Account, AccountAvailable } from '@lens-protocol/client'
12
import { Trans } from '@lingui/react/macro'
23
import { Icons } from '@masknet/icons'
34
import { SelectProviderModal, WalletIcon } from '@masknet/shared'
@@ -11,11 +12,10 @@ import {
1112
useWallet,
1213
useWeb3Utils,
1314
} from '@masknet/web3-hooks-base'
14-
import type { LensBaseAPI } from '@masknet/web3-providers/types'
1515
import { ChainId, ProviderType } from '@masknet/web3-shared-evm'
1616
import { Box, Button, Typography } from '@mui/material'
1717
import { memo, useMemo, useState } from 'react'
18-
import { getProfileAvatar } from '../../../utils.js'
18+
import { getAccountAvatar } from '../../../utils.js'
1919
import { ProfilePopup } from '../ProfilePopup.js'
2020

2121
const useStyles = makeStyles()((theme) => ({
@@ -54,14 +54,14 @@ const useStyles = makeStyles()((theme) => ({
5454
}))
5555

5656
interface HandlerDescriptionProps extends withClasses<'container'> {
57-
currentProfile?: LensBaseAPI.Profile
58-
profiles?: LensBaseAPI.Profile[]
59-
onChange: (profile: LensBaseAPI.Profile) => void
57+
currentAccount?: Account
58+
accounts?: AccountAvailable[]
59+
onChange: (profile: Account) => void
6060
}
6161

6262
export const HandlerDescription = memo<HandlerDescriptionProps>(function HandlerDescription({
63-
profiles,
64-
currentProfile,
63+
accounts,
64+
currentAccount,
6565
onChange,
6666
...props
6767
}) {
@@ -80,9 +80,9 @@ export const HandlerDescription = memo<HandlerDescriptionProps>(function Handler
8080
if (domain) return domain
8181
if (providerType === ProviderType.MaskWallet && wallet?.name) return wallet?.name
8282
return providerDescriptor?.name
83-
}, [account, domain, providerType, wallet?.name, providerDescriptor?.name])
83+
}, [domain, providerType, wallet?.name, providerDescriptor?.name])
8484

85-
if (!profiles?.length || !currentProfile) {
85+
if (!accounts?.length || !currentAccount) {
8686
return (
8787
<Box className={classes.container}>
8888
<Box className={classes.description}>
@@ -105,8 +105,8 @@ export const HandlerDescription = memo<HandlerDescriptionProps>(function Handler
105105
</Box>
106106
)
107107
}
108-
const avatar = getProfileAvatar(currentProfile) || new URL('../../assets/Lens.png', import.meta.url).href
109-
const displayName = currentProfile.metadata?.displayName ?? currentProfile.handle.localName
108+
const avatar = getAccountAvatar(currentAccount) || new URL('../../assets/Lens.png', import.meta.url).href
109+
const displayName = currentAccount.metadata?.name ?? currentAccount.username?.localName
110110
return (
111111
<Box className={classes.container}>
112112
<Box className={classes.description}>
@@ -121,11 +121,11 @@ export const HandlerDescription = memo<HandlerDescriptionProps>(function Handler
121121
<Icons.ArrowDrop size={18} onClick={(e) => setAnchorEl(e.currentTarget)} />
122122
<ProfilePopup
123123
walletName={walletName}
124-
profiles={profiles}
124+
accounts={accounts}
125125
anchorEl={anchorEl}
126126
open={!!anchorEl}
127127
onClose={() => setAnchorEl(null)}
128-
currentProfile={currentProfile}
128+
currentAccount={currentAccount}
129129
onChange={onChange}
130130
/>
131131
</Box>

packages/plugins/Web3Profile/src/SiteAdaptor/components/ProfilePopup.tsx

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1+
import type { Account, AccountAvailable, EvmAddress } from '@lens-protocol/client'
12
import { Trans } from '@lingui/react/macro'
23
import { Icons } from '@masknet/icons'
34
import { Image, SelectProviderModal, WalletIcon } from '@masknet/shared'
45
import { NetworkPluginID } from '@masknet/shared-base'
56
import { makeStyles, usePortalShadowRoot } from '@masknet/theme'
67
import { useChainContext, useProviderDescriptor, useWeb3Utils } from '@masknet/web3-hooks-base'
7-
import type { LensBaseAPI } from '@masknet/web3-providers/types'
8-
import { isSameAddress } from '@masknet/web3-shared-base'
98
import { ChainId, formatEthereumAddress } from '@masknet/web3-shared-evm'
109
import {
1110
Box,
@@ -20,7 +19,7 @@ import {
2019
Typography,
2120
} from '@mui/material'
2221
import { memo } from 'react'
23-
import { getProfileAvatar } from '../../utils.js'
22+
import { getAccountAvatar } from '../../utils.js'
2423

2524
const useStyles = makeStyles()((theme) => ({
2625
paper: {
@@ -38,6 +37,7 @@ const useStyles = makeStyles()((theme) => ({
3837
},
3938
avatar: {
4039
borderRadius: 99,
40+
overflow: 'hidden',
4141
},
4242
primary: {
4343
color: theme.palette.maskColor.main,
@@ -81,6 +81,7 @@ const useStyles = makeStyles()((theme) => ({
8181
maxHeight: 200,
8282
overflow: 'auto',
8383
marginBottom: theme.spacing(1.5),
84+
scrollbarWidth: 'none',
8485
'::-webkit-scrollbar': {
8586
backgroundColor: 'transparent',
8687
width: 18,
@@ -113,29 +114,28 @@ const useStyles = makeStyles()((theme) => ({
113114
interface ProfilePopupProps {
114115
anchorEl: HTMLElement | null
115116
open: boolean
116-
profiles: LensBaseAPI.Profile[]
117+
accounts: AccountAvailable[]
117118
onClose: () => void
118-
onChange: (profile: LensBaseAPI.Profile) => void
119-
currentProfile: LensBaseAPI.Profile
119+
onChange: (profile: Account) => void
120+
currentAccount: Account
120121
walletName?: string
121122
}
122123

123124
export const ProfilePopup = memo<ProfilePopupProps>(function ProfilePopup({
124125
anchorEl,
125126
open,
126-
profiles,
127+
accounts: availableAccounts,
127128
onClose,
128-
currentProfile,
129+
currentAccount,
129130
onChange,
130131
walletName,
131132
}) {
132-
const Utils = useWeb3Utils()
133-
134133
const { classes } = useStyles()
134+
const Utils = useWeb3Utils()
135135

136-
const { account } = useChainContext()
137-
136+
const { account: walletAddress } = useChainContext()
138137
const providerDescriptor = useProviderDescriptor()
138+
const currentAccountId = currentAccount.username?.id
139139

140140
return usePortalShadowRoot((container) => (
141141
<Popover
@@ -155,20 +155,24 @@ export const ProfilePopup = memo<ProfilePopupProps>(function ProfilePopup({
155155
horizontal: 'right',
156156
}}>
157157
<List disablePadding className={classes.list}>
158-
{profiles.map((profile) => {
159-
const avatar = getProfileAvatar(profile)
158+
{availableAccounts.map((available) => {
159+
const account = available.account
160+
const avatar = getAccountAvatar(account)
161+
const name = account.metadata?.name || account.username?.localName
162+
const ownerAddress: EvmAddress = account.username?.ownedBy
163+
const accountId = account.username?.id
160164
return (
161165
<ListItemButton
162166
className={classes.item}
163-
key={profile.id}
167+
key={accountId}
164168
onClick={() => {
165-
if (currentProfile.id === profile.id) return
166-
onChange(profile)
169+
if (currentAccountId && currentAccountId === accountId) return
170+
onChange(account)
167171
}}>
168172
<ListItemIcon>
169173
{avatar ?
170174
<Image
171-
className={classes.avatar}
175+
rounded
172176
size={36}
173177
src={avatar}
174178
fallback={<Icons.DarkLens size={36} className={classes.avatar} />}
@@ -177,13 +181,14 @@ export const ProfilePopup = memo<ProfilePopupProps>(function ProfilePopup({
177181
</ListItemIcon>
178182
<ListItemText
179183
classes={{ primary: classes.primary, root: classes.listItemText }}
180-
primary={profile.metadata?.displayName ?? profile.handle?.localName}
184+
primary={name}
185+
secondaryTypographyProps={{ component: 'div' }}
181186
secondary={
182187
<div className={classes.second}>
183188
<Typography component="div" className={classes.address}>
184-
{formatEthereumAddress(profile.ownedBy.address, 4)}
189+
{formatEthereumAddress(ownerAddress, 4)}
185190
</Typography>
186-
{!isSameAddress(profile.ownedBy.address, account) ?
191+
{available.__typename === 'AccountManaged' ?
187192
<Typography component="span" className={classes.managedTag}>
188193
Managed
189194
</Typography>
@@ -192,7 +197,7 @@ export const ProfilePopup = memo<ProfilePopupProps>(function ProfilePopup({
192197
}
193198
/>
194199
<ListItemSecondaryAction>
195-
<Radio checked={currentProfile.id === profile.id} />
200+
<Radio checked={currentAccountId === accountId} />
196201
</ListItemSecondaryAction>
197202
</ListItemButton>
198203
)
@@ -203,7 +208,7 @@ export const ProfilePopup = memo<ProfilePopupProps>(function ProfilePopup({
203208
<WalletIcon size={36} mainIcon={providerDescriptor?.icon} />
204209
<Box>
205210
<Typography className={classes.name}>{walletName}</Typography>
206-
<Typography className={classes.address}>{Utils.formatAddress(account, 4)}</Typography>
211+
<Typography className={classes.address}>{Utils.formatAddress(walletAddress, 4)}</Typography>
207212
</Box>
208213
</Box>
209214
<Button

packages/plugins/Web3Profile/src/SiteAdaptor/components/SocialBadges/Badges.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { memo, useRef, useEffect } from 'react'
2-
import { IconButton } from '@mui/material'
3-
import { makeStyles } from '@masknet/theme'
41
import { Icons } from '@masknet/icons'
52
import { Plugin } from '@masknet/plugin-infra'
3+
import { makeStyles } from '@masknet/theme'
64
import type { FireflyConfigAPI } from '@masknet/web3-providers/types'
5+
import { IconButton } from '@mui/material'
6+
import { memo, useEffect, useRef } from 'react'
77
import { closePopup, openPopup } from '../../emitter.js'
88

99
const BadgesIconSizeMap: Record<Plugin.SiteAdaptor.BadgesSlot, number> = {
@@ -77,7 +77,7 @@ export const SocialBadges = memo(function SocialBadges({ slot, lensAccounts, far
7777
hide()
7878
ob.disconnect()
7979
}
80-
// eslint-disable-next-line react-compiler/react-compiler
80+
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
8181
}, [buttonRef.current])
8282

8383
const size = BadgesIconSizeMap[slot]

0 commit comments

Comments
 (0)