mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 14:34:23 +01:00
Store Branding: Apply brand color to backend as well (#5992)
* Store Branding: Apply brand color to backend as well Closes #5990. * Add adjustments for different theme scenarios * Add description text * Make it optional to apply the brand color to the backend * Toggle color fixes
This commit is contained in:
@@ -17,6 +17,7 @@ namespace BTCPayServer.Client.Models
|
|||||||
public string Website { get; set; }
|
public string Website { get; set; }
|
||||||
|
|
||||||
public string BrandColor { get; set; }
|
public string BrandColor { get; set; }
|
||||||
|
public bool ApplyBrandColorToBackend { get; set; }
|
||||||
public string LogoUrl { get; set; }
|
public string LogoUrl { get; set; }
|
||||||
public string CssUrl { get; set; }
|
public string CssUrl { get; set; }
|
||||||
public string PaymentSoundUrl { get; set; }
|
public string PaymentSoundUrl { get; set; }
|
||||||
|
|||||||
@@ -1622,6 +1622,7 @@ namespace BTCPayServer.Tests
|
|||||||
CssUrl = "https://example.org/style.css",
|
CssUrl = "https://example.org/style.css",
|
||||||
LogoUrl = "https://example.org/logo.svg",
|
LogoUrl = "https://example.org/logo.svg",
|
||||||
BrandColor = "#003366",
|
BrandColor = "#003366",
|
||||||
|
ApplyBrandColorToBackend = true,
|
||||||
PaymentMethodCriteria = new List<PaymentMethodCriteriaData>
|
PaymentMethodCriteria = new List<PaymentMethodCriteriaData>
|
||||||
{
|
{
|
||||||
new()
|
new()
|
||||||
@@ -1637,6 +1638,7 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.Equal("https://example.org/style.css", updatedStore.CssUrl);
|
Assert.Equal("https://example.org/style.css", updatedStore.CssUrl);
|
||||||
Assert.Equal("https://example.org/logo.svg", updatedStore.LogoUrl);
|
Assert.Equal("https://example.org/logo.svg", updatedStore.LogoUrl);
|
||||||
Assert.Equal("#003366", updatedStore.BrandColor);
|
Assert.Equal("#003366", updatedStore.BrandColor);
|
||||||
|
Assert.True(updatedStore.ApplyBrandColorToBackend);
|
||||||
var s = (await client.GetStore(newStore.Id));
|
var s = (await client.GetStore(newStore.Id));
|
||||||
Assert.Equal("B", s.Name);
|
Assert.Equal("B", s.Name);
|
||||||
var pmc = Assert.Single(s.PaymentMethodCriteria);
|
var pmc = Assert.Single(s.PaymentMethodCriteria);
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
Website = data.StoreWebsite,
|
Website = data.StoreWebsite,
|
||||||
Archived = data.Archived,
|
Archived = data.Archived,
|
||||||
BrandColor = storeBlob.BrandColor,
|
BrandColor = storeBlob.BrandColor,
|
||||||
|
ApplyBrandColorToBackend = storeBlob.ApplyBrandColorToBackend,
|
||||||
CssUrl = storeBlob.CssUrl == null ? null : await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), storeBlob.CssUrl),
|
CssUrl = storeBlob.CssUrl == null ? null : await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), storeBlob.CssUrl),
|
||||||
LogoUrl = storeBlob.LogoUrl == null ? null : await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), storeBlob.LogoUrl),
|
LogoUrl = storeBlob.LogoUrl == null ? null : await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), storeBlob.LogoUrl),
|
||||||
PaymentSoundUrl = storeBlob.PaymentSoundUrl == null ? null : await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), storeBlob.PaymentSoundUrl),
|
PaymentSoundUrl = storeBlob.PaymentSoundUrl == null ? null : await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), storeBlob.PaymentSoundUrl),
|
||||||
@@ -255,6 +256,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
blob.PaymentTolerance = restModel.PaymentTolerance;
|
blob.PaymentTolerance = restModel.PaymentTolerance;
|
||||||
blob.PayJoinEnabled = restModel.PayJoinEnabled;
|
blob.PayJoinEnabled = restModel.PayJoinEnabled;
|
||||||
blob.BrandColor = restModel.BrandColor;
|
blob.BrandColor = restModel.BrandColor;
|
||||||
|
blob.ApplyBrandColorToBackend = restModel.ApplyBrandColorToBackend;
|
||||||
blob.LogoUrl = restModel.LogoUrl is null ? null : UnresolvedUri.Create(restModel.LogoUrl);
|
blob.LogoUrl = restModel.LogoUrl is null ? null : UnresolvedUri.Create(restModel.LogoUrl);
|
||||||
blob.CssUrl = restModel.CssUrl is null ? null : UnresolvedUri.Create(restModel.CssUrl);
|
blob.CssUrl = restModel.CssUrl is null ? null : UnresolvedUri.Create(restModel.CssUrl);
|
||||||
blob.PaymentSoundUrl = restModel.PaymentSoundUrl is null ? null : UnresolvedUri.Create(restModel.PaymentSoundUrl);
|
blob.PaymentSoundUrl = restModel.PaymentSoundUrl is null ? null : UnresolvedUri.Create(restModel.PaymentSoundUrl);
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public partial class UIStoresController
|
|||||||
LogoUrl = await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), storeBlob.LogoUrl),
|
LogoUrl = await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), storeBlob.LogoUrl),
|
||||||
CssUrl = await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), storeBlob.CssUrl),
|
CssUrl = await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), storeBlob.CssUrl),
|
||||||
BrandColor = storeBlob.BrandColor,
|
BrandColor = storeBlob.BrandColor,
|
||||||
|
ApplyBrandColorToBackend = storeBlob.ApplyBrandColorToBackend,
|
||||||
NetworkFeeMode = storeBlob.NetworkFeeMode,
|
NetworkFeeMode = storeBlob.NetworkFeeMode,
|
||||||
AnyoneCanCreateInvoice = storeBlob.AnyoneCanInvoice,
|
AnyoneCanCreateInvoice = storeBlob.AnyoneCanInvoice,
|
||||||
PaymentTolerance = storeBlob.PaymentTolerance,
|
PaymentTolerance = storeBlob.PaymentTolerance,
|
||||||
@@ -75,10 +76,11 @@ public partial class UIStoresController
|
|||||||
blob.RefundBOLT11Expiration = TimeSpan.FromDays(model.BOLT11Expiration);
|
blob.RefundBOLT11Expiration = TimeSpan.FromDays(model.BOLT11Expiration);
|
||||||
if (!string.IsNullOrEmpty(model.BrandColor) && !ColorPalette.IsValid(model.BrandColor))
|
if (!string.IsNullOrEmpty(model.BrandColor) && !ColorPalette.IsValid(model.BrandColor))
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(model.BrandColor), "Invalid color");
|
ModelState.AddModelError(nameof(model.BrandColor), "The brand color needs to be a valid hex color code");
|
||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
blob.BrandColor = model.BrandColor;
|
blob.BrandColor = model.BrandColor;
|
||||||
|
blob.ApplyBrandColorToBackend = model.ApplyBrandColorToBackend && !string.IsNullOrEmpty(model.BrandColor);
|
||||||
|
|
||||||
var userId = GetUserId();
|
var userId = GetUserId();
|
||||||
if (userId is null)
|
if (userId is null)
|
||||||
|
|||||||
@@ -191,6 +191,8 @@ namespace BTCPayServer.Data
|
|||||||
|
|
||||||
public List<UIStoresController.StoreEmailRule> EmailRules { get; set; }
|
public List<UIStoresController.StoreEmailRule> EmailRules { get; set; }
|
||||||
public string BrandColor { get; set; }
|
public string BrandColor { get; set; }
|
||||||
|
public bool ApplyBrandColorToBackend { get; set; }
|
||||||
|
|
||||||
[JsonConverter(typeof(UnresolvedUriJsonConverter))]
|
[JsonConverter(typeof(UnresolvedUriJsonConverter))]
|
||||||
public UnresolvedUri LogoUrl { get; set; }
|
public UnresolvedUri LogoUrl { get; set; }
|
||||||
[JsonConverter(typeof(UnresolvedUriJsonConverter))]
|
[JsonConverter(typeof(UnresolvedUriJsonConverter))]
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Abstractions.Extensions;
|
using BTCPayServer.Abstractions.Extensions;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
@@ -10,6 +9,7 @@ namespace BTCPayServer.Models;
|
|||||||
public class StoreBrandingViewModel
|
public class StoreBrandingViewModel
|
||||||
{
|
{
|
||||||
public string BrandColor { get; set; }
|
public string BrandColor { get; set; }
|
||||||
|
public bool ApplyBrandColorToBackend { get; set; }
|
||||||
public string LogoUrl { get; set; }
|
public string LogoUrl { get; set; }
|
||||||
public string CssUrl { get; set; }
|
public string CssUrl { get; set; }
|
||||||
|
|
||||||
@@ -20,13 +20,16 @@ public class StoreBrandingViewModel
|
|||||||
{
|
{
|
||||||
if (storeBlob == null)
|
if (storeBlob == null)
|
||||||
return new StoreBrandingViewModel();
|
return new StoreBrandingViewModel();
|
||||||
var result = new StoreBrandingViewModel(storeBlob);
|
var result = new StoreBrandingViewModel(storeBlob)
|
||||||
result.LogoUrl = await uriResolver.Resolve(request.GetAbsoluteRootUri(), storeBlob.LogoUrl);
|
{
|
||||||
result.CssUrl = await uriResolver.Resolve(request.GetAbsoluteRootUri(), storeBlob.CssUrl);
|
LogoUrl = await uriResolver.Resolve(request.GetAbsoluteRootUri(), storeBlob.LogoUrl),
|
||||||
|
CssUrl = await uriResolver.Resolve(request.GetAbsoluteRootUri(), storeBlob.CssUrl)
|
||||||
|
};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
private StoreBrandingViewModel(StoreBlob storeBlob)
|
private StoreBrandingViewModel(StoreBlob storeBlob)
|
||||||
{
|
{
|
||||||
BrandColor = storeBlob.BrandColor;
|
BrandColor = storeBlob.BrandColor;
|
||||||
|
ApplyBrandColorToBackend = storeBlob.ApplyBrandColorToBackend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ namespace BTCPayServer.Models.StoreViewModels
|
|||||||
[Display(Name = "Brand Color")]
|
[Display(Name = "Brand Color")]
|
||||||
public string BrandColor { get; set; }
|
public string BrandColor { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Apply the brand color to the store's backend as well")]
|
||||||
|
public bool ApplyBrandColorToBackend { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Logo")]
|
[Display(Name = "Logo")]
|
||||||
public IFormFile LogoFile { get; set; }
|
public IFormFile LogoFile { get; set; }
|
||||||
public string LogoUrl { get; set; }
|
public string LogoUrl { get; set; }
|
||||||
|
|||||||
@@ -1,4 +1,17 @@
|
|||||||
@inject BTCPayServer.Services.PoliciesSettings PoliciesSettings
|
@using BTCPayServer.Services
|
||||||
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
@inject PoliciesSettings PoliciesSettings
|
||||||
|
@inject UriResolver UriResolver
|
||||||
|
@{
|
||||||
|
ViewData.TryGetValue("StoreBranding", out var storeBranding);
|
||||||
|
var store = Context.GetStoreData();
|
||||||
|
var storeBlob = store?.GetStoreBlob();
|
||||||
|
var isBackend = store != null && storeBranding == null;
|
||||||
|
if (isBackend && storeBlob.ApplyBrandColorToBackend)
|
||||||
|
{
|
||||||
|
storeBranding = await StoreBrandingViewModel.CreateAsync(Context.Request, UriResolver, storeBlob);
|
||||||
|
}
|
||||||
|
}
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
@if (PoliciesSettings.DiscourageSearchEngines)
|
@if (PoliciesSettings.DiscourageSearchEngines)
|
||||||
@@ -14,7 +27,7 @@
|
|||||||
<link href="~/main/site.css" asp-append-version="true" rel="stylesheet" />
|
<link href="~/main/site.css" asp-append-version="true" rel="stylesheet" />
|
||||||
|
|
||||||
<partial name="LayoutHeadTheme" />
|
<partial name="LayoutHeadTheme" />
|
||||||
@if (ViewData.TryGetValue("StoreBranding", out var storeBranding) && storeBranding != null)
|
@if (storeBranding != null)
|
||||||
{
|
{
|
||||||
<partial name="LayoutHeadStoreBranding" model="storeBranding" />
|
<partial name="LayoutHeadStoreBranding" model="storeBranding" />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
|
@using BTCPayServer.Services
|
||||||
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@model StoreBrandingViewModel
|
@model StoreBrandingViewModel
|
||||||
|
@inject ThemeSettings Theme
|
||||||
@if (!string.IsNullOrEmpty(Model.BrandColor))
|
@if (!string.IsNullOrEmpty(Model.BrandColor))
|
||||||
{
|
{
|
||||||
|
var hasCustomeTheme = Theme.CustomTheme && Theme.CustomThemeCssUrl is not null;
|
||||||
var brand = Model.BrandColor;
|
var brand = Model.BrandColor;
|
||||||
var brandColor = ColorPalette.Default.FromHtml(brand);
|
var brandColor = ColorPalette.Default.FromHtml(brand);
|
||||||
var brandRgbValues = $"{brandColor.R}, {brandColor.G}, {brandColor.B}";
|
var brandRgbValues = $"{brandColor.R}, {brandColor.G}, {brandColor.B}";
|
||||||
var accent = ColorPalette.Default.AdjustBrightness(brand, (float)-0.15);
|
var brightness = brandColor.GetBrightness();
|
||||||
|
var accent = ColorPalette.Default.AdjustBrightness(brand, (float)-.15);
|
||||||
|
var accentColor = ColorPalette.Default.FromHtml(accent);
|
||||||
|
var accentRgbValues = $"{accentColor.R}, {accentColor.G}, {accentColor.B}";
|
||||||
var complement = ColorPalette.Default.TextColor(brand);
|
var complement = ColorPalette.Default.TextColor(brand);
|
||||||
var complementVar = $"var(--btcpay-{(complement == "black" ? "black" : "white")})";
|
var complementVar = $"var(--btcpay-{(complement == "black" ? "black" : "white")})";
|
||||||
<style>
|
<style>
|
||||||
@@ -14,19 +21,93 @@
|
|||||||
--btcpay-primary-shadow: @brand;
|
--btcpay-primary-shadow: @brand;
|
||||||
--btcpay-primary-bg-hover: @accent;
|
--btcpay-primary-bg-hover: @accent;
|
||||||
--btcpay-primary-bg-active: @accent;
|
--btcpay-primary-bg-active: @accent;
|
||||||
--btcpay-body-link: @brand;
|
|
||||||
--btcpay-body-link-accent: @accent;
|
--btcpay-body-link-accent: @accent;
|
||||||
|
--btcpay-body-link-accent-rgb: @accentRgbValues;
|
||||||
--btcpay-primary-text: @complementVar;
|
--btcpay-primary-text: @complementVar;
|
||||||
--btcpay-primary-text-hover: @complementVar;
|
--btcpay-primary-text-hover: @complementVar;
|
||||||
--btcpay-primary-text-active: @complementVar;
|
--btcpay-primary-text-active: @complementVar;
|
||||||
}
|
}
|
||||||
a {
|
|
||||||
color: var(--btcpay-body-link);
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: var(--btcpay-body-link-accent);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@if (brightness > .5 || (Theme.CustomThemeExtension == ThemeExtension.Dark && brightness < .5))
|
||||||
|
{
|
||||||
|
var brandAdjusted = ColorPalette.Default.AdjustBrightness(brand, (float)(.35-brightness));
|
||||||
|
var brandColorAdjusted = ColorPalette.Default.FromHtml(brandAdjusted);
|
||||||
|
var brandRgbValuesAdjusted = $"{brandColorAdjusted.R}, {brandColorAdjusted.G}, {brandColorAdjusted.B}";
|
||||||
|
var accentAdjusted = ColorPalette.Default.AdjustBrightness(brandAdjusted, (float)-.15);
|
||||||
|
var accentColorAdjusted = ColorPalette.Default.FromHtml(accentAdjusted);
|
||||||
|
var accentRgbValuesAdjusted = $"{accentColorAdjusted.R}, {accentColorAdjusted.G}, {accentColorAdjusted.B}";
|
||||||
|
var complementAdjusted = ColorPalette.Default.TextColor(brandAdjusted);
|
||||||
|
var complementVarAdjusted = $"var(--btcpay-{(complementAdjusted == "black" ? "black" : "white")})";
|
||||||
|
<style>
|
||||||
|
:root[data-theme='light'],
|
||||||
|
:root[data-btcpay-theme='light'] {
|
||||||
|
--btcpay-primary: @brandAdjusted;
|
||||||
|
--btcpay-primary-rgb: @brandRgbValuesAdjusted;
|
||||||
|
--btcpay-primary-shadow: @brandAdjusted;
|
||||||
|
--btcpay-primary-bg-hover: @accentAdjusted;
|
||||||
|
--btcpay-primary-bg-active: @accentAdjusted;
|
||||||
|
--btcpay-body-link-accent: @accentAdjusted;
|
||||||
|
--btcpay-body-link-accent-rgb: @accentRgbValuesAdjusted;
|
||||||
|
--btcpay-primary-text: @complementVarAdjusted;
|
||||||
|
--btcpay-primary-text-hover: @complementVarAdjusted;
|
||||||
|
--btcpay-primary-text-active: @complementVarAdjusted;
|
||||||
|
}
|
||||||
|
@@media (prefers-color-scheme: light) {
|
||||||
|
:root:not([data-btcpay-theme], [data-theme]) {
|
||||||
|
--btcpay-primary: @brandAdjusted;
|
||||||
|
--btcpay-primary-rgb: @brandRgbValuesAdjusted;
|
||||||
|
--btcpay-primary-shadow: @brandAdjusted;
|
||||||
|
--btcpay-primary-bg-hover: @accentAdjusted;
|
||||||
|
--btcpay-primary-bg-active: @accentAdjusted;
|
||||||
|
--btcpay-body-link-accent: @accentAdjusted;
|
||||||
|
--btcpay-body-link-accent-rgb: @accentRgbValuesAdjusted;
|
||||||
|
--btcpay-primary-text: @complementVarAdjusted;
|
||||||
|
--btcpay-primary-text-hover: @complementVarAdjusted;
|
||||||
|
--btcpay-primary-text-active: @complementVarAdjusted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
}
|
||||||
|
@if (brightness < .5 && (!hasCustomeTheme || Theme.CustomThemeExtension == ThemeExtension.Dark))
|
||||||
|
{
|
||||||
|
var brandAdjusted = ColorPalette.Default.AdjustBrightness(brand, (float)(.5-brightness));
|
||||||
|
var brandColorAdjusted = ColorPalette.Default.FromHtml(brandAdjusted);
|
||||||
|
var brandRgbValuesAdjusted = $"{brandColorAdjusted.R}, {brandColorAdjusted.G}, {brandColorAdjusted.B}";
|
||||||
|
var accentAdjusted = ColorPalette.Default.AdjustBrightness(brandAdjusted, (float).15);
|
||||||
|
var accentColorAdjusted = ColorPalette.Default.FromHtml(accentAdjusted);
|
||||||
|
var accentRgbValuesAdjusted = $"{accentColorAdjusted.R}, {accentColorAdjusted.G}, {accentColorAdjusted.B}";
|
||||||
|
var complementAdjusted = ColorPalette.Default.TextColor(brandAdjusted);
|
||||||
|
var complementVarAdjusted = $"var(--btcpay-{(complementAdjusted == "black" ? "black" : "white")})";
|
||||||
|
<style>
|
||||||
|
:root[data-theme='dark'],
|
||||||
|
:root[data-btcpay-theme='dark'] {
|
||||||
|
--btcpay-primary: @brandAdjusted;
|
||||||
|
--btcpay-primary-rgb: @brandRgbValuesAdjusted;
|
||||||
|
--btcpay-primary-shadow: @brandAdjusted;
|
||||||
|
--btcpay-primary-bg-hover: @accentAdjusted;
|
||||||
|
--btcpay-primary-bg-active: @accentAdjusted;
|
||||||
|
--btcpay-body-link-accent: @accentAdjusted;
|
||||||
|
--btcpay-body-link-accent-rgb: @accentRgbValuesAdjusted;
|
||||||
|
--btcpay-primary-text: @complementVarAdjusted;
|
||||||
|
--btcpay-primary-text-hover: @complementVarAdjusted;
|
||||||
|
--btcpay-primary-text-active: @complementVarAdjusted;
|
||||||
|
}
|
||||||
|
@@media (prefers-color-scheme: dark) {
|
||||||
|
:root:not([data-btcpay-theme], [data-theme]) {
|
||||||
|
--btcpay-primary: @brandAdjusted;
|
||||||
|
--btcpay-primary-rgb: @brandRgbValuesAdjusted;
|
||||||
|
--btcpay-primary-shadow: @brandAdjusted;
|
||||||
|
--btcpay-primary-bg-hover: @accentAdjusted;
|
||||||
|
--btcpay-primary-bg-active: @accentAdjusted;
|
||||||
|
--btcpay-body-link-accent: @accentAdjusted;
|
||||||
|
--btcpay-body-link-accent-rgb: @accentRgbValuesAdjusted;
|
||||||
|
--btcpay-primary-text: @complementVarAdjusted;
|
||||||
|
--btcpay-primary-text-hover: @complementVarAdjusted;
|
||||||
|
--btcpay-primary-text-active: @complementVarAdjusted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
}
|
||||||
<meta name="theme-color" content="@brand">
|
<meta name="theme-color" content="@brand">
|
||||||
}
|
}
|
||||||
@if (!string.IsNullOrEmpty(Model.CssUrl))
|
@if (!string.IsNullOrEmpty(Model.CssUrl))
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<div class="col-xxl-constrain col-xl-8">
|
<div class="col-xxl-constrain col-xl-8">
|
||||||
@if (!ViewContext.ModelState.IsValid)
|
@if (!ViewContext.ModelState.IsValid)
|
||||||
{
|
{
|
||||||
<div asp-validation-summary="All"></div>
|
<div asp-validation-summary="All" class="@(ViewContext.ModelState.ErrorCount.Equals(1) ? "no-marker" : "")"></div>
|
||||||
}
|
}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="Id" class="form-label"></label>
|
<label asp-for="Id" class="form-label"></label>
|
||||||
@@ -38,15 +38,29 @@
|
|||||||
<span asp-validation-for="StoreWebsite" class="text-danger"></span>
|
<span asp-validation-for="StoreWebsite" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="mt-5 mb-3" text-translate="true">Branding</h3>
|
<h3 class="mt-5 mb-3" text-translate="true">Branding</h3>
|
||||||
<div class="form-group">
|
<p>
|
||||||
|
The custom color, logo and CSS are applied on the public/customer-facing pages (Invoice, Payment Request, Pull Payment, etc.).
|
||||||
|
The brand color is used as the accent color for buttons, links, etc. It might get adapted to fit the light/dark color scheme.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
<label asp-for="BrandColor" class="form-label"></label>
|
<label asp-for="BrandColor" class="form-label"></label>
|
||||||
<div class="input-group">
|
<div class="d-flex flex-wrap">
|
||||||
<input id="BrandColorInput" class="form-control form-control-color flex-grow-0" type="color" style="width:3rem" aria-describedby="BrandColorValue" value="@Model.BrandColor" />
|
<div class="form-group me-4">
|
||||||
<input asp-for="BrandColor" class="form-control form-control-color flex-grow-0 font-monospace" pattern="@ColorPalette.Pattern" style="width:5.5rem;font-size:0.9rem" />
|
<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;font-size:0.9rem" />
|
||||||
|
</div>
|
||||||
|
<span asp-validation-for="BrandColor" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group d-flex align-items-center">
|
||||||
|
<input asp-for="ApplyBrandColorToBackend" type="checkbox" class="btcpay-toggle me-3" disabled="@(string.IsNullOrEmpty(Model.BrandColor))"/>
|
||||||
|
<label asp-for="ApplyBrandColorToBackend" class="form-check-label"></label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span asp-validation-for="BrandColor" class="text-danger"></span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="d-flex align-items-center justify-content-between gap-2">
|
<div class="d-flex align-items-center justify-content-between gap-2">
|
||||||
<label asp-for="LogoFile" class="form-label"></label>
|
<label asp-for="LogoFile" class="form-label"></label>
|
||||||
@@ -94,9 +108,6 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<span asp-validation-for="LogoFile" class="text-danger"></span>
|
<span asp-validation-for="LogoFile" class="text-danger"></span>
|
||||||
<div class="form-text">
|
|
||||||
Use this CSS to customize the public/customer-facing pages of this store. (Invoice, Payment Request, Pull Payment, etc.)
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -193,13 +204,17 @@
|
|||||||
(() => {
|
(() => {
|
||||||
const $colorValue = document.getElementById('BrandColor');
|
const $colorValue = document.getElementById('BrandColor');
|
||||||
const $colorInput = document.getElementById('BrandColorInput');
|
const $colorInput = document.getElementById('BrandColorInput');
|
||||||
|
const $applyToBackend = document.getElementById('ApplyBrandColorToBackend');
|
||||||
delegate('change', '#BrandColor', e => {
|
delegate('change', '#BrandColor', e => {
|
||||||
const value = e.target.value;
|
const value = e.target.value;
|
||||||
if (value.match(@Safe.Json(@ColorPalette.Pattern)))
|
if (value.match(@Safe.Json(ColorPalette.Pattern)))
|
||||||
$colorInput.value = value;
|
$colorInput.value = value;
|
||||||
|
$applyToBackend.disabled = !value;
|
||||||
});
|
});
|
||||||
delegate('change', '#BrandColorInput', e => {
|
delegate('change', '#BrandColorInput', e => {
|
||||||
$colorValue.value = e.target.value;
|
const value = e.target.value;
|
||||||
|
$colorValue.value = value;
|
||||||
|
$applyToBackend.disabled = !value;
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -12840,7 +12840,7 @@ input[type='number'].hide-number-spin {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btcpay-toggle:hover {
|
.btcpay-toggle:not(:disabled):hover {
|
||||||
background: var(--btcpay-toggle-bg-hover);
|
background: var(--btcpay-toggle-bg-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12855,8 +12855,8 @@ input.btcpay-toggle:checked,
|
|||||||
background: var(--btcpay-toggle-bg-active);
|
background: var(--btcpay-toggle-bg-active);
|
||||||
}
|
}
|
||||||
|
|
||||||
input.btcpay-toggle:checked:hover,
|
input.btcpay-toggle:not(:disabled):checked:hover,
|
||||||
.btcpay-toggle.btcpay-toggle--active:hover {
|
.btcpay-toggle.btcpay-toggle--active:not(:disabled):hover {
|
||||||
background: var(--btcpay-toggle-bg-active-hover);
|
background: var(--btcpay-toggle-bg-active-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Variables */
|
/* Variables */
|
||||||
:root {
|
:root {
|
||||||
--chart-main-rgb: 68, 164, 49;
|
--chart-main-rgb: var(--btcpay-primary-rgb);
|
||||||
--chart-series-a-rgb: var(--chart-main-rgb);
|
--chart-series-a-rgb: var(--chart-main-rgb);
|
||||||
--chart-series-b-rgb: 245, 0, 0;
|
--chart-series-b-rgb: 245, 0, 0;
|
||||||
--chart-series-c-rgb: 0, 109, 242;
|
--chart-series-c-rgb: 0, 109, 242;
|
||||||
@@ -186,8 +186,8 @@ h2 .icon.icon-info {
|
|||||||
top: -.0125em;
|
top: -.0125em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#descriptor p {
|
#mainContent section p {
|
||||||
max-width: 40em;
|
max-width: 46em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invoices */
|
/* Invoices */
|
||||||
|
|||||||
@@ -239,9 +239,9 @@
|
|||||||
--btcpay-form-shadow-invalid: var(--btcpay-danger-shadow);
|
--btcpay-form-shadow-invalid: var(--btcpay-danger-shadow);
|
||||||
|
|
||||||
--btcpay-toggle-bg: var(--btcpay-neutral-500);
|
--btcpay-toggle-bg: var(--btcpay-neutral-500);
|
||||||
--btcpay-toggle-bg-hover: var(--btcpay-neutral-600);
|
--btcpay-toggle-bg-hover: var(--btcpay-primary-bg-hover);
|
||||||
--btcpay-toggle-bg-active: var(--btcpay-primary);
|
--btcpay-toggle-bg-active: var(--btcpay-primary);
|
||||||
--btcpay-toggle-bg-active-hover: var(--btcpay-primary-600);
|
--btcpay-toggle-bg-active-hover: var(--btcpay-primary-bg-active);
|
||||||
|
|
||||||
--btcpay-footer-bg: var(--btcpay-body-bg);
|
--btcpay-footer-bg: var(--btcpay-body-bg);
|
||||||
--btcpay-footer-text: var(--btcpay-body-text-muted);
|
--btcpay-footer-text: var(--btcpay-body-text-muted);
|
||||||
|
|||||||
@@ -509,6 +509,11 @@
|
|||||||
"nullable": true,
|
"nullable": true,
|
||||||
"example": "#F7931A"
|
"example": "#F7931A"
|
||||||
},
|
},
|
||||||
|
"applyBrandColorToBackend": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Apply the brand color to the store's backend as well"
|
||||||
|
},
|
||||||
"defaultCurrency": {
|
"defaultCurrency": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The default currency of the store",
|
"description": "The default currency of the store",
|
||||||
|
|||||||
Reference in New Issue
Block a user