Store branding: Unify public pages (#4568)

Closes #3842.
This commit is contained in:
d11n 2023-01-30 09:23:49 +01:00 committed by GitHub
parent 14313291d5
commit f821e35cb0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 611 additions and 646 deletions

View file

@ -180,14 +180,25 @@ namespace BTCPayServer.Controllers
[AllowAnonymous] [AllowAnonymous]
public async Task<IActionResult> ViewPaymentRequest(string payReqId) public async Task<IActionResult> ViewPaymentRequest(string payReqId)
{ {
var result = await _PaymentRequestService.GetPaymentRequest(payReqId, GetUserId()); var vm = await _PaymentRequestService.GetPaymentRequest(payReqId, GetUserId());
if (result == null) if (vm == null)
{
return NotFound();
}
var store = await _storeRepository.FindStore(vm.StoreId);
if (store == null)
{ {
return NotFound(); return NotFound();
} }
result.HubPath = PaymentRequestHub.GetHubPath(Request); var storeBlob = store.GetStoreBlob();
return View(result); vm.StoreName = store.StoreName;
vm.BrandColor = storeBlob.BrandColor;
vm.LogoFileId = storeBlob.LogoFileId;
vm.CssFileId = storeBlob.CssFileId;
vm.HubPath = PaymentRequestHub.GetHubPath(Request);
return View(vm);
} }
[HttpGet("{payReqId}/form")] [HttpGet("{payReqId}/form")]

View file

@ -15,6 +15,7 @@ using BTCPayServer.Models.WalletViewModels;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Rates; using BTCPayServer.Services.Rates;
using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -29,18 +30,21 @@ namespace BTCPayServer.Controllers
private readonly PullPaymentHostedService _pullPaymentHostedService; private readonly PullPaymentHostedService _pullPaymentHostedService;
private readonly BTCPayNetworkJsonSerializerSettings _serializerSettings; private readonly BTCPayNetworkJsonSerializerSettings _serializerSettings;
private readonly IEnumerable<IPayoutHandler> _payoutHandlers; private readonly IEnumerable<IPayoutHandler> _payoutHandlers;
private readonly StoreRepository _storeRepository;
public UIPullPaymentController(ApplicationDbContextFactory dbContextFactory, public UIPullPaymentController(ApplicationDbContextFactory dbContextFactory,
CurrencyNameTable currencyNameTable, CurrencyNameTable currencyNameTable,
PullPaymentHostedService pullPaymentHostedService, PullPaymentHostedService pullPaymentHostedService,
BTCPayNetworkJsonSerializerSettings serializerSettings, BTCPayNetworkJsonSerializerSettings serializerSettings,
IEnumerable<IPayoutHandler> payoutHandlers) IEnumerable<IPayoutHandler> payoutHandlers,
StoreRepository storeRepository)
{ {
_dbContextFactory = dbContextFactory; _dbContextFactory = dbContextFactory;
_currencyNameTable = currencyNameTable; _currencyNameTable = currencyNameTable;
_pullPaymentHostedService = pullPaymentHostedService; _pullPaymentHostedService = pullPaymentHostedService;
_serializerSettings = serializerSettings; _serializerSettings = serializerSettings;
_payoutHandlers = payoutHandlers; _payoutHandlers = payoutHandlers;
_storeRepository = storeRepository;
} }
[AllowAnonymous] [AllowAnonymous]
@ -53,6 +57,11 @@ namespace BTCPayServer.Controllers
return NotFound(); return NotFound();
var blob = pp.GetBlob(); var blob = pp.GetBlob();
var store = await _storeRepository.FindStore(pp.StoreId);
if (store is null)
return NotFound();
var storeBlob = store.GetStoreBlob();
var payouts = (await ctx.Payouts.GetPayoutInPeriod(pp) var payouts = (await ctx.Payouts.GetPayoutInPeriod(pp)
.OrderByDescending(o => o.Date) .OrderByDescending(o => o.Date)
.ToListAsync()) .ToListAsync())
@ -68,6 +77,8 @@ namespace BTCPayServer.Controllers
ViewPullPaymentModel vm = new(pp, DateTimeOffset.UtcNow) ViewPullPaymentModel vm = new(pp, DateTimeOffset.UtcNow)
{ {
BrandColor = storeBlob.BrandColor,
CssFileId = storeBlob.CssFileId,
AmountFormatted = _currencyNameTable.FormatCurrency(blob.Limit, blob.Currency), AmountFormatted = _currencyNameTable.FormatCurrency(blob.Limit, blob.Currency),
AmountCollected = totalPaid, AmountCollected = totalPaid,
AmountCollectedFormatted = _currencyNameTable.FormatCurrency(totalPaid, blob.Currency), AmountCollectedFormatted = _currencyNameTable.FormatCurrency(totalPaid, blob.Currency),

View file

@ -140,6 +140,10 @@ namespace BTCPayServer.Models.PaymentRequestViewModels
public DateTime? ExpiryDate { get; set; } public DateTime? ExpiryDate { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string LogoFileId { get; set; }
public string CssFileId { get; set; }
public string BrandColor { get; set; }
public string StoreName { get; set; }
public string EmbeddedCSS { get; set; } public string EmbeddedCSS { get; set; }
public string CustomCSSLink { get; set; } public string CustomCSSLink { get; set; }

View file

@ -89,6 +89,8 @@ namespace BTCPayServer.Models
public DateTime? ExpiryDate { get; set; } public DateTime? ExpiryDate { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string BrandColor { get; set; }
public string CssFileId { get; set; }
public string EmbeddedCSS { get; set; } public string EmbeddedCSS { get; set; }
public string CustomCSSLink { get; set; } public string CustomCSSLink { get; set; }
public List<PayoutLine> Payouts { get; set; } = new(); public List<PayoutLine> Payouts { get; set; } = new();

View file

@ -93,7 +93,6 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
[RateLimitsFilter(ZoneLimits.PublicInvoices, Scope = RateLimitsScope.RemoteAddress)] [RateLimitsFilter(ZoneLimits.PublicInvoices, Scope = RateLimitsScope.RemoteAddress)]
public async Task<IActionResult> ContributeToCrowdfund(string appId, ContributeToCrowdfund request, CancellationToken cancellationToken) public async Task<IActionResult> ContributeToCrowdfund(string appId, ContributeToCrowdfund request, CancellationToken cancellationToken)
{ {
var app = await _appService.GetApp(appId, AppType.Crowdfund, true); var app = await _appService.GetApp(appId, AppType.Crowdfund, true);
if (app == null) if (app == null)

View file

@ -17,6 +17,10 @@ namespace BTCPayServer.Plugins.Crowdfund.Models
public string Title { get; set; } public string Title { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string MainImageUrl { get; set; } public string MainImageUrl { get; set; }
public string CssFileId { get; set; }
public string LogoFileId { get; set; }
public string StoreName { get; set; }
public string BrandColor { get; set; }
public string EmbeddedCSS { get; set; } public string EmbeddedCSS { get; set; }
public string CustomCSSLink { get; set; } public string CustomCSSLink { get; set; }
public DateTime? StartDate { get; set; } public DateTime? StartDate { get; set; }

View file

@ -78,6 +78,10 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
return View($"PointOfSale/Public/{viewType}", new ViewPointOfSaleViewModel return View($"PointOfSale/Public/{viewType}", new ViewPointOfSaleViewModel
{ {
Title = settings.Title, Title = settings.Title,
StoreName = store.StoreName,
BrandColor = storeBlob.BrandColor,
CssFileId = storeBlob.CssFileId,
LogoFileId = storeBlob.LogoFileId,
Step = step.ToString(CultureInfo.InvariantCulture), Step = step.ToString(CultureInfo.InvariantCulture),
ViewType = (PosViewType)viewType, ViewType = (PosViewType)viewType,
ShowCustomAmount = settings.ShowCustomAmount, ShowCustomAmount = settings.ShowCustomAmount,

View file

@ -41,8 +41,11 @@ namespace BTCPayServer.Plugins.PointOfSale.Models
public bool SymbolSpace { get; set; } public bool SymbolSpace { get; set; }
} }
public string LogoFileId { get; set; }
public string CssFileId { get; set; }
public string BrandColor { get; set; }
public string StoreName { get; set; }
public CurrencyInfoData CurrencyInfo { get; set; } public CurrencyInfoData CurrencyInfo { get; set; }
public PosViewType ViewType { get; set; } public PosViewType ViewType { get; set; }
public bool ShowCustomAmount { get; set; } public bool ShowCustomAmount { get; set; }
public bool ShowDiscount { get; set; } public bool ShowDiscount { get; set; }

View file

@ -134,6 +134,9 @@ namespace BTCPayServer.Services.Apps
perks = newPerksOrder.ToArray(); perks = newPerksOrder.ToArray();
} }
var store = appData.StoreData;
var storeBlob = store.GetStoreBlob();
return new ViewCrowdfundViewModel return new ViewCrowdfundViewModel
{ {
Title = settings.Title, Title = settings.Title,
@ -142,6 +145,10 @@ namespace BTCPayServer.Services.Apps
CustomCSSLink = settings.CustomCSSLink, CustomCSSLink = settings.CustomCSSLink,
MainImageUrl = settings.MainImageUrl, MainImageUrl = settings.MainImageUrl,
EmbeddedCSS = settings.EmbeddedCSS, EmbeddedCSS = settings.EmbeddedCSS,
StoreName = store.StoreName,
CssFileId = storeBlob.CssFileId,
LogoFileId = storeBlob.LogoFileId,
BrandColor = storeBlob.BrandColor,
StoreId = appData.StoreDataId, StoreId = appData.StoreDataId,
AppId = appData.Id, AppId = appData.Id,
StartDate = settings.StartDate?.ToUniversalTime(), StartDate = settings.StartDate?.ToUniversalTime(),

View file

@ -1,16 +1,15 @@
@model BTCPayServer.Plugins.Crowdfund.Models.ViewCrowdfundViewModel @model BTCPayServer.Plugins.Crowdfund.Models.ViewCrowdfundViewModel
@using BTCPayServer.Plugins.Crowdfund.Models @using BTCPayServer.Plugins.Crowdfund.Models
@inject BTCPayServer.Services.ThemeSettings Theme @inject BTCPayServer.Services.BTCPayServerEnvironment Env
@{ @{
ViewData["Title"] = Model.Title; ViewData["Title"] = Model.Title;
Layout = null; Layout = null;
} }
<!DOCTYPE html> <!DOCTYPE html>
<html class="h-100"> <html class="h-100" @(Env.IsDeveloping ? " data-devenv" : "")>
<head> <head>
<partial name="LayoutHead"/> <partial name="LayoutHead"/>
<link href="~/vendor/font-awesome/css/font-awesome.min.css" asp-append-version="true" rel="stylesheet" /> <partial name="LayoutHeadStoreBranding" model="@(Model.BrandColor, Model.CssFileId, Model.CustomCSSLink, Model.EmbeddedCSS)" />
<link href="~/vendor/bootstrap-vue/bootstrap-vue.css" asp-append-version="true" rel="stylesheet" /> <link href="~/vendor/bootstrap-vue/bootstrap-vue.css" asp-append-version="true" rel="stylesheet" />
<link href="~/crowdfund/styles/main.css" asp-append-version="true" rel="stylesheet" /> <link href="~/crowdfund/styles/main.css" asp-append-version="true" rel="stylesheet" />
@ -25,7 +24,7 @@
<vc:ui-extension-point location="crowdfund-head" model="@Model"></vc:ui-extension-point> <vc:ui-extension-point location="crowdfund-head" model="@Model"></vc:ui-extension-point>
</head> </head>
<body> <body class="min-vh-100">
@if (!Model.Enabled) @if (!Model.Enabled)
{ {
<div class="alert alert-warning text-center sticky-top mb-0 rounded-0" role="alert"> <div class="alert alert-warning text-center sticky-top mb-0 rounded-0" role="alert">
@ -36,7 +35,8 @@
{ {
<canvas id="fireworks" class="d-none"></canvas> <canvas id="fireworks" class="d-none"></canvas>
} }
<div class="container px-0 py-3" id="app" @(Model.SimpleDisplay ? "" : "v-cloak")>
<div class="public-page-wrap flex-column container" id="app" @(Model.SimpleDisplay ? "" : "v-cloak")>
<div class="row h-100 w-100 py-sm-0 py-md-4 mx-0"> <div class="row h-100 w-100 py-sm-0 py-md-4 mx-0">
<div class="card w-100 p-0 mx-0"> <div class="card w-100 p-0 mx-0">
@if (!string.IsNullOrEmpty(Model.MainImageUrl)) @if (!string.IsNullOrEmpty(Model.MainImageUrl))
@ -264,10 +264,6 @@
</div> </div>
<div class="card-footer text-muted d-flex flex-wrap align-items-center"> <div class="card-footer text-muted d-flex flex-wrap align-items-center">
<div class="me-3" v-text="`Updated ${lastUpdated}`">Updated @Model.Info.LastUpdated</div> <div class="me-3" v-text="`Updated ${lastUpdated}`">Updated @Model.Info.LastUpdated</div>
@if (!Theme.CustomTheme)
{
<vc:theme-switch css-class="text-muted me-3" />
}
<div class="form-check me-3 my-0 only-for-js" v-if="srvModel.animationsEnabled || animation"> <div class="form-check me-3 my-0 only-for-js" v-if="srvModel.animationsEnabled || animation">
<input class="form-check-input" type="checkbox" id="cbAnime" v-model="animation"> <input class="form-check-input" type="checkbox" id="cbAnime" v-model="animation">
<label class="form-check-label" for="cbAnime">Animations</label> <label class="form-check-label" for="cbAnime">Animations</label>
@ -288,6 +284,12 @@
:in-modal="true"> :in-modal="true">
</contribute> </contribute>
</b-modal> </b-modal>
<footer class="store-footer">
<a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
Powered by <partial name="_StoreFooterLogo" />
</a>
</footer>
</div> </div>
<template id="perks-template"> <template id="perks-template">

View file

@ -1,4 +1,4 @@
@model (string BrandColor, string CssFileId) @model (string BrandColor, string CssFileId, string CustomCSSLink, string EmbeddedCSS)
@using BTCPayServer.Abstractions.Extensions @using BTCPayServer.Abstractions.Extensions
@using Microsoft.AspNetCore.Mvc.TagHelpers @using Microsoft.AspNetCore.Mvc.TagHelpers
@using BTCPayServer.Abstractions.Contracts @using BTCPayServer.Abstractions.Contracts
@ -24,3 +24,12 @@
{ {
<link href="@cssUrl" asp-append-version="true" rel="stylesheet" /> <link href="@cssUrl" asp-append-version="true" rel="stylesheet" />
} }
@* Deprecated, but added for backwards-compatibility *@
@if (!string.IsNullOrEmpty(Model.CustomCSSLink))
{
<link href="@Model.CustomCSSLink" asp-append-version="true" rel="stylesheet" />
}
@if (!string.IsNullOrEmpty(Model.EmbeddedCSS))
{
@Safe.Raw(Model.EmbeddedCSS)
}

View file

@ -1,7 +1,7 @@
@using BTCPayServer.Plugins.PointOfSale.Models @using BTCPayServer.Plugins.PointOfSale.Models
@model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel @model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel
@{ @{
Layout = "PointOfSale/Public/_LayoutPos"; Layout = "PointOfSale/Public/_Layout";
var customTipPercentages = Model.CustomTipPercentages; var customTipPercentages = Model.CustomTipPercentages;
var anyInventoryItems = Model.Items.Any(item => item.Inventory.HasValue); var anyInventoryItems = Model.Items.Any(item => item.Inventory.HasValue);
} }
@ -189,35 +189,28 @@
<!-- Page Content --> <!-- Page Content -->
<div id="content"> <div id="content">
<div class="p-2 p-sm-4"> <div class="p-2 p-sm-4">
<div class="row">
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<div class="d-flex gap-3 mb-4">
<div class="col-sm-4 col-lg-2 order-sm-last text-end mb-2"> <div class="flex-fill position-relative">
<a class="js-cart btn btn-lg btn-outline-primary" href="#"> <input type="text" class="js-search form-control form-control-lg" placeholder="Find product">
<a class="js-search-reset btn btn-lg btn-link text-black" href="#">
<i class="fa fa-times-circle fa-lg"></i>
</a>
</div>
<a class="js-cart btn btn-lg btn-outline-primary text-nowrap" href="#">
<i class="fa fa-shopping-basket"></i>&nbsp; <i class="fa fa-shopping-basket"></i>&nbsp;
<span class="badge bg-light rounded-pill"> <span class="badge bg-light rounded-pill">
<span id="js-cart-items">0</span> <span id="js-cart-items">0</span>
</span> </span>
</a> </a>
</div> </div>
<div class="col-sm-8 col-lg-10 mb-2">
<div class="mb-2 position-relative">
<input type="text" class="js-search form-control form-control-lg" placeholder="Find product">
<a class="js-search-reset btn btn-lg btn-link text-black" href="#">
<i class="fa fa-times-circle fa-lg"></i>
</a>
</div>
</div>
</div>
@if (!string.IsNullOrEmpty(Model.Description)) @if (!string.IsNullOrEmpty(Model.Description))
{ {
<div class="row"> <div class="lead text-center mt-3">@Safe.Raw(Model.Description)</div>
<div class="overflow-hidden col-12">@Safe.Raw(Model.Description)</div>
</div>
} }
</div> </div>
<div id="js-pos-list" class="text-center mx-auto px-4"> <div id="js-pos-list" class="text-center mx-auto px-2 px-sm-4 py-4 py-sm-2">
<div class="card-deck my-3"> <div class="card-deck">
@for (var index = 0; index < Model.Items.Length; index++) @for (var index = 0; index < Model.Items.Length; index++)
{ {
var item = Model.Items[index]; var item = Model.Items[index];
@ -275,8 +268,8 @@
<!-- Sidebar --> <!-- Sidebar -->
<nav id="sidebar"> <nav id="sidebar">
<div class="bg-primary p-3 clearfix"> <div class="d-flex align-items-center pt-4 p-2">
<h3 class="text-white m-0 pull-left">Cart</h3> <h3 class="text-white m-0 me-auto">Cart</h3>
<a class="js-cart btn btn-sm bg-white text-black pull-right ms-5" href="#"> <a class="js-cart btn btn-sm bg-white text-black pull-right ms-5" href="#">
<i class="fa fa-times fa-lg"></i> <i class="fa fa-times fa-lg"></i>
</a> </a>
@ -302,12 +295,14 @@
<thead></thead> <thead></thead>
</table> </table>
<button id="js-cart-confirm" data-bs-toggle="modal" data-bs-target="#cartModal" class="btn btn-primary btn-lg w-100 mb-3 p-3" disabled="disabled" type="submit"> <button id="js-cart-confirm" data-bs-toggle="modal" data-bs-target="#cartModal" class="btn btn-primary btn-lg mx-2 mb-3 p-3" disabled="disabled" type="submit">
<b>Confirm</b> Confirm
</button> </button>
<div class="text-center mb-5 pb-5"> <footer class="store-footer">
<svg class="logo" viewBox="0 0 192 84" xmlns="http://www.w3.org/2000/svg"><g><path d="M5.206 83.433a4.86 4.86 0 01-4.859-4.861V5.431a4.86 4.86 0 119.719 0v73.141a4.861 4.861 0 01-4.86 4.861" fill="#CEDC21" class="logo-brand-light"/><path d="M5.209 83.433a4.862 4.862 0 01-2.086-9.253L32.43 60.274 2.323 38.093a4.861 4.861 0 015.766-7.826l36.647 26.999a4.864 4.864 0 01-.799 8.306L7.289 82.964a4.866 4.866 0 01-2.08.469" fill="#51B13E" class="logo-brand-medium"/><path d="M5.211 54.684a4.86 4.86 0 01-2.887-8.774L32.43 23.73 3.123 9.821a4.861 4.861 0 014.166-8.784l36.648 17.394a4.86 4.86 0 01.799 8.305l-36.647 27a4.844 4.844 0 01-2.878.948" fill="#CEDC21" class="logo-brand-light"/><path d="M10.066 31.725v20.553L24.01 42.006z" fill="#1E7A44" class="logo-brand-dark"/><path d="M10.066 5.431A4.861 4.861 0 005.206.57 4.86 4.86 0 00.347 5.431v61.165h9.72V5.431h-.001z" fill="#CEDC21" class="logo-brand-light"/><path d="M74.355 41.412c3.114.884 4.84 3.704 4.84 7.238 0 5.513-3.368 8.082-7.955 8.082H60.761V27.271h9.259c4.504 0 7.997 2.146 7.997 7.743 0 2.821-1.179 5.43-3.662 6.398m-4.293-.716c3.324 0 6.018-1.179 6.018-5.724 0-4.586-2.776-5.808-6.145-5.808h-7.197v11.531h7.324v.001zm1.052 14.099c3.366 0 6.06-1.768 6.06-6.145 0-4.713-3.072-6.144-6.901-6.144h-7.534v12.288h8.375v.001zM98.893 27.271v1.81h-8.122v27.651h-1.979V29.081h-8.123v-1.81zM112.738 26.85c5.01 0 9.554 2.524 10.987 8.543h-1.895c-1.348-4.923-5.303-6.732-9.134-6.732-6.944 0-10.605 5.681-10.605 13.341 0 8.08 3.661 13.256 10.646 13.256 4.125 0 7.828-1.85 9.26-7.279h1.895c-1.264 6.271-6.229 9.174-11.154 9.174-7.87 0-12.583-5.808-12.583-15.15 0-8.966 4.969-15.153 12.583-15.153M138.709 27.271c5.091 0 8.795 3.326 8.795 9.764 0 6.06-3.704 9.722-8.795 9.722h-7.746v9.976h-1.935V27.271h9.681zm0 17.549c3.745 0 6.816-2.397 6.816-7.827 0-5.429-2.947-7.869-6.816-7.869h-7.746V44.82h7.746zM147.841 56.732v-.255l11.741-29.29h.885l11.615 29.29v.255h-2.062l-3.322-8.501H153.27l-3.324 8.501h-2.105zm12.164-26.052l-6.059 15.697h12.078l-6.019-15.697zM189.551 27.271h2.104v.293l-9.176 16.92v12.248h-2.02V44.484l-9.216-16.961v-.252h2.147l3.997 7.492 4.043 7.786h.04l4.081-7.786z" class="logo-brand-text"/></g></svg> <a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
</div> Powered by <partial name="_StoreFooterLogo" />
</a>
</footer>
</nav> </nav>
</div> </div>

View file

@ -1,9 +1,11 @@
@model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel @model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel
@{ @{
Layout = "PointOfSale/Public/_LayoutPos"; Layout = "PointOfSale/Public/_Layout";
} }
<div class="public-page-wrap flex-column">
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<partial name="_StoreHeader" model="(string.IsNullOrEmpty(Model.Title) ? Model.StoreName : Model.Title, Model.LogoFileId)" />
@if (Context.Request.Query.ContainsKey("simple")) @if (Context.Request.Query.ContainsKey("simple"))
{ {
@ -16,3 +18,9 @@ else
</noscript> </noscript>
<partial name="PointOfSale/Public/VueLight" model="Model" /> <partial name="PointOfSale/Public/VueLight" model="Model" />
} }
<footer class="store-footer">
<a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
Powered by <partial name="_StoreFooterLogo" />
</a>
</footer>
</div>

View file

@ -1,11 +1,4 @@
<div class="container p-0 l-pos-wrapper"> <div class="container p-0 l-pos-wrapper my-0 mx-auto">
<div class="l-pos-header bg-primary py-3 px-3">
@if (!string.IsNullOrEmpty(Model.CustomLogoLink)) {
<img src="@Model.CustomLogoLink" height="40" asp-append-version="true">
} else {
<h1 class="mb-0">@Model.Title</h1>
}
</div>
<div class="py-5 px-3"> <div class="py-5 px-3">
<form method="post" asp-action="ViewPointOfSale" asp-route-appId="@Model.AppId" asp-antiforgery="false" data-buy> <form method="post" asp-action="ViewPointOfSale" asp-route-appId="@Model.AppId" asp-antiforgery="false" data-buy>
<div class="input-group"> <div class="input-group">
@ -14,9 +7,5 @@
<button class="btn btn-primary" type="submit">Pay</button> <button class="btn btn-primary" type="submit">Pay</button>
</div> </div>
</form> </form>
<div class="text-center mt-5 mb-3 py-2">
<svg class="logo" viewBox="0 0 192 84" xmlns="http://www.w3.org/2000/svg"><g><path d="M5.206 83.433a4.86 4.86 0 01-4.859-4.861V5.431a4.86 4.86 0 119.719 0v73.141a4.861 4.861 0 01-4.86 4.861" fill="#CEDC21" class="logo-brand-light"/><path d="M5.209 83.433a4.862 4.862 0 01-2.086-9.253L32.43 60.274 2.323 38.093a4.861 4.861 0 015.766-7.826l36.647 26.999a4.864 4.864 0 01-.799 8.306L7.289 82.964a4.866 4.866 0 01-2.08.469" fill="#51B13E" class="logo-brand-medium"/><path d="M5.211 54.684a4.86 4.86 0 01-2.887-8.774L32.43 23.73 3.123 9.821a4.861 4.861 0 014.166-8.784l36.648 17.394a4.86 4.86 0 01.799 8.305l-36.647 27a4.844 4.844 0 01-2.878.948" fill="#CEDC21" class="logo-brand-light"/><path d="M10.066 31.725v20.553L24.01 42.006z" fill="#1E7A44" class="logo-brand-dark"/><path d="M10.066 5.431A4.861 4.861 0 005.206.57 4.86 4.86 0 00.347 5.431v61.165h9.72V5.431h-.001z" fill="#CEDC21" class="logo-brand-light"/><path d="M74.355 41.412c3.114.884 4.84 3.704 4.84 7.238 0 5.513-3.368 8.082-7.955 8.082H60.761V27.271h9.259c4.504 0 7.997 2.146 7.997 7.743 0 2.821-1.179 5.43-3.662 6.398m-4.293-.716c3.324 0 6.018-1.179 6.018-5.724 0-4.586-2.776-5.808-6.145-5.808h-7.197v11.531h7.324v.001zm1.052 14.099c3.366 0 6.06-1.768 6.06-6.145 0-4.713-3.072-6.144-6.901-6.144h-7.534v12.288h8.375v.001zM98.893 27.271v1.81h-8.122v27.651h-1.979V29.081h-8.123v-1.81zM112.738 26.85c5.01 0 9.554 2.524 10.987 8.543h-1.895c-1.348-4.923-5.303-6.732-9.134-6.732-6.944 0-10.605 5.681-10.605 13.341 0 8.08 3.661 13.256 10.646 13.256 4.125 0 7.828-1.85 9.26-7.279h1.895c-1.264 6.271-6.229 9.174-11.154 9.174-7.87 0-12.583-5.808-12.583-15.15 0-8.966 4.969-15.153 12.583-15.153M138.709 27.271c5.091 0 8.795 3.326 8.795 9.764 0 6.06-3.704 9.722-8.795 9.722h-7.746v9.976h-1.935V27.271h9.681zm0 17.549c3.745 0 6.816-2.397 6.816-7.827 0-5.429-2.947-7.869-6.816-7.869h-7.746V44.82h7.746zM147.841 56.732v-.255l11.741-29.29h.885l11.615 29.29v.255h-2.062l-3.322-8.501H153.27l-3.324 8.501h-2.105zm12.164-26.052l-6.059 15.697h12.078l-6.019-15.697zM189.551 27.271h2.104v.293l-9.176 16.92v12.248h-2.02V44.484l-9.216-16.961v-.252h2.147l3.997 7.492 4.043 7.786h.04l4.081-7.786z" class="logo-brand-text"/></g></svg>
</div>
</div> </div>
</div> </div>

View file

@ -14,12 +14,10 @@
margin-bottom: 0; margin-bottom: 0;
} }
} }
.card { display: inline-block; width: 300px; page-break-inside: avoid; margin: 2em 1em 0 1em; }
</style> </style>
@{ @{
var store = await StoreRepository.FindStore(Model.StoreId); var store = await StoreRepository.FindStore(Model.StoreId);
Layout = "PointOfSale/Public/_LayoutPos"; Layout = "PointOfSale/Public/_Layout";
Context.Request.Query.TryGetValue("cryptocode", out var cryptoCodeValues); Context.Request.Query.TryGetValue("cryptocode", out var cryptoCodeValues);
var cryptoCode = cryptoCodeValues.FirstOrDefault() ?? "BTC"; var cryptoCode = cryptoCodeValues.FirstOrDefault() ?? "BTC";
var supported = store.GetSupportedPaymentMethods(BTCPayNetworkProvider).OfType<LNURLPaySupportedPaymentMethod>().OrderBy(method => method.CryptoCode == cryptoCode).FirstOrDefault(); var supported = store.GetSupportedPaymentMethods(BTCPayNetworkProvider).OfType<LNURLPaySupportedPaymentMethod>().OrderBy(method => method.CryptoCode == cryptoCode).FirstOrDefault();
@ -38,16 +36,25 @@
</a> </a>
</div> </div>
} }
<div class="container d-flex"> else
<div class="justify-content-center align-self-center text-center mx-auto px-2 py-5 w-100 m-auto">
<h1 class="mb-4">@Model.Title</h1>
@if (!string.IsNullOrEmpty(Model.Description))
{ {
<div class="row"> <div class="alert alert-info alert-dismissible d-flex align-items-center justify-content-center sticky-top mb-0 rounded-0 d-print-none fade show" role="alert">
<div class="overflow-hidden col-12">@Safe.Raw(Model.Description)</div> <button type="button" class="btn btn-info me-4 border border-light" onclick="window.print()">
<i class="fa fa-print"></i>&nbsp;Print
</button>
This view is intended for printing only —
<a asp-route-viewType="static" class="alert-link">Regular version</a>
</div> </div>
} }
<div class="container public-page-wrap flex-column">
<partial name="_StatusMessage" />
<partial name="_StoreHeader" model="(string.IsNullOrEmpty(Model.Title) ? Model.StoreName : Model.Title, Model.LogoFileId)" />
@if (!string.IsNullOrEmpty(Model.Description))
{
<div class="lead text-center">@Safe.Raw(Model.Description)</div>
}
<main class="flex-grow-1 justify-content-center align-self-center mx-auto py-3">
@if (supported is not null) @if (supported is not null)
{ {
if (Model.ShowCustomAmount) if (Model.ShowCustomAmount)
@ -67,17 +74,10 @@
} }
}).ToArray(); }).ToArray();
} }
<div class="alert alert-info alert-dismissible d-flex align-items-center justify-content-center sticky-top mb-0 rounded-0 d-print-none fade show" role="alert">
<button type="button" class="btn btn-info me-4 border border-light" onclick="window.print()">
<i class="fa fa-print"></i>&nbsp;Print
</button>
This view is intended for printing only —
<a asp-route-viewType="static" class="alert-link">Regular version</a>
</div>
} }
<div class="container text-center"> <div class="card-deck mx-auto">
@for (int x = 0; x < Model.Items.Length; x++) @for (var x = 0; x < Model.Items.Length; x++)
{ {
var item = Model.Items[x]; var item = Model.Items[x];
<div class="card" data-id="@x"> <div class="card" data-id="@x">
@ -115,12 +115,19 @@
ItemCode = item.Id ItemCode = item.Id
}, Context.Request.Scheme, Context.Request.Host.ToString())); }, Context.Request.Scheme, Context.Request.Host.ToString()));
var lnUrl = LNURL.EncodeUri(lnurlEndpoint, "payRequest", supported.UseBech32Scheme); var lnUrl = LNURL.EncodeUri(lnurlEndpoint, "payRequest", supported.UseBech32Scheme);
<a href="@lnUrl" rel="noreferrer noopener"><vc:qr-code data="@lnUrl.ToString().ToUpperInvariant()" /></a> <a href="@lnUrl" rel="noreferrer noopener" class="d-block mx-auto text-center">
<vc:qr-code data="@lnUrl.ToString().ToUpperInvariant()" />
</a>
} }
} }
</div> </div>
</div> </div>
} }
</div> </div>
</div> </main>
<footer class="store-footer">
<a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
Powered by <partial name="_StoreFooterLogo" />
</a>
</footer>
</div> </div>

