+3
-2
bskyembed/.eslintrc
+3
-2
bskyembed/.eslintrc
···
10
10
],
11
11
"rules": {
12
12
"simple-import-sort/imports": "warn",
13
-
"simple-import-sort/exports": "warn"
13
+
"simple-import-sort/exports": "warn",
14
+
'no-else-return': 'off'
14
15
},
15
16
"parserOptions": {
16
17
"sourceType": "module",
17
18
"ecmaVersion": "latest",
18
19
"project": "./bskyembed/tsconfig.json"
19
20
}
20
-
}
21
+
}
+1
bskyembed/assets/starterPack.svg
+1
bskyembed/assets/starterPack.svg
···
1
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><defs><linearGradient x1="0" y1="0" x2="100%" y2="0" gradientTransform="rotate(45)" id="sky_V5w1FF_xb91wVQ_1euhBX"><stop offset="0" stop-color="#0A7AFF"></stop><stop offset="1" stop-color="#59B9FF"></stop></linearGradient></defs><path fill="url(#sky_V5w1FF_xb91wVQ_1euhBX)" fill-rule="evenodd" clip-rule="evenodd" d="M11.26 5.227 5.02 6.899c-.734.197-1.17.95-.973 1.685l1.672 6.24c.197.734.951 1.17 1.685.973l6.24-1.672c.734-.197 1.17-.951.973-1.685L12.945 6.2a1.375 1.375 0 0 0-1.685-.973Zm-6.566.459a2.632 2.632 0 0 0-1.86 3.223l1.672 6.24a2.632 2.632 0 0 0 3.223 1.861l6.24-1.672a2.631 2.631 0 0 0 1.861-3.223l-1.672-6.24a2.632 2.632 0 0 0-3.223-1.861l-6.24 1.672Z"></path><path fill="url(#sky_V5w1FF_xb91wVQ_1euhBX)" fill-rule="evenodd" clip-rule="evenodd" d="M15.138 18.411a4.606 4.606 0 1 0 0-9.211 4.606 4.606 0 0 0 0 9.211Zm0 1.257a5.862 5.862 0 1 0 0-11.724 5.862 5.862 0 0 0 0 11.724Z"></path></svg>
+1
-1
bskyembed/package.json
+1
-1
bskyembed/package.json
+76
-16
bskyembed/src/components/embed.tsx
+76
-16
bskyembed/src/components/embed.tsx
···
6
6
AppBskyFeedDefs,
7
7
AppBskyFeedPost,
8
8
AppBskyGraphDefs,
9
+
AppBskyGraphStarterpack,
9
10
AppBskyLabelerDefs,
11
+
AtUri,
10
12
} from '@atproto/api'
11
13
import {ComponentChildren, h} from 'preact'
12
14
import {useMemo} from 'preact/hooks'
13
15
14
16
import infoIcon from '../../assets/circleInfo_stroke2_corner0_rounded.svg'
17
+
import starterPackIcon from '../../assets/starterPack.svg'
15
18
import {CONTENT_LABELS, labelsToInfo} from '../labels'
16
19
import {getRkey} from '../utils'
17
20
import {Link} from './link'
···
105
108
// Case 3.2: List
106
109
if (AppBskyGraphDefs.isListView(record)) {
107
110
return (
108
-
<GenericWithImage
111
+
<GenericWithImageEmbed
109
112
image={record.avatar}
110
113
title={record.name}
111
114
href={`/profile/${record.creator.did}/lists/${getRkey(record)}`}
···
122
125
// Case 3.3: Feed
123
126
if (AppBskyFeedDefs.isGeneratorView(record)) {
124
127
return (
125
-
<GenericWithImage
128
+
<GenericWithImageEmbed
126
129
image={record.avatar}
127
130
title={record.displayName}
128
131
href={`/profile/${record.creator.did}/feed/${getRkey(record)}`}
···
134
137
135
138
// Case 3.4: Labeler
136
139
if (AppBskyLabelerDefs.isLabelerView(record)) {
137
-
return (
138
-
<GenericWithImage
139
-
image={record.creator.avatar}
140
-
title={record.creator.displayName || record.creator.handle}
141
-
href={`/profile/${record.creator.did}`}
142
-
subtitle="Labeler"
143
-
description={`Liked by ${record.likeCount ?? 0} users`}
144
-
/>
145
-
)
140
+
// Embed type does not exist in the app, so show nothing
141
+
return null
146
142
}
147
143
148
-
// Case 3.5: Post not found
144
+
// Case 3.5: Starter pack
145
+
if (AppBskyGraphDefs.isStarterPackViewBasic(record)) {
146
+
return <StarterPackEmbed content={record} />
147
+
}
148
+
149
+
// Case 3.6: Post not found
149
150
if (AppBskyEmbedRecord.isViewNotFound(record)) {
150
151
return <Info>Quoted post not found, it may have been deleted.</Info>
151
152
}
152
153
153
-
// Case 3.6: Post blocked
154
+
// Case 3.7: Post blocked
154
155
if (AppBskyEmbedRecord.isViewBlocked(record)) {
155
156
return <Info>The quoted post is blocked.</Info>
156
157
}
157
158
158
-
throw new Error('Unknown embed type')
159
+
// Unknown embed type
160
+
return null
159
161
}
160
162
161
163
// Case 4: Record with media
···
182
184
)
183
185
}
184
186
185
-
throw new Error('Unsupported embed type')
187
+
// Unknown embed type
188
+
return null
186
189
} catch (err) {
187
190
return (
188
191
<Info>{err instanceof Error ? err.message : 'An error occurred'}</Info>
···
314
317
)
315
318
}
316
319
317
-
function GenericWithImage({
320
+
function GenericWithImageEmbed({
318
321
title,
319
322
subtitle,
320
323
href,
···
350
353
</Link>
351
354
)
352
355
}
356
+
357
+
function StarterPackEmbed({
358
+
content,
359
+
}: {
360
+
content: AppBskyGraphDefs.StarterPackViewBasic
361
+
}) {
362
+
if (!AppBskyGraphStarterpack.isRecord(content.record)) {
363
+
return null
364
+
}
365
+
366
+
const starterPackHref = getStarterPackHref(content)
367
+
const imageUri = getStarterPackImage(content)
368
+
369
+
return (
370
+
<Link
371
+
href={starterPackHref}
372
+
className="w-full rounded-lg overflow-hidden border flex flex-col items-stretch">
373
+
<img src={imageUri} className="aspect-[1.91/1] object-cover" />
374
+
<div className="py-3 px-4">
375
+
<div className="flex space-x-2 items-center">
376
+
<img src={starterPackIcon} className="w-10 h-10" />
377
+
<div>
378
+
<p className="font-semibold leading-[21px]">
379
+
{content.record.name}
380
+
</p>
381
+
<p className="text-sm text-textLight line-clamp-2 leading-[18px]">
382
+
Starter pack by{' '}
383
+
{content.creator.displayName || `@${content.creator.handle}`}
384
+
</p>
385
+
</div>
386
+
</div>
387
+
{content.record.description && (
388
+
<p className="text-sm mt-1">{content.record.description}</p>
389
+
)}
390
+
{!!content.joinedAllTimeCount && content.joinedAllTimeCount > 50 && (
391
+
<p className="text-sm font-semibold text-textLight mt-1">
392
+
{content.joinedAllTimeCount} users have joined!
393
+
</p>
394
+
)}
395
+
</div>
396
+
</Link>
397
+
)
398
+
}
399
+
400
+
// from #/lib/strings/starter-pack.ts
401
+
function getStarterPackImage(starterPack: AppBskyGraphDefs.StarterPackView) {
402
+
const rkey = new AtUri(starterPack.uri).rkey
403
+
return `https://ogcard.cdn.bsky.app/start/${starterPack.creator.did}/${rkey}`
404
+
}
405
+
406
+
function getStarterPackHref(
407
+
starterPack: AppBskyGraphDefs.StarterPackViewBasic,
408
+
) {
409
+
const rkey = new AtUri(starterPack.uri).rkey
410
+
const handleOrDid = starterPack.creator.handle || starterPack.creator.did
411
+
return `/starter-pack/${handleOrDid}/${rkey}`
412
+
}
+4
-1
bskyembed/src/components/post.tsx
+4
-1
bskyembed/src/components/post.tsx
···
132
132
key={counter}
133
133
href={segment.link.uri}
134
134
className="text-blue-400 hover:underline"
135
-
disableTracking={!segment.link.uri.startsWith('https://bsky.app')}>
135
+
disableTracking={
136
+
!segment.link.uri.startsWith('https://bsky.app') &&
137
+
!segment.link.uri.startsWith('https://go.bsky.app')
138
+
}>
136
139
{segment.text}
137
140
</Link>,
138
141
)
+2
-2
bskyembed/src/screens/post.tsx
+2
-2
bskyembed/src/screens/post.tsx
···
1
1
import '../index.css'
2
2
3
-
import {AppBskyFeedDefs, BskyAgent} from '@atproto/api'
3
+
import {AppBskyFeedDefs, AtpAgent} from '@atproto/api'
4
4
import {h, render} from 'preact'
5
5
6
6
import logo from '../../assets/logo.svg'
···
12
12
const root = document.getElementById('app')
13
13
if (!root) throw new Error('No root element')
14
14
15
-
const agent = new BskyAgent({
15
+
const agent = new AtpAgent({
16
16
service: 'https://public.api.bsky.app',
17
17
})
18
18
+46
-20
bskyembed/yarn.lock
+46
-20
bskyembed/yarn.lock
···
20
20
"@jridgewell/gen-mapping" "^0.3.5"
21
21
"@jridgewell/trace-mapping" "^0.3.24"
22
22
23
-
"@atproto/api@^0.12.2":
24
-
version "0.12.2"
25
-
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.2.tgz#5df6d4f60dea0395c84fdebd9e81a7e853edf130"
26
-
integrity sha512-UVzCiDZH2j0wrr/O8nb1edD5cYLVqB5iujueXUCbHS3rAwIxgmyLtA3Hzm2QYsGPo/+xsIg1fNvpq9rNT6KWUA==
23
+
"@atproto/api@0.13.1":
24
+
version "0.13.1"
25
+
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.1.tgz#fbf4306e4465d5467aaf031308c1b47dcc8039d0"
26
+
integrity sha512-DL3iBfavn8Nnl48FmnAreQB0k0cIkW531DJ5JAHUCQZo10Nq0ZLk2/WFxcs0KuBG5wuLnGUdo+Y6/GQPVq8dYw==
27
27
dependencies:
28
28
"@atproto/common-web" "^0.3.0"
29
-
"@atproto/lexicon" "^0.4.0"
29
+
"@atproto/lexicon" "^0.4.1"
30
30
"@atproto/syntax" "^0.3.0"
31
-
"@atproto/xrpc" "^0.5.0"
31
+
"@atproto/xrpc" "^0.6.0"
32
+
await-lock "^2.2.2"
32
33
multiformats "^9.9.0"
33
34
tlds "^1.234.0"
34
35
···
42
43
uint8arrays "3.0.0"
43
44
zod "^3.21.4"
44
45
45
-
"@atproto/lexicon@^0.4.0":
46
-
version "0.4.0"
47
-
resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.0.tgz#63e8829945d80c25524882caa8ed27b1151cc576"
48
-
integrity sha512-RvCBKdSI4M8qWm5uTNz1z3R2yIvIhmOsMuleOj8YR6BwRD+QbtUBy3l+xQ7iXf4M5fdfJFxaUNa6Ty0iRwdKqQ==
46
+
"@atproto/lexicon@^0.4.1":
47
+
version "0.4.1"
48
+
resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.1.tgz#19155210570a2fafbcc7d4f655d9b813948e72a0"
49
+
integrity sha512-bzyr+/VHXLQWbumViX5L7h1NKQObfs8Z+XZJl43OUK8nYFUI4e/sW1IZKRNfw7Wvi5YVNK+J+yP3DWIBZhkCYA==
49
50
dependencies:
50
51
"@atproto/common-web" "^0.3.0"
51
52
"@atproto/syntax" "^0.3.0"
52
53
iso-datestring-validator "^2.2.2"
53
54
multiformats "^9.9.0"
54
-
zod "^3.21.4"
55
+
zod "^3.23.8"
55
56
56
57
"@atproto/syntax@^0.3.0":
57
58
version "0.3.0"
58
59
resolved "https://registry.yarnpkg.com/@atproto/syntax/-/syntax-0.3.0.tgz#fafa2dbea9add37253005cb663e7373e05e618b3"
59
60
integrity sha512-Weq0ZBxffGHDXHl9U7BQc2BFJi/e23AL+k+i5+D9hUq/bzT4yjGsrCejkjq0xt82xXDjmhhvQSZ0LqxyZ5woxA==
60
61
61
-
"@atproto/xrpc@^0.5.0":
62
-
version "0.5.0"
63
-
resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.5.0.tgz#dacbfd8f7b13f0ab5bd56f8fdd4b460e132a6032"
64
-
integrity sha512-swu+wyOLvYW4l3n+VAuJbHcPcES+tin2Lsrp8Bw5aIXIICiuFn1YMFlwK9JwVUzTH21Py1s1nHEjr4CJeElJog==
62
+
"@atproto/xrpc@^0.6.0":
63
+
version "0.6.0"
64
+
resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.6.0.tgz#668c3262e67e2afa65951ea79a03bfe3720ddf5c"
65
+
integrity sha512-5BbhBTv5j6MC3iIQ4+vYxQE7nLy2dDGQ+LYJrH8PptOCUdq0Pwg6aRccQ3y52kUZlhE/mzOTZ8Ngiy9pSAyfVQ==
65
66
dependencies:
66
-
"@atproto/lexicon" "^0.4.0"
67
-
zod "^3.21.4"
67
+
"@atproto/lexicon" "^0.4.1"
68
+
zod "^3.23.8"
68
69
69
70
"@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2":
70
71
version "7.24.2"
···
1709
1710
integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==
1710
1711
dependencies:
1711
1712
possible-typed-array-names "^1.0.0"
1713
+
1714
+
await-lock@^2.2.2:
1715
+
version "2.2.2"
1716
+
resolved "https://registry.yarnpkg.com/await-lock/-/await-lock-2.2.2.tgz#a95a9b269bfd2f69d22b17a321686f551152bcef"
1717
+
integrity sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==
1712
1718
1713
1719
babel-plugin-polyfill-corejs2@^0.4.10:
1714
1720
version "0.4.10"
···
3730
3736
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-1.0.0-pre2.tgz#46a83a79f1b287807e9aaafc6a5dd8bcde626f9c"
3731
3737
integrity sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==
3732
3738
3733
-
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
3734
-
name string-width-cjs
3739
+
"string-width-cjs@npm:string-width@^4.2.0":
3740
+
version "4.2.3"
3741
+
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
3742
+
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
3743
+
dependencies:
3744
+
emoji-regex "^8.0.0"
3745
+
is-fullwidth-code-point "^3.0.0"
3746
+
strip-ansi "^6.0.1"
3747
+
3748
+
string-width@^4.1.0:
3735
3749
version "4.2.3"
3736
3750
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
3737
3751
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
···
3795
3809
define-properties "^1.2.1"
3796
3810
es-object-atoms "^1.0.0"
3797
3811
3798
-
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
3812
+
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
3813
+
version "6.0.1"
3814
+
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
3815
+
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
3816
+
dependencies:
3817
+
ansi-regex "^5.0.1"
3818
+
3819
+
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
3799
3820
version "6.0.1"
3800
3821
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
3801
3822
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
···
4192
4213
version "3.22.4"
4193
4214
resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff"
4194
4215
integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==
4216
+
4217
+
zod@^3.23.8:
4218
+
version "3.23.8"
4219
+
resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d"
4220
+
integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==
+14
-7
src/components/StarterPack/StarterPackCard.tsx
+14
-7
src/components/StarterPack/StarterPackCard.tsx
···
1
1
import React from 'react'
2
2
import {View} from 'react-native'
3
3
import {Image} from 'expo-image'
4
-
import {AppBskyGraphStarterpack, AtUri} from '@atproto/api'
5
-
import {StarterPackViewBasic} from '@atproto/api/dist/client/types/app/bsky/graph/defs'
4
+
import {AppBskyGraphDefs, AppBskyGraphStarterpack, AtUri} from '@atproto/api'
6
5
import {msg, Trans} from '@lingui/macro'
7
6
import {useLingui} from '@lingui/react'
8
7
import {useQueryClient} from '@tanstack/react-query'
···
17
16
import {BaseLink} from '#/components/Link'
18
17
import {Text} from '#/components/Typography'
19
18
20
-
export function Default({starterPack}: {starterPack?: StarterPackViewBasic}) {
19
+
export function Default({
20
+
starterPack,
21
+
}: {
22
+
starterPack?: AppBskyGraphDefs.StarterPackViewBasic
23
+
}) {
21
24
if (!starterPack) return null
22
25
return (
23
26
<Link starterPack={starterPack}>
···
29
32
export function Notification({
30
33
starterPack,
31
34
}: {
32
-
starterPack?: StarterPackViewBasic
35
+
starterPack?: AppBskyGraphDefs.StarterPackViewBasic
33
36
}) {
34
37
if (!starterPack) return null
35
38
return (
···
44
47
noIcon,
45
48
noDescription,
46
49
}: {
47
-
starterPack: StarterPackViewBasic
50
+
starterPack: AppBskyGraphDefs.StarterPackViewBasic
48
51
noIcon?: boolean
49
52
noDescription?: boolean
50
53
}) {
···
94
97
starterPack,
95
98
children,
96
99
}: {
97
-
starterPack: StarterPackViewBasic
100
+
starterPack: AppBskyGraphDefs.StarterPackViewBasic
98
101
onPress?: () => void
99
102
children: React.ReactNode
100
103
}) {
···
129
132
)
130
133
}
131
134
132
-
export function Embed({starterPack}: {starterPack: StarterPackViewBasic}) {
135
+
export function Embed({
136
+
starterPack,
137
+
}: {
138
+
starterPack: AppBskyGraphDefs.StarterPackViewBasic
139
+
}) {
133
140
const t = useTheme()
134
141
const imageUri = getStarterPackOgCard(starterPack)
135
142