Skip to content

Commit 993d939

Browse files
committed
feat: add social sharing buttons for blog posts
- Add SocialShare component with Twitter, LinkedIn, Facebook, and native share buttons - Create BlogPostItem wrapper to display sharing buttons on individual blog posts - Add responsive CSS styling for social sharing buttons - Only show sharing buttons on actual blog posts (not tag or author pages) - Include proper accessibility attributes and hover effects - Support both light and dark themes Fixes #1127
1 parent 8a51da4 commit 993d939

File tree

4 files changed

+259
-0
lines changed

4 files changed

+259
-0
lines changed

src/components/SocialShare.tsx

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import React from 'react';
2+
import { Twitter, Linkedin, Facebook, Share2 } from 'lucide-react';
3+
4+
interface SocialShareProps {
5+
title: string;
6+
description?: string;
7+
permalink: string;
8+
className?: string;
9+
}
10+
11+
const SocialShare: React.FC<SocialShareProps> = ({
12+
title,
13+
description,
14+
permalink,
15+
className = ''
16+
}) => {
17+
const shareUrl = `https://www.recodehive.com${permalink}`;
18+
const encodedUrl = encodeURIComponent(shareUrl);
19+
const encodedTitle = encodeURIComponent(title);
20+
const encodedDescription = encodeURIComponent(description || title);
21+
22+
const shareLinks = {
23+
twitter: `https://twitter.com/intent/tweet?url=${encodedUrl}&text=${encodedTitle}&via=recodehive`,
24+
linkedin: `https://www.linkedin.com/sharing/share-offsite/?url=${encodedUrl}`,
25+
facebook: `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`,
26+
};
27+
28+
const handleShare = (platform: keyof typeof shareLinks) => {
29+
window.open(shareLinks[platform], '_blank', 'noopener,noreferrer,width=600,height=400');
30+
};
31+
32+
const handleNativeShare = async () => {
33+
if (navigator.share) {
34+
try {
35+
await navigator.share({
36+
title,
37+
text: description || title,
38+
url: shareUrl,
39+
});
40+
} catch (error) {
41+
console.log('Error sharing:', error);
42+
}
43+
}
44+
};
45+
46+
return (
47+
<div className={`social-share ${className}`}>
48+
<h4 className="social-share-title">Share this post</h4>
49+
<div className="social-share-buttons">
50+
<button
51+
className="social-share-button twitter"
52+
onClick={() => handleShare('twitter')}
53+
aria-label="Share on Twitter"
54+
title="Share on Twitter"
55+
>
56+
<Twitter size={18} />
57+
<span>Twitter</span>
58+
</button>
59+
60+
<button
61+
className="social-share-button linkedin"
62+
onClick={() => handleShare('linkedin')}
63+
aria-label="Share on LinkedIn"
64+
title="Share on LinkedIn"
65+
>
66+
<Linkedin size={18} />
67+
<span>LinkedIn</span>
68+
</button>
69+
70+
<button
71+
className="social-share-button facebook"
72+
onClick={() => handleShare('facebook')}
73+
aria-label="Share on Facebook"
74+
title="Share on Facebook"
75+
>
76+
<Facebook size={18} />
77+
<span>Facebook</span>
78+
</button>
79+
80+
{navigator.share && (
81+
<button
82+
className="social-share-button native"
83+
onClick={handleNativeShare}
84+
aria-label="Share"
85+
title="Share"
86+
>
87+
<Share2 size={18} />
88+
<span>Share</span>
89+
</button>
90+
)}
91+
</div>
92+
</div>
93+
);
94+
};
95+
96+
export default SocialShare;

src/css/custom.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
color: inherit;
66
}
77

8+
@import "./social-share.css";
9+
810
/* You can override the default Infima variables here. */
911
@import "tailwindcss";
1012