View file

@ -1,22 +1,19 @@
@using BTCPayServer.Plugins.PointOfSale.Models @using BTCPayServer.Plugins.PointOfSale.Models
@model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel @model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel
@{ @{
Layout = "PointOfSale/Public/_LayoutPos"; Layout = "PointOfSale/Public/_Layout";
var anyInventoryItems = Model.Items.Any(item => item.Inventory.HasValue); var anyInventoryItems = Model.Items.Any(item => item.Inventory.HasValue);
} }
<div class="container d-flex h-100"> <div class="container public-page-wrap flex-column">
<div class="justify-content-center align-self-center text-center mx-auto px-2 py-3 w-100 m-auto">
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<partial name="_StoreHeader" model="(string.IsNullOrEmpty(Model.Title) ? Model.StoreName : Model.Title, Model.LogoFileId)" />
<h1 class="mb-4">@Model.Title</h1>
@if (!string.IsNullOrEmpty(Model.Description)) @if (!string.IsNullOrEmpty(Model.Description))
{ {
<div class="row"> <div class="lead text-center">@Safe.Raw(Model.Description)</div>
<div class="overflow-hidden col-12">@Safe.Raw(Model.Description)</div>
</div>
} }
<div class="card-deck my-3 mx-auto"> <main class="flex-grow-1 justify-content-center align-self-center text-center mx-auto py-3">
<div class="card-deck mx-auto">
@for (var x = 0; x < Model.Items.Length; x++) @for (var x = 0; x < Model.Items.Length; x++)
{ {
var item = Model.Items[x]; var item = Model.Items[x];
@ -85,7 +82,12 @@
</div> </div>
} }
</div> </div>
</div> </main>
<footer class="store-footer">
<a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
Powered by <partial name="_StoreFooterLogo" />
</a>
</footer>
</div> </div>
@functions { @functions {

View file

@ -1,18 +1,9 @@
@using Microsoft.AspNetCore.Mvc.TagHelpers
@model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel @model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel
<div id="app" class="l-pos-wrapper" v-cloak> <div id="app" class="l-pos-wrapper" v-cloak>
<form method="post" asp-action="ViewPointOfSale" asp-route-appId="@Model.AppId" asp-antiforgery="false" data-buy v-on:submit="handleFormSubmit"> <form method="post" asp-action="ViewPointOfSale" asp-route-appId="@Model.AppId" asp-antiforgery="false" data-buy v-on:submit="handleFormSubmit">
<div class="l-pos-header bg-primary py-3 px-3"> <div ref="display" class="l-pos-display pb-3 px-1"><div class="text-muted">{{srvModel.currencyCode}}</div><span ref="amount" v-bind:style="{fontSize: fontSize + 'px'}">{{ payTotal }}</span></div>
@if (!string.IsNullOrEmpty(Model.CustomLogoLink))
{
<img src="@Model.CustomLogoLink" height="40" asp-append-version="true" />
}
else
{
<h1 class="mb-0">@Model.Title</h1>
}
</div>
<div ref="display" class="l-pos-display pt-5 pb-3 px-3"><div class="text-muted">{{srvModel.currencyCode}}</div><span ref="amount" v-bind:style="{fontSize: fontSize + 'px'}">{{ payTotal }}</span></div>
<div class="l-pos-keypad"> <div class="l-pos-keypad">
<template <template
v-for="(key, index) in keys" v-for="(key, index) in keys"
@ -23,14 +14,13 @@
<div v-else class="btn btn-empty"></div> <div v-else class="btn btn-empty"></div>
</template> </template>
</div> </div>
<div class="d-flex align-items-center justify-content-center mt-4 gap-3">
<div class="l-pos-controls mt-2"> <div class="btn btn-outline-secondary btn-lg flex-fill" v-on:click="clearTotal">Clear</div>
<div class="btn btn-outline-secondary btn-lg mb-0" v-on:click="clearTotal">Clear</div> <button class="btn btn-primary btn-lg flex-fill" id="pay-button" type="submit" v-bind:disabled="payButtonLoading">
<button class="btn btn-primary btn-lg mb-0" id="pay-button" type="submit" v-bind:disabled="payButtonLoading">
<div v-if="payButtonLoading" class="spinner-border spinner-border-sm" id="pay-button-spinner" role="status"> <div v-if="payButtonLoading" class="spinner-border spinner-border-sm" id="pay-button-spinner" role="status">
<span class="sr-only">Loading...</span> <span class="sr-only">Loading...</span>
</div> </div>
<b>Pay</b> Pay
</button> </button>
</div> </div>
@ -81,14 +71,11 @@
v-on:click="removeTip" v-on:click="removeTip"
><i class="fa fa-times"></i></a> ><i class="fa fa-times"></i></a>
</div> </div>
<div class="row"> <div class="d-flex align-items-center justify-content-center mt-2 gap-3">
@if (Model.CustomTipPercentages != null && Model.CustomTipPercentages.Length > 0) @if (Model.CustomTipPercentages != null && Model.CustomTipPercentages.Length > 0)
{ {
@for (int i = 0; i < Model.CustomTipPercentages.Length; i++) @foreach (var percentage in Model.CustomTipPercentages)
{ {
var percentage = Model.CustomTipPercentages[i];
<div class="@(Model.CustomTipPercentages.Length > 3 ? "col-4" : "col")">
<button <button
class="js-cart-tip-btn btn btn-lg btn-light w-100 border mb-2" class="js-cart-tip-btn btn btn-lg btn-light w-100 border mb-2"
data-tip="@percentage" data-tip="@percentage"
@ -96,14 +83,8 @@
> >
@percentage% @percentage%
</button> </button>
</div>
} }
} }
</div> </div>
} }
<div class="text-center mt-4 mb-3 py-2">
<svg class="logo" viewBox="0 0 192 84" xmlns="http://www.w3.org/2000/svg"><g><path d="M5.206 83.433a4.86 4.86 0 01-4.859-4.861V5.431a4.86 4.86 0 119.719 0v73.141a4.861 4.861 0 01-4.86 4.861" fill="#CEDC21" class="logo-brand-light"/><path d="M5.209 83.433a4.862 4.862 0 01-2.086-9.253L32.43 60.274 2.323 38.093a4.861 4.861 0 015.766-7.826l36.647 26.999a4.864 4.864 0 01-.799 8.306L7.289 82.964a4.866 4.866 0 01-2.08.469" fill="#51B13E" class="logo-brand-medium"/><path d="M5.211 54.684a4.86 4.86 0 01-2.887-8.774L32.43 23.73 3.123 9.821a4.861 4.861 0 014.166-8.784l36.648 17.394a4.86 4.86 0 01.799 8.305l-36.647 27a4.844 4.844 0 01-2.878.948" fill="#CEDC21" class="logo-brand-light"/><path d="M10.066 31.725v20.553L24.01 42.006z" fill="#1E7A44" class="logo-brand-dark"/><path d="M10.066 5.431A4.861 4.861 0 005.206.57 4.86 4.86 0 00.347 5.431v61.165h9.72V5.431h-.001z" fill="#CEDC21" class="logo-brand-light"/><path d="M74.355 41.412c3.114.884 4.84 3.704 4.84 7.238 0 5.513-3.368 8.082-7.955 8.082H60.761V27.271h9.259c4.504 0 7.997 2.146 7.997 7.743 0 2.821-1.179 5.43-3.662 6.398m-4.293-.716c3.324 0 6.018-1.179 6.018-5.724 0-4.586-2.776-5.808-6.145-5.808h-7.197v11.531h7.324v.001zm1.052 14.099c3.366 0 6.06-1.768 6.06-6.145 0-4.713-3.072-6.144-6.901-6.144h-7.534v12.288h8.375v.001zM98.893 27.271v1.81h-8.122v27.651h-1.979V29.081h-8.123v-1.81zM112.738 26.85c5.01 0 9.554 2.524 10.987 8.543h-1.895c-1.348-4.923-5.303-6.732-9.134-6.732-6.944 0-10.605 5.681-10.605 13.341 0 8.08 3.661 13.256 10.646 13.256 4.125 0 7.828-1.85 9.26-7.279h1.895c-1.264 6.271-6.229 9.174-11.154 9.174-7.87 0-12.583-5.808-12.583-15.15 0-8.966 4.969-15.153 12.583-15.153M138.709 27.271c5.091 0 8.795 3.326 8.795 9.764 0 6.06-3.704 9.722-8.795 9.722h-7.746v9.976h-1.935V27.271h9.681zm0 17.549c3.745 0 6.816-2.397 6.816-7.827 0-5.429-2.947-7.869-6.816-7.869h-7.746V44.82h7.746zM147.841 56.732v-.255l11.741-29.29h.885l11.615 29.29v.255h-2.062l-3.322-8.501H153.27l-3.324 8.501h-2.105zm12.164-26.052l-6.059 15.697h12.078l-6.019-15.697zM189.551 27.271h2.104v.293l-9.176 16.92v12.248h-2.02V44.484l-9.216-16.961v-.252h2.147l3.997 7.492 4.043 7.786h.04l4.081-7.786z" class="logo-brand-text"/></g></svg>
</div> </div>
</div>

