Skip to content

Commit 7644f38

Browse files
dylanjeffersclaude
andauthored
Randomize locked text post placeholder and add gradient to mobile (#14044)
Replace hardcoded placeholder text with a deterministic pseudo-random generator (5–25 words per post) so each locked post looks visually distinct. Update mobile locked text post UI to show blurred placeholder text with a gradient overlay and unlock button, matching the web implementation, instead of a simple lock icon. https://claude.ai/code/session_019N9dxngkS7FAaf3nHYrkRy --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent f9d10e5 commit 7644f38

2 files changed

Lines changed: 75 additions & 19 deletions

File tree

packages/mobile/src/screens/coin-details-screen/components/TextPostCard.tsx

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { useComment } from '@audius/common/api'
22
import type { ID } from '@audius/common/models'
33
import { getLargestTimeUnitText } from '@audius/common/utils'
4+
import { View } from 'react-native'
5+
import LinearGradient from 'react-native-linear-gradient'
46

57
import {
8+
Button,
69
Flex,
710
IconLock,
811
Paper,
@@ -14,7 +17,28 @@ import { ProfilePicture } from 'app/components/core'
1417
import { UserLink } from 'app/components/user-link'
1518

1619
const messages = {
17-
locked: 'Hold this coin to unlock'
20+
unlock: 'Unlock',
21+
membersOnly: 'Members Only'
22+
}
23+
24+
/**
25+
* Generate a deterministic pseudo-random placeholder string for locked posts
26+
* so each post looks visually distinct behind the blur.
27+
*/
28+
const generatePlaceholder = (commentId: ID) => {
29+
const seed = Number(commentId)
30+
const wordCount = 5 + (seed % 21) // 5–25 words
31+
const words: string[] = []
32+
const pool = 'abcdefghijklmnopqrstuvwxyz'
33+
for (let i = 0; i < wordCount; i++) {
34+
const len = 3 + ((seed * (i + 1) * 7) % 8) // 3–10 chars per word
35+
let word = ''
36+
for (let j = 0; j < len; j++) {
37+
word += pool[(seed * (i + 1) * (j + 1) * 13) % pool.length]
38+
}
39+
words.push(word)
40+
}
41+
return words.join(' ')
1842
}
1943

2044
type TextPostCardProps = {
@@ -23,7 +47,7 @@ type TextPostCardProps = {
2347

2448
export const TextPostCard = ({ commentId }: TextPostCardProps) => {
2549
const { data: comment, isPending } = useComment(commentId)
26-
const { color, spacing, cornerRadius } = useTheme()
50+
const { color } = useTheme()
2751

2852
if (isPending) {
2953
return (
@@ -76,20 +100,35 @@ export const TextPostCard = ({ commentId }: TextPostCardProps) => {
76100
</Flex>
77101

78102
{isLocked ? (
79-
<Flex
80-
row
81-
alignItems='center'
82-
gap='s'
83-
style={{
84-
padding: spacing.m,
85-
borderRadius: cornerRadius.s,
86-
backgroundColor: color.background.surface2
87-
}}
88-
>
89-
<IconLock size='s' color='subdued' />
90-
<Text variant='body' size='s' color='subdued'>
91-
{messages.locked}
92-
</Text>
103+
<Flex column gap='m'>
104+
<View style={{ position: 'relative', overflow: 'hidden' }}>
105+
<Text variant='body' size='m' style={{ opacity: 0.4 }}>
106+
{generatePlaceholder(commentId)}
107+
</Text>
108+
<LinearGradient
109+
colors={['transparent', color.background.white]}
110+
style={{
111+
position: 'absolute',
112+
top: 0,
113+
left: 0,
114+
right: 0,
115+
bottom: 0
116+
}}
117+
start={{ x: 0, y: 0 }}
118+
end={{ x: 1, y: 0 }}
119+
/>
120+
</View>
121+
<Flex row alignItems='center' justifyContent='space-between'>
122+
<Button variant='secondary' size='small'>
123+
{messages.unlock}
124+
</Button>
125+
<Flex row alignItems='center' gap='xs'>
126+
<IconLock size='s' color='default' />
127+
<Text variant='body' size='s' strength='strong'>
128+
{messages.membersOnly}
129+
</Text>
130+
</Flex>
131+
</Flex>
93132
</Flex>
94133
) : (
95134
<Text variant='body' size='m'>

packages/web/src/pages/fan-club-detail-page/components/TextPostCard.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,25 @@ const messages = {
3939
edited: '(edited)'
4040
}
4141

42-
const LOCKED_PLACEHOLDER_TEXT =
43-
'This content is exclusively available for coin holders. Purchase coins to unlock access to this post and other exclusive content.'
42+
/**
43+
* Generate a deterministic pseudo-random placeholder string for locked posts
44+
* so each post looks visually distinct behind the blur.
45+
*/
46+
const generatePlaceholder = (commentId: ID) => {
47+
const seed = Number(commentId)
48+
const wordCount = 5 + (seed % 21) // 5–25 words
49+
const words = []
50+
const pool = 'abcdefghijklmnopqrstuvwxyz'
51+
for (let i = 0; i < wordCount; i++) {
52+
const len = 3 + ((seed * (i + 1) * 7) % 8) // 3–10 chars per word
53+
let word = ''
54+
for (let j = 0; j < len; j++) {
55+
word += pool[(seed * (i + 1) * (j + 1) * 13) % pool.length]
56+
}
57+
words.push(word)
58+
}
59+
return words.join(' ')
60+
}
4461

4562
type TextPostCardProps = {
4663
commentId: ID
@@ -165,7 +182,7 @@ export const TextPostCard = ({ commentId, mint }: TextPostCardProps) => {
165182
pointerEvents: 'none'
166183
}}
167184
>
168-
{LOCKED_PLACEHOLDER_TEXT}
185+
{generatePlaceholder(commentId)}
169186
</Text>
170187
<Flex
171188
row

0 commit comments

Comments
 (0)