diff --git a/app/app.vue b/app/app.vue
index 898cc04..0efe9cc 100644
--- a/app/app.vue
+++ b/app/app.vue
@@ -9,5 +9,5 @@ import 'vue-sonner/style.css'
-
+
diff --git a/app/components/changelog/ChangelogReactions.vue b/app/components/changelog/ChangelogReactions.vue
index 1231540..ba9f728 100644
--- a/app/components/changelog/ChangelogReactions.vue
+++ b/app/components/changelog/ChangelogReactions.vue
@@ -15,6 +15,10 @@ const picked = reactive>({})
const pickerOpen = ref(false)
const rootRef = ref(null)
+const { data: session } = useAuthSession()
+const isLoggedIn = computed(() => !!session.value?.user)
+const loginModal = useLoginModal()
+
// Initialize picked state from userReactions
for (const emoji of props.userReactions) {
picked[emoji] = true
@@ -29,6 +33,11 @@ const displayedReactions = computed(() =>
)
async function toggle(emoji: string) {
+ if (!isLoggedIn.value) {
+ pickerOpen.value = false
+ return loginModal.open()
+ }
+
const wasActive = picked[emoji]
// Optimistic update
diff --git a/app/components/post/PostDetail.vue b/app/components/post/PostDetail.vue
index 00884ec..d9f4fdb 100644
--- a/app/components/post/PostDetail.vue
+++ b/app/components/post/PostDetail.vue
@@ -2,6 +2,7 @@
import { MdEditor } from 'md-editor-v3'
import 'md-editor-v3/lib/style.css'
import '~/assets/css/md-editor-preview.css'
+import { toast } from 'vue-sonner'
import { sanitizeAttachmentHtml } from '~/utils/attachment';
@@ -280,6 +281,17 @@ async function handleDeleteComment(commentId: string) {
watch(commentSort, () => {
store.fetchComments(props.slug, commentSort.value)
})
+
+async function handleShare() {
+ // Canonical post URL — independent of current location (post may be opened in a modal)
+ const url = `${window.location.origin}/p/${props.slug}`
+ try {
+ await navigator.clipboard.writeText(url)
+ toast.success('Link copied to clipboard')
+ } catch {
+ toast.error('Failed to copy link')
+ }
+}
@@ -474,8 +486,10 @@ watch(commentSort, () => {
+
+