Skip to content

Commit d7dde6e

Browse files
authored
Merge pull request #3050 from appwrite/feat/threads-author-pages
Feat/threads author pages
2 parents d1d2f78 + 9decbad commit d7dde6e

13 files changed

Lines changed: 399 additions & 20 deletions

File tree

src/icons/optimized/persons.svg

Lines changed: 1 addition & 0 deletions
Loading

src/icons/svg/persons.svg

Lines changed: 6 additions & 0 deletions
Loading

src/lib/components/ui/icon/sprite/sprite.svelte

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,6 @@
105105
fill-rule="evenodd"
106106
></path>
107107
</symbol>
108-
<symbol id="mongo" stroke="currentColor" viewBox="0 0 120 258">
109-
<path
110-
d="M83.009 28.756 C 72.133 15.909,62.767 2.861,60.854 0.151 C 60.653 -0.050,60.350 -0.050,60.149 0.151 C 58.236 2.861,48.870 15.909,37.994 28.756 C -55.359 147.292,52.697 227.287,52.697 227.287 L 53.603 227.889 C 54.409 240.235,56.423 258.000,56.423 258.000 L 60.451 258.000 L 64.479 258.000 C 64.479 258.000,66.493 240.335,67.299 227.889 L 68.205 227.187 C 68.306 227.187,176.362 147.292,83.009 28.756 M60.451 225.480 C 60.451 225.480,55.617 221.365,54.308 219.257 L 54.308 219.057 L 60.149 89.981 C 60.149 89.580,60.753 89.580,60.753 89.981 L 66.594 219.057 L 66.594 219.257 C 65.285 221.365,60.451 225.480,60.451 225.480 Z"
111-
fill="currentColor"
112-
stroke="none"
113-
fill-rule="evenodd"
114-
></path>
115-
</symbol>
116108
<symbol id="divider-vertical" stroke="currentColor" viewBox="0 0 20 20">
117109
<path
118110
d="M9.750 3.463 C 9.591 3.536,9.520 3.610,9.451 3.775 C 9.406 3.884,9.400 4.585,9.400 10.009 L 9.400 16.119 9.475 16.268 C 9.696 16.705,10.304 16.705,10.525 16.268 L 10.600 16.119 10.599 10.001 C 10.599 4.136,10.596 3.878,10.537 3.750 C 10.464 3.591,10.390 3.520,10.225 3.451 C 10.064 3.384,9.914 3.388,9.750 3.463 "
@@ -137,6 +129,22 @@
137129
fill-rule="evenodd"
138130
></path>
139131
</symbol>
132+
<symbol id="mongo" stroke="currentColor" viewBox="0 0 120 258">
133+
<path
134+
d="M83.009 28.756 C 72.133 15.909,62.767 2.861,60.854 0.151 C 60.653 -0.050,60.350 -0.050,60.149 0.151 C 58.236 2.861,48.870 15.909,37.994 28.756 C -55.359 147.292,52.697 227.287,52.697 227.287 L 53.603 227.889 C 54.409 240.235,56.423 258.000,56.423 258.000 L 60.451 258.000 L 64.479 258.000 C 64.479 258.000,66.493 240.335,67.299 227.889 L 68.205 227.187 C 68.306 227.187,176.362 147.292,83.009 28.756 M60.451 225.480 C 60.451 225.480,55.617 221.365,54.308 219.257 L 54.308 219.057 L 60.149 89.981 C 60.149 89.580,60.753 89.580,60.753 89.981 L 66.594 219.057 L 66.594 219.257 C 65.285 221.365,60.451 225.480,60.451 225.480 Z"
135+
fill="currentColor"
136+
stroke="none"
137+
fill-rule="evenodd"
138+
></path>
139+
</symbol>
140+
<symbol id="zzz-persons" stroke="currentColor" viewBox="0 0 20 20">
141+
<path
142+
d="M7.017 2.438 C 6.652 2.484,6.313 2.588,5.948 2.766 C 3.954 3.733,3.295 6.168,4.523 8.025 C 4.691 8.278,5.064 8.669,5.333 8.875 C 5.631 9.102,6.217 9.382,6.617 9.489 C 6.914 9.569,7.009 9.578,7.500 9.578 C 7.989 9.578,8.086 9.569,8.376 9.491 C 8.735 9.394,9.224 9.176,9.523 8.978 C 9.778 8.809,10.169 8.437,10.375 8.167 C 10.602 7.869,10.882 7.283,10.989 6.883 C 11.069 6.586,11.078 6.491,11.078 6.000 C 11.078 5.511,11.069 5.414,10.991 5.124 C 10.831 4.530,10.527 3.973,10.133 3.553 C 9.335 2.703,8.182 2.290,7.017 2.438 M8.133 3.681 C 8.234 3.709,8.444 3.794,8.600 3.871 C 8.829 3.984,8.942 4.070,9.187 4.315 C 9.448 4.575,9.513 4.664,9.643 4.934 C 9.840 5.347,9.883 5.537,9.883 6.000 C 9.883 6.467,9.840 6.656,9.641 7.067 C 9.510 7.335,9.441 7.430,9.184 7.687 C 8.925 7.947,8.835 8.014,8.566 8.144 C 7.857 8.486,7.143 8.486,6.434 8.144 C 6.165 8.014,6.074 7.946,5.814 7.686 C 5.552 7.425,5.487 7.336,5.357 7.066 C 5.160 6.653,5.117 6.463,5.117 6.000 C 5.117 5.537,5.160 5.347,5.357 4.934 C 5.487 4.664,5.552 4.575,5.814 4.314 C 6.074 4.053,6.165 3.987,6.434 3.857 C 6.608 3.774,6.832 3.689,6.933 3.670 C 7.034 3.650,7.147 3.627,7.183 3.619 C 7.310 3.589,7.951 3.631,8.133 3.681 M13.234 3.673 C 12.906 3.841,12.805 4.232,13.010 4.538 C 13.061 4.615,13.185 4.703,13.402 4.817 C 13.577 4.909,13.800 5.043,13.897 5.115 C 14.273 5.391,14.639 5.963,14.751 6.448 C 14.780 6.575,14.804 6.824,14.804 7.000 C 14.804 7.176,14.780 7.425,14.751 7.552 C 14.639 8.038,14.273 8.609,13.886 8.901 C 13.786 8.976,13.565 9.108,13.394 9.194 C 13.174 9.305,13.062 9.383,13.009 9.462 C 12.806 9.769,12.907 10.159,13.234 10.327 C 13.445 10.436,13.623 10.413,14.007 10.227 C 14.960 9.765,15.637 8.921,15.925 7.836 C 15.998 7.560,16.009 7.447,16.009 7.000 C 16.009 6.553,15.998 6.440,15.925 6.164 C 15.636 5.076,14.968 4.244,14.010 3.777 C 13.618 3.587,13.445 3.564,13.234 3.673 M4.952 10.438 C 4.337 10.497,3.556 10.743,3.025 11.046 C 1.978 11.644,1.149 12.594,0.749 13.656 C 0.464 14.411,0.401 14.858,0.401 16.135 C 0.400 17.090,0.402 17.124,0.475 17.268 C 0.696 17.705,1.304 17.705,1.525 17.268 C 1.597 17.125,1.600 17.085,1.600 16.242 C 1.600 14.895,1.669 14.485,2.014 13.783 C 2.406 12.987,2.987 12.406,3.783 12.014 C 4.216 11.801,4.605 11.685,5.044 11.636 C 5.472 11.588,9.528 11.588,9.956 11.636 C 11.453 11.803,12.759 12.884,13.216 14.333 C 13.357 14.781,13.399 15.211,13.399 16.218 C 13.400 17.086,13.403 17.125,13.475 17.268 C 13.696 17.706,14.301 17.705,14.527 17.266 C 14.604 17.117,14.604 17.116,14.590 15.983 C 14.574 14.720,14.550 14.537,14.311 13.833 C 13.676 11.963,11.966 10.619,9.983 10.434 C 9.544 10.393,5.385 10.396,4.952 10.438 M15.732 10.975 C 15.294 11.196,15.295 11.809,15.734 12.023 C 15.816 12.063,16.041 12.171,16.233 12.264 C 17.021 12.642,17.625 13.256,18.018 14.076 C 18.324 14.715,18.400 15.165,18.400 16.335 C 18.400 17.082,18.404 17.126,18.475 17.268 C 18.696 17.705,19.304 17.705,19.525 17.268 C 19.597 17.125,19.600 17.085,19.600 16.267 C 19.600 15.330,19.573 15.018,19.448 14.512 C 19.055 12.916,17.853 11.560,16.320 10.983 C 16.047 10.880,15.923 10.879,15.732 10.975 "
143+
stroke="none"
144+
fill-rule="evenodd"
145+
fill="currentColor"
146+
></path>
147+
</symbol>
140148
<symbol id="ycombinator" stroke="currentColor" viewBox="0 0 24 24">
141149
<path
142150
d="M3.000 12.000 L 3.000 21.000 12.000 21.000 L 21.000 21.000 21.000 12.000 L 21.000 3.000 12.000 3.000 L 3.000 3.000 3.000 12.000 M9.813 7.550 C 9.928 7.832,11.602 11.179,11.718 11.360 C 11.782 11.459,11.835 11.567,11.837 11.600 C 11.839 11.633,11.886 11.758,11.942 11.877 C 12.043 12.093,12.043 12.094,12.107 12.003 C 12.142 11.952,12.228 11.774,12.299 11.606 C 12.369 11.438,12.479 11.216,12.543 11.114 C 12.607 11.012,13.047 10.135,13.520 9.165 L 14.380 7.402 15.051 7.401 L 15.722 7.400 15.666 7.490 C 15.636 7.540,14.933 8.859,14.105 10.422 L 12.600 13.265 12.600 15.132 L 12.600 17.000 12.000 17.000 L 11.400 17.000 11.400 15.102 L 11.400 13.204 9.844 10.302 L 8.288 7.400 9.020 7.400 L 9.751 7.400 9.813 7.550 "