View file

@ -1,17 +1,15 @@
@inject BTCPayServer.Services.ThemeSettings Theme
@inject IWebHostEnvironment WebHostEnvironment
@using BTCPayServer.Services.Apps @using BTCPayServer.Services.Apps
@using BTCPayServer.Abstractions.Extensions @using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Abstractions.TagHelpers @using BTCPayServer.Abstractions.TagHelpers
@using Microsoft.AspNetCore.Hosting @using Microsoft.AspNetCore.Hosting
@using Microsoft.AspNetCore.Mvc.TagHelpers @using Microsoft.AspNetCore.Mvc.TagHelpers
@using Newtonsoft.Json
@using Newtonsoft.Json.Linq @using Newtonsoft.Json.Linq
@using System.IO @using System.IO
@inject IWebHostEnvironment WebHostEnvironment
@inject BTCPayServer.Services.BTCPayServerEnvironment Env
@model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel @model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel
@{ @{
ViewData["Title"] = Model.Title; ViewData["Title"] = string.IsNullOrEmpty(Model.Title) ? Model.StoreName : Model.Title;
Layout = null; Layout = null;
async Task<string> GetDynamicManifest(string title) async Task<string> GetDynamicManifest(string title)
@ -33,69 +31,53 @@
return $"data:application/manifest+json,{Safe.Json(jObject)}"; return $"data:application/manifest+json,{Safe.Json(jObject)}";
} }
} }
<!DOCTYPE html> <!DOCTYPE html>
<html class="h-100"> <html class="h-100" lang="en" @(Env.IsDeveloping ? " data-devenv" : "")>
<head> <head>
<title>@Model.Title</title> <partial name="LayoutHead"/>
<meta charset="utf-8" /> <partial name="LayoutHeadStoreBranding" model="@(Model.BrandColor, Model.CssFileId, Model.CustomCSSLink, Model.EmbeddedCSS)" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<link rel="apple-touch-icon" href="~/img/icons/icon-512x512.png"> <link rel="apple-touch-icon" href="~/img/icons/icon-512x512.png">
<link rel="apple-touch-startup-image" href="~/img/splash.png"> <link rel="apple-touch-startup-image" href="~/img/splash.png">
<link rel="manifest" href="@(await GetDynamicManifest(Model.Title))"> <link rel="manifest" href="@(await GetDynamicManifest(ViewData["Title"]!.ToString()))">
<link href="~/main/bootstrap/bootstrap.css" asp-append-version="true" rel="stylesheet" />
<link href="~/vendor/font-awesome/css/font-awesome.css" asp-append-version="true" rel="stylesheet" />
<link href="~/vendor/flatpickr/flatpickr.css" asp-append-version="true" rel="stylesheet" />
<link href="~/main/fonts/OpenSans.css" asp-append-version="true" rel="stylesheet" />
<link href="~/main/layout.css" asp-append-version="true" rel="stylesheet" />
<link href="~/main/site.css" asp-append-version="true" rel="stylesheet" />
<link href="@Context.Request.GetRelativePathOrAbsolute(Theme.CssUri)" rel="stylesheet" asp-append-version="true"/>
@if (Model.CustomCSSLink != null) @if (Model.CustomCSSLink != null)
{ {
<link href="@Model.CustomCSSLink" rel="stylesheet" asp-append-version="true" /> <link href="@Model.CustomCSSLink" rel="stylesheet" asp-append-version="true" />
} }
<link href="~/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" asp-append-version="true" />
@if (Model.ViewType == PosViewType.Cart) @if (Model.ViewType == PosViewType.Cart)
{ {
<link rel="stylesheet" href="~/cart/css/style.css" asp-append-version="true"> <link rel="stylesheet" href="~/cart/css/style.css" asp-append-version="true">
<script type="text/javascript"> <script>var srvModel = @Safe.Json(Model);</script>
var srvModel = @Safe.Json(Model);
</script>
<script src="~/vendor/jquery/jquery.min.js" asp-append-version="true"></script> <script src="~/vendor/jquery/jquery.min.js" asp-append-version="true"></script>
<script src="~/vendor/bootstrap/bootstrap.bundle.min.js" asp-append-version="true"></script> <script src="~/vendor/bootstrap/bootstrap.bundle.min.js" asp-append-version="true"></script>
<script src="~/cart/js/cart.js" asp-append-version="true"></script> <script src="~/cart/js/cart.js" asp-append-version="true"></script>
<script src="~/cart/js/cart.jquery.js" asp-append-version="true"></script> <script src="~/cart/js/cart.jquery.js" asp-append-version="true"></script>
} }
@if (Model.ViewType == PosViewType.Light) @if (Model.ViewType == PosViewType.Light)
{ {
<link href="~/light-pos/styles/main.css" asp-append-version="true" rel="stylesheet" /> <link href="~/light-pos/styles/main.css" asp-append-version="true" rel="stylesheet" />
<script>var srvModel = @Safe.Json(Model);</script>
<script type="text/javascript">
var srvModel = @Safe.Json(Model);
</script>
<script src="~/vendor/jquery/jquery.min.js" asp-append-version="true"></script> <script src="~/vendor/jquery/jquery.min.js" asp-append-version="true"></script>
<script src="~/vendor/bootstrap/bootstrap.bundle.min.js" asp-append-version="true"></script> <script src="~/vendor/bootstrap/bootstrap.bundle.min.js" asp-append-version="true"></script>
<script src="~/vendor/vuejs/vue.min.js" asp-append-version="true"></script> <script src="~/vendor/vuejs/vue.min.js" asp-append-version="true"></script>
<script src="~/light-pos/app.js" asp-append-version="true"></script> <script src="~/light-pos/app.js" asp-append-version="true"></script>
} }
<style> <style>
.lead :last-child {
margin-bottom: 0;
}
.card-deck { .card-deck {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-gap: 1.5rem; grid-gap: 1.5rem;
} }
.card {
page-break-inside: avoid;
}
.card:only-of-type { .card:only-of-type {
max-width: 320px; max-width: 320px;
margin: auto !important; margin: auto !important;
} }
.js-cart-item-minus .fa, .js-cart-item-minus .fa,
.js-cart-item-plus .fa { .js-cart-item-plus .fa {
background: #fff; background: #fff;
@ -112,7 +94,7 @@
@Safe.Raw($"<style>{Model.EmbeddedCSS}</style>"); @Safe.Raw($"<style>{Model.EmbeddedCSS}</style>");
} }
</head> </head>
<body class="h-100"> <body class="min-vh-100">
@RenderBody() @RenderBody()
</body> </body>
</html> </html>

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 84" role="img" alt="BTCPay Server" class="ms-1"><path d="M5.206 83.433a4.86 4.86 0 01-4.859-4.861V5.431a4.86 4.86 0 119.719 0v73.141a4.861 4.861 0 01-4.86 4.861" fill="currentColor" class="logo-brand-light"/><path d="M5.209 83.433a4.862 4.862 0 01-2.086-9.253L32.43 60.274 2.323 38.093a4.861 4.861 0 015.766-7.826l36.647 26.999a4.864 4.864 0 01-.799 8.306L7.289 82.964a4.866 4.866 0 01-2.08.469" fill="currentColor" class="logo-brand-medium"/><path d="M5.211 54.684a4.86 4.86 0 01-2.887-8.774L32.43 23.73 3.123 9.821a4.861 4.861 0 014.166-8.784l36.648 17.394a4.86 4.86 0 01.799 8.305l-36.647 27a4.844 4.844 0 01-2.878.948" fill="currentColor" class="logo-brand-light"/><path d="M10.066 31.725v20.553L24.01 42.006z" fill="currentColor" class="logo-brand-dark"/><path d="M10.066 5.431A4.861 4.861 0 005.206.57 4.86 4.86 0 00.347 5.431v61.165h9.72V5.431h-.001z" fill="currentColor" class="logo-brand-light"/><path d="M74.355 41.412c3.114.884 4.84 3.704 4.84 7.238 0 5.513-3.368 8.082-7.955 8.082H60.761V27.271h9.259c4.504 0 7.997 2.146 7.997 7.743 0 2.821-1.179 5.43-3.662 6.398m-4.293-.716c3.324 0 6.018-1.179 6.018-5.724 0-4.586-2.776-5.808-6.145-5.808h-7.197v11.531h7.324v.001zm1.052 14.099c3.366 0 6.06-1.768 6.06-6.145 0-4.713-3.072-6.144-6.901-6.144h-7.534v12.288h8.375v.001zM98.893 27.271v1.81h-8.122v27.651h-1.979V29.081h-8.123v-1.81zM112.738 26.85c5.01 0 9.554 2.524 10.987 8.543h-1.895c-1.348-4.923-5.303-6.732-9.134-6.732-6.944 0-10.605 5.681-10.605 13.341 0 8.08 3.661 13.256 10.646 13.256 4.125 0 7.828-1.85 9.26-7.279h1.895c-1.264 6.271-6.229 9.174-11.154 9.174-7.87 0-12.583-5.808-12.583-15.15 0-8.966 4.969-15.153 12.583-15.153M138.709 27.271c5.091 0 8.795 3.326 8.795 9.764 0 6.06-3.704 9.722-8.795 9.722h-7.746v9.976h-1.935V27.271h9.681zm0 17.549c3.745 0 6.816-2.397 6.816-7.827 0-5.429-2.947-7.869-6.816-7.869h-7.746V44.82h7.746zM147.841 56.732v-.255l11.741-29.29h.885l11.615 29.29v.255h-2.062l-3.322-8.501H153.27l-3.324 8.501h-2.105zm12.164-26.052l-6.059 15.697h12.078l-6.019-15.697zM189.551 27.271h2.104v.293l-9.176 16.92v12.248h-2.02V44.484l-9.216-16.961v-.252h2.147l3.997 7.492 4.043 7.786h.04l4.081-7.786z" fill="currentColor" class="logo-brand-text"/></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -0,0 +1,16 @@
@inject IFileService FileService
@using BTCPayServer.Abstractions.Contracts
@using BTCPayServer.Abstractions.Extensions
@model (string Title, string LogoFileId)
@{
var logoUrl = !string.IsNullOrEmpty(Model.LogoFileId)
? await FileService.GetFileUrl(Context.Request.GetAbsoluteRootUri(), Model.LogoFileId)
: null;
}
<header class="store-header">
@if (!string.IsNullOrEmpty(logoUrl))
{
<img src="@logoUrl" alt="@Model.Title" class="store-logo"/>
}
<h1 class="store-name">@Model.Title</h1>
</header>

