diff options
| author | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-06-25 13:56:02 +0900 |
|---|---|---|
| committer | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-06-25 13:56:02 +0900 |
| commit | c40643a98487d0dbe4d9b89877fb98249055c31d (patch) | |
| tree | d77b47696c4b5f639328cc8da8a9af9a240c3a91 | |
| parent | fdb543c2ec991906f8bafc752a4a5e24aa07e349 (diff) | |
全ページにSNS共有ボタンと見出しアンカーリンクを追加
- SocialShare コンポーネント: X/Facebook/LINE 共有ボタンを
各ページフッターに表示
- Footer コンポーネントを上書きして SocialShare を組み込み
- 見出し(h2/h3)にホバーでコピー可能なアンカーリンクを追加
- custom.css にアンカーリンクのスタイルを追加
| -rw-r--r-- | astro.config.mjs | 6 | ||||
| -rw-r--r-- | src/components/SocialShare.astro | 77 | ||||
| -rw-r--r-- | src/components/starlight/Footer.astro | 64 | ||||
| -rw-r--r-- | src/styles/custom.css | 22 |
4 files changed, 169 insertions, 0 deletions
diff --git a/astro.config.mjs b/astro.config.mjs index 8b38f9c..6f7f212 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -225,12 +225,18 @@ export default defineConfig({ { tag: "script", content: + "document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.sl-markdown-content h2[id], .sl-markdown-content h3[id]').forEach(h => { const a = document.createElement('a'); a.href = '#' + h.id; a.className = 'heading-anchor'; a.innerHTML = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/></svg>'; a.title = 'この見出しへのリンクをコピー'; a.addEventListener('click', e => { e.preventDefault(); const url = location.origin + location.pathname + '#' + h.id; navigator.clipboard.writeText(url).then(() => { a.classList.add('copied'); setTimeout(() => a.classList.remove('copied'), 1500); }); }); h.prepend(a); }); });", + }, + { + tag: "script", + content: "document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('[href=\"#_top\"] span').forEach(el => { if (el.textContent === 'トップへ戻る') el.textContent = ''; }); });", }, ], components: { PageTitle: "./src/components/starlight/PageTitle.astro", SocialIcons: "./src/components/starlight/SocialIcons.astro", + Footer: "./src/components/starlight/Footer.astro", }, }), ], diff --git a/src/components/SocialShare.astro b/src/components/SocialShare.astro new file mode 100644 index 0000000..a818822 --- /dev/null +++ b/src/components/SocialShare.astro @@ -0,0 +1,77 @@ +--- +export interface Props { + /** Page URL (defaults to current page) */ + url?: string; + /** Page title */ + title?: string; +} + +const { url, title } = Astro.props; +const pageUrl = url ?? Astro.url.href; +const pageTitle = title ?? ""; + +const encodedUrl = encodeURIComponent(pageUrl); +const encodedTitle = encodeURIComponent(pageTitle); + +const SHARE_LINKS = [ + { + label: "X", + href: `https://x.com/intent/tweet?url=${encodedUrl}&text=${encodedTitle}`, + svg: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4l11.733 16h4.267l-11.733-16z"/><path d="M4 20l6.768-6.768m2.46-2.46L20 4"/></svg>', + }, + { + label: "Facebook", + href: `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`, + svg: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"/></svg>', + }, + { + label: "LINE", + href: `https://social-plugins.line.me/lineit/share?url=${encodedUrl}`, + svg: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12h2"/><path d="M6 8v8"/><path d="M10 6v12"/><path d="M14 9.5V20"/><path d="M18 6v12"/><path d="M22 8v8"/></svg>', + }, +]; +--- + +<div class="social-share"> + <span class="social-share-label">Share:</span> + {SHARE_LINKS.map((link) => ( + <a + href={link.href} + target="_blank" + rel="noopener noreferrer" + class="social-share-btn" + title={`${link.label}で共有`} + > + <span set:html={link.svg} /> + </a> + ))} +</div> + +<style> + @layer starlight.core { + .social-share { + display: flex; + align-items: center; + gap: 0.5rem; + margin-top: 2rem; + padding-top: 1rem; + border-top: 1px solid var(--sl-color-gray-5); + } + .social-share-label { + font-size: 0.85rem; + color: var(--sl-color-gray-2); + } + .social-share-btn { + color: var(--sl-color-gray-2); + padding: 0.35rem; + border-radius: 4px; + transition: color 0.2s, background 0.2s; + display: flex; + align-items: center; + } + .social-share-btn:hover { + color: var(--sl-color-white); + background: var(--sl-color-gray-5); + } + } +</style> diff --git a/src/components/starlight/Footer.astro b/src/components/starlight/Footer.astro new file mode 100644 index 0000000..7b10569 --- /dev/null +++ b/src/components/starlight/Footer.astro @@ -0,0 +1,64 @@ +--- +import EditLink from 'virtual:starlight/components/EditLink'; +import LastUpdated from 'virtual:starlight/components/LastUpdated'; +import Pagination from 'virtual:starlight/components/Pagination'; +import config from 'virtual:starlight/user-config'; +import { Icon } from '@astrojs/starlight/components'; +import SocialShare from '../SocialShare.astro'; +--- + +<footer class="sl-flex"> + <div class="meta sl-flex"> + <EditLink /> + <LastUpdated /> + </div> + <Pagination /> + + <SocialShare /> + + { + config.credits && ( + <a class="kudos sl-flex" href="https://starlight.astro.build"> + <Icon name={'starlight'} /> {Astro.locals.t('builtWithStarlight.label')} + </a> + ) + } +</footer> + +<style> + @layer starlight.core { + footer { + flex-direction: column; + gap: 1.5rem; + } + .meta { + gap: 0.75rem 3rem; + justify-content: space-between; + flex-wrap: wrap; + margin-top: 3rem; + font-size: var(--sl-text-sm); + color: var(--sl-color-gray-3); + } + .meta > :global(p:only-child) { + margin-inline-start: auto; + } + + .kudos { + align-items: center; + gap: 0.5em; + margin: 1.5rem auto; + font-size: var(--sl-text-xs); + text-decoration: none; + color: var(--sl-color-gray-3); + } + .kudos:hover { + color: var(--sl-color-white); + } + } + + @layer starlight.components { + .kudos :global(svg) { + color: var(--sl-color-orange); + } + } +</style> diff --git a/src/styles/custom.css b/src/styles/custom.css index 67a4c79..f765954 100644 --- a/src/styles/custom.css +++ b/src/styles/custom.css @@ -1048,3 +1048,25 @@ main:has(.home-hero) { font-size: 0.75em; vertical-align: super; } + +/* ── Heading Anchor Links ── */ +.heading-anchor { + opacity: 0; + margin-left: -1.2em; + padding-right: 0.3em; + color: var(--sl-color-gray-3); + text-decoration: none; + transition: opacity 0.2s; + float: left; +} +h2:hover .heading-anchor, +h3:hover .heading-anchor, +.heading-anchor.copied { + opacity: 1; +} +.heading-anchor:hover { + color: var(--sl-color-accent); +} +.heading-anchor.copied { + color: var(--sl-color-green-high, #16a34a); +} |
