diff options
Diffstat (limited to 'docs/superpowers/plans/2026-04-17-social-share-widget.md')
| -rw-r--r-- | docs/superpowers/plans/2026-04-17-social-share-widget.md | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/docs/superpowers/plans/2026-04-17-social-share-widget.md b/docs/superpowers/plans/2026-04-17-social-share-widget.md new file mode 100644 index 0000000..aa40088 --- /dev/null +++ b/docs/superpowers/plans/2026-04-17-social-share-widget.md @@ -0,0 +1,456 @@ +# Social Sharing Widget Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add a reusable icon-only social sharing widget (9 targets) to the sidebar and as an inline embed on the repository page. + +**Architecture:** A single partial `social-share.html` accepts a `mode` parameter (`sidebar` or `inline`) that controls grid layout. Sidebar mode uses a 2-column grid; inline mode uses a 5-column centered grid. Alpine.js handles clipboard copy with icon swap feedback. Brand icons are inline SVGs styled to match Feather Icons visually. + +**Tech Stack:** Hugo partials, Alpine.js (already loaded), Feather Icons (already loaded via CDN), Tailwind CSS utility classes, Hugo i18n. + +--- + +## File Map + +| Action | Path | Purpose | +|---|---|---| +| Create | `themes/danix-xyz-hacker/layouts/partials/social-share.html` | The widget partial — all 9 buttons, both modes | +| Modify | `themes/danix-xyz-hacker/layouts/partials/sidebar.html` | Add sidebar call between author and related posts | +| Modify | `themes/danix-xyz-hacker/layouts/repository/list.html` | Add inline call after `.Content`, before cards | +| Modify | `themes/danix-xyz-hacker/i18n/en.yaml` | Add 7 new sharing keys | +| Modify | `themes/danix-xyz-hacker/i18n/it.yaml` | Add 7 new sharing keys (Italian) | +| Modify | `i18n/en.yaml` | Keep in sync with theme i18n | +| Modify | `i18n/it.yaml` | Keep in sync with theme i18n | + +--- + +## Task 1: Add i18n Keys to All Four Translation Files + +**Files:** +- Modify: `themes/danix-xyz-hacker/i18n/en.yaml` +- Modify: `themes/danix-xyz-hacker/i18n/it.yaml` +- Modify: `i18n/en.yaml` +- Modify: `i18n/it.yaml` + +- [ ] **Step 1: Add keys to `themes/danix-xyz-hacker/i18n/en.yaml`** + +The file currently has a `# Sharing` section ending at `facebook: "Facebook"` (line 39). Append these keys immediately after `facebook`: + +```yaml +# Sharing +share: "Share" +shareOn: "Share on" +copyLink: "Copy link" +twitter: "Twitter" +facebook: "Facebook" +reddit: "Reddit" +pinterest: "Pinterest" +whatsapp: "WhatsApp" +telegram: "Telegram" +signal: "Signal" +shareViaEmail: "Share via email" +linkCopied: "Link copied!" +``` + +- [ ] **Step 2: Add keys to `themes/danix-xyz-hacker/i18n/it.yaml`** + +Same section, currently ending at `facebook: "Facebook"` (line 39). Replace that section with: + +```yaml +# Sharing +share: "Condividi" +shareOn: "Condividi su" +copyLink: "Copia link" +twitter: "Twitter" +facebook: "Facebook" +reddit: "Reddit" +pinterest: "Pinterest" +whatsapp: "WhatsApp" +telegram: "Telegram" +signal: "Signal" +shareViaEmail: "Condividi via email" +linkCopied: "Link copiato!" +``` + +- [ ] **Step 3: Add keys to `i18n/en.yaml`** + +This file has a `# Sharing` section. Add the same 7 new keys after `facebook`: + +```yaml +reddit: "Reddit" +pinterest: "Pinterest" +whatsapp: "WhatsApp" +telegram: "Telegram" +signal: "Signal" +shareViaEmail: "Share via email" +linkCopied: "Link copied!" +``` + +- [ ] **Step 4: Add keys to `i18n/it.yaml`** + +Same as above for Italian: + +```yaml +reddit: "Reddit" +pinterest: "Pinterest" +whatsapp: "WhatsApp" +telegram: "Telegram" +signal: "Signal" +shareViaEmail: "Condividi via email" +linkCopied: "Link copiato!" +``` + +- [ ] **Step 5: Verify Hugo builds without i18n warnings** + +```bash +hugo -D 2>&1 | grep -i "i18n\|warn\|error" | head -20 +``` + +Expected: no i18n-related warnings or errors. + +- [ ] **Step 6: Commit** + +```bash +git add themes/danix-xyz-hacker/i18n/en.yaml themes/danix-xyz-hacker/i18n/it.yaml i18n/en.yaml i18n/it.yaml +git commit -m "i18n: add social sharing translation keys (EN + IT)" +``` + +--- + +## Task 2: Create the Social Share Partial + +**Files:** +- Create: `themes/danix-xyz-hacker/layouts/partials/social-share.html` + +- [ ] **Step 1: Create the partial with full content** + +Create `themes/danix-xyz-hacker/layouts/partials/social-share.html` with the following complete content: + +```html +{{ $page := .page }} +{{ $mode := .mode | default "sidebar" }} +{{ $url := $page.Permalink | urlquery }} +{{ $title := $page.Title | urlquery }} + +{{ $gridClass := "grid-cols-2 gap-2" }} +{{ if eq $mode "inline" }} + {{ $gridClass = "grid-cols-5 gap-3 justify-items-center" }} +{{ end }} + +<div class="p-4 border border-border/30 rounded mb-6"> + <h3 class="text-lg font-semibold text-accent mb-3">{{ i18n "share" }}</h3> + <nav aria-label="{{ i18n "share" }}"> + <div class="grid {{ $gridClass }}"> + + <!-- Copy link --> + <div x-data="{ copied: false }"> + <button + @click="navigator.clipboard.writeText('{{ $page.Permalink }}').then(() => { copied = true; setTimeout(() => copied = false, 2000) })" + :aria-label="copied ? '{{ i18n "linkCopied" }}' : '{{ i18n "copyLink" }}'" + class="btn-icon hover:text-accent hover:bg-surface transition-colors focus-visible:ring-2 focus-visible:ring-accent" + > + <i x-show="!copied" data-feather="copy" class="w-5 h-5" aria-hidden="true"></i> + <i x-show="copied" data-feather="check" class="w-5 h-5 text-accent2" aria-hidden="true"></i> + </button> + </div> + + <!-- Email --> + <a + href="mailto:?subject={{ $title }}&body={{ $title }}%0A%0A{{ $page.Permalink | urlquery }}" + aria-label="{{ i18n "shareViaEmail" }}" + class="btn-icon hover:text-accent hover:bg-surface transition-colors focus-visible:ring-2 focus-visible:ring-accent" + > + <i data-feather="mail" class="w-5 h-5" aria-hidden="true"></i> + </a> + + <!-- Facebook --> + <a + href="https://www.facebook.com/sharer/sharer.php?u={{ $url }}" + target="_blank" rel="noopener noreferrer" + aria-label="{{ i18n "facebook" }}" + class="btn-icon hover:text-accent hover:bg-surface transition-colors focus-visible:ring-2 focus-visible:ring-accent" + > + <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"> + <path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"/> + </svg> + </a> + + <!-- Twitter / X --> + <a + href="https://twitter.com/intent/tweet?url={{ $url }}&text={{ $title }}" + target="_blank" rel="noopener noreferrer" + aria-label="{{ i18n "twitter" }}" + class="btn-icon hover:text-accent hover:bg-surface transition-colors focus-visible:ring-2 focus-visible:ring-accent" + > + <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" stroke="none" aria-hidden="true" focusable="false"> + <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/> + </svg> + </a> + + <!-- Reddit --> + <a + href="https://www.reddit.com/submit?url={{ $url }}&title={{ $title }}" + target="_blank" rel="noopener noreferrer" + aria-label="{{ i18n "reddit" }}" + class="btn-icon hover:text-accent hover:bg-surface transition-colors focus-visible:ring-2 focus-visible:ring-accent" + > + <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" stroke="none" aria-hidden="true" focusable="false"> + <path d="M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm5.01 4.744c.688 0 1.25.561 1.25 1.249a1.25 1.25 0 0 1-2.498.056l-2.597-.547-.8 3.747c1.824.07 3.48.632 4.674 1.488.308-.309.73-.491 1.207-.491.968 0 1.754.786 1.754 1.754 0 .716-.435 1.333-1.01 1.614a3.111 3.111 0 0 1 .042.52c0 2.694-3.13 4.87-7.004 4.87-3.874 0-7.004-2.176-7.004-4.87 0-.183.015-.366.043-.534A1.748 1.748 0 0 1 4.028 12c0-.968.786-1.754 1.754-1.754.463 0 .898.196 1.207.49 1.207-.883 2.878-1.43 4.744-1.487l.885-4.182a.342.342 0 0 1 .14-.197.35.35 0 0 1 .238-.042l2.906.617a1.214 1.214 0 0 1 1.108-.701zM9.25 12C8.561 12 8 12.562 8 13.25c0 .687.561 1.248 1.25 1.248.687 0 1.248-.561 1.248-1.249 0-.688-.561-1.249-1.249-1.249zm5.5 0c-.687 0-1.248.561-1.248 1.25 0 .687.561 1.248 1.249 1.248.688 0 1.249-.561 1.249-1.249 0-.687-.562-1.249-1.25-1.249zm-5.466 3.99a.327.327 0 0 0-.231.094.33.33 0 0 0 0 .463c.842.842 2.484.913 2.961.913.477 0 2.105-.056 2.961-.913a.361.361 0 0 0 .029-.463.33.33 0 0 0-.464 0c-.547.533-1.684.73-2.512.73-.828 0-1.979-.196-2.512-.73a.326.326 0 0 0-.232-.095z"/> + </svg> + </a> + + <!-- Pinterest --> + <a + href="https://pinterest.com/pin/create/button/?url={{ $url }}&description={{ $title }}" + target="_blank" rel="noopener noreferrer" + aria-label="{{ i18n "pinterest" }}" + class="btn-icon hover:text-accent hover:bg-surface transition-colors focus-visible:ring-2 focus-visible:ring-accent" + > + <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" stroke="none" aria-hidden="true" focusable="false"> + <path d="M12 0C5.373 0 0 5.373 0 12c0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738a.36.36 0 0 1 .083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.632-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24 12 24c6.627 0 12-5.373 12-12S18.627 0 12 0z"/> + </svg> + </a> + + <!-- WhatsApp --> + <a + href="https://api.whatsapp.com/send?text={{ $title }}%20{{ $page.Permalink | urlquery }}" + target="_blank" rel="noopener noreferrer" + aria-label="{{ i18n "whatsapp" }}" + class="btn-icon hover:text-accent hover:bg-surface transition-colors focus-visible:ring-2 focus-visible:ring-accent" + > + <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" stroke="none" aria-hidden="true" focusable="false"> + <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 0 1-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 0 1-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 0 1 2.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0 0 12.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 0 0 5.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 0 0-3.48-8.413z"/> + </svg> + </a> + + <!-- Telegram --> + <a + href="https://t.me/share/url?url={{ $url }}&text={{ $title }}" + target="_blank" rel="noopener noreferrer" + aria-label="{{ i18n "telegram" }}" + class="btn-icon hover:text-accent hover:bg-surface transition-colors focus-visible:ring-2 focus-visible:ring-accent" + > + <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" stroke="none" aria-hidden="true" focusable="false"> + <path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/> + </svg> + </a> + + <!-- Signal --> + <a + href="https://signal.me/#p/{{ $page.Permalink | urlquery }}" + target="_blank" rel="noopener noreferrer" + aria-label="{{ i18n "signal" }}" + class="btn-icon hover:text-accent hover:bg-surface transition-colors focus-visible:ring-2 focus-visible:ring-accent" + > + <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" stroke="none" aria-hidden="true" focusable="false"> + <path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm.157 5.32a6.68 6.68 0 0 1 6.143 4.032l.734-.267.55 1.513-.717.261a6.71 6.71 0 0 1 .133 1.327 6.68 6.68 0 0 1-.176 1.51l.69.252-.55 1.513-.707-.258A6.68 6.68 0 0 1 12 18.68a6.68 6.68 0 0 1-6.294-4.455l-.66.24-.55-1.513.677-.247A6.71 6.71 0 0 1 5 12.187a6.71 6.71 0 0 1 .16-1.438l-.698-.254.55-1.513.725.264A6.68 6.68 0 0 1 12.157 5.32zM12 7.2a4.8 4.8 0 1 0 0 9.6A4.8 4.8 0 0 0 12 7.2z"/> + </svg> + </a> + + </div> + </nav> +</div> +``` + +- [ ] **Step 2: Verify Hugo builds cleanly** + +```bash +hugo -D 2>&1 | tail -10 +``` + +Expected: build completes, no errors. Page count unchanged (partial not yet included anywhere). + +- [ ] **Step 3: Commit** + +```bash +git add themes/danix-xyz-hacker/layouts/partials/social-share.html +git commit -m "feat: add social-share partial with 9 targets and two layout modes" +``` + +--- + +## Task 3: Wire into Sidebar + +**Files:** +- Modify: `themes/danix-xyz-hacker/layouts/partials/sidebar.html` + +Current sidebar structure: +- Lines 1–8: Author widget +- Lines 10–42: Related posts widget (articles only) + +- [ ] **Step 1: Insert the partial call after the author widget** + +In `themes/danix-xyz-hacker/layouts/partials/sidebar.html`, insert the call between the closing `</div>` of the author widget (line 8) and the related posts comment (line 10): + +```html +<aside class="order-last md:order-none md:col-span-1"> + <!-- Author info widget (optional - can be expanded) --> + <div class="p-4 border border-border/30 rounded mb-6"> + <h3 class="text-lg font-semibold text-accent mb-3">{{ i18n "author" }}</h3> + <p class="text-text-dim text-sm leading-relaxed"> + {{ .Site.Params.author }} + </p> + </div> + + <!-- Social sharing widget --> + {{ partial "social-share.html" (dict "page" . "mode" "sidebar") }} + + <!-- Related posts widget (articles only) --> + {{ if and .Site.Params.relatedPosts (eq .Type "articles") }} + ... +``` + +- [ ] **Step 2: Build and verify sidebar renders on an article** + +```bash +hugo -D 2>&1 | tail -5 +``` + +Then open an article page in the built `public/` directory and verify the widget is present: + +```bash +grep -A 5 "share" public/articles/git-setup-own-server/index.html | head -20 +``` + +Expected: HTML contains the `<nav aria-label=` share widget with button elements. + +- [ ] **Step 3: Verify widget also appears on a page (not just articles)** + +```bash +grep -c "btn-icon" public/is/index.html +``` + +Expected: at least 9 (one per share button). + +- [ ] **Step 4: Commit** + +```bash +git add themes/danix-xyz-hacker/layouts/partials/sidebar.html +git commit -m "feat: add social sharing widget to sidebar (articles and pages)" +``` + +--- + +## Task 4: Wire into Repository Page (Inline Mode) + +**Files:** +- Modify: `themes/danix-xyz-hacker/layouts/repository/list.html` + +Current structure relevant lines: +- Line 15: `<div class="prose dark:prose-invert max-w-none mb-12">{{ .Content }}</div>` +- Line 20: `<section class="mt-16">` (cards grid) + +- [ ] **Step 1: Insert the inline partial call after `.Content` block** + +Replace the prose block and following section in `themes/danix-xyz-hacker/layouts/repository/list.html`: + +```html + <!-- Page Content (markdown sections) --> + <div class="prose dark:prose-invert max-w-none mb-12"> + {{ .Content }} + </div> + + <!-- Social sharing (inline mode) --> + <div class="mb-12"> + {{ partial "social-share.html" (dict "page" . "mode" "inline") }} + </div> + + <!-- Repository Cards Section --> + <section class="mt-16"> +``` + +- [ ] **Step 2: Build and verify repository page contains the inline widget** + +```bash +hugo -D 2>&1 | tail -5 +grep -c "btn-icon" public/repository/index.html +``` + +Expected: at least 9 matches (one per share button). + +- [ ] **Step 3: Verify grid class is inline (5-col)** + +```bash +grep "grid-cols-5" public/repository/index.html +``` + +Expected: one match — `grid grid-cols-5 gap-3 justify-items-center`. + +- [ ] **Step 4: Commit** + +```bash +git add themes/danix-xyz-hacker/layouts/repository/list.html +git commit -m "feat: embed social sharing widget inline on repository page" +``` + +--- + +## Task 5: CSS Rebuild and Final Verification + +**Files:** +- Run: `npm run build` (compiles `main.css` → `main.min.css`) + +The new classes used (`grid-cols-5`, `justify-items-center`, `focus-visible:ring-2`, `focus-visible:ring-accent`, `text-accent2`) need to be compiled into the CSS bundle. All are Tailwind utilities — they just need to appear in template files for Tailwind's content scanner to pick them up. + +- [ ] **Step 1: Rebuild CSS** + +```bash +npm run build 2>&1 | tail -5 +``` + +Expected: exits with no errors, `themes/danix-xyz-hacker/assets/css/main.min.css` is updated. + +- [ ] **Step 2: Full build check** + +```bash +hugo -D 2>&1 | tail -10 +``` + +Expected: clean build, same page counts as before. + +- [ ] **Step 3: Spot-check rendered output — sidebar mode** + +```bash +grep -A 3 "grid-cols-2" public/articles/git-setup-own-server/index.html | head -10 +``` + +Expected: `<div class="grid grid-cols-2 gap-2">` present. + +- [ ] **Step 4: Spot-check rendered output — inline mode** + +```bash +grep -A 3 "grid-cols-5" public/repository/index.html | head -10 +``` + +Expected: `<div class="grid grid-cols-5 gap-3 justify-items-center">` present. + +- [ ] **Step 5: Spot-check copy button Alpine.js attributes** + +```bash +grep -A 10 "x-data.*copied" public/articles/git-setup-own-server/index.html | head -15 +``` + +Expected: `x-data="{ copied: false }"` with `@click` containing `navigator.clipboard.writeText` and the article's full permalink URL. + +- [ ] **Step 6: Spot-check Twitter URL includes title and permalink** + +```bash +grep "twitter.com/intent" public/articles/git-setup-own-server/index.html +``` + +Expected: URL contains both `url=` and `text=` query parameters with URL-encoded values. + +- [ ] **Step 7: Spot-check Italian translation** + +```bash +grep "Condividi" public/it/articles/git-setup-own-server/index.html | head -5 +``` + +Expected: `aria-label="Condividi"` on the `<nav>` element. + +- [ ] **Step 8: Final commit** + +```bash +git add themes/danix-xyz-hacker/assets/css/main.min.css +git commit -m "build: rebuild CSS to include social sharing widget utility classes" +``` |
