tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
28
pulls
pipelines
add canvas pages and previews
awarm.space
4 months ago
055e5cab
ce10575f
+419
-38
5 changed files
expand all
collapse all
unified
split
actions
publishToPublication.ts
app
lish
[did]
[publication]
[rkey]
CanvasPage.tsx
PostContent.tsx
PostPages.tsx
PublishedPageBlock.tsx
+84
-12
actions/publishToPublication.ts
···
12
12
PubLeafletBlocksUnorderedList,
13
13
PubLeafletDocument,
14
14
PubLeafletPagesLinearDocument,
15
15
+
PubLeafletPagesCanvas,
15
16
PubLeafletRichtextFacet,
16
17
PubLeafletBlocksWebsite,
17
18
PubLeafletBlocksCode,
···
95
96
$type: "pub.leaflet.pages.linearDocument",
96
97
blocks: firstPageBlocks,
97
98
},
98
98
-
...pages.map((p) => ({
99
99
-
$type: "pub.leaflet.pages.linearDocument",
100
100
-
id: p.id,
101
101
-
blocks: p.blocks,
102
102
-
})),
99
99
+
...pages.map((p) => {
100
100
+
if (p.type === "canvas") {
101
101
+
return {
102
102
+
$type: "pub.leaflet.pages.canvas" as const,
103
103
+
id: p.id,
104
104
+
blocks: p.blocks as PubLeafletPagesCanvas.Block[],
105
105
+
};
106
106
+
} else {
107
107
+
return {
108
108
+
$type: "pub.leaflet.pages.linearDocument" as const,
109
109
+
id: p.id,
110
110
+
blocks: p.blocks as PubLeafletPagesLinearDocument.Block[],
111
111
+
};
112
112
+
}
113
113
+
}),
103
114
],
104
115
};
105
116
let rkey = draft?.doc ? new AtUri(draft.doc).rkey : TID.nextStr();
···
139
150
root_entity: string,
140
151
) {
141
152
let scan = scanIndexLocal(facts);
142
142
-
let pages: { id: string; blocks: PubLeafletPagesLinearDocument.Block[] }[] =
143
143
-
[];
153
153
+
let pages: {
154
154
+
id: string;
155
155
+
blocks: PubLeafletPagesLinearDocument.Block[] | PubLeafletPagesCanvas.Block[];
156
156
+
type: "doc" | "canvas";
157
157
+
}[] = [];
144
158
145
159
let firstEntity = scan.eav(root_entity, "root/page")?.[0];
146
160
if (!firstEntity) throw new Error("No root page");
···
229
243
let [page] = scan.eav(b.value, "block/card");
230
244
if (!page) return;
231
245
let [pageType] = scan.eav(page.data.value, "page/type");
232
232
-
let blocks = getBlocksWithTypeLocal(facts, page.data.value);
233
233
-
pages.push({
234
234
-
id: page.data.value,
235
235
-
blocks: await blocksToRecord(blocks),
236
236
-
});
246
246
+
247
247
+
if (pageType?.data.value === "canvas") {
248
248
+
let canvasBlocks = await canvasBlocksToRecord(page.data.value);
249
249
+
pages.push({
250
250
+
id: page.data.value,
251
251
+
blocks: canvasBlocks,
252
252
+
type: "canvas",
253
253
+
});
254
254
+
} else {
255
255
+
let blocks = getBlocksWithTypeLocal(facts, page.data.value);
256
256
+
pages.push({
257
257
+
id: page.data.value,
258
258
+
blocks: await blocksToRecord(blocks),
259
259
+
type: "doc",
260
260
+
});
261
261
+
}
262
262
+
237
263
let block: $Typed<PubLeafletBlocksPage.Main> = {
238
264
$type: "pub.leaflet.blocks.page",
239
265
id: page.data.value,
···
359
385
return block;
360
386
}
361
387
return;
388
388
+
}
389
389
+
390
390
+
async function canvasBlocksToRecord(
391
391
+
pageID: string,
392
392
+
): Promise<PubLeafletPagesCanvas.Block[]> {
393
393
+
let canvasBlocks = scan.eav(pageID, "canvas/block");
394
394
+
return (
395
395
+
await Promise.all(
396
396
+
canvasBlocks.map(async (canvasBlock) => {
397
397
+
let blockEntity = canvasBlock.data.value;
398
398
+
let position = canvasBlock.data.position;
399
399
+
400
400
+
// Get the block content
401
401
+
let blockType = scan.eav(blockEntity, "block/type")?.[0];
402
402
+
if (!blockType) return null;
403
403
+
404
404
+
let block: Block = {
405
405
+
type: blockType.data.value,
406
406
+
value: blockEntity,
407
407
+
parent: pageID,
408
408
+
position: "",
409
409
+
factID: canvasBlock.id,
410
410
+
};
411
411
+
412
412
+
let content = await blockToRecord(block);
413
413
+
if (!content) return null;
414
414
+
415
415
+
// Get canvas-specific properties
416
416
+
let width =
417
417
+
scan.eav(blockEntity, "canvas/block/width")?.[0]?.data.value || 360;
418
418
+
let rotation =
419
419
+
scan.eav(blockEntity, "canvas/block/rotation")?.[0]?.data.value;
420
420
+
421
421
+
let canvasBlockRecord: PubLeafletPagesCanvas.Block = {
422
422
+
$type: "pub.leaflet.pages.canvas#block",
423
423
+
block: content,
424
424
+
x: position.x,
425
425
+
y: position.y,
426
426
+
width,
427
427
+
...(rotation !== undefined && { rotation }),
428
428
+
};
429
429
+
430
430
+
return canvasBlockRecord;
431
431
+
}),
432
432
+
)
433
433
+
).filter((b): b is PubLeafletPagesCanvas.Block => b !== null);
362
434
}
363
435
}
364
436
+177
app/lish/[did]/[publication]/[rkey]/CanvasPage.tsx
···
1
1
+
"use client";
2
2
+
import {
3
3
+
PubLeafletPagesCanvas,
4
4
+
PubLeafletPagesLinearDocument,
5
5
+
PubLeafletPublication,
6
6
+
} from "lexicons/api";
7
7
+
import { PostPageData } from "./getPostPageData";
8
8
+
import { ProfileViewDetailed } from "@atproto/api/dist/client/types/app/bsky/actor/defs";
9
9
+
import { AppBskyFeedDefs } from "@atproto/api";
10
10
+
import { PageWrapper } from "components/Pages/Page";
11
11
+
import { Block } from "./PostContent";
12
12
+
import { CanvasBackgroundPattern } from "components/Canvas";
13
13
+
14
14
+
export function CanvasPage({
15
15
+
document,
16
16
+
blocks,
17
17
+
did,
18
18
+
profile,
19
19
+
preferences,
20
20
+
pubRecord,
21
21
+
prerenderedCodeBlocks,
22
22
+
bskyPostData,
23
23
+
document_uri,
24
24
+
pageId,
25
25
+
pageOptions,
26
26
+
fullPageScroll,
27
27
+
pages,
28
28
+
}: {
29
29
+
document_uri: string;
30
30
+
document: PostPageData;
31
31
+
blocks: PubLeafletPagesCanvas.Block[];
32
32
+
profile?: ProfileViewDetailed;
33
33
+
pubRecord: PubLeafletPublication.Record;
34
34
+
did: string;
35
35
+
prerenderedCodeBlocks?: Map<string, string>;
36
36
+
bskyPostData: AppBskyFeedDefs.PostView[];
37
37
+
preferences: { showComments?: boolean };
38
38
+
pageId?: string;
39
39
+
pageOptions?: React.ReactNode;
40
40
+
fullPageScroll: boolean;
41
41
+
pages: (PubLeafletPagesLinearDocument.Main | PubLeafletPagesCanvas.Main)[];
42
42
+
}) {
43
43
+
let hasPageBackground = !!pubRecord.theme?.showPageBackground;
44
44
+
45
45
+
return (
46
46
+
<PageWrapper
47
47
+
pageType="canvas"
48
48
+
fullPageScroll={fullPageScroll}
49
49
+
cardBorderHidden={!hasPageBackground}
50
50
+
id={pageId ? `post-page-${pageId}` : "post-page"}
51
51
+
drawerOpen={false}
52
52
+
pageOptions={pageOptions}
53
53
+
>
54
54
+
<CanvasContent
55
55
+
blocks={blocks}
56
56
+
did={did}
57
57
+
prerenderedCodeBlocks={prerenderedCodeBlocks}
58
58
+
bskyPostData={bskyPostData}
59
59
+
pageId={pageId}
60
60
+
pages={pages}
61
61
+
/>
62
62
+
</PageWrapper>
63
63
+
);
64
64
+
}
65
65
+
66
66
+
function CanvasContent({
67
67
+
blocks,
68
68
+
did,
69
69
+
prerenderedCodeBlocks,
70
70
+
bskyPostData,
71
71
+
pageId,
72
72
+
pages,
73
73
+
}: {
74
74
+
blocks: PubLeafletPagesCanvas.Block[];
75
75
+
did: string;
76
76
+
prerenderedCodeBlocks?: Map<string, string>;
77
77
+
bskyPostData: AppBskyFeedDefs.PostView[];
78
78
+
pageId?: string;
79
79
+
pages: (PubLeafletPagesLinearDocument.Main | PubLeafletPagesCanvas.Main)[];
80
80
+
}) {
81
81
+
let height = blocks.length > 0 ? Math.max(...blocks.map((b) => b.y), 0) : 0;
82
82
+
83
83
+
return (
84
84
+
<div className="canvasWrapper h-full w-fit overflow-y-scroll">
85
85
+
<div
86
86
+
style={{
87
87
+
minHeight: height + 512,
88
88
+
contain: "size layout paint",
89
89
+
}}
90
90
+
className="relative h-full w-[1272px]"
91
91
+
>
92
92
+
<CanvasBackground />
93
93
+
{blocks
94
94
+
.sort((a, b) => {
95
95
+
if (a.y === b.y) {
96
96
+
return a.x - b.x;
97
97
+
}
98
98
+
return a.y - b.y;
99
99
+
})
100
100
+
.map((canvasBlock, index) => {
101
101
+
return (
102
102
+
<CanvasBlock
103
103
+
key={index}
104
104
+
canvasBlock={canvasBlock}
105
105
+
did={did}
106
106
+
prerenderedCodeBlocks={prerenderedCodeBlocks}
107
107
+
bskyPostData={bskyPostData}
108
108
+
pageId={pageId}
109
109
+
pages={pages}
110
110
+
index={index}
111
111
+
/>
112
112
+
);
113
113
+
})}
114
114
+
</div>
115
115
+
</div>
116
116
+
);
117
117
+
}
118
118
+
119
119
+
function CanvasBlock({
120
120
+
canvasBlock,
121
121
+
did,
122
122
+
prerenderedCodeBlocks,
123
123
+
bskyPostData,
124
124
+
pageId,
125
125
+
pages,
126
126
+
index,
127
127
+
}: {
128
128
+
canvasBlock: PubLeafletPagesCanvas.Block;
129
129
+
did: string;
130
130
+
prerenderedCodeBlocks?: Map<string, string>;
131
131
+
bskyPostData: AppBskyFeedDefs.PostView[];
132
132
+
pageId?: string;
133
133
+
pages: (PubLeafletPagesLinearDocument.Main | PubLeafletPagesCanvas.Main)[];
134
134
+
index: number;
135
135
+
}) {
136
136
+
let { x, y, width, rotation } = canvasBlock;
137
137
+
let transform = `translate(${x}px, ${y}px)${rotation ? ` rotate(${rotation}deg)` : ""}`;
138
138
+
139
139
+
// Wrap the block in a LinearDocument.Block structure for compatibility
140
140
+
let linearBlock: PubLeafletPagesLinearDocument.Block = {
141
141
+
$type: "pub.leaflet.pages.linearDocument#block",
142
142
+
block: canvasBlock.block,
143
143
+
};
144
144
+
145
145
+
return (
146
146
+
<div
147
147
+
className="absolute rounded-lg flex items-stretch origin-center p-3"
148
148
+
style={{
149
149
+
top: 0,
150
150
+
left: 0,
151
151
+
width,
152
152
+
transform,
153
153
+
}}
154
154
+
>
155
155
+
<div className="contents">
156
156
+
<Block
157
157
+
pageId={pageId}
158
158
+
pages={pages}
159
159
+
bskyPostData={bskyPostData}
160
160
+
block={linearBlock}
161
161
+
did={did}
162
162
+
index={[index]}
163
163
+
preview={false}
164
164
+
prerenderedCodeBlocks={prerenderedCodeBlocks}
165
165
+
/>
166
166
+
</div>
167
167
+
</div>
168
168
+
);
169
169
+
}
170
170
+
171
171
+
const CanvasBackground = () => {
172
172
+
return (
173
173
+
<div className="w-full h-full pointer-events-none">
174
174
+
<CanvasBackgroundPattern pattern="grid" />
175
175
+
</div>
176
176
+
);
177
177
+
};
+9
-3
app/lish/[did]/[publication]/[rkey]/PostContent.tsx
···
9
9
PubLeafletBlocksWebsite,
10
10
PubLeafletDocument,
11
11
PubLeafletPagesLinearDocument,
12
12
+
PubLeafletPagesCanvas,
12
13
PubLeafletBlocksHorizontalRule,
13
14
PubLeafletBlocksBlockquote,
14
15
PubLeafletBlocksBskyPost,
···
46
47
className?: string;
47
48
prerenderedCodeBlocks?: Map<string, string>;
48
49
bskyPostData: AppBskyFeedDefs.PostView[];
49
49
-
pages: PubLeafletPagesLinearDocument.Main[];
50
50
+
pages: (PubLeafletPagesLinearDocument.Main | PubLeafletPagesCanvas.Main)[];
50
51
}) {
51
52
return (
52
53
<div
···
91
92
block: PubLeafletPagesLinearDocument.Block;
92
93
did: string;
93
94
isList?: boolean;
94
94
-
pages: PubLeafletPagesLinearDocument.Main[];
95
95
+
pages: (PubLeafletPagesLinearDocument.Main | PubLeafletPagesCanvas.Main)[];
95
96
previousBlock?: PubLeafletPagesLinearDocument.Block;
96
97
prerenderedCodeBlocks?: Map<string, string>;
97
98
bskyPostData: AppBskyFeedDefs.PostView[];
···
137
138
let id = b.block.id;
138
139
let page = pages.find((p) => p.id === id);
139
140
if (!page) return;
141
141
+
142
142
+
const isCanvas = PubLeafletPagesCanvas.isMain(page);
143
143
+
140
144
return (
141
145
<PublishedPageLinkBlock
142
146
blocks={page.blocks}
···
144
148
parentPageId={pageId}
145
149
did={did}
146
150
bskyPostData={bskyPostData}
151
151
+
isCanvas={isCanvas}
152
152
+
pages={pages}
147
153
/>
148
154
);
149
155
}
···
354
360
355
361
function ListItem(props: {
356
362
index: number[];
357
357
-
pages: PubLeafletPagesLinearDocument.Main[];
363
363
+
pages: (PubLeafletPagesLinearDocument.Main | PubLeafletPagesCanvas.Main)[];
358
364
item: PubLeafletBlocksUnorderedList.ListItem;
359
365
did: string;
360
366
className?: string;
+48
-20
app/lish/[did]/[publication]/[rkey]/PostPages.tsx
···
2
2
import {
3
3
PubLeafletDocument,
4
4
PubLeafletPagesLinearDocument,
5
5
+
PubLeafletPagesCanvas,
5
6
PubLeafletPublication,
6
7
} from "lexicons/api";
7
8
import { PostPageData } from "./getPostPageData";
···
21
22
import { useParams } from "next/navigation";
22
23
import { decodeQuotePosition } from "./quotePosition";
23
24
import { LinearDocumentPage } from "./LinearDocumentPage";
25
25
+
import { CanvasPage } from "./CanvasPage";
24
26
25
27
const usePostPageUIState = create(() => ({
26
28
pages: [] as string[],
···
157
159
158
160
{pages.map((p) => {
159
161
let page = record.pages.find(
160
160
-
(page) => (page as PubLeafletPagesLinearDocument.Main).id === p,
161
161
-
) as PubLeafletPagesLinearDocument.Main | undefined;
162
162
+
(page) =>
163
163
+
(page as PubLeafletPagesLinearDocument.Main | PubLeafletPagesCanvas.Main).id === p,
164
164
+
) as PubLeafletPagesLinearDocument.Main | PubLeafletPagesCanvas.Main | undefined;
162
165
if (!page) return null;
166
166
+
167
167
+
const isCanvas = PubLeafletPagesCanvas.isMain(page);
168
168
+
163
169
return (
164
170
<Fragment key={p}>
165
171
<SandwichSpacer />
166
166
-
<LinearDocumentPage
167
167
-
fullPageScroll={false}
168
168
-
document={document}
169
169
-
blocks={page.blocks}
170
170
-
did={did}
171
171
-
preferences={preferences}
172
172
-
pubRecord={pubRecord}
173
173
-
prerenderedCodeBlocks={prerenderedCodeBlocks}
174
174
-
bskyPostData={bskyPostData}
175
175
-
document_uri={document_uri}
176
176
-
pageId={page.id}
177
177
-
pageOptions={
178
178
-
<PageOptions
179
179
-
onClick={() => closePage(page?.id!)}
180
180
-
hasPageBackground={hasPageBackground}
181
181
-
/>
182
182
-
}
183
183
-
/>
172
172
+
{isCanvas ? (
173
173
+
<CanvasPage
174
174
+
fullPageScroll={false}
175
175
+
document={document}
176
176
+
blocks={(page as PubLeafletPagesCanvas.Main).blocks}
177
177
+
did={did}
178
178
+
preferences={preferences}
179
179
+
pubRecord={pubRecord}
180
180
+
prerenderedCodeBlocks={prerenderedCodeBlocks}
181
181
+
bskyPostData={bskyPostData}
182
182
+
document_uri={document_uri}
183
183
+
pageId={page.id}
184
184
+
pages={record.pages as PubLeafletPagesLinearDocument.Main[]}
185
185
+
pageOptions={
186
186
+
<PageOptions
187
187
+
onClick={() => closePage(page?.id!)}
188
188
+
hasPageBackground={hasPageBackground}
189
189
+
/>
190
190
+
}
191
191
+
/>
192
192
+
) : (
193
193
+
<LinearDocumentPage
194
194
+
fullPageScroll={false}
195
195
+
document={document}
196
196
+
blocks={(page as PubLeafletPagesLinearDocument.Main).blocks}
197
197
+
did={did}
198
198
+
preferences={preferences}
199
199
+
pubRecord={pubRecord}
200
200
+
prerenderedCodeBlocks={prerenderedCodeBlocks}
201
201
+
bskyPostData={bskyPostData}
202
202
+
document_uri={document_uri}
203
203
+
pageId={page.id}
204
204
+
pageOptions={
205
205
+
<PageOptions
206
206
+
onClick={() => closePage(page?.id!)}
207
207
+
hasPageBackground={hasPageBackground}
208
208
+
/>
209
209
+
}
210
210
+
/>
211
211
+
)}
184
212
{drawer && drawer.pageId === page.id && (
185
213
<InteractionDrawer
186
214
pageId={page.id}
+101
-3
app/lish/[did]/[publication]/[rkey]/PublishedPageBlock.tsx
···
4
4
import { useUIState } from "src/useUIState";
5
5
import { CSSProperties, useContext, useRef } from "react";
6
6
import { useCardBorderHidden } from "components/Pages/useCardBorderHidden";
7
7
-
import { PostContent } from "./PostContent";
7
7
+
import { PostContent, Block } from "./PostContent";
8
8
import {
9
9
PubLeafletBlocksHeader,
10
10
PubLeafletBlocksText,
11
11
PubLeafletComment,
12
12
PubLeafletPagesLinearDocument,
13
13
+
PubLeafletPagesCanvas,
13
14
PubLeafletPublication,
14
15
} from "lexicons/api";
15
16
import { AppBskyFeedDefs } from "@atproto/api";
···
23
24
} from "./Interactions/Interactions";
24
25
import { CommentTiny } from "components/Icons/CommentTiny";
25
26
import { QuoteTiny } from "components/Icons/QuoteTiny";
27
27
+
import { CanvasBackgroundPattern } from "components/Canvas";
26
28
27
29
export function PublishedPageLinkBlock(props: {
28
28
-
blocks: PubLeafletPagesLinearDocument.Block[];
30
30
+
blocks: PubLeafletPagesLinearDocument.Block[] | PubLeafletPagesCanvas.Block[];
29
31
parentPageId: string | undefined;
30
32
pageId: string;
31
33
did: string;
···
33
35
className?: string;
34
36
prerenderedCodeBlocks?: Map<string, string>;
35
37
bskyPostData: AppBskyFeedDefs.PostView[];
38
38
+
isCanvas?: boolean;
39
39
+
pages?: (PubLeafletPagesLinearDocument.Main | PubLeafletPagesCanvas.Main)[];
36
40
}) {
37
41
//switch to use actually state
38
42
let openPages = useOpenPages();
···
55
59
openPage(props.parentPageId, props.pageId);
56
60
}}
57
61
>
58
58
-
<DocLinkBlock {...props} />
62
62
+
{props.isCanvas ? (
63
63
+
<CanvasLinkBlock
64
64
+
blocks={props.blocks as PubLeafletPagesCanvas.Block[]}
65
65
+
did={props.did}
66
66
+
pageId={props.pageId}
67
67
+
bskyPostData={props.bskyPostData}
68
68
+
pages={props.pages || []}
69
69
+
/>
70
70
+
) : (
71
71
+
<DocLinkBlock
72
72
+
{...props}
73
73
+
blocks={props.blocks as PubLeafletPagesLinearDocument.Block[]}
74
74
+
/>
75
75
+
)}
59
76
</div>
60
77
);
61
78
}
···
228
245
</div>
229
246
);
230
247
};
248
248
+
249
249
+
const CanvasLinkBlock = (props: {
250
250
+
blocks: PubLeafletPagesCanvas.Block[];
251
251
+
did: string;
252
252
+
pageId: string;
253
253
+
bskyPostData: AppBskyFeedDefs.PostView[];
254
254
+
pages: (PubLeafletPagesLinearDocument.Main | PubLeafletPagesCanvas.Main)[];
255
255
+
}) => {
256
256
+
let pageWidth = `var(--page-width-unitless)`;
257
257
+
let height = props.blocks.length > 0 ? Math.max(...props.blocks.map((b) => b.y), 0) : 0;
258
258
+
259
259
+
return (
260
260
+
<div
261
261
+
style={{ contain: "size layout paint" }}
262
262
+
className={`pageLinkBlockPreview shrink-0 h-[200px] w-full overflow-clip relative`}
263
263
+
>
264
264
+
<div
265
265
+
className={`absolute top-0 left-0 origin-top-left pointer-events-none w-full`}
266
266
+
style={{
267
267
+
width: `calc(1px * ${pageWidth})`,
268
268
+
height: "calc(1150px * 2)",
269
269
+
transform: `scale(calc(((${pageWidth} - 36) / 1272 )))`,
270
270
+
}}
271
271
+
>
272
272
+
<div
273
273
+
style={{
274
274
+
minHeight: height + 512,
275
275
+
contain: "size layout paint",
276
276
+
}}
277
277
+
className="relative h-full w-[1272px]"
278
278
+
>
279
279
+
<div className="w-full h-full pointer-events-none">
280
280
+
<CanvasBackgroundPattern pattern="grid" />
281
281
+
</div>
282
282
+
{props.blocks
283
283
+
.sort((a, b) => {
284
284
+
if (a.y === b.y) {
285
285
+
return a.x - b.x;
286
286
+
}
287
287
+
return a.y - b.y;
288
288
+
})
289
289
+
.map((canvasBlock, index) => {
290
290
+
let { x, y, width, rotation } = canvasBlock;
291
291
+
let transform = `translate(${x}px, ${y}px)${rotation ? ` rotate(${rotation}deg)` : ""}`;
292
292
+
293
293
+
// Wrap the block in a LinearDocument.Block structure for compatibility
294
294
+
let linearBlock: PubLeafletPagesLinearDocument.Block = {
295
295
+
$type: "pub.leaflet.pages.linearDocument#block",
296
296
+
block: canvasBlock.block,
297
297
+
};
298
298
+
299
299
+
return (
300
300
+
<div
301
301
+
key={index}
302
302
+
className="absolute rounded-lg flex items-stretch origin-center p-3"
303
303
+
style={{
304
304
+
top: 0,
305
305
+
left: 0,
306
306
+
width,
307
307
+
transform,
308
308
+
}}
309
309
+
>
310
310
+
<div className="contents">
311
311
+
<Block
312
312
+
pageId={props.pageId}
313
313
+
pages={props.pages}
314
314
+
bskyPostData={props.bskyPostData}
315
315
+
block={linearBlock}
316
316
+
did={props.did}
317
317
+
index={[index]}
318
318
+
preview={true}
319
319
+
/>
320
320
+
</div>
321
321
+
</div>
322
322
+
);
323
323
+
})}
324
324
+
</div>
325
325
+
</div>
326
326
+
</div>
327
327
+
);
328
328
+
};