src/lib/components/ui/icon/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ export type IconType =
1212
| 'github'
1313
| 'ticket'
1414
| 'sparkle'
15-
| 'mongo'
1615
| 'divider-vertical'
1716
| 'nuxt'
1817
| 'chevron-up'
@@ -68,4 +67,6 @@ export type IconType =
6867
| 'minus'
6968
| 'chevron-left'
7069
| 'light'
71-
| 'mcp';
70+
| 'mcp'
71+
| 'mongo'
72+
| 'zzz-persons';

src/lib/utils/metadata.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,40 @@ export function createDiscussionForumPageSchema(options: {
254254

255255
return escapeJsonLtForHtmlScript(JSON.stringify(graph));
256256
}
257+
258+
export function createAuthorPageSchema({
259+
canonicalUrl,
260+
author
261+
}: {
262+
canonicalUrl: string;
263+
author: {
264+
display_name: string;
265+
username: string;
266+
avatar?: string;
267+
thread_count: number;
268+
reply_count: number;
269+
bio?: string;
270+
};
271+
}): string {
272+
const schema: Record<string, unknown> = {
273+
'@context': 'https://schema.org',
274+
'@type': 'ProfilePage',
275+
url: canonicalUrl,
276+
mainEntity: {
277+
'@type': 'Person',
278+
name: author.display_name,
279+
alternateName: author.username,
280+
...(author.avatar ? { image: author.avatar } : {}),
281+
...(author.bio ? { description: author.bio } : {}),
282+
interactionStatistic: [
283+
{
284+
'@type': 'InteractionCounter',
285+
interactionType: 'https://schema.org/WriteAction',
286+
userInteractionCount: author.thread_count + author.reply_count
287+
}
288+
]
289+
}
290+
};
291+
292+
return escapeJsonLtForHtmlScript(JSON.stringify(schema));
293+
}

src/routes/docs/references/[version]/[platform]/[service]/+page.svelte

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@
175175
});
176176
}
177177
178+
function formatGroup(group: string) {
179+
return group.replace(/([a-z])([A-Z])/g, '$1 $2');
180+
}
181+
178182
function groupMethodsByGroup(methods: SDKMethod[]) {
179183
return methods.reduce<Record<string, SDKMethod[]>>((acc, method) => {
180184
const groupKey = method.group || '';
@@ -387,7 +391,7 @@
387391
<li class="web-references-menu-group">
388392
{#if group !== ''}
389393
<h6 class="text-eyebrow text-greyscale-500 mb-2 uppercase">
390-
{group}
394+
{formatGroup(group)}
391395
</h6>
392396
{/if}
393397
<ul class="flex flex-col gap-2">

src/routes/threads/ThreadCard.svelte

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@
77
export let query: string;
88
99
$: highlightTerms = query?.split(' ') ?? [];
10+
$: isResolved = thread.is_resolved || /\[(solved|resolved|closed|fixed)\]/i.test(thread.title);
11+
12+
function timeAgo(dateStr: string): string {
13+
const diff = (Date.now() - new Date(dateStr).getTime()) / 1000;
14+
const formatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
15+
if (diff < 3600) return formatter.format(-Math.floor(diff / 60), 'minute');
16+
if (diff < 86400) return formatter.format(-Math.floor(diff / 3600), 'hour');
17+
if (diff < 2592000) return formatter.format(-Math.floor(diff / 86400), 'day');
18+
if (diff < 31536000) return formatter.format(-Math.floor(diff / 2592000), 'month');
19+
return formatter.format(-Math.floor(diff / 31536000), 'year');
20+
}
1021
</script>
1122

1223
{#key highlightTerms}
@@ -30,19 +41,32 @@
3041

3142
<div class="mt-4 flex min-w-0 flex-wrap justify-between gap-4">
3243
<ul class="flex min-w-0 flex-wrap gap-2">
44+
{#if isResolved}
45+
<li class="min-w-0">
46+
<div class="web-tag tag-resolved truncate">
47+
<span class="web-icon-check"></span>
48+
Resolved
49+
</div>
50+
</li>
51+
{/if}
3352
{#each thread.tags ?? [] as tag, index (tag + index)}
3453
<li class="min-w-0">
3554
<div class="web-tag truncate">{tag}</div>
3655
</li>
3756
{/each}
3857
</ul>
3958

40-
<div
41-
class="web-icon-button is-more-content web-u-pointer-events-none flex shrink-0 items-center"
42-
aria-label="Replies"
43-
>
44-
<span class="web-icon-message web-u-font-size-16" aria-hidden="true"></span>
45-
<span class="text-caption font-inter">{thread.message_count}</span>
59+
<div class="flex shrink-0 items-center gap-3">
60+
<div
61+
class="web-icon-button is-more-content web-u-pointer-events-none flex items-center"
62+
aria-label="Replies"
63+
>
64+
<span class="web-icon-message web-u-font-size-16" aria-hidden="true"></span>
65+
<span class="text-caption font-inter">{thread.message_count}</span>
66+
</div>
67+
{#if thread.last_activity}
68+
<span class="text-caption">{timeAgo(thread.last_activity)}</span>
69+
{/if}
4670
</div>
4771
</div>
4872
</a>
@@ -54,6 +78,11 @@
5478
overflow: hidden;
5579
}
5680
81+
.tag-resolved {
82+
color: #22c55e;
83+
border-color: rgba(34, 197, 94, 0.3);
84+
}
85+
5786
.thread {
5887
position: relative;
5988
max-width: 100%;

src/routes/threads/[id]/+page.svelte

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
let { data } = $props();
1414
1515
const title = $derived(data.title + ' - Threads' + TITLE_SUFFIX);
16+
const isResolved = $derived(
17+
data.is_resolved || /\[(solved|resolved|closed|fixed)\]/i.test(data.title)
18+
);
1619
const description = DEFAULT_DESCRIPTION;
1720
const discordLink = $derived(
1821
`https://discord.com/channels/564160730845151244/${data.discord_id}`
@@ -55,6 +58,52 @@
5558
<span class="web-icon-arrow-up"></span>
5659
<span class="text">{data.vote_count}</span>
5760
</li>
61+
{#if isResolved}
62+
<li class="web-tag is-success">
63+
<span class="web-icon-check"></span>
64+
<span class="text">Resolved</span>
65+
</li>
66+
{/if}
67+
{#if data.participant_count}
68+
<li class="web-tag">
69+
<svg
70+
width="16"
71+
height="16"
72+
viewBox="0 0 20 20"
73+
fill="none"
74+
xmlns="http://www.w3.org/2000/svg"
75+
aria-hidden="true"
76+
style="flex-shrink:0"
77+
>
78+
<circle
79+
cx="7.5"
80+
cy="6"
81+
r="3"
82+
stroke="currentColor"
83+
stroke-width="1.2"
84+
/>
85+
<path
86+
d="M1 17v-1.5A4.5 4.5 0 0 1 5.5 11h4A4.5 4.5 0 0 1 14 15.5V17"
87+
stroke="currentColor"
88+
stroke-width="1.2"
89+
stroke-linecap="round"
90+
/>
91+
<path
92+
d="M13.5 4.2a3 3 0 0 1 0 5.6"
93+
stroke="currentColor"
94+
stroke-width="1.2"
95+
stroke-linecap="round"
96+
/>
97+
<path
98+
d="M16 11.5a4.5 4.5 0 0 1 3 4.2V17"
99+
stroke="currentColor"
100+
stroke-width="1.2"
101+
stroke-linecap="round"
102+
/>
103+
</svg>
104+
<span class="text">{data.participant_count}</span>
105+
</li>
106+
{/if}
58107
{#each data.tags ?? [] as tag}
59108
<li class="web-tag">
60109
<span class="text">{tag}</span>

src/routes/threads/[id]/MessageCard.svelte

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,14 @@
2929
<div class="author-img">
3030
<img src={message.author_avatar} alt="" class="h-full w-full rounded-[inherit]" />
3131
</div>
32-
<span class="text-sub-body text-primary font-medium">{message.author}</span>
32+
{#if message.author_id}
33+
<a
34+
href="/threads/authors/{message.author_id}"
35+
class="text-sub-body text-primary web-link font-medium">{message.author}</a
36+
>
37+
{:else}
38+
<span class="text-sub-body text-primary font-medium">{message.author}</span>
39+
{/if}
3340
</div>
3441
<span class="timestamp text-caption">
3542
{formatTimestamp(message.timestamp)}
@@ -45,6 +52,12 @@
4552
}}
4653
/>
4754
</div>
55+
{#if message.reaction_count}
56+
<div class="reactions">
57+
<span class="web-icon-heart" aria-hidden="true"></span>
58+
<span class="text-caption">{message.reaction_count}</span>
59+
</div>
60+
{/if}
4861
<slot />
4962
</div>
5063

@@ -71,6 +84,15 @@
7184
gap: 0.5rem;
7285
}
7386
87+
.reactions {
88+
display: flex;
89+
align-items: center;
90+
gap: 0.25rem;
91+
margin-block-start: 0.75rem;
92+
opacity: 0.7;
93+
font-size: 0.875rem;
94+
}
95+
7496
.author-img {
7597
--p-size: 1.5rem; // 24px
7698

0 commit comments

Comments
 (0)