src/css/social-share.css

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/* Social Share Component Styles */
2+
.social-share {
3+
margin: 2rem 0;
4+
padding: 1.5rem;
5+
border: 1px solid var(--ifm-color-emphasis-200);
6+
border-radius: 8px;
7+
background: var(--ifm-color-emphasis-50);
8+
}
9+
10+
.social-share-title {
11+
font-size: 1.1rem;
12+
font-weight: 600;
13+
margin: 0 0 1rem 0;
14+
color: var(--ifm-color-emphasis-900);
15+
display: flex;
16+
align-items: center;
17+
gap: 0.5rem;
18+
}
19+
20+
.social-share-title::before {
21+
content: '📢';
22+
font-size: 1.2rem;
23+
}
24+
25+
.social-share-buttons {
26+
display: flex;
27+
gap: 0.75rem;
28+
flex-wrap: wrap;
29+
}
30+
31+
.social-share-button {
32+
display: flex;
33+
align-items: center;
34+
gap: 0.5rem;
35+
padding: 0.5rem 1rem;
36+
border: none;
37+
border-radius: 6px;
38+
font-size: 0.9rem;
39+
font-weight: 500;
40+
cursor: pointer;
41+
transition: all 0.2s ease;
42+
text-decoration: none;
43+
min-height: 36px;
44+
}
45+
46+
.social-share-button:hover {
47+
transform: translateY(-2px);
48+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
49+
}
50+
51+
.social-share-button:active {
52+
transform: translateY(0);
53+
}
54+
55+
/* Twitter Button */
56+
.social-share-button.twitter {
57+
background: linear-gradient(135deg, #1da1f2, #1991db);
58+
color: white;
59+
}
60+
61+
.social-share-button.twitter:hover {
62+
background: linear-gradient(135deg, #1991db, #1681c2);
63+
}
64+
65+
/* LinkedIn Button */
66+
.social-share-button.linkedin {
67+
background: linear-gradient(135deg, #0077b5, #005885);
68+
color: white;
69+
}
70+
71+
.social-share-button.linkedin:hover {
72+
background: linear-gradient(135deg, #005885, #004471);
73+
}
74+
75+
/* Facebook Button */
76+
.social-share-button.facebook {
77+
background: linear-gradient(135deg, #1877f2, #166fe5);
78+
color: white;
79+
}
80+
81+
.social-share-button.facebook:hover {
82+
background: linear-gradient(135deg, #166fe5, #145fd0);
83+
}
84+
85+
/* Native Share Button */
86+
.social-share-button.native {
87+
background: linear-gradient(135deg, #6c757d, #5a6268);
88+
color: white;
89+
}
90+
91+
.social-share-button.native:hover {
92+
background: linear-gradient(135deg, #5a6268, #495057);
93+
}
94+
95+
/* Dark theme adjustments */
96+
[data-theme='dark'] .social-share {
97+
background: var(--ifm-color-emphasis-100);
98+
border-color: var(--ifm-color-emphasis-300);
99+
}
100+
101+
[data-theme='dark'] .social-share-title {
102+
color: var(--ifm-color-emphasis-0);
103+
}
104+
105+
/* Mobile responsiveness */
106+
@media (max-width: 768px) {
107+
.social-share {
108+
padding: 1rem;
109+
margin: 1.5rem 0;
110+
}
111+
112+
.social-share-buttons {
113+
gap: 0.5rem;
114+
}
115+
116+
.social-share-button {
117+
padding: 0.4rem 0.8rem;
118+
font-size: 0.85rem;
119+
min-height: 32px;
120+
}
121+
122+
.social-share-button span {
123+
display: none; /* Hide text on mobile, show only icons */
124+
}
125+
126+
.social-share-button {
127+
min-width: 36px;
128+
justify-content: center;
129+
}
130+
}
131+
132+
@media (max-width: 480px) {
133+
.social-share-buttons {
134+
justify-content: center;
135+
}
136+
}

src/theme/BlogPostItem/index.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
import BlogPostItem from '@theme-original/BlogPostItem';
3+
import SocialShare from '../../components/SocialShare';
4+
5+
export default function BlogPostItemWrapper(props) {
6+
const { metadata } = props;
7+
8+
// Only show social sharing buttons for actual blog posts (not tag pages or author pages)
9+
const isBlogPost = metadata && metadata.title && metadata.permalink && metadata.permalink.startsWith('/blog/') && !metadata.permalink.includes('/tags/') && !metadata.permalink.includes('/authors/');
10+
11+
return (
12+
<div className="blog-post-item-wrapper">
13+
<BlogPostItem {...props} />
14+
{isBlogPost && (
15+
<div className="blog-post-social-share">
16+
<SocialShare
17+
title={metadata.title}
18+
description={metadata.description}
19+
permalink={metadata.permalink}
20+
/>
21+
</div>
22+
)}
23+
</div>
24+
);
25+
}

0 commit comments

Comments
 (0)