Skip to content

Commit d13a052

Browse files
authored
feat: mf-6648 refine tag render (#12181)
* feat: mf-6648 refine tag render * refactor: depreate enhanceTag * feat: search joined name
1 parent 83ca2e9 commit d13a052

File tree

12 files changed

+251
-85
lines changed

12 files changed

+251
-85
lines changed

packages/mask/content-script/site-adaptors/twitter.com/customization/render-fragments.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { useActivatedPluginsSiteAdaptor } from '@masknet/plugin-infra/content-sc
22
import type { RenderFragmentsContextType } from '@masknet/typed-message-react'
33
import { Link } from '@mui/material'
44
import { memo } from 'react'
5-
import { useTagEnhancer } from '../../../../shared-ui/TypedMessageRender/Components/Text.js'
65

76
/**
87
* For images that are rendered at the end of the post (parsed by postImagesParser), hide it in the render fragment so it won't render twice.
@@ -11,23 +10,31 @@ export const IMAGE_RENDER_IGNORE = 'IMAGE_RENDER_IGNORE'
1110
export const TwitterRenderFragments: RenderFragmentsContextType = {
1211
AtLink: memo(function (props) {
1312
const target = '/' + props.children.slice(1)
14-
return <Link href={target} children={props.children} fontSize="inherit" />
13+
const link = <Link href={target} children={props.children} fontSize="inherit" />
14+
const MentionModifier = useActivatedPluginsSiteAdaptor(false).find((x) => x.MentionModifier)?.MentionModifier
15+
if (!MentionModifier) return link
16+
return <MentionModifier {...props} href={target} fallback={link} />
1517
}),
1618
HashLink: memo(function (props) {
1719
const text = props.children.slice(1)
1820
const target = `/hashtag/${encodeURIComponent(text)}?src=hashtag_click`
19-
const { hasMatch, ...events } = useTagEnhancer('hash', text)
20-
return (
21-
<Link {...events} href={target} fontSize="inherit">
21+
const link = (
22+
<Link href={target} fontSize="inherit">
2223
{props.children}
2324
{props.suggestedPostImage}
2425
</Link>
2526
)
27+
const TagModifier = useActivatedPluginsSiteAdaptor(false).find((x) => x.TagModifier)?.TagModifier
28+
if (!TagModifier) return link
29+
30+
return <TagModifier {...props} href={target} fallback={link} />
2631
}),
2732
CashLink: memo(function (props) {
2833
const target = `/search?q=${encodeURIComponent(props.children)}&src=cashtag_click`
29-
const { hasMatch, ...events } = useTagEnhancer('cash', props.children.slice(1))
30-
return <Link {...events} href={target} children={props.children} fontSize="inherit" />
34+
const link = <Link href={target} children={props.children} fontSize="inherit" />
35+
const TagModifier = useActivatedPluginsSiteAdaptor(false).find((x) => x.TagModifier)?.TagModifier
36+
if (!TagModifier) return link
37+
return <TagModifier {...props} href={target} fallback={link} />
3138
}),
3239
Image: memo(function ImageFragment(props: RenderFragmentsContextType.ImageProps) {
3340
return props.width === 0 || props.meta?.get(IMAGE_RENDER_IGNORE) ?

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,3 @@ const indexedDB: KVStorageBackend = {
2525
}
2626
setupMaskKVStorageBackend(indexedDB, memory)
2727
setupLegacySettingsAtNonBackground(Services.Settings.getLegacySettingsInitialValue)
28-
29-
indexedDB

packages/plugin-infra/src/types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,17 +265,31 @@ export namespace Plugin.SiteAdaptor {
265265
/** This UI will be rendered as plugin wrapper page */
266266
wrapperProps?: PluginWrapperProps
267267
/**
268+
* @deprecated use TagModifier instead.
268269
* A hook for if this plugin can enhance the #hash or $cash tag.
269270
*/
270271
enhanceTag?: {
271272
onClick?: (kind: 'cash' | 'hash', content: string, event: React.MouseEvent<HTMLAnchorElement>) => void
272273
onHover?: (kind: 'cash' | 'hash', content: string, event: React.MouseEvent<HTMLAnchorElement>) => () => void
273274
}
275+
/** Modifier for the #hash or $cash tag. */
276+
TagModifier?: React.ComponentType<{
277+
children: string
278+
style?: React.CSSProperties
279+
href: string
280+
fallback?: React.ReactNode
281+
}>
274282
TextModifier?: React.ComponentType<{
275283
children: string
276284
style?: React.CSSProperties
277285
fallback?: React.ReactNode
278286
}>
287+
MentionModifier?: React.ComponentType<{
288+
children: string
289+
style?: React.CSSProperties
290+
href: string
291+
fallback?: React.ReactNode
292+
}>
279293
LinkModifier?: React.ComponentType<{
280294
children: string
281295
style?: React.CSSProperties

packages/plugins/Trader/src/SiteAdaptor/cashTag.tsx

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import type { Plugin } from '@masknet/plugin-infra'
2+
import { PluginTraderMessages } from '@masknet/plugin-trader'
3+
import { makeStyles } from '@masknet/theme'
4+
import type { Web3Helper } from '@masknet/web3-helpers'
5+
import { DSearch } from '@masknet/web3-providers'
6+
import { TrendingAPI } from '@masknet/web3-providers/types'
7+
import { SearchResultType, type FungibleTokenResult, type NonFungibleCollectionResult } from '@masknet/web3-shared-base'
8+
import { Link } from '@mui/material'
9+
import { useQuery } from '@tanstack/react-query'
10+
import { memo, useRef } from 'react'
11+
12+
const useStyles = makeStyles()(() => ({
13+
tag: {
14+
display: 'inline-flex',
15+
alignItems: 'center',
16+
gap: 4,
17+
verticalAlign: 'bottom',
18+
},
19+
icon: {
20+
cursor: 'pointer',
21+
lineHeight: '16px',
22+
width: 16,
23+
height: 16,
24+
borderRadius: 16,
25+
overflow: 'hidden',
26+
objectFit: 'cover',
27+
},
28+
}))
29+
30+
type TagSearchResult =
31+
| FungibleTokenResult<Web3Helper.ChainIdAll, Web3Helper.SchemaTypeAll>
32+
| NonFungibleCollectionResult<Web3Helper.ChainIdAll, Web3Helper.SchemaTypeAll>
33+
34+
export const MentionModifier = memo<PropsOf<Plugin.SiteAdaptor.Definition['MentionModifier']>>(
35+
function MentionModifier({ children, href }) {
36+
const { classes } = useStyles()
37+
const { data } = useQuery({
38+
queryKey: ['mention', children],
39+
queryFn: async () => {
40+
return DSearch.search<TagSearchResult>(
41+
children.slice(1),
42+
SearchResultType.CollectionListByTwitterHandle,
43+
)
44+
},
45+
})
46+
const timerRef = useRef<NodeJS.Timeout>(undefined)
47+
if (data?.length) {
48+
return (
49+
<span
50+
className={classes.tag}
51+
onMouseEnter={(event) => {
52+
const element = event.currentTarget
53+
timerRef.current = setTimeout(() => {
54+
PluginTraderMessages.trendingAnchorObserved.sendToLocal({
55+
name: children.slice(1),
56+
type: children.startsWith('#') ? TrendingAPI.TagType.HASH : TrendingAPI.TagType.CASH,
57+
anchorBounding: element.getBoundingClientRect(),
58+
anchorEl: element,
59+
isCollectionProjectPopper: true,
60+
})
61+
}, 300)
62+
}}
63+
onMouseLeave={() => {
64+
clearTimeout(timerRef.current)
65+
}}>
66+
<img width={16} height={16} className={classes.icon} src={data[0].logoURL} />
67+
<Link fontSize="inherit" href={href}>
68+
{children}
69+
</Link>
70+
</span>
71+
)
72+
}
73+
return children
74+
},
75+
)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { memo, useRef } from 'react'
2+
import type { Plugin } from '@masknet/plugin-infra'
3+
import { useQuery } from '@tanstack/react-query'
4+
import { DSearch } from '@masknet/web3-providers'
5+
import type { Web3Helper } from '@masknet/web3-helpers'
6+
import type { FungibleTokenResult, NonFungibleCollectionResult } from '@masknet/web3-shared-base'
7+
import { makeStyles } from '@masknet/theme'
8+
import { PluginTraderMessages } from '@masknet/plugin-trader'
9+
import { TrendingAPI } from '@masknet/web3-providers/types'
10+
import { Link } from '@mui/material'
11+
12+
const useStyles = makeStyles()(() => ({
13+
tag: {
14+
display: 'inline-flex',
15+
alignItems: 'center',
16+
gap: 4,
17+
verticalAlign: 'bottom',
18+
},
19+
icon: {
20+
cursor: 'pointer',
21+
lineHeight: '16px',
22+
width: 16,
23+
height: 16,
24+
borderRadius: 16,
25+
overflow: 'hidden',
26+
objectFit: 'cover',
27+
},
28+
}))
29+
30+
type TagSearchResult =
31+
| FungibleTokenResult<Web3Helper.ChainIdAll, Web3Helper.SchemaTypeAll>
32+
| NonFungibleCollectionResult<Web3Helper.ChainIdAll, Web3Helper.SchemaTypeAll>
33+
34+
export const TagModifier = memo<PropsOf<Plugin.SiteAdaptor.Definition['TagModifier']>>(function TagModifier({
35+
children,
36+
href,
37+
}) {
38+
const { classes } = useStyles()
39+
const { data } = useQuery({
40+
queryKey: ['tag', children],
41+
queryFn: async () => {
42+
return DSearch.search<TagSearchResult>(children)
43+
},
44+
})
45+
const timerRef = useRef<NodeJS.Timeout>(undefined)
46+
if (data?.length) {
47+
return (
48+
<span
49+
className={classes.tag}
50+
onMouseEnter={(event) => {
51+
const element = event.currentTarget
52+
timerRef.current = setTimeout(() => {
53+
PluginTraderMessages.trendingAnchorObserved.sendToLocal({
54+
name: children.slice(1),
55+
type: children.startsWith('#') ? TrendingAPI.TagType.HASH : TrendingAPI.TagType.CASH,
56+
anchorBounding: element.getBoundingClientRect(),
57+
anchorEl: element,
58+
})
59+
}, 300)
60+
}}
61+
onMouseLeave={() => {
62+
clearTimeout(timerRef.current)
63+
}}>
64+
<img width={16} height={16} className={classes.icon} src={data[0].logoURL} />
65+
<Link fontSize="inherit" href={href}>
66+
{children}
67+
</Link>
68+
</span>
69+
)
70+
}
71+
return children
72+
})

packages/plugins/Trader/src/SiteAdaptor/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Trans } from '@lingui/react/macro'
12
import { Icons } from '@masknet/icons'
23
import type { Plugin } from '@masknet/plugin-infra'
34
import { ApplicationEntry } from '@masknet/shared'
@@ -9,13 +10,13 @@ import { SearchResultType } from '@masknet/web3-shared-base'
910
import { Telemetry } from '@masknet/web3-telemetry'
1011
import { EventID, EventType } from '@masknet/web3-telemetry/types'
1112
import { base } from '../base.js'
12-
import { enhanceTag } from './cashTag.js'
13+
import { TagModifier } from './components/TagModifier.js'
1314
import { setupStorage, type StorageOptions } from './storage.js'
1415
import { ExchangeInjection } from './trader/ExchangeInjection.js'
1516
import { TrendingViewProvider } from './trending/context.js'
1617
import { TagInspector } from './trending/TagInspector.js'
1718
import { TrendingView } from './trending/TrendingView.js'
18-
import { Trans } from '@lingui/react/macro'
19+
import { MentionModifier } from './components/MentionModifier.js'
1920

2021
function openDialog() {
2122
return CrossIsolationMessages.events.swapDialogEvent.sendToLocal({
@@ -70,7 +71,8 @@ const site: Plugin.SiteAdaptor.Definition = {
7071
</>
7172
)
7273
},
73-
enhanceTag,
74+
TagModifier,
75+
MentionModifier,
7476
ApplicationEntries:
7577
// temporarily disabled
7678
process.env.MASK_ENABLE_EXCHANGE ?

packages/plugins/Trader/src/SiteAdaptor/trending/TrendingPopper.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ export const TrendingPopper = memo(function TrendingPopper({ children, locked }:
6262
const location = useLocation()
6363
useRenderPhraseCallbackOnDepsChange(() => setActive(false), [location.state?.key, location.href])
6464

65-
const badgeBoundingBottom = badgeBounding?.bottom ?? 0
66-
const badgeBoundingLeft = badgeBounding?.left ?? 0
65+
const badgeBoundingBottom = badgeBounding?.bottom || 0
66+
const badgeBoundingLeft = badgeBounding?.left || 0
67+
const badgeBoundingWidth = badgeBounding?.width || 0
6768
const positionY_Type = badgeBoundingBottom < 550 ? 'bottom' : 'top'
68-
const positionX_Type = window.innerWidth - badgeBoundingLeft < 700 ? 'right' : 'left'
6969

7070
if (!type) return null
7171

@@ -78,7 +78,7 @@ export const TrendingPopper = memo(function TrendingPopper({ children, locked }:
7878
<div
7979
style={{
8080
position: 'absolute',
81-
left: positionX_Type === 'left' ? badgeBoundingLeft - 20 : badgeBoundingLeft - 300,
81+
left: badgeBoundingLeft - 300 + badgeBoundingWidth / 2,
8282
...(positionY_Type === 'bottom' ?
8383
{ top: badgeBoundingBottom + initialOffsetY + 10 }
8484
: { bottom: window.innerHeight - badgeBoundingBottom + 10 - initialOffsetY }),

packages/plugins/Trader/src/messages.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import { getPluginMessage, getPluginRPC, type PluginMessageEmitter } from '@masknet/plugin-infra'
2-
import type { GasConfig } from '@masknet/web3-shared-evm'
32
import type { Web3Helper } from '@masknet/web3-helpers'
43
import type { SocialIdentity } from '@masknet/shared-base'
54
import { PLUGIN_ID } from './constants/index.js'
65
import type { TagType } from './types/index.js'
76

87
interface TrendingAnchorEvent {
98
name: string
10-
type: TagType
9+
type?: TagType
1110
anchorBounding: DOMRect
1211
anchorEl: HTMLElement | null
1312
address?: string
@@ -16,22 +15,13 @@ interface TrendingAnchorEvent {
1615
currentResult?: Web3Helper.TokenResultAll
1716
}
1817

19-
interface SwapSettingsEvent {
20-
open: boolean
21-
gasConfig?: GasConfig
22-
}
23-
2418
export interface TraderMessage {
2519
/**
20+
* TODO Get rid of this, just put popper alongside the triggers, the tags.
2621
* View a cash tag
2722
*/
2823
trendingAnchorObserved: TrendingAnchorEvent
2924

30-
/**
31-
* Swap settings dialog
32-
*/
33-
swapSettingsUpdated: SwapSettingsEvent
34-
3525
rpc: unknown
3626
}
3727

packages/web3-providers/src/DSearch/helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import { fetchCachedJSON } from '../helpers/fetchJSON.js'
44
export function fetchFromDSearch<T>(request: RequestInfo | URL, init?: RequestInit) {
55
return fetchCachedJSON<T>(request, init, {
66
squashExpiration: 0,
7-
cacheDuration: Duration.THIRTY_MINUTES,
7+
cacheDuration: Duration.ONE_DAY,
88
})
99
}

0 commit comments

Comments
 (0)