mirror of
https://github.com/samber/awesome-prometheus-alerts.git
synced 2026-06-21 00:47:18 +08:00
Sends rule_copy, wget_copy events on clipboard interactions, bypassing ad blockers. Tracks user_id (localStorage apa_uid), session_id (sessionStorage apa_sid), session/lifetime copy counts, full rule coordinates (group/service/exporter/rule slugs + indices), page context, and browser environment. Event name is the Tinybird data source name, scoped to "rule" or "exporter" per copy type.
135 lines
5.3 KiB
Text
135 lines
5.3 KiB
Text
---
|
|
import { GITHUB_URL } from '../data/site';
|
|
|
|
interface Props {
|
|
targetId: string;
|
|
label?: string;
|
|
variant?: 'icon' | 'text';
|
|
class?: string;
|
|
withAttribution?: boolean;
|
|
nudge?: boolean;
|
|
copyData?: Record<string, unknown> | null;
|
|
}
|
|
|
|
const { targetId, label = 'Copy', variant = 'icon', class: extraClass = '', withAttribution = false, nudge = false, copyData = null } = Astro.props;
|
|
const btnId = `copy-btn-${targetId}`;
|
|
const nudgeId = `star-nudge-${btnId}`;
|
|
---
|
|
|
|
{variant === 'icon' ? (
|
|
<span class={`inline-flex items-center gap-1 ${extraClass}`}>
|
|
<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"
|
|
>
|
|
<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>
|
|
{nudge && (
|
|
<a
|
|
id={nudgeId}
|
|
href={GITHUB_URL}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
class="hidden items-center gap-0.5 text-xs text-yellow-500 hover:text-yellow-600 dark:text-yellow-400 dark:hover:text-yellow-300 transition-colors whitespace-nowrap"
|
|
aria-label="Star on GitHub"
|
|
>
|
|
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
|
|
</svg>
|
|
Star
|
|
</a>
|
|
)}
|
|
</span>
|
|
) : (
|
|
<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, nudgeId, withAttribution, nudge, GITHUB_URL, copyData }}>
|
|
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;
|
|
|
|
let text = target.textContent ?? '';
|
|
text = withAttribution
|
|
? `# Source: ${GITHUB_URL}\n${text.trim()}`
|
|
: text.trim();
|
|
|
|
try {
|
|
await navigator.clipboard.writeText(text);
|
|
} catch {
|
|
// Fallback for older browsers
|
|
const ta = document.createElement('textarea');
|
|
ta.value = text;
|
|
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);
|
|
|
|
// Inline star nudge
|
|
if (nudge) {
|
|
const nudgeEl = document.getElementById(nudgeId);
|
|
if (nudgeEl) {
|
|
nudgeEl.classList.remove('hidden');
|
|
nudgeEl.classList.add('inline-flex');
|
|
setTimeout(() => {
|
|
nudgeEl.classList.add('hidden');
|
|
nudgeEl.classList.remove('inline-flex');
|
|
}, 3000);
|
|
}
|
|
}
|
|
|
|
if (copyData) {
|
|
window.dispatchEvent(new CustomEvent('apa-copy', { detail: copyData }));
|
|
}
|
|
window.dispatchEvent(new CustomEvent('copy-success'));
|
|
});
|
|
</script>
|