Merge pull request #6631 from thgO-O/refactor/clipboard-styling-issue-6625

Refactor: Move clipboard styling from attributes to CSS classes
This commit is contained in:
Pavlenex
2025-03-18 11:19:07 +04:00
committed by GitHub
13 changed files with 55 additions and 49 deletions

View File

@@ -31,7 +31,7 @@
}
@if (Model.Copy)
{
<button type="button" class="btn btn-link p-0" @(prefix)data-clipboard="@Model.Text">
<button type="button" class="btn btn-link p-0 clipboard-button" @(prefix)data-clipboard="@Model.Text">
<vc:icon symbol="actions-copy" />
</button>
}

View File

@@ -7,7 +7,7 @@
<template id="@BitcoinCheckoutModelExtension.CheckoutBodyComponentName">
@await Component.InvokeAsync("UiExtensionPoint", new {location = "checkout-bitcoin-pre-content", model = Model})
<div class="payment-box">
<div v-if="model.invoiceBitcoinUrlQR" class="qr-container" :data-qr-value="model.invoiceBitcoinUrlQR" :data-clipboard="model.invoiceBitcoinUrl" data-clipboard-confirm-element="#Address_@Model.PaymentMethodId [data-clipboard]">
<div v-if="model.invoiceBitcoinUrlQR" class="qr-container clipboard-button" :data-qr-value="model.invoiceBitcoinUrlQR" :data-clipboard="model.invoiceBitcoinUrl" data-clipboard-confirm-element="#Address_@Model.PaymentMethodId [data-clipboard]">
<div>
<qrcode :value="model.invoiceBitcoinUrlQR" tag="div" :options="qrOptions" />
</div>

View File

@@ -4,7 +4,7 @@
<template id="@LNCheckoutModelExtension.CheckoutBodyComponentName">
<div class="payment-box">
@await Component.InvokeAsync("UiExtensionPoint" , new { location="checkout-lightning-pre-content", model = Model})
<div v-if="model.invoiceBitcoinUrlQR" class="qr-container" :data-qr-value="model.invoiceBitcoinUrlQR" :data-clipboard="model.invoiceBitcoinUrl" data-clipboard-confirm-element="#Lightning_@Model.PaymentMethodId [data-clipboard]">
<div v-if="model.invoiceBitcoinUrlQR" class="qr-container clipboard-button" :data-qr-value="model.invoiceBitcoinUrlQR" :data-clipboard="model.invoiceBitcoinUrl" data-clipboard-confirm-element="#Lightning_@Model.PaymentMethodId [data-clipboard]">
<div>
<qrcode :value="model.invoiceBitcoinUrlQR" tag="div" :options="qrOptions" />
</div>

View File

@@ -409,7 +409,7 @@
<div class="row" v-show="!errors.any()">
<div class="col-xxl-8">
<pre><code id="mainCode" class="html"></code></pre>
<button class="btn btn-outline-secondary" data-clipboard-target="#mainCode">
<button class="btn btn-outline-secondary clipboard-button" data-clipboard-target="#mainCode">
<vc:icon symbol="actions-copy"/>&nbsp;<span text-translate="true">Copy Code</span>
</button>
</div>

View File

