mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-21 22:11:48 +01:00
Store settings: Add branding options (#4131)
* Add logo upload * Add brand color definition * Cleanups * Add logo to store selector * Improve brand color handling * Update color input * Add logo dimensions hint * Fixes * Fix pattern and warning in js logs for color validation * Fix condition, add test Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
This commit is contained in:
parent
9533809631
commit
f9f1a22e3b
10 changed files with 152 additions and 14 deletions
|
@ -644,15 +644,26 @@ namespace BTCPayServer.Tests
|
||||||
s.Driver.FindElement(By.Id("enable-pay-button")).Click();
|
s.Driver.FindElement(By.Id("enable-pay-button")).Click();
|
||||||
s.Driver.FindElement(By.Id("disable-pay-button")).Click();
|
s.Driver.FindElement(By.Id("disable-pay-button")).Click();
|
||||||
s.FindAlertMessage();
|
s.FindAlertMessage();
|
||||||
s.GoToStore(StoreNavPages.General);
|
s.GoToStore();
|
||||||
Assert.False(s.Driver.FindElement(By.Id("AnyoneCanCreateInvoice")).Selected);
|
Assert.False(s.Driver.FindElement(By.Id("AnyoneCanCreateInvoice")).Selected);
|
||||||
s.Driver.SetCheckbox(By.Id("AnyoneCanCreateInvoice"), true);
|
s.Driver.SetCheckbox(By.Id("AnyoneCanCreateInvoice"), true);
|
||||||
s.Driver.FindElement(By.Id("Save")).Click();
|
s.Driver.FindElement(By.Id("Save")).Click();
|
||||||
s.FindAlertMessage();
|
s.FindAlertMessage();
|
||||||
Assert.True(s.Driver.FindElement(By.Id("AnyoneCanCreateInvoice")).Selected);
|
Assert.True(s.Driver.FindElement(By.Id("AnyoneCanCreateInvoice")).Selected);
|
||||||
|
|
||||||
|
// Store settings: Set and unset brand color
|
||||||
|
s.GoToStore();
|
||||||
|
s.Driver.FindElement(By.Id("BrandColor")).SendKeys("#f7931a");
|
||||||
|
s.Driver.FindElement(By.Id("Save")).Click();
|
||||||
|
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
|
||||||
|
Assert.Equal("#f7931a", s.Driver.FindElement(By.Id("BrandColor")).GetAttribute("value"));
|
||||||
|
s.Driver.FindElement(By.Id("BrandColor")).Clear();
|
||||||
|
s.Driver.FindElement(By.Id("Save")).Click();
|
||||||
|
Assert.Contains("Store successfully updated", s.FindAlertMessage().Text);
|
||||||
|
Assert.Equal(string.Empty, s.Driver.FindElement(By.Id("BrandColor")).GetAttribute("value"));
|
||||||
|
|
||||||
// Alice should be able to delete the store
|
// Alice should be able to delete the store
|
||||||
s.GoToStore(StoreNavPages.General);
|
s.GoToStore();
|
||||||
s.Driver.FindElement(By.Id("DeleteStore")).Click();
|
s.Driver.FindElement(By.Id("DeleteStore")).Click();
|
||||||
s.Driver.WaitForElement(By.Id("ConfirmInput")).SendKeys("DELETE");
|
s.Driver.WaitForElement(By.Id("ConfirmInput")).SendKeys("DELETE");
|
||||||
s.Driver.FindElement(By.Id("ConfirmContinue")).Click();
|
s.Driver.FindElement(By.Id("ConfirmContinue")).Click();
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using NBitcoin.Crypto;
|
using NBitcoin.Crypto;
|
||||||
|
|
||||||
namespace BTCPayServer
|
namespace BTCPayServer
|
||||||
{
|
{
|
||||||
public class ColorPalette
|
public class ColorPalette
|
||||||
{
|
{
|
||||||
|
public const string Pattern = "^#[0-9a-fA-F]{6}$";
|
||||||
|
public static bool IsValid(string color)
|
||||||
|
{
|
||||||
|
return Regex.Match(color, Pattern).Success;
|
||||||
|
}
|
||||||
public string TextColor(string bgColor)
|
public string TextColor(string bgColor)
|
||||||
{
|
{
|
||||||
int nThreshold = 105;
|
int nThreshold = 105;
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
@inject BTCPayServer.Services.BTCPayServerEnvironment _env
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@inject SignInManager<ApplicationUser> _signInManager
|
@using BTCPayServer.Abstractions.Extensions
|
||||||
|
@using BTCPayServer.Abstractions.TagHelpers
|
||||||
|
@using BTCPayServer.Abstractions.Contracts
|
||||||
|
@inject BTCPayServer.Services.BTCPayServerEnvironment Env
|
||||||
|
@inject SignInManager<ApplicationUser> SignInManager
|
||||||
|
@inject IFileService FileService
|
||||||
@model BTCPayServer.Components.StoreSelector.StoreSelectorViewModel
|
@model BTCPayServer.Components.StoreSelector.StoreSelectorViewModel
|
||||||
@functions {
|
@functions {
|
||||||
@* ReSharper disable once CSharpWarnings::CS1998 *@
|
@* ReSharper disable once CSharpWarnings::CS1998 *@
|
||||||
|
@ -8,9 +13,9 @@
|
||||||
{
|
{
|
||||||
var logoSrc = $"{ViewContext.HttpContext.Request.PathBase}/img/logo.svg";
|
var logoSrc = $"{ViewContext.HttpContext.Request.PathBase}/img/logo.svg";
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" alt="BTCPay Server" class="logo"><use href="@logoSrc#small" class="logo-small" /><use href="@logoSrc#large" class="logo-large" /></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" role="img" alt="BTCPay Server" class="logo"><use href="@logoSrc#small" class="logo-small" /><use href="@logoSrc#large" class="logo-large" /></svg>
|
||||||
@if (_env.NetworkType != NBitcoin.ChainName.Mainnet)
|
@if (Env.NetworkType != NBitcoin.ChainName.Mainnet)
|
||||||
{
|
{
|
||||||
<span class="badge bg-warning ms-1 ms-sm-0" style="font-size:10px;">@_env.NetworkType.ToString()</span>
|
<span class="badge bg-warning ms-1 ms-sm-0" style="font-size:10px;">@Env.NetworkType.ToString()</span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private string StoreName(string title)
|
private string StoreName(string title)
|
||||||
|
@ -37,7 +42,14 @@ else
|
||||||
{
|
{
|
||||||
<div id="StoreSelectorDropdown" class="dropdown only-for-js">
|
<div id="StoreSelectorDropdown" class="dropdown only-for-js">
|
||||||
<button id="StoreSelectorToggle" class="btn btn-secondary dropdown-toggle rounded-pill px-3 @(Model.CurrentStoreId == null ? "text-secondary" : "")" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
<button id="StoreSelectorToggle" class="btn btn-secondary dropdown-toggle rounded-pill px-3 @(Model.CurrentStoreId == null ? "text-secondary" : "")" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
<vc:icon symbol="store"/>
|
@if (!string.IsNullOrEmpty(Model.CurrentStoreLogoFileId))
|
||||||
|
{
|
||||||
|
<img class="logo" src="@(await FileService.GetFileUrl(Context.Request.GetAbsoluteRootUri(), Model.CurrentStoreLogoFileId))" alt="@Model.CurrentDisplayName" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<vc:icon symbol="store"/>
|
||||||
|
}
|
||||||
<span>@(Model.CurrentStoreId == null ? "Select Store" : Model.CurrentDisplayName)</span>
|
<span>@(Model.CurrentStoreId == null ? "Select Store" : Model.CurrentDisplayName)</span>
|
||||||
<vc:icon symbol="caret-down"/>
|
<vc:icon symbol="caret-down"/>
|
||||||
</button>
|
</button>
|
||||||
|
@ -60,7 +72,7 @@ else
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
else if (_signInManager.IsSignedIn(User))
|
else if (SignInManager.IsSignedIn(User))
|
||||||
{
|
{
|
||||||
<a asp-controller="UIUserStores" asp-action="CreateStore" class="btn btn-primary w-100 rounded-pill" id="StoreSelectorCreate">Create Store</a>
|
<a asp-controller="UIUserStores" asp-action="CreateStore" class="btn btn-primary w-100 rounded-pill" id="StoreSelectorCreate">Create Store</a>
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,12 +50,15 @@ namespace BTCPayServer.Components.StoreSelector
|
||||||
.OrderBy(s => s.Text)
|
.OrderBy(s => s.Text)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
var blob = currentStore?.GetStoreBlob();
|
||||||
|
|
||||||
var vm = new StoreSelectorViewModel
|
var vm = new StoreSelectorViewModel
|
||||||
{
|
{
|
||||||
Options = options,
|
Options = options,
|
||||||
CurrentStoreId = currentStore?.Id,
|
CurrentStoreId = currentStore?.Id,
|
||||||
CurrentDisplayName = currentStore?.StoreName,
|
CurrentDisplayName = currentStore?.StoreName,
|
||||||
CurrentStoreIsOwner = currentStore?.Role == StoreRoles.Owner
|
CurrentStoreIsOwner = currentStore?.Role == StoreRoles.Owner,
|
||||||
|
CurrentStoreLogoFileId = blob?.LogoFileId
|
||||||
};
|
};
|
||||||
|
|
||||||
return View(vm);
|
return View(vm);
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace BTCPayServer.Components.StoreSelector
|
||||||
{
|
{
|
||||||
public List<StoreSelectorOption> Options { get; set; }
|
public List<StoreSelectorOption> Options { get; set; }
|
||||||
public string CurrentStoreId { get; set; }
|
public string CurrentStoreId { get; set; }
|
||||||
|
public string CurrentStoreLogoFileId { get; set; }
|
||||||
public string CurrentDisplayName { get; set; }
|
public string CurrentDisplayName { get; set; }
|
||||||
public bool CurrentStoreIsOwner { get; set; }
|
public bool CurrentStoreIsOwner { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Abstractions.Constants;
|
using BTCPayServer.Abstractions.Constants;
|
||||||
|
using BTCPayServer.Abstractions.Contracts;
|
||||||
using BTCPayServer.Abstractions.Models;
|
using BTCPayServer.Abstractions.Models;
|
||||||
using BTCPayServer.Client;
|
using BTCPayServer.Client;
|
||||||
using BTCPayServer.Configuration;
|
using BTCPayServer.Configuration;
|
||||||
|
@ -60,6 +61,7 @@ namespace BTCPayServer.Controllers
|
||||||
IAuthorizationService authorizationService,
|
IAuthorizationService authorizationService,
|
||||||
EventAggregator eventAggregator,
|
EventAggregator eventAggregator,
|
||||||
AppService appService,
|
AppService appService,
|
||||||
|
IFileService fileService,
|
||||||
WebhookSender webhookNotificationManager,
|
WebhookSender webhookNotificationManager,
|
||||||
IDataProtectionProvider dataProtector,
|
IDataProtectionProvider dataProtector,
|
||||||
IOptions<ExternalServicesOptions> externalServiceOptions)
|
IOptions<ExternalServicesOptions> externalServiceOptions)
|
||||||
|
@ -75,6 +77,7 @@ namespace BTCPayServer.Controllers
|
||||||
_policiesSettings = policiesSettings;
|
_policiesSettings = policiesSettings;
|
||||||
_authorizationService = authorizationService;
|
_authorizationService = authorizationService;
|
||||||
_appService = appService;
|
_appService = appService;
|
||||||
|
_fileService = fileService;
|
||||||
DataProtector = dataProtector.CreateProtector("ConfigProtector");
|
DataProtector = dataProtector.CreateProtector("ConfigProtector");
|
||||||
WebhookNotificationManager = webhookNotificationManager;
|
WebhookNotificationManager = webhookNotificationManager;
|
||||||
_EventAggregator = eventAggregator;
|
_EventAggregator = eventAggregator;
|
||||||
|
@ -102,6 +105,7 @@ namespace BTCPayServer.Controllers
|
||||||
private readonly PoliciesSettings _policiesSettings;
|
private readonly PoliciesSettings _policiesSettings;
|
||||||
private readonly IAuthorizationService _authorizationService;
|
private readonly IAuthorizationService _authorizationService;
|
||||||
private readonly AppService _appService;
|
private readonly AppService _appService;
|
||||||
|
private readonly IFileService _fileService;
|
||||||
private readonly EventAggregator _EventAggregator;
|
private readonly EventAggregator _EventAggregator;
|
||||||
private readonly IOptions<ExternalServicesOptions> _externalServiceOptions;
|
private readonly IOptions<ExternalServicesOptions> _externalServiceOptions;
|
||||||
|
|
||||||
|
@ -593,6 +597,8 @@ namespace BTCPayServer.Controllers
|
||||||
Id = store.Id,
|
Id = store.Id,
|
||||||
StoreName = store.StoreName,
|
StoreName = store.StoreName,
|
||||||
StoreWebsite = store.StoreWebsite,
|
StoreWebsite = store.StoreWebsite,
|
||||||
|
LogoFileId = storeBlob.LogoFileId,
|
||||||
|
BrandColor = storeBlob.BrandColor,
|
||||||
NetworkFeeMode = storeBlob.NetworkFeeMode,
|
NetworkFeeMode = storeBlob.NetworkFeeMode,
|
||||||
AnyoneCanCreateInvoice = storeBlob.AnyoneCanInvoice,
|
AnyoneCanCreateInvoice = storeBlob.AnyoneCanInvoice,
|
||||||
PaymentTolerance = storeBlob.PaymentTolerance,
|
PaymentTolerance = storeBlob.PaymentTolerance,
|
||||||
|
@ -620,7 +626,7 @@ namespace BTCPayServer.Controllers
|
||||||
needUpdate = true;
|
needUpdate = true;
|
||||||
CurrentStore.StoreWebsite = model.StoreWebsite;
|
CurrentStore.StoreWebsite = model.StoreWebsite;
|
||||||
}
|
}
|
||||||
|
|
||||||
var blob = CurrentStore.GetStoreBlob();
|
var blob = CurrentStore.GetStoreBlob();
|
||||||
blob.AnyoneCanInvoice = model.AnyoneCanCreateInvoice;
|
blob.AnyoneCanInvoice = model.AnyoneCanCreateInvoice;
|
||||||
blob.NetworkFeeMode = model.NetworkFeeMode;
|
blob.NetworkFeeMode = model.NetworkFeeMode;
|
||||||
|
@ -628,6 +634,41 @@ namespace BTCPayServer.Controllers
|
||||||
blob.DefaultCurrency = model.DefaultCurrency;
|
blob.DefaultCurrency = model.DefaultCurrency;
|
||||||
blob.InvoiceExpiration = TimeSpan.FromMinutes(model.InvoiceExpiration);
|
blob.InvoiceExpiration = TimeSpan.FromMinutes(model.InvoiceExpiration);
|
||||||
blob.RefundBOLT11Expiration = TimeSpan.FromDays(model.BOLT11Expiration);
|
blob.RefundBOLT11Expiration = TimeSpan.FromDays(model.BOLT11Expiration);
|
||||||
|
if (!string.IsNullOrEmpty(model.BrandColor) && !ColorPalette.IsValid(model.BrandColor))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(model.BrandColor), "Invalid color");
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
blob.BrandColor = model.BrandColor;
|
||||||
|
|
||||||
|
if (model.LogoFile != null)
|
||||||
|
{
|
||||||
|
if (model.LogoFile.ContentType.StartsWith("image/", StringComparison.InvariantCulture))
|
||||||
|
{
|
||||||
|
var userId = GetUserId();
|
||||||
|
|
||||||
|
// delete existing image
|
||||||
|
if (!string.IsNullOrEmpty(blob.LogoFileId))
|
||||||
|
{
|
||||||
|
await _fileService.RemoveFile(blob.LogoFileId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add new image
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var storedFile = await _fileService.AddFile(model.LogoFile, userId);
|
||||||
|
blob.LogoFileId = storedFile.Id;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
TempData[WellKnownTempData.ErrorMessage] = $"Could not save logo: {e.Message}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TempData[WellKnownTempData.ErrorMessage] = "The uploaded logo file needs to be an image";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (CurrentStore.SetStoreBlob(blob))
|
if (CurrentStore.SetStoreBlob(blob))
|
||||||
{
|
{
|
||||||
|
|
|
@ -191,6 +191,8 @@ namespace BTCPayServer.Data
|
||||||
public TimeSpan RefundBOLT11Expiration { get; set; }
|
public TimeSpan RefundBOLT11Expiration { get; set; }
|
||||||
|
|
||||||
public List<UIStoresController.StoreEmailRule> EmailRules { get; set; }
|
public List<UIStoresController.StoreEmailRule> EmailRules { get; set; }
|
||||||
|
public string LogoFileId { get; set; }
|
||||||
|
public string BrandColor { get; set; }
|
||||||
|
|
||||||
public IPaymentFilter GetExcludedPaymentMethods()
|
public IPaymentFilter GetExcludedPaymentMethods()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using BTCPayServer.Client.Models;
|
using BTCPayServer.Client.Models;
|
||||||
using BTCPayServer.Validation;
|
using BTCPayServer.Validation;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace BTCPayServer.Models.StoreViewModels
|
namespace BTCPayServer.Models.StoreViewModels
|
||||||
{
|
{
|
||||||
|
@ -21,6 +22,13 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||||
[MaxLength(500)]
|
[MaxLength(500)]
|
||||||
public string StoreWebsite { get; set; }
|
public string StoreWebsite { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Logo")]
|
||||||
|
public IFormFile LogoFile { get; set; }
|
||||||
|
public string LogoFileId { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Brand Color")]
|
||||||
|
public string BrandColor { get; set; }
|
||||||
|
|
||||||
public bool CanDelete { get; set; }
|
public bool CanDelete { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Allow anyone to create invoice")]
|
[Display(Name = "Allow anyone to create invoice")]
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
@using BTCPayServer.Abstractions.Models
|
@using BTCPayServer.Abstractions.Models
|
||||||
|
@using BTCPayServer.TagHelpers
|
||||||
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
@using BTCPayServer.Abstractions.Contracts
|
||||||
|
@inject IFileService FileService;
|
||||||
@model GeneralSettingsViewModel
|
@model GeneralSettingsViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "../Shared/_NavLayout.cshtml";
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
ViewData.SetActivePage(StoreNavPages.General, "General", Context.GetStoreData().Id);
|
ViewData.SetActivePage(StoreNavPages.General, "General", Context.GetStoreData().Id);
|
||||||
|
var canUpload = await FileService.IsAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -11,7 +16,7 @@
|
||||||
{
|
{
|
||||||
<div asp-validation-summary="All" class="text-danger"></div>
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
}
|
}
|
||||||
<form method="post">
|
<form method="post" enctype="multipart/form-data">
|
||||||
<h3 class="mb-3">General</h3>
|
<h3 class="mb-3">General</h3>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="Id" class="form-label"></label>
|
<label asp-for="Id" class="form-label"></label>
|
||||||
|
@ -28,6 +33,35 @@
|
||||||
<span asp-validation-for="StoreWebsite" class="text-danger"></span>
|
<span asp-validation-for="StoreWebsite" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h3 class="mb-3">Branding</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="LogoFile" class="form-label"></label>
|
||||||
|
@if (canUpload)
|
||||||
|
{
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<input asp-for="LogoFile" type="file" class="form-control flex-grow">
|
||||||
|
@if (!string.IsNullOrEmpty(Model.LogoFileId))
|
||||||
|
{
|
||||||
|
<img src="@(await FileService.GetFileUrl(Context.Request.GetAbsoluteRootUri(), Model.LogoFileId))" alt="@Model.StoreName" class="rounded-circle ms-3" style="width:2.1rem;height:2.1rem;"/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<p class="form-text text-muted">Please upload an image with square dimension, as it will be displayed in 1:1 format and circular.</p>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input asp-for="LogoFile" type="file" class="form-control" disabled>
|
||||||
|
<p class="form-text text-muted">In order to upload a logo, a <a asp-controller="UIServer" asp-action="Files">file storage</a> must be configured.</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="BrandColor" class="form-label"></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="BrandColorInput" class="form-control form-control-color flex-grow-0" type="color" style="width:3rem" aria-describedby="BrandColorValue" value="@Model.BrandColor" />
|
||||||
|
<input asp-for="BrandColor" class="form-control form-control-color flex-grow-0 font-monospace" pattern="@ColorPalette.Pattern" style="width:5.5rem" />
|
||||||
|
</div>
|
||||||
|
<span asp-validation-for="BrandColor" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h3 class="mt-5 mb-3">Payment</h3>
|
<h3 class="mt-5 mb-3">Payment</h3>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="DefaultCurrency" class="form-label"></label>
|
<label asp-for="DefaultCurrency" class="form-label"></label>
|
||||||
|
@ -101,5 +135,19 @@
|
||||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete store", "The store will be permanently deleted. This action will also delete all invoices, apps and data associated with the store.", "Delete"))" />
|
<partial name="_Confirm" model="@(new ConfirmModel("Delete store", "The store will be permanently deleted. This action will also delete all invoices, apps and data associated with the store.", "Delete"))" />
|
||||||
|
|
||||||
@section PageFootContent {
|
@section PageFootContent {
|
||||||
<partial name="_ValidationScriptsPartial" />
|
<partial name="_ValidationScriptsPartial"/>
|
||||||
|
<script>
|
||||||
|
(() => {
|
||||||
|
const $colorValue = document.getElementById('BrandColor');
|
||||||
|
const $colorInput = document.getElementById('BrandColorInput');
|
||||||
|
delegate('change', '#BrandColor', e => {
|
||||||
|
const value = e.target.value;
|
||||||
|
if (value.match(@Safe.Json(@ColorPalette.Pattern)))
|
||||||
|
$colorInput.value = value;
|
||||||
|
});
|
||||||
|
delegate('change', '#BrandColorInput', e => {
|
||||||
|
$colorValue.value = e.target.value;
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,16 +150,22 @@
|
||||||
content: none;
|
content: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#StoreSelectorToggle .logo,
|
||||||
#StoreSelectorToggle .icon {
|
#StoreSelectorToggle .icon {
|
||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
transition: color 0.15s ease-in-out;
|
transition: color 0.15s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#StoreSelectorToggle .logo,
|
||||||
#StoreSelectorToggle .icon.icon-store {
|
#StoreSelectorToggle .icon.icon-store {
|
||||||
margin-right: var(--btcpay-space-s);
|
margin-right: var(--btcpay-space-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#StoreSelectorToggle .logo {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
#StoreSelectorToggle .icon.icon-caret-down {
|
#StoreSelectorToggle .icon.icon-caret-down {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
color: var(--btcpay-body-text-muted);
|
color: var(--btcpay-body-text-muted);
|
||||||
|
|
Loading…
Add table
Reference in a new issue