Skip to content

Commit

Permalink
✨ Add starterpack support (#137)
Browse files Browse the repository at this point in the history
* ✨ Add starterpack support

* ✨ Add og card image for starter packs and cleanup
  • Loading branch information
foysalit authored Jun 25, 2024
1 parent fa54018 commit 11f3127
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 5 deletions.
1 change: 1 addition & 0 deletions components/common/PreviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const PreviewTitleMap = {
[CollectionId.FeedGenerator]: 'Reported feed',
[CollectionId.List]: 'Reported list',
[CollectionId.Profile]: 'Reported profile',
[CollectionId.StarterPack]: 'Reported starter pack',
}

const getPreviewTitleForAtUri = (uri: string): string => {
Expand Down
4 changes: 4 additions & 0 deletions components/common/RecordCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ProfileAvatar } from '@/repositories/ProfileAvatar'
import { ShieldCheckIcon } from '@heroicons/react/24/solid'
import { ProfileViewDetailed } from '@atproto/api/dist/client/types/app/bsky/actor/defs'
import { isSelfLabels } from '@atproto/api/dist/client/types/com/atproto/label/defs'
import { StarterPackRecordCard } from './starterpacks/RecordCard'

export function RecordCard(props: { uri: string; showLabels?: boolean }) {
const { uri, showLabels = false } = props
Expand All @@ -28,6 +29,9 @@ export function RecordCard(props: { uri: string; showLabels?: boolean }) {
if (parsed.collection === CollectionId.List) {
return <ListRecordCard uri={uri} />
}
if (parsed.collection === CollectionId.StarterPack) {
return <StarterPackRecordCard uri={uri} />
}
if (parsed?.collection === CollectionId.Profile) {
return (
<BaseRecordCard
Expand Down
176 changes: 176 additions & 0 deletions components/common/starterpacks/RecordCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { useQuery } from '@tanstack/react-query'
import Link from 'next/link'
import { Loading, LoadingFailed } from '@/common/Loader'
import client from '@/lib/client'
import { buildBlueSkyAppUrl, parseAtUri } from '@/lib/util'
import { AppBskyGraphDefs } from '@atproto/api'
import { SOCIAL_APP_URL, STARTER_PACK_OG_CARD_URL } from '@/lib/constants'

export const StarterPackRecordCard = ({ uri }: { uri: string }) => {
const { error, data, isFetching } = useQuery({
retry: false,
queryKey: ['starterpack', uri],
queryFn: async () => {
const { data } = await client.api.app.bsky.graph.getStarterPack(
{
starterPack: uri,
},
{ headers: client.proxyHeaders() },
)
return data
},
})

if (isFetching) {
return <Loading />
}

if (error) {
return <LoadingFailed error={error} />
}

if (!data) {
return <LoadingFailed error="Feed generator data not found!" />
}

const {
starterPack: {
creator,
list,
feeds,
joinedWeekCount,
joinedAllTimeCount,
indexedAt,
record,
},
} = data
const displayName = record['name'] || 'Untitled'
const rkey = uri.split('/').pop()

const meta: string[] = [
`${joinedWeekCount} Joined last week`,
`${joinedAllTimeCount} Joined all time`,
`${feeds?.length || 'No'} feed(s) included`,
]

if (indexedAt) {
meta.push(new Date(indexedAt as string).toLocaleString())
}

return (
<div className="bg-white dark:bg-slate-800">
<div className="flex w-full space-x-4">
<div className="flex-shrink-0">
<img
className="h-6 w-6 rounded-full"
// Probably should use a different default avatar for all feed generator app-wide
src={creator.avatar || '/img/default-avatar.jpg'}
alt={`Avatar of the creator of starter pack ${displayName}`}
/>
</div>
<div className="min-w-0 flex-1">
<p className="text-sm font-medium text-gray-900 dark:text-gray-200">
<>
<Link
href={`/repositories/${uri?.replace('at://', '')}`}
className="hover:underline"
>
<span className="font-bold">{displayName}</span>
</Link>
<span className="ml-1">by</span>
<Link href={`/repositories/${creator.did}`}>
<span className="ml-1 text-gray-500 dark:text-gray-50">
@{creator.handle}
</span>
</Link>
</>{' '}
&nbsp;&middot;&nbsp;
<a
href={buildBlueSkyAppUrl({ did: creator.did })}
target="_blank"
rel="noreferrer"
>
Peek
</a>
</p>
</div>
</div>
<div className="pb-2 pl-10">
<a
href={`${SOCIAL_APP_URL}/start/${creator.handle}/${rkey}`}
target="_blank"
>
<img
className="rounded"
src={`${STARTER_PACK_OG_CARD_URL}/${creator.did}/${rkey}`}
alt="Starter pack OG card"
/>
</a>
{!!feeds?.length && (
<div className="text-gray-800 dark:text-gray-300">
<h5 className="font-bold">Feeds</h5>
<ul>
{feeds.map((feed) => (
<li key={feed.did} className="flex items-center">
<Link href={`/repositories/${feed.uri.replace('at://', '')}`}>
{feed.displayName}
</Link>
&nbsp;&middot;&nbsp;
<a
href={buildBlueSkyAppUrl({
did: feed.creator.did,
collection: 'feed',
rkey: feed.uri.split('/').pop(),
})}
target="_blank"
rel="noreferrer"
className="text-sm"
>
Peek
</a>
</li>
))}
</ul>
</div>
)}
{!!list && <ListSummary list={list} />}
{!!meta.length && (
<p className="text-sm text-gray-500">{meta.join(' - ')}</p>
)}
</div>
</div>
)
}

const ListSummary = ({ list }: { list: AppBskyGraphDefs.ListViewBasic }) => {
const listUri = parseAtUri(list.uri)
if (!listUri) {
return null
}
const { did, rkey } = listUri

return (
<div className="text-gray-800 dark:text-gray-300">
<h5 className="font-bold">List</h5>
<div className="flex items-center">
<Link href={`/repositories/${list.uri.replace('at://', '')}`}>
{list.name}
</Link>
&nbsp;&middot;&nbsp;
{list.listItemCount} members &nbsp;&middot;&nbsp;
<a
href={buildBlueSkyAppUrl({
did,
rkey: rkey || '',
collection: 'lists',
})}
target="_blank"
rel="noreferrer"
className="text-sm"
>
Peek
</a>
</div>
</div>
)
}
22 changes: 22 additions & 0 deletions components/reports/SubjectOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,28 @@ export function SubjectOverview(props: {
)
}

if (summary.collection === CollectionId.StarterPack) {
return (
<div className="flex flex-row items-center">
<CollectionLink
repoUrl={createAtUri(summary).replace('at://', '')}
uri={createAtUri(summary)}
collectionName="starterpack"
/>
{!hideActor && (
<>
by
<OtherReportsForAuthorLink
did={summary.did}
repoText={repoText}
className="ml-1"
/>
</>
)}
</div>
)
}

if (summary.collection === CollectionId.Profile) {
return (
<div className="flex flex-row items-center">
Expand Down
4 changes: 4 additions & 0 deletions components/reports/helpers/subject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export enum CollectionId {
List = 'app.bsky.graph.list',
Post = 'app.bsky.feed.post',
LabelerService = 'app.bsky.labeler.service',
StarterPack = 'app.bsky.graph.starterpack',
}
export const getProfileUriForDid = (did: string) =>
`at://${did}/${CollectionId.Profile}/self`
Expand All @@ -89,6 +90,9 @@ export const getCollectionName = (collection: string) => {
if (collection === CollectionId.LabelerService) {
return 'Labeler'
}
if (collection === CollectionId.StarterPack) {
return 'Starter Pack'
}
// If the collection is a string with ., use the last two segments as the title
// so app.bsky.graph.list -> graph list
if (collection.includes('.')) {
Expand Down
15 changes: 15 additions & 0 deletions components/repositories/RecordView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,21 @@ function Details({ record }: { record: GetRecord.OutputSchema }) {
return (
<div className="mx-auto mt-6 max-w-5xl px-4 sm:px-6 lg:px-8">
<dl className="grid grid-cols-1 gap-x-4 gap-y-8 sm:grid-cols-2 mb-10">
{record.value?.['displayName'] && (
<DataField
label="Display Name"
value={`${record.value['displayName']}`}
/>
)}
{record.value?.['name'] && (
<DataField label="Name" value={`${record.value['name']}`} />
)}
{record.value?.['description'] && (
<DataField
label="Description"
value={`${record.value['description']}`}
/>
)}
<DataField label="Handle" value={record.repo.handle} showCopyButton>
<Link href={`/repositories/${record.repo.did}`} className="underline">
{record.repo.handle}
Expand Down
2 changes: 2 additions & 0 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ export const SOCIAL_APP_DOMAIN = 'bsky.app'
export const SOCIAL_APP_URL = `https://${SOCIAL_APP_DOMAIN}`

export const DM_DISABLE_TAG = 'chat-disabled'

export const STARTER_PACK_OG_CARD_URL = `https://ogcard.cdn.bsky.app/start`
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"e2e:run": "$(yarn bin)/cypress run"
},
"dependencies": {
"@atproto/api": "^0.12.17",
"@atproto/api": "0.12.22",
"@headlessui/react": "^1.7.7",
"@heroicons/react": "^2.0.13",
"@tanstack/react-query": "^4.22.0",
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# yarn lockfile v1


"@atproto/api@^0.12.17":
version "0.12.17"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.17.tgz#6fc98f9e4a831d5d0bb792a4dd2388713a587ed9"
integrity sha512-hj2LnEJGM27xPB1cugZHMnsvPDzjcIc0JtrGS11LO8+XJ/QYL192/HVdPQR82rN8XMlSPHXhNoeI2NJna8MUGQ==
"@atproto/[email protected].22":
version "0.12.22"
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.22.tgz#1880a93a0caa4485cd8463bd1e10bf2424b9826c"
integrity sha512-TIXSnf3qqyX40Ei/FkK4H24w+7s5rOc63TPwrGakRBOqIgSNBKOggei8I600fJ/AXB7HO6Vp9tBmDVOt2+021A==
dependencies:
"@atproto/common-web" "^0.3.0"
"@atproto/lexicon" "^0.4.0"
Expand Down

0 comments on commit 11f3127

Please sign in to comment.