Propagate shared copy-button component and clipboard helper.
Deploy Ladill Give / deploy (push) Successful in 44s
Deploy Ladill Give / deploy (push) Successful in 44s
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,6 +8,7 @@ registerLadillSearchShortcut();
|
|||||||
|
|
||||||
|
|
||||||
import Alpine from 'alpinejs';
|
import Alpine from 'alpinejs';
|
||||||
|
import { registerLadillClipboard } from './ladill-clipboard';
|
||||||
import collapse from '@alpinejs/collapse';
|
import collapse from '@alpinejs/collapse';
|
||||||
import QRCodeStyling from 'qr-code-styling';
|
import QRCodeStyling from 'qr-code-styling';
|
||||||
window.QRCodeStyling = QRCodeStyling;
|
window.QRCodeStyling = QRCodeStyling;
|
||||||
@@ -15,6 +16,7 @@ import qrcode from 'qrcode-generator';
|
|||||||
window.qrcode = qrcode;
|
window.qrcode = qrcode;
|
||||||
|
|
||||||
Alpine.plugin(collapse);
|
Alpine.plugin(collapse);
|
||||||
|
registerLadillClipboard(Alpine);
|
||||||
|
|
||||||
Alpine.data('notificationDropdown', (config = {}) => ({
|
Alpine.data('notificationDropdown', (config = {}) => ({
|
||||||
open: false,
|
open: false,
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
const COPY_FEEDBACK_MS = 2000;
|
||||||
|
|
||||||
|
export async function writeClipboardText(text) {
|
||||||
|
const value = String(text ?? '');
|
||||||
|
if (!value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (navigator.clipboard?.writeText) {
|
||||||
|
await navigator.clipboard.writeText(value);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// fall through to legacy copy
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const textarea = document.createElement('textarea');
|
||||||
|
textarea.value = value;
|
||||||
|
textarea.style.position = 'fixed';
|
||||||
|
textarea.style.opacity = '0';
|
||||||
|
document.body.appendChild(textarea);
|
||||||
|
textarea.select();
|
||||||
|
const ok = document.execCommand('copy');
|
||||||
|
document.body.removeChild(textarea);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerLadillClipboard(Alpine) {
|
||||||
|
Alpine.data('copyButton', (text = '') => ({
|
||||||
|
copied: false,
|
||||||
|
text: text ?? '',
|
||||||
|
resetTimer: null,
|
||||||
|
async copy() {
|
||||||
|
const ok = await writeClipboardText(this.text);
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.copied = true;
|
||||||
|
|
||||||
|
if (this.resetTimer) {
|
||||||
|
clearTimeout(this.resetTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.resetTimer = setTimeout(() => {
|
||||||
|
this.copied = false;
|
||||||
|
}, COPY_FEEDBACK_MS);
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
@props([
|
||||||
|
'text' => '',
|
||||||
|
'label' => 'Copy',
|
||||||
|
'copiedLabel' => 'Copied!',
|
||||||
|
'icon' => false,
|
||||||
|
'copiedClass' => '',
|
||||||
|
])
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
x-data="copyButton(@js($text))"
|
||||||
|
@click="copy()"
|
||||||
|
:title="copied ? @js($copiedLabel) : @js($icon ? 'Copy' : $label)"
|
||||||
|
:class="copied ? @js($copiedClass) : ''"
|
||||||
|
{{ $attributes->class($icon ? 'inline-flex shrink-0 items-center justify-center' : '') }}
|
||||||
|
>
|
||||||
|
@if ($icon)
|
||||||
|
<svg x-show="!copied" class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" 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 x-show="copied" x-cloak class="h-4 w-4 text-emerald-600" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"/>
|
||||||
|
</svg>
|
||||||
|
@elseif ($slot->isNotEmpty())
|
||||||
|
{{ $slot }}
|
||||||
|
@else
|
||||||
|
<span x-text="copied ? @js($copiedLabel) : @js($label)"></span>
|
||||||
|
@endif
|
||||||
|
</button>
|
||||||
Reference in New Issue
Block a user