View file

@ -1,7 +1,5 @@
@using BTCPayServer.Components.ThemeSwitch
@using Microsoft.AspNetCore.Mvc.TagHelpers @using Microsoft.AspNetCore.Mvc.TagHelpers
@inject BTCPayServer.Services.BTCPayServerEnvironment env @inject BTCPayServer.Services.BTCPayServerEnvironment env
@inject BTCPayServer.Services.ThemeSettings Theme
@model BTCPayServer.Forms.Models.FormViewModel @model BTCPayServer.Forms.Models.FormViewModel
@{ @{
Layout = null; Layout = null;
@ -14,9 +12,9 @@
<partial name="LayoutHead"/> <partial name="LayoutHead"/>
<meta name="robots" content="noindex,nofollow"> <meta name="robots" content="noindex,nofollow">
</head> </head>
<body> <body class="min-vh-100">
<div class="min-vh-100 d-flex flex-column"> <div class="public-page-wrap flex-column">
<main class="flex-grow-1 py-5"> <main class="flex-grow-1">
<div class="container" style="max-width:720px;"> <div class="container" style="max-width:720px;">
<partial name="_StatusMessage" model="@(new ViewDataDictionary(ViewData) {{"Margin", "mb-4"}})"/> <partial name="_StatusMessage" model="@(new ViewDataDictionary(ViewData) {{"Margin", "mb-4"}})"/>
@if (!ViewContext.ModelState.IsValid) @if (!ViewContext.ModelState.IsValid)
@ -39,16 +37,10 @@
</div> </div>
</div> </div>
</main> </main>
<footer class="pt-2 pb-4 d-print-none"> <footer class="store-footer">
<div class="container d-flex flex-wrap align-items-center justify-content-center"> <a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
<span class="text-muted mx-2"> Powered by <partial name="_StoreFooterLogo" />
Powered by <a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">BTCPay Server</a> </a>
</span>
@if (!Theme.CustomTheme)
{
<vc:theme-switch css-class="text-muted mx-2" responsive="none"/>
}
</div>
</footer> </footer>
</div> </div>
<partial name="LayoutFoot"/> <partial name="LayoutFoot"/>

View file

@ -1,11 +1,10 @@
@inject LanguageService LangService
@inject BTCPayServerEnvironment Env
@inject IFileService FileService
@inject IEnumerable<IUIExtension> UiExtensions
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
@using BTCPayServer.Services @using BTCPayServer.Services
@using BTCPayServer.Abstractions.Contracts @using BTCPayServer.Abstractions.Contracts
@using Microsoft.AspNetCore.Mvc.TagHelpers @using Microsoft.AspNetCore.Mvc.TagHelpers
@inject LanguageService LangService
@inject BTCPayServerEnvironment Env
@inject IEnumerable<IUIExtension> UiExtensions
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
@model PaymentModel @model PaymentModel
@{ @{
Layout = null; Layout = null;
@ -13,9 +12,6 @@
var hasPaymentPlugins = UiExtensions.Any(extension => extension.Location == "checkout-payment-method"); var hasPaymentPlugins = UiExtensions.Any(extension => extension.Location == "checkout-payment-method");
var paymentMethodCount = Model.AvailableCryptos.Count; var paymentMethodCount = Model.AvailableCryptos.Count;
var logoUrl = !string.IsNullOrEmpty(Model.LogoFileId)
? await FileService.GetFileUrl(Context.Request.GetAbsoluteRootUri(), Model.LogoFileId)
: null;
} }
@functions { @functions {
private string PaymentMethodName(PaymentModel.AvailableCrypto pm) private string PaymentMethodName(PaymentModel.AvailableCrypto pm)
@ -36,17 +32,11 @@
<partial name="LayoutHead"/> <partial name="LayoutHead"/>
<meta name="robots" content="noindex,nofollow"> <meta name="robots" content="noindex,nofollow">
<link href="~/checkout-v2/checkout.css" asp-append-version="true" rel="stylesheet" /> <link href="~/checkout-v2/checkout.css" asp-append-version="true" rel="stylesheet" />
<partial name="LayoutHeadStoreBranding" model="@(Model.BrandColor, Model.CssFileId)" /> <partial name="LayoutHeadStoreBranding" model="@(Model.BrandColor, Model.CssFileId, "", "")" />
</head> </head>
<body class="min-vh-100"> <body class="min-vh-100">
<div id="Checkout-v2" class="wrap gap-4" v-cloak v-waitForT> <div id="Checkout-v2" class="public-page-wrap" v-cloak v-waitForT>
<header class="store-header"> <partial name="_StoreHeader" model="(Model.StoreName, Model.LogoFileId)" />
@if (!string.IsNullOrEmpty(logoUrl))
{
<img src="@logoUrl" alt="@Model.StoreName" class="store-logo"/>
}
<h1 class="store-name">@Model.StoreName</h1>
</header>
<main class="shadow-lg"> <main class="shadow-lg">
<nav v-if="isModal"> <nav v-if="isModal">
<button type="button" v-if="isModal" id="close" v-on:click="close"> <button type="button" v-if="isModal" id="close" v-on:click="close">
@ -164,13 +154,10 @@
{ {
<checkout-cheating invoice-id="@Model.InvoiceId" :btc-due="srvModel.btcDue" :is-paid="isPaid" :payment-method-id="pmId"></checkout-cheating> <checkout-cheating invoice-id="@Model.InvoiceId" :btc-due="srvModel.btcDue" :is-paid="isPaid" :payment-method-id="pmId"></checkout-cheating>
} }
<footer> <footer class="store-footer">
<div>
<a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener"> <a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
{{$t("powered_by")}} {{$t("powered_by")}} <partial name="_StoreFooterLogo" />
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 84" role="img" alt="BTCPay Server" class="ms-1"><path d="M5.206 83.433a4.86 4.86 0 01-4.859-4.861V5.431a4.86 4.86 0 119.719 0v73.141a4.861 4.861 0 01-4.86 4.861" fill="currentColor" class="logo-brand-light"/><path d="M5.209 83.433a4.862 4.862 0 01-2.086-9.253L32.43 60.274 2.323 38.093a4.861 4.861 0 015.766-7.826l36.647 26.999a4.864 4.864 0 01-.799 8.306L7.289 82.964a4.866 4.866 0 01-2.08.469" fill="currentColor" class="logo-brand-medium"/><path d="M5.211 54.684a4.86 4.86 0 01-2.887-8.774L32.43 23.73 3.123 9.821a4.861 4.861 0 014.166-8.784l36.648 17.394a4.86 4.86 0 01.799 8.305l-36.647 27a4.844 4.844 0 01-2.878.948" fill="currentColor" class="logo-brand-light"/><path d="M10.066 31.725v20.553L24.01 42.006z" fill="currentColor" class="logo-brand-dark"/><path d="M10.066 5.431A4.861 4.861 0 005.206.57 4.86 4.86 0 00.347 5.431v61.165h9.72V5.431h-.001z" fill="currentColor" class="logo-brand-light"/><path d="M74.355 41.412c3.114.884 4.84 3.704 4.84 7.238 0 5.513-3.368 8.082-7.955 8.082H60.761V27.271h9.259c4.504 0 7.997 2.146 7.997 7.743 0 2.821-1.179 5.43-3.662 6.398m-4.293-.716c3.324 0 6.018-1.179 6.018-5.724 0-4.586-2.776-5.808-6.145-5.808h-7.197v11.531h7.324v.001zm1.052 14.099c3.366 0 6.06-1.768 6.06-6.145 0-4.713-3.072-6.144-6.901-6.144h-7.534v12.288h8.375v.001zM98.893 27.271v1.81h-8.122v27.651h-1.979V29.081h-8.123v-1.81zM112.738 26.85c5.01 0 9.554 2.524 10.987 8.543h-1.895c-1.348-4.923-5.303-6.732-9.134-6.732-6.944 0-10.605 5.681-10.605 13.341 0 8.08 3.661 13.256 10.646 13.256 4.125 0 7.828-1.85 9.26-7.279h1.895c-1.264 6.271-6.229 9.174-11.154 9.174-7.87 0-12.583-5.808-12.583-15.15 0-8.966 4.969-15.153 12.583-15.153M138.709 27.271c5.091 0 8.795 3.326 8.795 9.764 0 6.06-3.704 9.722-8.795 9.722h-7.746v9.976h-1.935V27.271h9.681zm0 17.549c3.745 0 6.816-2.397 6.816-7.827 0-5.429-2.947-7.869-6.816-7.869h-7.746V44.82h7.746zM147.841 56.732v-.255l11.741-29.29h.885l11.615 29.29v.255h-2.062l-3.322-8.501H153.27l-3.324 8.501h-2.105zm12.164-26.052l-6.059 15.697h12.078l-6.019-15.697zM189.551 27.271h2.104v.293l-9.176 16.92v12.248h-2.02V44.484l-9.216-16.961v-.252h2.147l3.997 7.492 4.043 7.786h.04l4.081-7.786z" fill="currentColor" class="logo-brand-text"/></svg>
</a> </a>
</div>
@* TODO: Re-add this once checkout v2 has been translated @* TODO: Re-add this once checkout v2 has been translated
<select asp-for="DefaultLang" asp-items="@LangService.GetLanguageSelectListItems()" class="form-select w-auto" v-on:change="changeLanguage"></select> <select asp-for="DefaultLang" asp-items="@LangService.GetLanguageSelectListItems()" class="form-select w-auto" v-on:change="changeLanguage"></select>
*@ *@

View file

@ -2,24 +2,20 @@
@using BTCPayServer.Client @using BTCPayServer.Client
@using BTCPayServer.Client.Models @using BTCPayServer.Client.Models
@using BTCPayServer.Services.Rates @using BTCPayServer.Services.Rates
@inject BTCPayServer.Services.BTCPayServerEnvironment env @inject BTCPayServer.Services.BTCPayServerEnvironment Env
@inject BTCPayServer.Services.ThemeSettings Theme @inject BTCPayServer.Services.ThemeSettings Theme
@inject CurrencyNameTable CurrencyNameTable @inject CurrencyNameTable CurrencyNameTable
@using BTCPayServer.Abstractions.Contracts
@inject IFileService FileService
@{ @{
Layout = null; Layout = null;
ViewData["Title"] = $"Receipt from {Model.StoreName}"; ViewData["Title"] = $"Receipt from {Model.StoreName}";
var isProcessing = Model.Status == InvoiceStatus.Processing; var isProcessing = Model.Status == InvoiceStatus.Processing;
var isSettled = Model.Status == InvoiceStatus.Settled; var isSettled = Model.Status == InvoiceStatus.Settled;
var logoUrl = !string.IsNullOrEmpty(Model.LogoFileId)
? await FileService.GetFileUrl(Context.Request.GetAbsoluteRootUri(), Model.LogoFileId)
: null;
} }
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" @(env.IsDeveloping ? " data-devenv" : "")> <html lang="en" @(Env.IsDeveloping ? " data-devenv" : "")>
<head> <head>
<partial name="LayoutHead" /> <partial name="LayoutHead" />
<partial name="LayoutHeadStoreBranding" model="@(Model.BrandColor, Model.CssFileId, "", "")" />
<meta name="robots" content="noindex,nofollow"> <meta name="robots" content="noindex,nofollow">
@if (isProcessing) @if (isProcessing)
{ {
@ -32,32 +28,25 @@
#posData td > table:last-child { margin-bottom: 0 !important; } #posData td > table:last-child { margin-bottom: 0 !important; }
#posData table > tbody > tr:first-child > td > h4 { margin-top: 0 !important; } #posData table > tbody > tr:first-child > td > h4 { margin-top: 0 !important; }
</style> </style>
<partial name="LayoutHeadStoreBranding" model="@(Model.BrandColor, Model.CssFileId)" />
</head> </head>
<body> <body class="min-vh-100">
<div class="min-vh-100 d-flex flex-column"> <div class="public-page-wrap flex-column">
<main class="flex-grow-1 py-5"> <main class="flex-grow-1">
<div class="container" style="max-width:720px;"> <div class="container" style="max-width:720px;">
<partial name="_StatusMessage" model="@(new ViewDataDictionary(ViewData) { { "Margin", "mb-4" } })"/> <partial name="_StatusMessage" model="@(new ViewDataDictionary(ViewData) { { "Margin", "mb-4" } })"/>
<div class="d-flex flex-column justify-content-center gap-4"> <div class="d-flex flex-column justify-content-center gap-4">
<header class="store-header"> <partial name="_StoreHeader" model="(Model.StoreName, Model.LogoFileId)" />
@if (!string.IsNullOrEmpty(logoUrl))
{
<img src="@logoUrl" alt="@Model.StoreName" class="store-logo" />
}
<h1 class="store-name">@Model.StoreName</h1>
</header>
<div id="InvoiceSummary" class="bg-tile p-3 p-sm-4 rounded d-flex flex-wrap align-items-center"> <div id="InvoiceSummary" class="bg-tile p-3 p-sm-4 rounded d-flex flex-wrap align-items-center">
@if (isProcessing) @if (isProcessing)
{ {
<div class="lead text-center text-muted py-5 px-4 fw-semibold" id="invoice-processing"> <div class="lead text-center p-4 fw-semibold" id="invoice-processing">
The invoice has detected a payment but is still waiting to be settled. The invoice has detected a payment but is still waiting to be settled.
</div> </div>
} }
else if (!isSettled) else if (!isSettled)
{ {
<div class="lead text-center text-muted py-5 px-4 fw-semibold" id="invoice-unsettled"> <div class="lead text-center p-4 fw-semibold" id="invoice-unsettled">
The invoice is not settled. The invoice is not settled.
</div> </div>
} }
@ -173,21 +162,15 @@
</div> </div>
</div> </div>
</main> </main>
<footer class="pt-2 pb-4 d-print-none"> <footer class="store-footer">
<p class="container text-center" permission="@Policies.CanViewInvoices"> <p permission="@Policies.CanViewInvoices">
<a asp-action="Invoice" asp-route-invoiceId="@Model.InvoiceId"> <a asp-action="Invoice" asp-route-invoiceId="@Model.InvoiceId">
Admin details Admin details
</a> </a>
</p> </p>
<div class="container d-flex flex-wrap align-items-center justify-content-center"> <a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
<span class="text-muted mx-2"> Powered by <partial name="_StoreFooterLogo" />
Powered by <a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">BTCPay Server</a> </a>
</span>
@if (!Theme.CustomTheme)
{
<vc:theme-switch css-class="text-muted mx-2" />
}
</div>
</footer> </footer>
</div> </div>
<partial name="LayoutFoot"/> <partial name="LayoutFoot"/>

View file

@ -1,10 +1,8 @@
@using BTCPayServer.Services.Invoices @using BTCPayServer.Services.Invoices
@using BTCPayServer.Client.Models @using BTCPayServer.Client.Models
@using BTCPayServer.Client @using BTCPayServer.Client
@using BTCPayServer.Components.ThemeSwitch
@model BTCPayServer.Models.PaymentRequestViewModels.ViewPaymentRequestViewModel @model BTCPayServer.Models.PaymentRequestViewModels.ViewPaymentRequestViewModel
@inject BTCPayServer.Services.BTCPayServerEnvironment env @inject BTCPayServer.Services.BTCPayServerEnvironment Env
@inject BTCPayServer.Services.ThemeSettings Theme
@{ @{
ViewData["Title"] = Model.Title; ViewData["Title"] = Model.Title;
Layout = null; Layout = null;
@ -34,17 +32,11 @@
} }
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" @(env.IsDeveloping ? " data-devenv" : "")> <html lang="en" @(Env.IsDeveloping ? " data-devenv" : "")>
<head> <head>
<partial name="LayoutHead" /> <partial name="LayoutHead" />
<link href="~/vendor/font-awesome/css/font-awesome.min.css" asp-append-version="true" rel="stylesheet" /> <partial name="LayoutHeadStoreBranding" model="@(Model.BrandColor, Model.CssFileId, Model.CustomCSSLink, Model.EmbeddedCSS)" />
<link href="~/vendor/bootstrap-vue/bootstrap-vue.css" asp-append-version="true" rel="stylesheet" /> <link href="~/vendor/bootstrap-vue/bootstrap-vue.css" asp-append-version="true" rel="stylesheet" />
<link href="~/main/site.css" asp-append-version="true" rel="stylesheet" />
@if (Model.CustomCSSLink != null)
{
<link href="@Model.CustomCSSLink" rel="stylesheet" asp-append-version="true" />
}
<script type="text/javascript"> <script type="text/javascript">
var srvModel = @Safe.Json(Model); var srvModel = @Safe.Json(Model);
</script> </script>
@ -57,7 +49,6 @@
<script src="~/payment-request/helpers/math.js" asp-append-version="true"></script> <script src="~/payment-request/helpers/math.js" asp-append-version="true"></script>
<script src="~/payment-request/services/listener.js" asp-append-version="true"></script> <script src="~/payment-request/services/listener.js" asp-append-version="true"></script>
<script src="~/modal/btcpay.js" asp-append-version="true"></script> <script src="~/modal/btcpay.js" asp-append-version="true"></script>
@Safe.Raw(Model.EmbeddedCSS)
<style> <style>
.invoice { margin-top: var(--btcpay-space-s); } .invoice { margin-top: var(--btcpay-space-s); }
.invoice + .invoice { margin-top: var(--btcpay-space-m); } .invoice + .invoice { margin-top: var(--btcpay-space-m); }
@ -69,8 +60,8 @@
} }
</style> </style>
</head> </head>
<body> <body class="min-vh-100">
<div id="app" class="min-vh-100 d-flex flex-column"> <div id="app" class="d-flex flex-column min-vh-100 pb-l">
<nav class="btcpay-header navbar sticky-top py-3 py-lg-4 d-print-block"> <nav class="btcpay-header navbar sticky-top py-3 py-lg-4 d-print-block">
<div class="container"> <div class="container">
<div class="row align-items-center" style="width:calc(100% + 30px)"> <div class="row align-items-center" style="width:calc(100% + 30px)">
@ -378,21 +369,15 @@
</div> </div>
</div> </div>
</main> </main>
<footer class="pt-2 pb-4 d-print-none"> <footer class="store-footer">
<p class="container text-center" permission="@Policies.CanModifyStoreSettings"> <p permission="@Policies.CanModifyStoreSettings">
<a asp-controller="UIPaymentRequest" asp-action="EditPaymentRequest" asp-route-storeId="@Model.StoreId" asp-route-payReqId="@Model.Id"> <a asp-controller="UIPaymentRequest" asp-action="EditPaymentRequest" asp-route-storeId="@Model.StoreId" asp-route-payReqId="@Model.Id">
Edit payment request Edit payment request
</a> </a>
</p> </p>
<div class="container d-flex flex-wrap align-items-center justify-content-center"> <a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
<span class="text-muted mx-2"> Powered by <partial name="_StoreFooterLogo" />
Powered by <a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">BTCPay Server</a> </a>
</span>
@if (!Theme.CustomTheme)
{
<vc:theme-switch css-class="text-muted mx-2" />
}
</div>
</footer> </footer>
</div> </div>
<partial name="LayoutFoot"/> <partial name="LayoutFoot"/>

View file

@ -1,10 +1,11 @@
@inject BTCPayServer.Services.BTCPayServerEnvironment Env
@model BTCPayServer.Controllers.ShowLightningNodeInfoViewModel @model BTCPayServer.Controllers.ShowLightningNodeInfoViewModel
@{ @{
Layout = null; Layout = null;
ViewData["Title"] = $"{Model.StoreName} {Model.CryptoCode} Lightning Node"; ViewData["Title"] = $"{Model.StoreName} {Model.CryptoCode} Lightning Node";
} }
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en" @(Env.IsDeveloping ? " data-devenv" : "")>
<head> <head>
<partial name="LayoutHead" /> <partial name="LayoutHead" />
<link href="~/main/qrcode.css" rel="stylesheet" asp-append-version="true" /> <link href="~/main/qrcode.css" rel="stylesheet" asp-append-version="true" />

View file

@ -1,5 +1,4 @@
@inject BTCPayServer.Services.BTCPayServerEnvironment Env @inject BTCPayServer.Services.BTCPayServerEnvironment Env
@inject BTCPayServer.Services.ThemeSettings Theme
@inject BTCPayNetworkProvider BtcPayNetworkProvider @inject BTCPayNetworkProvider BtcPayNetworkProvider
@using BTCPayServer.Client @using BTCPayServer.Client
@using BTCPayServer.Components.ThemeSwitch @using BTCPayServer.Components.ThemeSwitch
@ -43,21 +42,14 @@
<html lang="en" @(Env.IsDeveloping ? " data-devenv" : "")> <html lang="en" @(Env.IsDeveloping ? " data-devenv" : "")>
<head> <head>
<partial name="LayoutHead" /> <partial name="LayoutHead" />
<link href="~/vendor/font-awesome/css/font-awesome.min.css" asp-append-version="true" rel="stylesheet" /> <partial name="LayoutHeadStoreBranding" model="@(Model.BrandColor, Model.CssFileId, Model.CustomCSSLink, Model.EmbeddedCSS)" />
<link href="~/vendor/bootstrap-vue/bootstrap-vue.css" asp-append-version="true" rel="stylesheet" /> <link href="~/vendor/bootstrap-vue/bootstrap-vue.css" asp-append-version="true" rel="stylesheet" />
<link href="~/main/site.css" asp-append-version="true" rel="stylesheet" />
@if (Model.CustomCSSLink != null)
{
<link href="@Model.CustomCSSLink" rel="stylesheet" asp-append-version="true" />
}
@Safe.Raw(Model.EmbeddedCSS)
<style> <style>
.no-marker > ul { list-style-type: none; } .no-marker > ul { list-style-type: none; }
</style> </style>
</head> </head>
<body> <body class="min-vh-100">
<div class="min-vh-100 d-flex flex-column"> <div id="app" class="d-flex flex-column min-vh-100 pb-l">
@if (Model.IsPending) @if (Model.IsPending)
{ {
<nav class="btcpay-header navbar sticky-top py-3 py-lg-4 d-print-none"> <nav class="btcpay-header navbar sticky-top py-3 py-lg-4 d-print-none">
@ -215,24 +207,15 @@
</div> </div>
</div> </div>
</main> </main>
<footer class="pt-2 pb-4 d-print-none"> <footer class="store-footer">
<p class="container text-center" permission="@Policies.CanViewStoreSettings"> <p permission="@Policies.CanViewStoreSettings">
<a asp-action="EditPullPayment" <a asp-action="EditPullPayment" asp-controller="UIPullPayment" asp-route-storeId="@Model.StoreId" asp-route-pullPaymentId="@Model.Id">
asp-controller="UIPullPayment"
asp-route-storeId="@Model.StoreId"
asp-route-pullPaymentId="@Model.Id">
Edit pull payment Edit pull payment
</a> </a>
</p> </p>
<div class="container d-flex flex-wrap align-items-center justify-content-center"> <a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
<span class="text-muted mx-2"> Powered by <partial name="_StoreFooterLogo" />
Powered by <a href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">BTCPay Server</a> </a>
</span>
@if (!Theme.CustomTheme)
{
<vc:theme-switch css-class="text-muted mx-2" />
}
</div>
</footer> </footer>
</div> </div>
<partial name="LayoutFoot" /> <partial name="LayoutFoot" />

View file

@ -51,10 +51,6 @@
background-color: #dee2e6; background-color: #dee2e6;
} }
#js-cart-confirm {
border-radius: 0;
}
.js-search-reset { .js-search-reset {
position: absolute; position: absolute;
right: 0px; right: 0px;
@ -74,8 +70,10 @@
} }
#sidebar { #sidebar {
width: 400px;
position: fixed; position: fixed;
width: 400px;
display: flex;
flex-direction: column;
top: 0; top: 0;
right: 0; right: 0;
height: 100vh; height: 100vh;
@ -85,6 +83,7 @@
color: var(--btcpay-white); color: var(--btcpay-white);
background: var(--btcpay-bg-dark); background: var(--btcpay-bg-dark);
transition: all 0.3s; transition: all 0.3s;
padding-bottom: var(--btcpay-space-l);
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
} }

View file

@ -8,12 +8,8 @@
--border-radius: var(--btcpay-border-radius-l); --border-radius: var(--btcpay-border-radius-l);
--wrap-max-width: 400px; --wrap-max-width: 400px;
} }
.wrap { .public-page-wrap {
display: flex;
flex-direction: column; flex-direction: column;
min-height: 100vh;
margin: 0 auto;
padding: var(--btcpay-space-l); var(--btcpay-space-m);
max-width: var(--wrap-max-width); max-width: var(--wrap-max-width);
} }
main { main {
@ -222,27 +218,8 @@ section dl > div dd {
#result #expired .top .icn .icon { #result #expired .top .icn .icon {
color: var(--btcpay-body-text-muted); color: var(--btcpay-body-text-muted);
} }
footer {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--btcpay-space-m);
margin-top: auto;
padding: var(--section-padding) var(--section-padding) 0;
}
footer,
footer a,
#DefaultLang { #DefaultLang {
color: var(--btcpay-body-text-muted); color: var(--btcpay-body-text-muted);
}
footer a {
transition-duration: unset;
}
footer a svg {
height: 2rem;
width: 4rem;
}
#DefaultLang {
background-color: transparent; background-color: transparent;
box-shadow: none; box-shadow: none;
border: none; border: none;
@ -250,25 +227,11 @@ footer a svg {
cursor: pointer; cursor: pointer;
margin-left: -4.5rem; /* Adjust for visual center */ margin-left: -4.5rem; /* Adjust for visual center */
} }
footer a:hover,
#DefaultLang:hover { #DefaultLang:hover {
color: var(--btcpay-body-text-hover); color: var(--btcpay-body-text-hover);
} }
footer a:hover .logo-brand-light {
color: var(--btcpay-brand-secondary);
}
footer a:hover .logo-brand-medium {
color: var(--btcpay-brand-primary);
}
footer a:hover .logo-brand-dark {
color: var(--btcpay-brand-tertiary);
}
@media (max-width: 400px) { @media (max-width: 400px) {
.wrap {
padding-left: 0;
padding-right: 0;
}
main { main {
border-radius: 0; border-radius: 0;
} }

View file

@ -25,10 +25,6 @@
line-height: 80px; line-height: 80px;
} }
.l-pos-keypad {
margin-left: 2%;
}
.l-pos-keypad .btn { .l-pos-keypad .btn {
width: 32%; width: 32%;
margin-right: 1%; margin-right: 1%;
@ -40,14 +36,6 @@
font-size: 1.3rem; font-size: 1.3rem;
} }
.l-pos-controls .btn {
width: 47%;
border-radius: 0;
margin-right: 0%;
margin-left: 2%;
margin-bottom: 1%;
}
.logo { .logo {
height: 40px; height: 40px;
} }

