Skip to content
47 changes: 39 additions & 8 deletions app/components/BlueskyComment.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,18 @@ function getHostname(uri: string): string {
</script>

<template>
<div :class="depth === 0 ? 'flex gap-3' : 'flex gap-3 mt-3'">
<!-- Avatar -->
<!--
Depth 0: classic avatar-column layout (all screens)
Depth 1+: Medium-style inline avatar on mobile, avatar-column on desktop
-->
<div :class="depth === 0 ? 'flex gap-3' : 'sm:flex sm:gap-3'">
<!-- Column avatar: always shown at depth 0, desktop-only at depth 1+ -->
<a
:href="`https://bsky.app/profile/${comment.author.handle}`"
target="_blank"
rel="noopener noreferrer"
class="shrink-0"
:class="depth > 0 ? 'hidden sm:block' : ''"
>
<img
v-if="comment.author.avatar"
Expand All @@ -71,16 +76,39 @@ function getHostname(uri: string): string {

<div class="flex-1 min-w-0">
<!-- Author info + timestamp -->
<div class="flex flex-wrap items-baseline gap-x-2 gap-y-0">
<div class="flex flex-wrap items-center gap-x-2 gap-y-0">
<!-- Inline avatar: mobile-only for nested comments -->
<a
v-if="depth > 0"
:href="`https://bsky.app/profile/${comment.author.handle}`"
target="_blank"
rel="noopener noreferrer"
class="font-medium text-fg hover:underline"
class="shrink-0 sm:hidden"
>
<img
v-if="comment.author.avatar"
:src="comment.author.avatar"
:alt="comment.author.displayName || comment.author.handle"
class="w-6 h-6 rounded-full"
width="24"
height="24"
loading="lazy"
/>
<div
v-else
class="w-6 h-6 rounded-full bg-border flex items-center justify-center text-fg-muted text-xs"
>
{{ (comment.author.displayName || comment.author.handle).charAt(0).toUpperCase() }}
</div>
</a>
<a
:href="`https://bsky.app/profile/${comment.author.handle}`"
target="_blank"
rel="noopener noreferrer"
:class="['font-medium text-fg hover:underline', depth > 0 ? 'text-sm' : '']"
>
{{ comment.author.displayName || comment.author.handle }}
</a>
<span class="text-fg-subtle text-sm">@{{ comment.author.handle }}</span>
<span class="text-fg-subtle text-sm">·</span>
<a
:href="getCommentUrl(props.comment)"
Expand All @@ -93,7 +121,7 @@ function getHostname(uri: string): string {
</div>

<!-- Comment text with rich segments -->
<p class="text-fg-muted whitespace-pre-wrap">
<p class="text-fg-muted whitespace-pre-wrap mt-2 mb-3">
<template v-for="(segment, i) in processedSegments" :key="i">
<a
v-if="segment.url"
Expand Down Expand Up @@ -162,7 +190,7 @@ function getHostname(uri: string): string {
<!-- Like/repost counts -->
<div
v-if="comment.likeCount > 0 || comment.repostCount > 0"
class="mt-2 flex gap-4 text-sm text-fg-subtle"
class="mt-1 flex gap-4 text-sm text-fg-subtle"
>
<span v-if="comment.likeCount > 0">
{{ $t('blog.atproto.like_count', { count: comment.likeCount }, comment.likeCount) }}
Expand All @@ -174,7 +202,10 @@ function getHostname(uri: string): string {

<!-- Nested replies -->
<template v-if="comment.replies.length > 0">
<div v-if="depth < MaxDepth" class="mt-2 ps-2 border-is-2 border-border flex flex-col">
<div
v-if="depth < MaxDepth"
class="mt-3 ps-3 border-is-2 border-border flex flex-col gap-3"
>
<BlueskyComment
v-for="reply in comment.replies"
:key="reply.uri"
Expand Down
4 changes: 2 additions & 2 deletions app/components/global/BlogPostFederatedArticles.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const federatedArticles = computed(() => {
</script>

<template>
<aside class="px-4 sm:-mx-6 sm:px-6 sm:-my-3 sm:py-3 sm:rounded-md">
<aside class="sm:-mx-6 sm:px-6 sm:-my-3 sm:py-3 sm:rounded-md">
<h2 class="font-mono text-xl font-medium text-fg mt-0">
{{ headline }}
</h2>
Expand All @@ -55,7 +55,7 @@ const federatedArticles = computed(() => {
rel="noopener noreferrer"
v-for="article in federatedArticles"
:key="article.url"
class="grid grid-cols-[auto_1fr] gap-x-5 no-underline hover:no-underline rounded-lg border border-border p-4 transition-shadow hover:shadow-lg hover:shadow-gray-500/50"
class="grid grid-cols-[auto_1fr] gap-x-5 no-underline hover:no-underline rounded-lg border border-border p-4 transition-all hover:shadow-md hover:shadow-fg/5 hover:border-border-hover"
>
<AuthorAvatar v-if="article.author" :author="article.author" size="md" class="row-span-2" />
<div class="flex flex-col">
Expand Down
17 changes: 16 additions & 1 deletion app/components/global/BlogPostWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const blueskyPostUri = computed(() => blueskyLink.value?.postUri ?? null)
<AuthorList :authors="post.authors" variant="expanded" />
</div>
</div>
<article class="max-w-prose mx-auto p-2 prose dark:prose-invert">
<article class="max-w-prose mx-auto prose dark:prose-invert">
<div class="text-sm text-fg-muted font-mono mb-4">
<DateTime :datetime="frontmatter.date" year="numeric" month="short" day="numeric" />
</div>
Expand All @@ -77,4 +77,19 @@ const blueskyPostUri = computed(() => blueskyLink.value?.postUri ?? null)
:deep(.markdown-body) {
@apply prose dark:prose-invert;
}

:deep(.prose a:not(.not-prose a):not([class*='no-underline'])) {
text-decoration: underline;
text-underline-offset: 0.2rem;
text-decoration-thickness: 1px;
text-decoration-color: var(--fg-subtle);
transition:
text-decoration-color 0.2s,
color 0.2s;
}

:deep(.prose a:not(.not-prose a):not([class*='no-underline']):hover) {
text-decoration-color: var(--fg);
color: var(--fg);
}
</style>
14 changes: 8 additions & 6 deletions app/components/global/BlueskyPostEmbed.client.vue
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,16 @@ const postUrl = computed(() => {
:href="postUrl ?? '#'"
target="_blank"
rel="noopener noreferrer"
class="not-prose block rounded-lg border border-border bg-bg-subtle p-4 sm:p-5 no-underline hover:border-border-hover transition-colors duration-200"
class="not-prose block rounded-lg border border-border bg-bg-subtle p-4 sm:p-5 no-underline hover:border-border-hover transition-colors duration-200 relative group"
>
<!-- Bluesky icon -->
<span
class="i-simple-icons:bluesky w-5 h-5 text-fg-subtle group-hover:text-blue-500 absolute top-4 end-4 sm:top-5 sm:end-5"
aria-hidden="true"
/>

<!-- Author row -->
<div class="flex items-center gap-3 mb-3">
<div class="flex items-center gap-3 mb-3 pe-7">
<img
v-if="post.author.avatar"
:src="`${post.author.avatar}?size=48`"
Expand All @@ -126,10 +132,6 @@ const postUrl = computed(() => {
</div>
<div class="text-sm text-fg-subtle truncate">@{{ post.author.handle }}</div>
</div>
<span
class="i-simple-icons:bluesky w-5 h-5 text-fg-subtle ms-auto shrink-0"
aria-hidden="true"
/>
</div>

<!-- Post text -->
Expand Down
2 changes: 1 addition & 1 deletion i18n/locales/az-AZ.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"reply_count": "{count} cavab",
"like_count": "{count} bəyənmə",
"repost_count": "{count} yenidən paylaşım",
"more_replies": "{count} cavab daha..."
"more_replies": "daha {count} cavab... | daha {count} cavab..."
}
},
"settings": {
Expand Down
2 changes: 1 addition & 1 deletion i18n/locales/cs-CZ.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"reply_count": "{count} odpověď | {count} odpovědi | {count} odpovědí",
"like_count": "{count} lajk | {count} lajky | {count} lajků",
"repost_count": "{count} repost | {count} reposty | {count} repostů",
"more_replies": "{count} další odpověď ... | {count} další odpovědi ... | {count} dalších odpovědí ..."
"more_replies": "ještě {count} odpověď… | ještě {count} odpovědi… | ještě {count} odpovědí"
}
},
"settings": {
Expand Down
2 changes: 1 addition & 1 deletion i18n/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"reply_count": "{count} Antwort | {count} Antworten",
"like_count": "{count} Like | {count} Likes",
"repost_count": "{count} Repost | {count} Reposts",
"more_replies": "{count} weitere Antwort anzeigen | {count} weitere Antworten anzeigen"
"more_replies": "noch {count} Antwort… | noch {count} Antworten"
}
},
"settings": {
Expand Down
2 changes: 1 addition & 1 deletion i18n/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"reply_count": "{count} réponse | {count} réponses",
"like_count": "{count} j'aime | {count} j'aime",
"repost_count": "{count} repartage | {count} repartages",
"more_replies": "{count} réponse de plus... | {count} réponses de plus..."
"more_replies": "{count} réponse supplémentaire... | {count} réponses supplémentaires..."
}
},
"settings": {
Expand Down
2 changes: 1 addition & 1 deletion i18n/locales/id-ID.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
"reply_count": "{count} balasan | {count} balasan",
"like_count": "{count} suka | {count} suka",
"repost_count": "{count} repost | {count} repost",
"more_replies": "{count} balasan lainnya... | {count} balasan lainnya..."
"more_replies": "{count} balasan lagi... | {count} balasan lagi..."
}
},
"settings": {
Expand Down
2 changes: 1 addition & 1 deletion i18n/locales/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"reply_count": "{count} 件の返信",
"like_count": "{count} 件のいいね",
"repost_count": "{count} 件のリポスト",
"more_replies": "さらに {count} 件のリプライを表示..."
"more_replies": "さらに{count}件の返信…"
}
},
"settings": {
Expand Down
2 changes: 1 addition & 1 deletion i18n/locales/pl-PL.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"reply_count": "{count} odpowiedzi | {count} odpowiedź | {count} odpowiedzi | {count} odpowiedzi | {count} odpowiedzi",
"like_count": "{count} polubień | {count} polubienie | {count} polubienia | {count} polubień | {count} polubień",
"repost_count": "{count} udostępnień | {count} udostępnienie | {count} udostępnienia | {count} udostępnień | {count} udostępnień",
"more_replies": "{count} odpowiedzi więcej... | {count} odpowiedź więcej... | {count} odpowiedzi więcej... | {count} odpowiedzi więcej... | {count} odpowiedzi więcej..."
"more_replies": "jeszcze {count} odpowiedź… | jeszcze {count} odpowiedzi… | jeszcze {count} odpowiedzi"
}
},
"settings": {
Expand Down
2 changes: 1 addition & 1 deletion i18n/locales/ru-RU.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"reply_count": "{count} ответ | {count} ответа | {count} ответов",
"like_count": "{count} лайк | {count} лайка | {count} лайков",
"repost_count": "{count} репост | {count} репоста | {count} репостов",
"more_replies": "Ещё {count} ответ | Ещё {count} ответа | Ещё {count} ответов"
"more_replies": "ещё {count} ответ... | ещё {count} ответа... | ещё {count} ответов..."
}
},
"settings": {
Expand Down
2 changes: 1 addition & 1 deletion i18n/locales/tr-TR.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"reply_count": "{count} yanıt",
"like_count": "{count} beğeni",
"repost_count": "{count} yeniden paylaşım",
"more_replies": "{count} yanıt daha..."
"more_replies": "{count} yanıt daha... | {count} yanıt daha..."
}
},
"settings": {
Expand Down
2 changes: 1 addition & 1 deletion i18n/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"reply_count": "{count} 条回复 | {count} 条回复",
"like_count": "{count} 个赞 | {count} 个赞",
"repost_count": "{count} 次转发 | {count} 次转发",
"more_replies": "还有 {count} 条回复... | 还有 {count} 条回复..."
"more_replies": "还有 {count} 条回复..."
}
},
"settings": {
Expand Down
Loading