Added sticky share to social media component in blog website#323
Added sticky share to social media component in blog website#323DARSHAN-R-DARSHAN wants to merge 1 commit intokeploy:mainfrom
Conversation
Signed-off-by: DARSHAN-R-DARSHAN <darshanramanji07@gmail.com>
91269d1 to
5d85191
Compare
|
Hi! @amaan-bhati, I think that the share option would look cool if it is on both PostHeader and below the blog banner. |
|
Thank you for contributing and taking the initiative to work on this! Feel free to explore other open issues in the repository and pick one that hasn’t been addressed yet. We’d be happy to review another contribution from you. Thanks again for your effort! |
|
Hey @DARSHAN-R-DARSHAN 👋 — thanks for putting this PR together, we appreciate the effort! We've gone ahead and requested a Copilot review on this. Here's some context from the reviewer:
Once you've had a chance to go through the comments, please address the feedback and resolve the threads — and we'll get this across the line. Feel free to ask if anything's unclear. Happy coding! 💙 |
There was a problem hiding this comment.
Pull request overview
This PR adds a “sticky” social sharing UI to the blog post sidebar so readers can share the current post (Twitter/X, LinkedIn, and copy link) while scrolling.
Changes:
- Added share URL construction and clipboard-copy behavior to
PostBody. - Rendered a new “Share this” icon row in the sticky
<aside>sidebar.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| const currentURL = encodeURIComponent( | ||
| `keploy.io/${router.basePath + router.asPath}` | ||
| ); | ||
| const twitterShareUrl = `https://twitter.com/share?url=${currentURL}`; | ||
| const linkedinShareUrl = `https://www.linkedin.com/shareArticle?url=${currentURL}`; | ||
| const copyToClipboard = async () => { | ||
| try { | ||
| await navigator.clipboard.writeText(`https://keploy.io/blog${router.asPath}`); | ||
| setCopied(true); | ||
| setTimeout(() => setCopied(false), 2000); | ||
| } catch (err) { | ||
| console.error("Failed to copy!", err); |
There was a problem hiding this comment.
currentURL is built as keploy.io/${router.basePath + router.asPath} which omits the protocol and will produce a double-slash before the path (e.g. keploy.io//blog/... because the path starts with /). This can lead to malformed share URLs. Build the absolute URL from the existing SITE_URL (or window.location.origin) and normalize slashes before encodeURIComponent.
| const currentURL = encodeURIComponent( | |
| `keploy.io/${router.basePath + router.asPath}` | |
| ); | |
| const twitterShareUrl = `https://twitter.com/share?url=${currentURL}`; | |
| const linkedinShareUrl = `https://www.linkedin.com/shareArticle?url=${currentURL}`; | |
| const copyToClipboard = async () => { | |
| try { | |
| await navigator.clipboard.writeText(`https://keploy.io/blog${router.asPath}`); | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| } catch (err) { | |
| console.error("Failed to copy!", err); | |
| const origin = | |
| typeof window !== "undefined" | |
| ? window.location.origin | |
| : "https://keploy.io"; | |
| const normalizedPath = `${router.basePath || ""}${router.asPath || "/"}` | |
| .replace(/\/{2,}/g, "/") | |
| .replace(/^([^/])/, "/$1"); | |
| const absoluteCurrentURL = `${origin.replace(/\/+$/, "")}${normalizedPath}`; | |
| const currentURL = encodeURIComponent(absoluteCurrentURL); | |
| const twitterShareUrl = `https://twitter.com/share?url=${currentURL}`; | |
| const linkedinShareUrl = `https://www.linkedin.com/shareArticle?url=${currentURL}`; | |
| const copyToClipboard = async () => { | |
| try { | |
| await navigator.clipboard.writeText(absoluteCurrentURL); | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| } catch (err) { | |
| console.error("Failed to copy the article link. Please copy the URL from your browser address bar instead.", err); |
|
|
||
| const currentURL = encodeURIComponent( | ||
| `keploy.io/${router.basePath + router.asPath}` | ||
| ); | ||
| const twitterShareUrl = `https://twitter.com/share?url=${currentURL}`; | ||
| const linkedinShareUrl = `https://www.linkedin.com/shareArticle?url=${currentURL}`; | ||
| const copyToClipboard = async () => { | ||
| try { | ||
| await navigator.clipboard.writeText(`https://keploy.io/blog${router.asPath}`); | ||
| setCopied(true); | ||
| setTimeout(() => setCopied(false), 2000); | ||
| } catch (err) { | ||
| console.error("Failed to copy!", err); |
There was a problem hiding this comment.
The clipboard URL is hard-coded to https://keploy.io/blog${router.asPath} while the share URLs use a different construction. This can drift if the basePath/domain changes and can create inconsistent shared vs copied URLs. Prefer deriving all three from a single canonical base (e.g. SITE_URL) and the current path.
| const currentURL = encodeURIComponent( | |
| `keploy.io/${router.basePath + router.asPath}` | |
| ); | |
| const twitterShareUrl = `https://twitter.com/share?url=${currentURL}`; | |
| const linkedinShareUrl = `https://www.linkedin.com/shareArticle?url=${currentURL}`; | |
| const copyToClipboard = async () => { | |
| try { | |
| await navigator.clipboard.writeText(`https://keploy.io/blog${router.asPath}`); | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| } catch (err) { | |
| console.error("Failed to copy!", err); | |
| const currentPath = `${router.basePath || ""}${router.asPath || ""}`; | |
| const siteUrl = | |
| typeof window !== "undefined" | |
| ? window.location.origin | |
| : "https://keploy.io"; | |
| const canonicalUrl = `${siteUrl}${currentPath}`; | |
| const encodedCanonicalUrl = encodeURIComponent(canonicalUrl); | |
| const twitterShareUrl = `https://twitter.com/share?url=${encodedCanonicalUrl}`; | |
| const linkedinShareUrl = `https://www.linkedin.com/shareArticle?url=${encodedCanonicalUrl}`; | |
| const copyToClipboard = async () => { | |
| try { | |
| await navigator.clipboard.writeText(canonicalUrl); | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| } catch (err) { | |
| console.error("Failed to copy the link. Please copy the URL from your browser address bar instead.", err); |
| setCopied(true); | ||
| setTimeout(() => setCopied(false), 2000); | ||
| } catch (err) { |
There was a problem hiding this comment.
setTimeout(() => setCopied(false), 2000) is not cleared on unmount, which can cause a state update on an unmounted component when navigating away quickly. Store the timeout id (e.g. in a ref) and clear it in an effect cleanup.
| <Link | ||
| href={twitterShareUrl} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| className="twitter-share-button text-xl text-black transition-colors duration-300 hover:text-blue-500" | ||
| > | ||
| <FaXTwitter className="icon" /> | ||
| </Link> | ||
| <Link | ||
| href={linkedinShareUrl} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| className="linkedin-share-button text-xl text-black transition-colors duration-300 hover:text-blue-500" | ||
| > | ||
| <FaLinkedin className="icon" /> | ||
| </Link> |
There was a problem hiding this comment.
The Twitter/LinkedIn share links render icon-only content without an accessible name. Add an aria-label (or visually-hidden text) to each link so screen readers can announce what the control does.
| className="w-full h-60" | ||
| /> | ||
| </div> */} | ||
| <div className="flex flex-row gap-5 items-center gap-3 sm:gap-5 order-2 sm:order-none mt-2 md:mb-2"> |
There was a problem hiding this comment.
The container class list includes conflicting gap utilities (gap-5 and gap-3 sm:gap-5) which makes the effective spacing depend on class order and is easy to misread. Remove the redundant gap-* so only the intended spacing remains.
| <div className="flex flex-row gap-5 items-center gap-3 sm:gap-5 order-2 sm:order-none mt-2 md:mb-2"> | |
| <div className="flex flex-row items-center gap-3 sm:gap-5 order-2 sm:order-none mt-2 md:mb-2"> |
| setCopied(true); | ||
| setTimeout(() => setCopied(false), 2000); | ||
| } catch (err) { | ||
| console.error("Failed to copy!", err); |
There was a problem hiding this comment.
The new console.error("Failed to copy!", err) message doesn't give a user-actionable next step. Consider handling this as UI feedback (e.g. show a non-intrusive message like “Copy failed — please copy from the address bar”) instead of (or in addition to) logging.
| console.error("Failed to copy!", err); | |
| const copyFailureMessage = "Copy failed — please copy the link from the address bar."; | |
| window.alert(copyFailureMessage); | |
| console.error(copyFailureMessage, err); |
Fix: keploy/keploy#3298
What I did
Now