@@ -33,7 +33,7 @@
</a>
@if (!string.IsNullOrEmpty(_env.OnionUrl) && !Context.Request.IsOnion())
{
<button type="button" class="d-flex align-items-center btn btn-link" data-clipboard="@_env.OnionUrl" data-clipboard-hover>
<button type="button" class="d-flex align-items-center btn btn-link clipboard-button clipboard-button-hover" data-clipboard="@_env.OnionUrl" data-clipboard-hover>
<vc:icon symbol="logo-tor"/>
<span text-translate="true">Copy Tor URL</span>
</button>

View File

@@ -58,7 +58,7 @@
}
else
{
<h2 id="AmountDue" v-text="`${srvModel.due} ${srvModel.paymentMethodCurrency}`" :data-clipboard="asNumber(srvModel.due)" data-clipboard-hover :data-amount-due="srvModel.due">@Model.Due @Model.PaymentMethodCurrency</h2>
<h2 id="AmountDue" class="clipboard-button clipboard-button-hover" v-text="`${srvModel.due} ${srvModel.paymentMethodCurrency}`" :data-clipboard="asNumber(srvModel.due)" data-clipboard-hover :data-amount-due="srvModel.due">@Model.Due @Model.PaymentMethodCurrency</h2>
}
</div>
<div id="PaymentInfo" class="info mt-3 mb-2" v-collapsible="showInfo">
@@ -126,11 +126,11 @@
<dl class="mb-0">
<div>
<dt v-t="'invoice_id'"></dt>
<dd v-text="srvModel.invoiceId" :data-clipboard="srvModel.invoiceId" :data-clipboard-confirm="$t('copy_confirm')"></dd>
<dd class="clipboard-button" v-text="srvModel.invoiceId" :data-clipboard="srvModel.invoiceId" :data-clipboard-confirm="$t('copy_confirm')"></dd>
</div>
<div v-if="srvModel.orderId">
<dt v-t="'order_id'"></dt>
<dd v-text="srvModel.orderId" :data-clipboard="srvModel.orderId" :data-clipboard-confirm="$t('copy_confirm')"></dd>
<dd class="clipboard-button" v-text="srvModel.orderId" :data-clipboard="srvModel.orderId" :data-clipboard-confirm="$t('copy_confirm')"></dd>
</div>
</dl>
<payment-details
@@ -163,11 +163,11 @@
<dl class="mb-0">
<div>
<dt v-t="'invoice_id'"></dt>
<dd v-text="srvModel.invoiceId" :data-clipboard="srvModel.invoiceId" data-clipboard-hover="start"></dd>
<dd class="clipboard-button clipboard-button-hover" v-text="srvModel.invoiceId" :data-clipboard="srvModel.invoiceId" data-clipboard-hover="start"></dd>
</div>
<div v-if="srvModel.orderId">
<dt v-t="'order_id'"></dt>
<dd v-text="srvModel.orderId" :data-clipboard="srvModel.orderId" data-clipboard-hover="start"></dd>
<dd class="clipboard-button clipboard-button-hover" v-text="srvModel.orderId" :data-clipboard="srvModel.orderId" data-clipboard-hover="start"></dd>
</div>
</dl>
<payment-details
@@ -196,11 +196,11 @@
<dl class="mb-0">
<div>
<dt v-t="'invoice_id'"></dt>
<dd v-text="srvModel.invoiceId" :data-clipboard="srvModel.invoiceId" data-clipboard-hover="start"></dd>
<dd class="clipboard-button clipboard-button-hover" v-text="srvModel.invoiceId" :data-clipboard="srvModel.invoiceId" data-clipboard-hover="start"></dd>
</div>
<div v-if="srvModel.orderId">
<dt v-t="'order_id'"></dt>
<dd v-text="srvModel.orderId" :data-clipboard="srvModel.orderId" data-clipboard-hover="start"></dd>
<dd class="clipboard-button clipboard-button-hover" v-text="srvModel.orderId" :data-clipboard="srvModel.orderId" data-clipboard-hover="start"></dd>
</div>
</dl>
<payment-details
@@ -251,37 +251,37 @@
<dl>
<div v-if="orderAmount > 0" id="PaymentDetails-TotalPrice" key="TotalPrice">
<dt v-t="'total_price'"></dt>
<dd :data-clipboard="asNumber(srvModel.orderAmount)" data-clipboard-hover="start">{{srvModel.orderAmount}} {{ srvModel.paymentMethodCurrency }}</dd>
<dd class="clipboard-button clipboard-button-hover" :data-clipboard="asNumber(srvModel.orderAmount)" data-clipboard-hover="start">{{srvModel.orderAmount}} {{ srvModel.paymentMethodCurrency }}</dd>
</div>
<div v-if="orderAmount > 0 && srvModel.orderAmountFiat" id="PaymentDetails-TotalFiat" key="TotalFiat">
<dt v-t="'total_fiat'"></dt>
<dd :data-clipboard="asNumber(srvModel.orderAmountFiat)" data-clipboard-hover="start">{{srvModel.orderAmountFiat}}</dd>
<dd class="clipboard-button clipboard-button-hover" :data-clipboard="asNumber(srvModel.orderAmountFiat)" data-clipboard-hover="start">{{srvModel.orderAmountFiat}}</dd>
</div>
<div v-if="srvModel.rate && srvModel.paymentMethodCurrency" id="PaymentDetails-ExchangeRate" key="ExchangeRate">
<dt v-t="'exchange_rate'"></dt>
<dd :data-clipboard="asNumber(srvModel.rate)" data-clipboard-hover="start">
<dd class="clipboard-button clipboard-button-hover" :data-clipboard="asNumber(srvModel.rate)" data-clipboard-hover="start">
<template v-if="srvModel.paymentMethodCurrency === 'sats'">1 sat = {{ srvModel.rate }}</template>
<template v-else>1 {{ srvModel.paymentMethodCurrency }} = {{ srvModel.rate }}</template>
</dd>
</div>
<div v-if="srvModel.networkFee" id="PaymentDetails-NetworkCost" key="NetworkCost">
<dt v-t="'network_cost'"></dt>
<dd :data-clipboard="asNumber(srvModel.networkFee)" data-clipboard-hover="start">
<dd class="clipboard-button clipboard-button-hover" :data-clipboard="asNumber(srvModel.networkFee)" data-clipboard-hover="start">
<div v-if="srvModel.txCountForFee > 0" v-t="{ path: 'tx_count', args: { count: srvModel.txCount } }"></div>
<div v-text="`${srvModel.networkFee} ${srvModel.paymentMethodCurrency}`"></div>
</dd>
</div>
<div v-if="paid > 0" id="PaymentDetails-AmountPaid" key="AmountPaid">
<dt v-t="'amount_paid'"></dt>
<dd :data-clipboard="asNumber(srvModel.paid)" data-clipboard-hover="start" v-text="`${srvModel.paid} ${srvModel.paymentMethodCurrency}`"></dd>
<dd class="clipboard-button clipboard-button-hover" :data-clipboard="asNumber(srvModel.paid)" data-clipboard-hover="start" v-text="`${srvModel.paid} ${srvModel.paymentMethodCurrency}`"></dd>
</div>
<div v-if="due > 0" id="PaymentDetails-AmountDue" key="AmountDue">
<dt v-t="'amount_due'"></dt>
<dd :data-clipboard="asNumber(srvModel.due)" data-clipboard-hover="start" v-text="`${srvModel.due} ${srvModel.paymentMethodCurrency}`"></dd>
<dd class="clipboard-button clipboard-button-hover" :data-clipboard="asNumber(srvModel.due)" data-clipboard-hover="start" v-text="`${srvModel.due} ${srvModel.paymentMethodCurrency}`"></dd>
</div>
<div v-if="showRecommendedFee" id="PaymentDetails-RecommendedFee" key="RecommendedFee">
<dt v-t="'recommended_fee'"></dt>
<dd :data-clipboard="asNumber(srvModel.feeRate)" data-clipboard-hover="start" v-t="{ path: 'fee_rate', args: { feeRate: srvModel.feeRate } }"></dd>
<dd class="clipboard-button clipboard-button-hover" :data-clipboard="asNumber(srvModel.feeRate)" data-clipboard-hover="start" v-t="{ path: 'fee_rate', args: { feeRate: srvModel.feeRate } }"></dd>
</div>
</dl>
</script>

