Skip to content

Commit a793c0f

Browse files
committed
Add social media sharing component with localization support
1 parent de00136 commit a793c0f

File tree

4 files changed

+186
-0
lines changed

4 files changed

+186
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
<script setup lang="ts">
2+
const props = defineProps({
3+
url: {
4+
type: String,
5+
required: true
6+
},
7+
title: {
8+
type: String,
9+
required: true
10+
},
11+
description: {
12+
type: String,
13+
default: ''
14+
},
15+
isLargePage: {
16+
type: Boolean,
17+
default: false
18+
}
19+
});
20+
21+
// The isLargePage prop is passed from the parent component
22+
23+
// Function to track share events (for future PostHog integration)
24+
const trackShareEvent = (platform: string) => {
25+
// This function will be used for PostHog tracking in the future
26+
// For now, it's just a placeholder
27+
console.log(`Shared on ${platform}`);
28+
};
29+
30+
// Function to add tracking parameter for large pages
31+
const getShareUrl = (baseUrl: string, platform: string) => {
32+
// Check if this is one of the large pages that needs tracking
33+
if (props.isLargePage) {
34+
// Add tracking query parameter
35+
return `${baseUrl}?utm_source=${platform}&utm_medium=social&utm_campaign=share`;
36+
}
37+
return baseUrl;
38+
};
39+
40+
// Share URLs for different platforms
41+
const facebookShareUrl = computed(() => {
42+
const baseUrl = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(props.url)}`;
43+
return getShareUrl(baseUrl, 'facebook');
44+
});
45+
46+
const twitterShareUrl = computed(() => {
47+
const baseUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(props.url)}&text=${encodeURIComponent(props.title)}`;
48+
return getShareUrl(baseUrl, 'twitter');
49+
});
50+
51+
const linkedinShareUrl = computed(() => {
52+
const baseUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(props.url)}`;
53+
return getShareUrl(baseUrl, 'linkedin');
54+
});
55+
56+
const whatsappShareUrl = computed(() => {
57+
const baseUrl = `https://wa.me/?text=${encodeURIComponent(props.title + ' ' + props.url)}`;
58+
return getShareUrl(baseUrl, 'whatsapp');
59+
});
60+
61+
const emailShareUrl = computed(() => {
62+
const baseUrl = `mailto:?subject=${encodeURIComponent(props.title)}&body=${encodeURIComponent(props.description + '\n\n' + props.url)}`;
63+
return getShareUrl(baseUrl, 'email');
64+
});
65+
</script>
66+
67+
<template>
68+
<div class="social-media-share">
69+
<h3 class="text-lg font-bold mb-3">{{ $t('article.share') }}</h3>
70+
<div class="flex space-x-3">
71+
<!-- Facebook -->
72+
<a :href="facebookShareUrl"
73+
target="_blank"
74+
rel="noopener noreferrer"
75+
class="social-button bg-blue-600 hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:outline-none"
76+
:aria-label="$t('article.share_on_facebook')"
77+
@click="trackShareEvent('facebook')"
78+
data-ph-capture-attribute-platform="facebook">
79+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
80+
<path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z" />
81+
</svg>
82+
</a>
83+
84+
<!-- Twitter -->
85+
<a :href="twitterShareUrl"
86+
target="_blank"
87+
rel="noopener noreferrer"
88+
class="social-button bg-sky-500 hover:bg-sky-600 focus:ring-2 focus:ring-sky-400 focus:outline-none"
89+
:aria-label="$t('article.share_on_twitter')"
90+
@click="trackShareEvent('twitter')"
91+
data-ph-capture-attribute-platform="twitter">
92+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
93+
<path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z" />
94+
</svg>
95+
</a>
96+
97+
<!-- LinkedIn -->
98+
<a :href="linkedinShareUrl"
99+
target="_blank"
100+
rel="noopener noreferrer"
101+
class="social-button bg-blue-700 hover:bg-blue-800 focus:ring-2 focus:ring-blue-600 focus:outline-none"
102+
:aria-label="$t('article.share_on_linkedin')"
103+
@click="trackShareEvent('linkedin')"
104+
data-ph-capture-attribute-platform="linkedin">
105+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
106+
<path d="M4.98 3.5c0 1.381-1.11 2.5-2.48 2.5s-2.48-1.119-2.48-2.5c0-1.38 1.11-2.5 2.48-2.5s2.48 1.12 2.48 2.5zm.02 4.5h-5v16h5v-16zm7.982 0h-4.968v16h4.969v-8.399c0-4.67 6.029-5.052 6.029 0v8.399h4.988v-10.131c0-7.88-8.922-7.593-11.018-3.714v-2.155z" />
107+
</svg>
108+
</a>
109+
110+
<!-- WhatsApp -->
111+
<a :href="whatsappShareUrl"
112+
target="_blank"
113+
rel="noopener noreferrer"
114+
class="social-button bg-green-500 hover:bg-green-600 focus:ring-2 focus:ring-green-400 focus:outline-none"
115+
:aria-label="$t('article.share_on_whatsapp')"
116+
@click="trackShareEvent('whatsapp')"
117+
data-ph-capture-attribute-platform="whatsapp">
118+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
119+
<path d="M.057 24l1.687-6.163c-1.041-1.804-1.588-3.849-1.587-5.946.003-6.556 5.338-11.891 11.893-11.891 3.181.001 6.167 1.24 8.413 3.488 2.245 2.248 3.481 5.236 3.48 8.414-.003 6.557-5.338 11.892-11.893 11.892-1.99-.001-3.951-.5-5.688-1.448l-6.305 1.654zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-5.462-4.415-9.89-9.881-9.892-5.452 0-9.887 4.434-9.889 9.884-.001 2.225.651 3.891 1.746 5.634l-.999 3.648 3.742-.981zm11.387-5.464c-.074-.124-.272-.198-.57-.347-.297-.149-1.758-.868-2.031-.967-.272-.099-.47-.149-.669.149-.198.297-.768.967-.941 1.165-.173.198-.347.223-.644.074-.297-.149-1.255-.462-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.297-.347.446-.521.151-.172.2-.296.3-.495.099-.198.05-.372-.025-.521-.075-.148-.669-1.611-.916-2.206-.242-.579-.487-.501-.669-.51l-.57-.01c-.198 0-.52.074-.792.372s-1.04 1.016-1.04 2.479 1.065 2.876 1.213 3.074c.149.198 2.095 3.2 5.076 4.487.709.306 1.263.489 1.694.626.712.226 1.36.194 1.872.118.571-.085 1.758-.719 2.006-1.413.248-.695.248-1.29.173-1.414z" />
120+
</svg>
121+
</a>
122+
123+
<!-- Email -->
124+
<a :href="emailShareUrl"
125+
class="social-button bg-gray-600 hover:bg-gray-700 focus:ring-2 focus:ring-gray-500 focus:outline-none"
126+
:aria-label="$t('article.share_by_email')"
127+
@click="trackShareEvent('email')"
128+
data-ph-capture-attribute-platform="email">
129+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
130+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
131+
</svg>
132+
</a>
133+
</div>
134+
</div>
135+
</template>
136+
137+
<style scoped>
138+
.social-button {
139+
display: flex;
140+
align-items: center;
141+
justify-content: center;
142+
width: 40px;
143+
height: 40px;
144+
border-radius: 50%;
145+
color: white;
146+
transition: all 0.2s ease;
147+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
148+
}
149+
150+
.social-button:hover {
151+
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
152+
transform: translateY(-1px);
153+
}
154+
155+
.social-button:active {
156+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
157+
transform: translateY(0);
158+
}
159+
</style>

