CopyPostId
4 variants. Open one in isolation: use the link on each card.
CopiedFeedbackLeft
Open alone →CopiedFeedbackLeftWithGitHub
Open alone →Default
Open alone →WithGitHubEdit
Open alone →---import Link from '../0_atoms/Link.astro'
/** * Footer affordance for post detail pages: shows the muted post ID, copies it * to the clipboard on click, and (optionally) renders a single-letter `e` link * to the GitHub editor for the source file. * * The inline `style="opacity: 0; transition: …"` on `.copy-post-id-feedback` is * a documented exception (functional, JS-driven; not a theme token). See * `AGENTS.md → CSS / Styling Architecture`. */interface Props { postId: string /** When set, an `e` link is rendered next to the post ID. */ githubEditHref?: string /** * Where the transient “Copied!” label sits in the row: * `left` → `Copied!` · post ID · optional GitHub `e`; * `right` (default) → post ID · optional GitHub `e` · `Copied!`. */ copiedFeedbackPosition?: 'left' | 'right' class?: string}
const { postId, githubEditHref, copiedFeedbackPosition = 'right', class: className,} = Astro.props---
<span class:list={['copy-post-id-root flex min-w-0 items-center gap-2', className]}> {copiedFeedbackPosition === 'left' ? ( <span class="meta copy-post-id-feedback shrink-0 text-xs" style="opacity: 0; transition: opacity 0.2s ease;" >Copied!</span> ) : null} <span class="inline-flex min-w-0 items-center gap-0"> <button type="button" class="meta copy-post-id-btn min-w-0 cursor-pointer border-0 bg-transparent p-0 leading-none text-ink-faint transition-colors hover:text-ink-muted" data-post-id={postId} aria-label="Copy post ID to clipboard" > <span class="min-w-0 truncate">{postId}</span> </button> {githubEditHref ? ( <Link href={githubEditHref} external variant="faint" isMeta={true} class="shrink-0 leading-none" aria-label="Edit this post on GitHub" title="Edit on GitHub" >e</Link> ) : null} </span> {copiedFeedbackPosition === 'right' ? ( <span class="meta copy-post-id-feedback shrink-0 text-xs" style="opacity: 0; transition: opacity 0.2s ease;" >Copied!</span> ) : null}</span>
<script> document.querySelectorAll<HTMLButtonElement>('.copy-post-id-btn').forEach(btn => { const feedback = btn.closest('.copy-post-id-root')?.querySelector<HTMLElement>('.copy-post-id-feedback') let copyTimer: ReturnType<typeof setTimeout> | null = null btn.addEventListener('click', async () => { const postId = btn.dataset.postId if (!postId) return try { await navigator.clipboard.writeText(postId) if (feedback) { if (copyTimer) clearTimeout(copyTimer) feedback.style.opacity = '1' copyTimer = setTimeout(() => { if (feedback) feedback.style.opacity = '0' }, 1500) } } catch { // clipboard unavailable } }) })</script>