View File

@@ -124,7 +124,7 @@
var address = $"{Model.Items[index].Username}@{Context.Request.Host.ToUriComponent()}";
<tr>
<td>
<div class="input-group" data-clipboard="@address">
<div class="input-group clipboard-button" data-clipboard="@address">
<input type="text" class="form-control copy-cursor lightning-address-value" readonly="readonly" value="@address"/>
<button type="button" class="btn btn-outline-secondary px-3">
<vc:icon symbol="actions-copy" />

View File

@@ -51,7 +51,7 @@
<button type="button" class="btn btn-link only-for-js p-0" data-reveal-btn text-translate="true">Reveal</button>
<div hidden class="gap-2 align-items-center">
<code>@keyData.Id</code>
<button type="button" class="btn btn-link d-flex p-0" data-clipboard="@keyData.Id">
<button type="button" class="btn btn-link d-flex p-0 clipboard-button" data-clipboard="@keyData.Id">
<vc:icon symbol="actions-copy" />
</button>
</div>

View File

@@ -47,7 +47,7 @@
<p class="mb-2" text-translate="true">Scan the QR Code or enter the following key into your two-factor authenticator app:</p>
<div class="input-group input-group-sm mb-4">
<input readonly class="form-control font-monospace" value="@Model.SharedKey" id="SharedKey" style="max-width:20rem">
<button type="button" class="btn btn-outline-secondary" data-clipboard-target="#SharedKey">
<button type="button" class="btn btn-outline-secondary clipboard-button" data-clipboard-target="#SharedKey">
<vc:icon symbol="actions-copy" />
</button>
</div>

