wip bsky client for the web & android
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: bite & explode posts

vi a738b0c4 3562cc62

+81 -30
+44
src/components/Feed/FeedItem.vue
··· 15 15 IconLinkRounded, 16 16 IconOpenInNewRounded, 17 17 IconForwardRounded, 18 + IconPets, 19 + IconBombRounded, 18 20 } from '@iconify-prerendered/vue-material-symbols' 19 21 20 22 import { useNavigationStore } from '@/stores/navigation' ··· 28 30 import ExternalEmbed from './Embeds/ExternalEmbed.vue' 29 31 import VideoEmbed from './Embeds/VideoEmbed.vue' 30 32 import { tap } from '@/utils/haptics' 33 + import { createRecord } from '@/utils/atproto' 31 34 32 35 type PostInput = AppBskyFeedDefs.PostView | AppBskyEmbedRecord.ViewRecord 33 36 ··· 114 117 ) 115 118 tap() 116 119 } 120 + } 121 + 122 + const actions = { 123 + bite: async () => { 124 + await createRecord( 125 + 'net.wafrn.feed.bite', 126 + { 127 + $type: 'net.wafrn.feed.bite', 128 + subject: `at://${props.post?.author.did}/app.bsky.feed.post/${rkey.value}`, 129 + createdAt: new Date().toISOString(), 130 + }, 131 + { 132 + error: `failed to bite the post :c`, 133 + success: `bit the post!`, 134 + }, 135 + ) 136 + }, 137 + explode: async () => { 138 + await createRecord( 139 + 'net.wafrn.feed.explode', 140 + { 141 + $type: 'net.wafrn.feed.explode', 142 + subject: `at://${props.post?.author.did}/app.bsky.feed.post/${rkey.value}`, 143 + createdAt: new Date().toISOString(), 144 + }, 145 + { 146 + error: `failed to explode the post :c`, 147 + success: `exploded the post!`, 148 + }, 149 + ) 150 + }, 117 151 } 118 152 119 153 const handleShare = () => { ··· 472 506 ? IconBookmarkAddedRounded 473 507 : IconBookmarkRounded, 474 508 onClick: handleBookmark, 509 + }, 510 + { 511 + label: 'Bite post', 512 + icon: IconPets, 513 + onClick: actions.bite, 514 + }, 515 + { 516 + label: 'Explode post', 517 + icon: IconBombRounded, 518 + onClick: actions.explode, 475 519 }, 476 520 ], 477 521 },
+36
src/utils/atproto.ts
··· 1 1 import type { AppBskyFeedDefs } from '@atcute/bluesky' 2 2 import type { ComAtprotoRepoStrongRef } from '@atcute/atproto' 3 + import { ok } from '@atcute/client' 3 4 import type { ActorIdentifier, Blob, LegacyBlob } from '@atcute/lexicons' 4 5 import { isLegacyBlob } from '@atcute/lexicons/interfaces' 6 + 7 + import { useToastStore } from '@/stores/toast' 8 + import { useAuthStore } from '@/stores/auth' 9 + 10 + import type { CollectionString } from '@/types/atproto' 11 + 12 + const toast = useToastStore() 13 + const auth = useAuthStore() 5 14 6 15 export function createStrongRef(post: AppBskyFeedDefs.PostView): ComAtprotoRepoStrongRef.Main { 7 16 return { ··· 19 28 20 29 return `${pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}` 21 30 } 31 + 32 + export async function createRecord( 33 + collection: CollectionString, 34 + record: Record<string, unknown>, 35 + message: { error: string; success: string } = { 36 + error: 'Failed to perform action', 37 + success: 'Yayyyyyy done!!', 38 + }, 39 + ) { 40 + const rpc = auth.getRpc() 41 + 42 + try { 43 + await ok( 44 + rpc.post('com.atproto.repo.createRecord', { 45 + input: { 46 + collection, 47 + repo: auth.session!.info.sub, 48 + record: { $type: collection, ...record }, 49 + }, 50 + }), 51 + ) 52 + toast.success(message.success) 53 + } catch (e) { 54 + console.error(message.error, e) 55 + toast.error(message.error) 56 + } 57 + }
+1 -30
src/views/Profile/ProfileView.vue
··· 17 17 18 18 import { useAuthStore } from '@/stores/auth' 19 19 import { usePostStore } from '@/stores/posts' 20 - import { useToastStore } from '@/stores/toast' 21 20 import { useModalStore } from '@/stores/modal' 22 21 23 22 import { useEnvironmentStore } from '@/stores/environment' ··· 37 36 38 37 import type { ActorIdentifier } from '@atcute/lexicons' 39 38 import AppLink from '@/components/Navigation/AppLink.vue' 40 - import type { CollectionString } from '@/types/atproto' 41 39 import { getIdentity } from '@/utils/identity' 42 40 import { HostPluralSystemMember, type HostPluralFrontLog } from '@/lex' 43 - import { blobUrl } from '@/utils/atproto' 41 + import { blobUrl, createRecord } from '@/utils/atproto' 44 42 45 43 const props = defineProps<{ id: string }>() 46 44 47 45 const auth = useAuthStore() 48 46 const postStore = usePostStore() 49 - const toast = useToastStore() 50 47 const env = useEnvironmentStore() 51 48 const modal = useModalStore() 52 49 ··· 326 323 } catch (e) { 327 324 console.error('follow toggle failed', e) 328 325 if (profile.value.viewer) profile.value.viewer.following = originalState 329 - } 330 - } 331 - 332 - async function createRecord( 333 - collection: CollectionString, 334 - record: Record<string, unknown>, 335 - message: { error: string; success: string } = { 336 - error: 'Failed to perform action', 337 - success: 'Yayyyyyy done!!', 338 - }, 339 - ) { 340 - const rpc = auth.getRpc() 341 - try { 342 - await ok( 343 - rpc.post('com.atproto.repo.createRecord', { 344 - input: { 345 - collection, 346 - repo: auth.session!.info.sub, 347 - record: { $type: collection, ...record }, 348 - }, 349 - }), 350 - ) 351 - toast.success(message.success) 352 - } catch (e) { 353 - console.error(message.error, e) 354 - toast.error(message.error) 355 326 } 356 327 } 357 328