View file

@ -205,29 +205,6 @@ h2 small .fa-question-circle-o {
margin-top: .5rem; margin-top: .5rem;
} }
/* Store header */
.store-header {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--btcpay-space-s);
}
.store-logo {
--logo-size: 3rem;
--logo-bg: transparent;
--logo-radius: 50%;
width: var(--logo-size);
height: var(--logo-size);
background: var(--logo-bg);
border-radius: var(--logo-radius);
}
.store-name {
font-size: 1.3rem;
}
/* Print */ /* Print */
@media print { @media print {
.table td, .table td,
@ -626,3 +603,73 @@ svg.icon-note {
input:checked + .btcpay-list-select-item { input:checked + .btcpay-list-select-item {
border-color: var(--btcpay-form-border-focus); border-color: var(--btcpay-form-border-focus);
} }
/* Public pages */
.public-page-wrap {
display: flex;
gap: 1.5rem;
min-height: 100vh;
margin: 0 auto;
padding: var(--btcpay-space-l) var(--btcpay-space-m);
}
@media (max-width: 400px) {
.public-page-wrap {
padding-left: 0;
padding-right: 0;
}
}
.store-header {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--btcpay-space-s);
}
.store-logo {
--logo-size: 3rem;
--logo-bg: transparent;
--logo-radius: 50%;
width: var(--logo-size);
height: var(--logo-size);
background: var(--logo-bg);
border-radius: var(--logo-radius);
}
.store-name {
font-size: 1.3rem;
}
.store-footer {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--btcpay-space-m);
margin-top: auto;
color: var(--btcpay-body-text-muted);
padding: 1.5rem 1.5rem 0;
}
.store-footer,
.store-footer a {
color: var(--btcpay-body-text-muted);
}
.store-footer a {
transition-duration: unset;
}
.store-footer a svg {
height: 2rem;
width: 4rem;
}
.store-footer a:hover {
color: var(--btcpay-body-text-hover);
}
.store-footer a:hover .logo-brand-light {
color: var(--btcpay-brand-secondary);
}
.store-footer a:hover .logo-brand-medium {
color: var(--btcpay-brand-primary);
}
.store-footer a:hover .logo-brand-dark {
color: var(--btcpay-brand-tertiary);
}