View File

@@ -54,7 +54,7 @@ else
<input id="@fileId-name" class="form-control-plaintext" readonly="readonly" value="@file.FileName">
<label text-translate="true">File name</label>
</div>
<button type="button" class="btn btn-link" data-clipboard="@file.FileName">
<button type="button" class="btn btn-link clipboard-button" data-clipboard="@file.FileName">
<vc:icon symbol="actions-copy" />
</button>
</div>
@@ -65,7 +65,7 @@ else
<input id="@fileId" class="form-control-plaintext" readonly="readonly" value="@fileId">
<label text-translate="true">File Id</label>
</div>
<button type="button" class="btn btn-link" data-clipboard="@fileId">
<button type="button" class="btn btn-link clipboard-button" data-clipboard="@fileId">
<vc:icon symbol="actions-copy" />
</button>
</div>
@@ -76,12 +76,12 @@ else
<input id="@fileId-url" class="form-control-plaintext" readonly="readonly" value="@url">
<label text-translate="true">Permanent Url</label>
</div>
<button type="button" class="btn btn-link" data-clipboard="@url">
<button type="button" class="btn btn-link clipboard-button" data-clipboard="@url">
<vc:icon symbol="actions-copy" />
</button>
</div>
</div>
<button type="button" class="btn btn-link" data-clipboard="@url">
<button type="button" class="btn btn-link clipboard-button" data-clipboard="@url">
<vc:icon symbol="copy" />
</button>
</div>

View File