i18n/locales/de.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,13 @@
3636
},
3737
"accessibility": {
3838
"logo_alt": "OneLiteFeather Logo"
39+
},
40+
"article": {
41+
"share": "Diesen Artikel teilen",
42+
"share_on_facebook": "Auf Facebook teilen",
43+
"share_on_twitter": "Auf Twitter teilen",
44+
"share_on_linkedin": "Auf LinkedIn teilen",
45+
"share_on_whatsapp": "Auf WhatsApp teilen",
46+
"share_by_email": "Per E-Mail teilen"
3947
}
4048
}

i18n/locales/en.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,13 @@
3636
},
3737
"accessibility": {
3838
"logo_alt": "OneLiteFeather Logo"
39+
},
40+
"article": {
41+
"share": "Share this article",
42+
"share_on_facebook": "Share on Facebook",
43+
"share_on_twitter": "Share on Twitter",
44+
"share_on_linkedin": "Share on LinkedIn",
45+
"share_on_whatsapp": "Share on WhatsApp",
46+
"share_by_email": "Share by Email"
3947
}
4048
}

pages/[...slug].vue

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import {definePageMeta} from "#imports";
3+
import SocialMediaShare from "~/components/blog/SocialMediaShare.vue";
34
const { locale, t, locales } = useI18n()
45
const route = useRoute()
56
const config = useRuntimeConfig()
@@ -124,6 +125,16 @@ useHead(article?.value?.head || {})
124125
<time v-if="article?.pubDate" class="text-sm text-gray-500 dark:text-gray-400"><i18n-d :value="article?.pubDate"></i18n-d></time>
125126
<ContentRenderer class="text-gray-700 dark:text-gray-300 mt-2" :value="article">
126127
</ContentRenderer>
128+
129+
<!-- Social Media Sharing Buttons -->
130+
<div class="mt-6">
131+
<SocialMediaShare
132+
:url="config.public.siteUrl + '/' + locale.value + '/' + article.slug"
133+
:title="article.title"
134+
:description="article.description || ''"
135+
:is-large-page="['alles-was-man-ueber-ethanol-wissen-sollte', 'riding-the-rollercoaster-of-automation-with-proxmox-and-ansible', 'plugins-open-for-adoption', 'effizientes-logging-in-paper-plugins', 'dev-blog-1'].includes(article.slug)"
136+
/>
137+
</div>
127138
</div>
128139
</article>
129140
</div>

0 commit comments

Comments
 (0)