tangled
alpha
login
or
join now
mackuba.eu
/
skythread
14
fork
atom
Thread viewer for Bluesky
14
fork
atom
overview
issues
pulls
pipelines
renamed post context to "placement"
mackuba.eu
3 months ago
a7a8aff0
f1bd5071
+42
-42
16 changed files
expand all
collapse all
unified
split
src
components
embeds
QuoteComponent.svelte
posts
BlockedPostContent.svelte
BlockedPostView.svelte
PostComponent.svelte
PostFooter.svelte
PostHeader.svelte
PostWrapper.svelte
ThreadRootParent.svelte
pages
HashtagPage.svelte
LycanSearchPage.svelte
NotificationsPage.svelte
QuotesPage.svelte
ThreadPage.svelte
TimelineSearchPage.svelte
types.d.ts
utils
post_presenter.ts
+1
-1
src/components/embeds/QuoteComponent.svelte
···
56
56
{#snippet quoteContent(record: ATProtoRecord)}
57
57
{#if record instanceof BasePost}
58
58
<div class="quote-embed">
59
59
-
<PostWrapper post={record} context="quote" />
59
59
+
<PostWrapper post={record} placement="quote" />
60
60
</div>
61
61
62
62
{:else if record instanceof FeedGeneratorRecord}
+2
-2
src/components/posts/BlockedPostContent.svelte
···
6
6
import PostBody from './PostBody.svelte';
7
7
import ThreadRootParentRaw from './ThreadRootParentRaw.svelte';
8
8
9
9
-
let { post, context }: { post: Post, context: PostContext } = $props();
9
9
+
let { post, placement }: { post: Post, placement: PostPlacement } = $props();
10
10
11
11
-
setContext('post', { post, context });
11
11
+
setContext('post', { post, placement });
12
12
</script>
13
13
14
14
{#if post.isPageRoot && post.parentReference}
+3
-3
src/components/posts/BlockedPostView.svelte
···
10
10
type Props = {
11
11
reason: string;
12
12
post: BlockedPost | DetachedQuotePost;
13
13
-
context: PostContext;
13
13
+
placement: PostPlacement;
14
14
}
15
15
16
16
-
let { reason, post, context }: Props = $props();
16
16
+
let { reason, post, placement }: Props = $props();
17
17
18
18
let biohazardEnabled = $derived(account.biohazardEnabled !== false);
19
19
let loading = $state(false);
···
77
77
{/if}
78
78
</p>
79
79
80
80
-
<BlockedPostContent post={reloadedPost} {context} />
80
80
+
<BlockedPostContent post={reloadedPost} {placement} />
81
81
{:else}
82
82
<MissingPostView post={new MissingPost(post.data)} />
83
83
{/if}
+8
-8
src/components/posts/PostComponent.svelte
···
30
30
31
31
type Props = {
32
32
post: Post,
33
33
-
context: PostContext,
33
33
+
placement: PostPlacement,
34
34
highlightedMatches?: string[] | undefined,
35
35
class?: string | undefined
36
36
}
37
37
38
38
-
let { post, context, highlightedMatches = undefined, ...props }: Props = $props();
38
38
+
let { post, placement, highlightedMatches = undefined, ...props }: Props = $props();
39
39
40
40
let collapsed = $state(false);
41
41
let replies: AnyPost[] = $state(post.replies);
···
43
43
let missingHiddenReplies: number | undefined = $state();
44
44
let hiddenRepliesError: Error | undefined = $state();
45
45
46
46
-
setContext('post', { post, context });
46
46
+
setContext('post', { post, placement });
47
47
48
48
// TODO: make Post reactive
49
49
let quoteCount: number | undefined = $state(post.quoteCount);
···
122
122
{/if}
123
123
{/snippet}
124
124
125
125
-
<div class="post post-{context} {props.class || ''}" class:muted={post.muted} class:collapsed={collapsed}>
125
125
+
<div class="post post-{placement} {props.class || ''}" class:muted={post.muted} class:collapsed={collapsed}>
126
126
<PostHeader />
127
127
128
128
-
{#if context == 'thread' && !post.isPageRoot}
128
128
+
{#if placement == 'thread' && !post.isPageRoot}
129
129
<EdgeMargin bind:collapsed />
130
130
{/if}
131
131
···
141
141
{/if}
142
142
143
143
{#if post.replyCount == 1 && (replies[0] instanceof Post) && replies[0].author.did == post.author.did}
144
144
-
<PostComponent post={replies[0]} context="thread" class="flat" />
144
144
+
<PostComponent post={replies[0]} placement="thread" class="flat" />
145
145
{:else}
146
146
{#each replies as reply (reply.uri)}
147
147
{#if shouldRenderReply(reply)}
148
148
-
<PostWrapper post={reply} context="thread" />
148
148
+
<PostWrapper post={reply} placement="thread" />
149
149
{/if}
150
150
{/each}
151
151
{/if}
152
152
153
153
-
{#if context == 'thread' && !repliesLoaded}
153
153
+
{#if placement == 'thread' && !repliesLoaded}
154
154
{#if post.hasMoreReplies}
155
155
<LoadMoreLink onLoad={onMoreRepliesLoaded} onError={onRepliesLoadingError} />
156
156
{:else if post.hasHiddenReplies && account.biohazardEnabled !== false}
+5
-5
src/components/posts/PostFooter.svelte
···
6
6
import { showLoginDialog } from '../../skythread.js';
7
7
import { showError } from '../../utils.js';
8
8
9
9
-
let { post, context }: { post: Post, context: PostContext } = getContext('post');
9
9
+
let { post, placement }: { post: Post, placement: PostPlacement } = getContext('post');
10
10
let { quoteCount }: { quoteCount: number | undefined } = $props();
11
11
12
12
let isLiked = $state(post.liked);
···
67
67
<span><i class="fa-solid fa-retweet"></i> {post.repostCount}</span>
68
68
{/if}
69
69
70
70
-
{#if post.replyCount > 0 && (context == 'quotes' || context == 'feed')}
70
70
+
{#if post.replyCount > 0 && (placement == 'quotes' || placement == 'feed')}
71
71
<span>
72
72
<i class="fa-regular fa-message"></i>
73
73
<a href="{linkToPostThread(post)}">{post.replyCount > 1 ? `${post.replyCount} replies` : '1 reply'}</a>
74
74
</span>
75
75
{/if}
76
76
77
77
-
{#if quoteCount && context != 'quote'}
78
78
-
{#if context == 'quotes' || context == 'feed' || post.isPageRoot}
77
77
+
{#if quoteCount && placement != 'quote'}
78
78
+
{#if placement == 'quotes' || placement == 'feed' || post.isPageRoot}
79
79
<span>
80
80
<i class="fa-regular fa-comments"></i>
81
81
<a href={linkToQuotesPage(post.linkToPost)}>{quoteCount > 1 ? `${quoteCount} quotes` : '1 quote'}</a>
···
87
87
{/if}
88
88
{/if}
89
89
90
90
-
{#if context == 'thread' && post.isRestrictingReplies}
90
90
+
{#if placement == 'thread' && post.isRestrictingReplies}
91
91
<span><i class="fa-solid fa-ban"></i> Limited replies</span>
92
92
{/if}
93
93
+4
-4
src/components/posts/PostHeader.svelte
···
4
4
import { PostPresenter } from '../../utils/post_presenter.js';
5
5
import PostSubtreeLink from './PostSubtreeLink.svelte';
6
6
7
7
-
let { post, context }: { post: Post, context: PostContext } = getContext('post');
8
8
-
let presenter = new PostPresenter(post, context);
7
7
+
let { post, placement }: { post: Post, placement: PostPlacement } = getContext('post');
8
8
+
let presenter = new PostPresenter(post, placement);
9
9
10
10
let avatar: HTMLImageElement | undefined = $state();
11
11
···
43
43
44
44
<a class="time" href="{post.linkToPost}" target="_blank" title="{post.createdAt.toISOString()}">{presenter.formattedTimestamp}</a>
45
45
46
46
-
{#if (post.replyCount > 0 && !post.isPageRoot) || ['quote', 'quotes', 'feed'].includes(context)}
46
46
+
{#if (post.replyCount > 0 && !post.isPageRoot) || ['quote', 'quotes', 'feed'].includes(placement)}
47
47
<span class="separator">•</span>
48
48
49
49
-
{#if ['quote', 'quotes', 'feed'].includes(context)}
49
49
+
{#if ['quote', 'quotes', 'feed'].includes(placement)}
50
50
<PostSubtreeLink {post} title="Load thread" />
51
51
{:else}
52
52
<PostSubtreeLink {post} title="Load this subtree" />
+5
-5
src/components/posts/PostWrapper.svelte
···
14
14
- feed - a post on the hashtag feed page
15
15
*/
16
16
17
17
-
let { post, context }: { post: AnyPost, context: PostContext } = $props();
17
17
+
let { post, placement }: { post: AnyPost, placement: PostPlacement } = $props();
18
18
</script>
19
19
20
20
{#if post instanceof Post}
21
21
-
<PostComponent {post} {context} />
21
21
+
<PostComponent {post} {placement} />
22
22
{:else}
23
23
-
<div class="post post-{context} blocked">
23
23
+
<div class="post post-{placement} blocked">
24
24
{#if post instanceof BlockedPost}
25
25
-
<BlockedPostView {post} {context} reason="Blocked post" />
25
25
+
<BlockedPostView {post} {placement} reason="Blocked post" />
26
26
{:else if post instanceof DetachedQuotePost}
27
27
-
<BlockedPostView {post} {context} reason="Hidden quote" />
27
27
+
<BlockedPostView {post} {placement} reason="Hidden quote" />
28
28
{:else}
29
29
<MissingPostView {post} />
30
30
{/if}
+1
-1
src/components/posts/ThreadRootParent.svelte
···
13
13
</p>
14
14
{:else if post instanceof BlockedPost}
15
15
<div class="back">
16
16
-
<BlockedPostView {post} context="parent" reason="Parent post blocked" />
16
16
+
<BlockedPostView {post} placement="parent" reason="Parent post blocked" />
17
17
</div>
18
18
{:else if post instanceof MissingPost}
19
19
<p class="back">
+1
-1
src/pages/HashtagPage.svelte
···
56
56
</header>
57
57
58
58
{#each posts as post (post.uri)}
59
59
-
<PostComponent {post} context="feed" />
59
59
+
<PostComponent {post} placement="feed" />
60
60
{/each}
61
61
{:else if !loadingFailed}
62
62
<MainLoader />
+1
-1
src/pages/LycanSearchPage.svelte
···
206
206
<p>...</p>
207
207
{:else}
208
208
{#each results as post (post.uri)}
209
209
-
<PostComponent {post} context="feed" {highlightedMatches} />
209
209
+
<PostComponent {post} placement="feed" {highlightedMatches} />
210
210
{/each}
211
211
{#if finishedPosts}
212
212
<p class="results-end">{results.length > 0 ? "No more results." : "No results."}</p>
+1
-1
src/pages/NotificationsPage.svelte
···
58
58
<FeedPostParent uri={post.parentReference.uri} />
59
59
{/if}
60
60
61
61
-
<PostComponent {post} context="feed" />
61
61
+
<PostComponent {post} placement="feed" />
62
62
{/each}
63
63
{:else if !loadingFailed}
64
64
<MainLoader />
+1
-1
src/pages/QuotesPage.svelte
···
65
65
<FeedPostParent uri={post.parentReference.uri} />
66
66
{/if}
67
67
68
68
-
<PostComponent {post} context="quotes" />
68
68
+
<PostComponent {post} placement="quotes" />
69
69
{/each}
70
70
{:else if !loadingFailed}
71
71
<MainLoader />
+2
-2
src/pages/ThreadPage.svelte
···
66
66
<ThreadRootParentRaw uri={post.parentReference.uri} />
67
67
{/if}
68
68
69
69
-
<PostComponent {post} context="thread" bind:this={rootComponent} />
69
69
+
<PostComponent {post} placement="thread" bind:this={rootComponent} />
70
70
{:else}
71
71
-
<PostWrapper {post} context="thread" />
71
71
+
<PostWrapper {post} placement="thread" />
72
72
{/if}
73
73
{:else if !loadingFailed}
74
74
<MainLoader />
+1
-1
src/pages/TimelineSearchPage.svelte
···
79
79
80
80
<div class="results">
81
81
{#each results as post (post.uri)}
82
82
-
<PostComponent {post} context="feed" />
82
82
+
<PostComponent {post} placement="feed" />
83
83
{/each}
84
84
</div>
85
85
{/if}
+1
-1
src/types.d.ts
···
25
25
| import("./models/posts.js").MissingPost
26
26
| import("./models/posts.js").DetachedQuotePost;
27
27
28
28
-
type PostContext = 'thread' | 'parent' | 'quote' | 'quotes' | 'feed';
28
28
+
type PostPlacement = 'thread' | 'parent' | 'quote' | 'quotes' | 'feed';
+5
-5
src/utils/post_presenter.ts
···
13
13
*/
14
14
15
15
post: Post;
16
16
-
context: PostContext;
16
16
+
placement: PostPlacement;
17
17
18
18
-
constructor(post: Post, context: PostContext) {
18
18
+
constructor(post: Post, placement: PostPlacement) {
19
19
this.post = post;
20
20
-
this.context = context;
20
20
+
this.placement = placement;
21
21
}
22
22
23
23
get timeFormatForTimestamp(): Intl.DateTimeFormatOptions {
24
24
-
if (this.context == 'quotes' || this.context == 'feed') {
24
24
+
if (this.placement == 'quotes' || this.placement == 'feed') {
25
25
return { weekday: 'short', day: 'numeric', month: 'short', year: 'numeric', hour: 'numeric', minute: 'numeric' };
26
26
-
} else if (this.post.isPageRoot || this.context != 'thread') {
26
26
+
} else if (this.post.isPageRoot || this.placement != 'thread') {
27
27
return { day: 'numeric', month: 'short', year: 'numeric', hour: 'numeric', minute: 'numeric' };
28
28
} else if (this.post.pageRoot && !sameDay(this.post.createdAt, this.post.pageRoot.createdAt)) {
29
29
return { day: 'numeric', month: 'short', hour: 'numeric', minute: 'numeric' };