@@ -127,7 +127,7 @@
</div>
<div class="form-group">
<label asp-for="DerivationScheme" class="form-label"></label>
<div class="input-group" data-clipboard="@Model.DerivationScheme">
<div class="input-group clipboard-button" data-clipboard="@Model.DerivationScheme">
<input asp-for="DerivationScheme" class="form-control" readonly />
<button type="button" class="btn btn-outline-secondary px-3">
<vc:icon symbol="actions-copy" />
@@ -138,7 +138,7 @@
{
<div class="form-group">
<label asp-for="DerivationSchemeInput" class="form-label"></label>
<div class="input-group" data-clipboard="@Model.DerivationSchemeInput">
<div class="input-group clipboard-button" data-clipboard="@Model.DerivationSchemeInput">
<input asp-for="DerivationSchemeInput" class="form-control" readonly/>
<button type="button" class="btn btn-outline-secondary px-3">
<vc:icon symbol="actions-copy" />
@@ -156,7 +156,7 @@
<vc:icon symbol="qr-code" /> @StringLocalizer["Show export QR"]
</button>
</div>
<div class="input-group" data-clipboard="@Model.AccountKeys[i].AccountKey">
<div class="input-group clipboard-button" data-clipboard="@Model.AccountKeys[i].AccountKey">
<input asp-for="@Model.AccountKeys[i].AccountKey" class="form-control" readonly />
<button type="button" class="btn btn-outline-secondary px-3">
<vc:icon symbol="actions-copy" />

View File

@@ -55,7 +55,7 @@
<div class="only-for-js col-sm-10 col-xxl-8 mx-auto" id="app">
<div class="tab-content text-center">
<div class="tab-pane payment-box" id="link-tab" role="tabpanel">
<div class="qr-container" data-clipboard="@Model.PaymentLink">
<div class="qr-container clipboard-button" data-clipboard="@Model.PaymentLink">
<vc:qr-code data="@Model.PaymentLink"/>
@if (Model.CryptoImage is not null)
{
@@ -70,7 +70,7 @@
</div>
</div>
<div class="tab-pane payment-box show active" id="address-tab" role="tabpanel">
<div class="qr-container" data-clipboard="@Model.Address">
<div class="qr-container clipboard-button" data-clipboard="@Model.Address">
<vc:qr-code data="@Model.Address"/>
@if (Model.CryptoImage is not null)
{

View File

@@ -1099,14 +1099,28 @@ input.ts-wrapper.form-control:not(.ts-hidden-accessible,.ts-inline) {
}
/* Copy */
[data-clipboard],
[data-clipboard] input[readonly] {
.clipboard-button, .clipboard-button input[readonly] {
cursor: copy;
color: var(--btcpay-body-text-muted);
}
[data-clipboard-hover] {
.clipboard-button:hover {
color: rgba(var(--btcpay-body-link-rgb), var(--btcpay-link-opacity, 1)) !important;
}
.clipboard-button[data-clipboard-confirming] {
color: var(--btcpay-success) !important;
}
.clipboard-button[data-clipboard-confirming]::before {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M13.7808 4.21934C13.9213 4.35997 14.0002 4.55059 14.0002 4.74934C14.0002 4.94809 13.9213 5.13871 13.7808 5.27934L6.53082 12.5293C6.3902 12.6698 6.19957 12.7487 6.00082 12.7487C5.80207 12.7487 5.61145 12.6698 5.47082 12.5293L2.22082 9.27934C2.08834 9.13717 2.01622 8.94912 2.01965 8.75482C2.02308 8.56052 2.10179 8.37513 2.2392 8.23772C2.37661 8.10031 2.562 8.02159 2.7563 8.01816C2.9506 8.01474 3.13865 8.08686 3.28082 8.21934L6.00082 10.9393L12.7208 4.21934C12.8614 4.07889 13.0521 4 13.2508 4C13.4496 4 13.6402 4.07889 13.7808 4.21934Z' fill='%2351B13E'/%3E%3C/svg%3E ");
}
.clipboard-button-hover {
position: relative;
}
[data-clipboard-hover]::before {
.clipboard-button-hover::before {
content: '';
position: absolute;
top: .45rem;
@@ -1121,27 +1135,19 @@ input.ts-wrapper.form-control:not(.ts-hidden-accessible,.ts-inline) {
background-repeat: no-repeat;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M13.3333 6H7.33333C6.59695 6 6 6.59695 6 7.33333V13.3333C6 14.0697 6.59695 14.6667 7.33333 14.6667H13.3333C14.0697 14.6667 14.6667 14.0697 14.6667 13.3333V7.33333C14.6667 6.59695 14.0697 6 13.3333 6Z' stroke='%236E7681' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M3.33203 10.0007H2.66536C2.31174 10.0007 1.9726 9.86018 1.72256 9.61013C1.47251 9.36008 1.33203 9.02094 1.33203 8.66732V2.66732C1.33203 2.3137 1.47251 1.97456 1.72256 1.72451C1.9726 1.47446 2.31174 1.33398 2.66536 1.33398H8.66536C9.01899 1.33398 9.35813 1.47446 9.60817 1.72451C9.85822 1.97456 9.9987 2.3137 9.9987 2.66732V3.33398' stroke='%236E7681' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
[data-clipboard-hover="start"]::before {
.clipboard-button-hover[data-clipboard-hover="start"]::before {
left: auto;
right: calc(100% + var(--btcpay-space-s));
}
[data-clipboard-hover][data-clipboard-confirming]::before {
.clipboard-button-hover[data-clipboard-confirming]::before {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M13.7808 4.21934C13.9213 4.35997 14.0002 4.55059 14.0002 4.74934C14.0002 4.94809 13.9213 5.13871 13.7808 5.27934L6.53082 12.5293C6.3902 12.6698 6.19957 12.7487 6.00082 12.7487C5.80207 12.7487 5.61145 12.6698 5.47082 12.5293L2.22082 9.27934C2.08834 9.13717 2.01622 8.94912 2.01965 8.75482C2.02308 8.56052 2.10179 8.37513 2.2392 8.23772C2.37661 8.10031 2.562 8.02159 2.7563 8.01816C2.9506 8.01474 3.13865 8.08686 3.28082 8.21934L6.00082 10.9393L12.7208 4.21934C12.8614 4.07889 13.0521 4 13.2508 4C13.4496 4 13.6402 4.07889 13.7808 4.21934Z' fill='%2351B13E'/%3E%3C/svg%3E ");
}
[data-clipboard-hover]:hover::before {
.clipboard-button-hover:hover::before {
opacity: 1;
}
.btn[data-clipboard],
.btn[data-clipboard-target] {
color: var(--btcpay-body-text-muted);
}
.btn[data-clipboard]:hover,
.btn[data-clipboard-target]:hover {
color: rgba(var(--btcpay-body-link-rgb), var(--btcpay-link-opacity, 1));
}
.btn[data-clipboard-confirming] {
color: var(--btcpay-success) !important;
}
.btn .icon-scan-qr {
--icon-size: 1.1875rem;