diff --git a/README.md b/README.md index 59b9d99..62120f5 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Lightweight social sharing component for web applications. Zero dependencies, fr - 🌐 Multiple platforms: WhatsApp, Facebook, X, LinkedIn, Telegram, Reddit, Email, Pinterest, Discord - 🎯 Zero dependencies - pure vanilla JavaScript -- ⚛️ Framework support: React, Preact, Next.js, Qwik, Vue, Angular, or plain HTML +- ⚛️ Framework support: React, Preact, Next.js, Nuxt.js, Qwik, Vue, Angular, WordPress, Hugo, Jekyll or plain HTML - 🔄 Auto-detects current URL and page title - 📱 Fully responsive and mobile-ready - 🎨 Customizable themes (dark/light) @@ -103,11 +103,11 @@ Lightweight social sharing component for web applications. Zero dependencies, fr No matter which framework you use, integration always follows the same 3 steps: -| Step | What to do | Where | -| -------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- | -| **1️⃣ Load Library** | Add CSS + JS (CDN links) | Global layout file — `index.html` / `layout.tsx` / `_document.tsx` | -| **2️⃣ Add Container** | Place `
` | The UI component where you want the button to appear | -| **3️⃣ Initialize** | Call `new SocialShareButton({ container: "#share-button" })` | Inside that component, after the DOM is ready (e.g. `useEffect`, `mounted`, `ngAfterViewInit`) | +| Step | What to do | Where | +| -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------ | +| **1️⃣ Load Library** | Add CSS + JS (CDN links) | Global layout file — `index.html` / `layout.tsx` / `_document.tsx` / `functions.php` | +| **2️⃣ Add Container** | Place `
` | The UI component or WordPress `wp_footer` hook | +| **3️⃣ Initialize** | Call `new SocialShareButton({ container: "#share-button" })` | Inside that component or WordPress `wp_footer` hook | > 💡 Pick your framework below for the full copy-paste snippet: @@ -437,12 +437,12 @@ new window.SocialShareButton({
- + ``` @@ -486,6 +486,161 @@ export default function Header() { +
+🔷 WordPress + +### Step 1: Enqueue in `functions.php` + +Add the following to your theme's `functions.php` to load the library directly from this repository via jsDelivr CDN: + +> **Note:** This package is not published to npm. Use the jsDelivr + GitHub CDN link below to load the correct distributable from the [AOSSIE-Org/SocialShareButton](https://github.com/AOSSIE-Org/SocialShareButton) repository. + +```php +function enqueue_social_share_button() { + wp_enqueue_style( + 'social-share-button', + 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css' + ); + wp_enqueue_script( + 'social-share-button', + 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js', + [], + null, + true // Load in footer + ); +} +add_action('wp_enqueue_scripts', 'enqueue_social_share_button'); +``` + +### Step 2: Initialize in `functions.php` (Footer Hook) + +Use the `wp_footer` hook with a **priority of 21** to inject the container and initialization script. The priority must be higher than the default (10) so WordPress prints the enqueued footer scripts _before_ this function runs: + +```php +function init_social_share_button() { ?> +
+ + + +
+💚 Nuxt.js + +### Step 1: Add CDN to your layout file (e.g., `app.vue` or `layouts/default.vue`) + +```html + + + + + + +``` + +### Step 2: Obtain the Nuxt wrapper component + +Currently, the wrapper is not available via CDN and must be added manually. Copy the `src/social-share-button-nuxt.vue` file from this repository into your Nuxt project's `components/` folder. Rename it to `SocialShareButton.vue` to match the usage below. + +### Step 3: Use the component in your page or component + +Open an **existing** page — typically `pages/index.vue`. Since the component is in the `components/` folder, Nuxt 3 will auto-import it. + +```vue + + + +``` + +
+ +
+📄 Hugo / Jekyll + +### Step 1: Add CDN to your base layout + +Hugo: `layouts/_default/baseof.html` +Jekyll: `_layouts/default.html` + +```html + + + + + + + +``` + +### Step 2: Add the container and initialize + +Place this script where you want the button to appear (e.g. at the bottom of a post template). + +**Hugo (Post Template):** + +```html +
+ +``` + +**Jekyll (Post Template):** + +```html +
+ +``` + +
+ --- ## Configuration diff --git a/index.html b/index.html index ce23d40..a765bc4 100644 --- a/index.html +++ b/index.html @@ -42,6 +42,7 @@ margin-bottom: 10px; font-weight: 700; } + .brand { display: flex; align-items: center; @@ -256,6 +257,7 @@ } +
@@ -451,9 +453,9 @@

⚛️ Preact Integration

> <link rel="stylesheet" - href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.css"> + href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css"> <script - src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.js"></script> + src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js"></script>
@@ -474,6 +476,47 @@

⚛️ Preact Integration

+ + +
+

🔷 WordPress Integration

+

Integrate SocialShareButton into your WordPress theme without any extra plugins.

+ +

Step 1: Enqueue the CSS and JS in functions.php

+
+ + + + function enqueue_social_share_button() { wp_enqueue_style( 'social-share-button', + 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css' + ); wp_enqueue_script( 'social-share-button', + 'https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js', + [], null, true // Load in footer ); } add_action('wp_enqueue_scripts', + 'enqueue_social_share_button'); + +
+ +

Step 2: Initialize the button in the footer

+
+ + + + function init_social_share_button() { ?> <div id="share-button"></div> + <script> new SocialShareButton({ container: '#share-button', url: + window.location.href, title: document.title, theme: 'dark', buttonText: 'Share' }); + </script> <?php } add_action('wp_footer', 'init_social_share_button', + 21); +
+

Ready to Get Started?

@@ -501,6 +544,7 @@

Ready to Get Started?

⚡ Qwik / QwikCity Integration

Resumability-optimized wrapper for the fastest performance.

+

Step 1: Add CDN to your layout

⚡ Qwik / QwikCity Integration > <link rel="stylesheet" - href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.css"> + href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css"> <script - src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.4/src/social-share-button.js"></script> + src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js" + defer></script> +
+ +

Step 2: Use the component

+
+ + import { component$ } from '@builder.io/qwik'; import { SocialShareButton } from - './social-share-button-qwik'; export default component$(() => ( <SocialShareButton + './social-share-button-qwik'; export default component$(() => ( <SocialShareButton url="https://your-website.com" theme="light" buttonText="Share Now" buttonStyle="primary" /> ));
+ +
+

💚 Nuxt.js Integration

+

Step 1: Include CSS and JS via CDN

+ +
+ + + + <link rel="stylesheet" + href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css"> + <script + src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js" + defer></script> + +
+ +

+ Step 2: Obtain the Nuxt wrapper component. Currently, the wrapper is not + available via CDN and must be added manually. Copy the + src/social-share-button-nuxt.vue file from this repository into your Nuxt + project's components/ folder. Rename it to + SocialShareButton.vue to match the usage below. +

+ +

+ Step 3: Register the component (automatically handled by Nuxt 3 when + placed in components/). +

+ +

Step 4: Show usage in a pages/index.vue file

+
+ + + + <!-- pages/index.vue --> <template> <SocialShareButton + url="https://your-website.com" title="Check this out!" description="An amazing website" + theme="dark" button-text="Share" /> </template> <script setup> // + Component is auto-imported from components/ in Nuxt 3 </script> + +
+
+

▲ Next.js Integration

Use the component inside a Next.js page

- import SocialShareButton from 'social-share-button'; export default function Home() { + + + + import SocialShareButton from 'social-share-button'; export default function Home() { return ( <SocialShareButton url="https://your-website.com" title="Check this out!" - /> ); } + /> ); } +
@@ -541,11 +653,17 @@

🟢 Vue / Vite Integration

Use inside a Vue component

- <template> <SocialShareButton url="https://your-website.com" title="Check this + + + + <template> <SocialShareButton url="https://your-website.com" title="Check this out!" /> </template> <script setup> import SocialShareButton from - 'social-share-button' </script> + 'social-share-button' </script> +
@@ -554,33 +672,63 @@

🅰️ Angular Integration

Use inside an Angular component template

- <social-share-button [url]="'https://your-website.com'" [title]="'Check this out!'" - > </social-share-button> + + + + <social-share-button [url]="'https://your-website.com'" [title]="'Check this out!'" + > </social-share-button> +
- -
-

Ready to Get Started?

- - View on GitHub → - + +
+

📄 Hugo / Jekyll Integration

+

Drop-in integration for Static Site Generators (SSG).

- - Join Discord - +

Hugo (layouts/_default/baseof.html):

+
+ + + + <!-- In <head> --> <link rel="stylesheet" + href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css"> + <!-- Before </body> --> <div id="share-button"></div> <script + src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js" + defer></script> <script> window.addEventListener('DOMContentLoaded', () + => { new SocialShareButton({ container: '#share-button', url: window.location.href, + title: document.title, description: {{ .Description | jsonify }}, theme: 'dark' }); }); + </script> + +
+ +

Jekyll (_layouts/default.html):

+
+ + + + <!-- In <head> --> <link rel="stylesheet" + href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css"> + <!-- Before </body> --> <div id="share-button"></div> <script + src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js" + defer></script> <script> window.addEventListener('DOMContentLoaded', () + => { new SocialShareButton({ container: '#share-button', url: window.location.href, + title: document.title, description: {{ page.description | jsonify }}, theme: 'dark' }); + }); </script> + +
@@ -753,8 +901,13 @@

Ready to Get Started?

copyButtons.forEach((button) => { button.addEventListener("click", () => { - const codeBlock = button.closest(".code-block")?.querySelector("code"); - const text = codeBlock ? codeBlock.innerText : ""; + const codeBlockContainer = button.closest(".code-block"); + const codeBlocks = codeBlockContainer + ? codeBlockContainer.querySelectorAll("code") + : []; + const text = Array.from(codeBlocks) + .map((code) => code.textContent) + .join("\n"); const originalText = button.textContent; const statusSpan = button.nextElementSibling; @@ -763,8 +916,21 @@

Ready to Get Started?

clearTimeout(button.copyResetTimer); } + if (!navigator.clipboard || !navigator.clipboard.writeText) { + button.textContent = originalText; + if (statusSpan && statusSpan.classList.contains("copy-status")) { + statusSpan.textContent = "Failed to copy to clipboard"; + } + button.copyResetTimer = setTimeout(() => { + button.textContent = originalText; + if (statusSpan && statusSpan.classList.contains("copy-status")) { + statusSpan.textContent = "Code copied to clipboard"; + } + }, 2000); + return; + } + navigator.clipboard - .writeText(text) .then(() => { if (statusSpan && statusSpan.classList.contains("copy-status")) { statusSpan.textContent = "Code copied to clipboard"; diff --git a/src/social-share-button-nuxt.vue b/src/social-share-button-nuxt.vue new file mode 100644 index 0000000..0b4a6d0 --- /dev/null +++ b/src/social-share-button-nuxt.vue @@ -0,0 +1,124 @@ + + + + diff --git a/src/social-share-button-preact.jsx b/src/social-share-button-preact.jsx index 5de3b55..1f240d2 100644 --- a/src/social-share-button-preact.jsx +++ b/src/social-share-button-preact.jsx @@ -135,8 +135,8 @@ export default function SocialShareButton({ * Synchronizes prop changes from Preact down to the vanilla JS instance * without re-mounting the entire component. */ - - // Stringify array dependencies to prevent unnecessary re-runs when + + // Stringify array dependencies to prevent unnecessary re-runs when // parent components pass fresh array literals on every render. const hashtagsDep = JSON.stringify(hashtags); const platformsDep = JSON.stringify(platforms); diff --git a/src/social-share-button.js b/src/social-share-button.js index c3dd721..228d508 100644 --- a/src/social-share-button.js +++ b/src/social-share-button.js @@ -86,15 +86,10 @@ class SocialShareButton { `; this.button = button; - if (this.options.container) { - const container = - typeof this.options.container === "string" - ? document.querySelector(this.options.container) - : this.options.container; + const container = this._getContainer(); - if (container) { - container.appendChild(button); - } + if (container) { + container.appendChild(button); } } @@ -599,6 +594,18 @@ class SocialShareButton { this.eventsAttached = false; // Reset re-entrancy guard } + /** + * Updates specific library settings dynamically after initialization. + * + * NOTE: Currently, this method only supports updating non-structural properties: + * `url`, `buttonColor`, and `buttonHoverColor`. + * Changing structural or DOM-dependent options (such as `theme`, `buttonText`, + * `buttonStyle`, `platforms`, or `analytics`) will update the internal options + * object, but requires destroying and recreating the button instance to fully + * reflect the changes in the DOM. + * + * @param {Object} options - Partial options object to merge. + */ updateOptions(options) { this.options = { ...this.options, ...options }; @@ -699,9 +706,32 @@ class SocialShareButton { _getContainer() { if (!this.options.container) return null; if (typeof document === "undefined") return null; - return typeof this.options.container === "string" - ? document.querySelector(this.options.container) - : this.options.container; + + let container = null; + try { + container = + typeof this.options.container === "string" + ? document.querySelector(this.options.container) + : this.options.container; + } catch (error) { + this._debugWarn("Invalid container selector provided in _getContainer", error); + return null; + } + + // Safety check: ensure the resolved value is actually a DOM Element. + // This prevents crashes if a user passes a non-DOM object to the container option. + if ( + container && + !( + (typeof Element !== "undefined" && container instanceof Element) || + container.nodeType === 1 + ) + ) { + this._debugWarn(`Provided container is not a valid DOM Element: ${container}`, null); + return null; + } + + return container; } /** diff --git a/wordpress-demo-project/index.html b/wordpress-demo-project/index.html new file mode 100644 index 0000000..8acd89a --- /dev/null +++ b/wordpress-demo-project/index.html @@ -0,0 +1,104 @@ + + + + + + WordPress Demo - SocialShareButton + + + + + +
+
+
My WordPress Site
+
+ +
+

SocialShareButton WordPress Demo

+

+ This demo simulates the WordPress integration using the wp_footer hook method + described in the README. +

+

+ In a real WordPress environment, the scripts would be enqueued via + functions.php and the button initialized in the footer. +

+ +
+

Share this page:

+ +
+
+
+ +
+

Proudly powered by WordPress

+
+
+ + + + + + + +