mirror of
https://github.com/samber/awesome-prometheus-alerts.git
synced 2026-06-21 17:07:24 +08:00
Show a dismissible toast (bottom-right, 20s auto-hide) nudging users to star the GitHub repo. Fires every 5 copies via a sessionStorage counter. CopyButton dispatches a copy-success custom event; StarToast listens for it and manages display logic.
92 lines
3.8 KiB
Text
92 lines
3.8 KiB
Text
---
|
|
interface Props {
|
|
targetId: string;
|
|
label?: string;
|
|
variant?: 'icon' | 'text';
|
|
class?: string;
|
|
}
|
|
|
|
const { targetId, label = 'Copy', variant = 'icon', class: extraClass = '' } = Astro.props;
|
|
const btnId = `copy-btn-${targetId}`;
|
|
---
|
|
|
|
{variant === 'icon' ? (
|
|
<button
|
|
id={btnId}
|
|
data-copy-target={targetId}
|
|
aria-label="Copy to clipboard"
|
|
class={`copy-btn inline-flex items-center gap-1.5 px-2 py-1 text-xs rounded text-slate-400 dark:text-slate-500 hover:text-slate-700 dark:hover:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700 transition-colors ${extraClass}`}
|
|
>
|
|
<svg class="copy-icon w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
|
</svg>
|
|
<svg class="check-icon w-3.5 h-3.5 hidden text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
</svg>
|
|
<span class="copy-label sr-only">Copy</span>
|
|
<span class="copied-label hidden text-green-500 not-sr-only text-xs">Copied!</span>
|
|
</button>
|
|
) : (
|
|
<button
|
|
id={btnId}
|
|
data-copy-target={targetId}
|
|
class={`copy-btn inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 text-slate-600 dark:text-slate-300 hover:border-brand dark:hover:border-brand-dark hover:text-brand dark:hover:text-brand-dark transition-colors ${extraClass}`}
|
|
>
|
|
<svg class="copy-icon w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
|
</svg>
|
|
<svg class="check-icon w-3.5 h-3.5 hidden text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
</svg>
|
|
<span class="copy-label">{label}</span>
|
|
<span class="copied-label hidden text-green-600 dark:text-green-400">Copied!</span>
|
|
</button>
|
|
)}
|
|
|
|
<script define:vars={{ btnId }}>
|
|
const btn = document.getElementById(btnId);
|
|
if (!(btn instanceof HTMLButtonElement)) return;
|
|
if (btn.dataset.copyBound === 'true') return;
|
|
|
|
btn.dataset.copyBound = 'true';
|
|
btn.addEventListener('click', async () => {
|
|
const targetId = btn.dataset.copyTarget;
|
|
if (!targetId) return;
|
|
const target = document.getElementById(targetId);
|
|
if (!target) return;
|
|
|
|
const text = target.textContent ?? '';
|
|
try {
|
|
await navigator.clipboard.writeText(text.trim());
|
|
} catch {
|
|
// Fallback for older browsers
|
|
const ta = document.createElement('textarea');
|
|
ta.value = text.trim();
|
|
ta.style.cssText = 'position:fixed;top:0;left:0;opacity:0;';
|
|
document.body.appendChild(ta);
|
|
ta.select();
|
|
document.execCommand('copy');
|
|
document.body.removeChild(ta);
|
|
}
|
|
|
|
// Visual feedback
|
|
const copyIcon = btn.querySelector('.copy-icon');
|
|
const checkIcon = btn.querySelector('.check-icon');
|
|
const copyLabel = btn.querySelector('.copy-label');
|
|
const copiedLabel = btn.querySelector('.copied-label');
|
|
|
|
copyIcon?.classList.add('hidden');
|
|
checkIcon?.classList.remove('hidden');
|
|
copyLabel?.classList.add('hidden');
|
|
copiedLabel?.classList.remove('hidden');
|
|
|
|
setTimeout(() => {
|
|
copyIcon?.classList.remove('hidden');
|
|
checkIcon?.classList.add('hidden');
|
|
copyLabel?.classList.remove('hidden');
|
|
copiedLabel?.classList.add('hidden');
|
|
}, 2000);
|
|
|
|
window.dispatchEvent(new CustomEvent('copy-success'));
|
|
});
|
|
</script>
|