Unify public page styles (#5462)

Based on #5413 and needs it to get merged first.

- Uses `--wrap-max-width` on `.public-page-wrap` rather than inner `.container` classes
- Applies `.tile` class to boxes and makes them connect to the edge of the screen below `400px` width.
This commit is contained in:
d11n 2023-11-21 10:13:26 +01:00 committed by GitHub
parent b4daa76aeb
commit 6d288271cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 155 additions and 165 deletions

View file

@ -29,6 +29,7 @@
@Safe.Raw($"<style>{Model.EmbeddedCSS}</style>")
}
<style>
#app { --wrap-max-width: 1320px; }
#crowdfund-main-image {
border-radius: var(--btcpay-border-radius);
object-fit: cover;
@ -57,7 +58,7 @@
<canvas id="fireworks" class="d-none"></canvas>
}
<div class="public-page-wrap container" id="app" @(Model.SimpleDisplay ? "" : "v-cloak")>
<div class="public-page-wrap" id="app" @(Model.SimpleDisplay ? "" : "v-cloak")>
@if (!string.IsNullOrEmpty(Model.MainImageUrl))
{
<img v-if="srvModel.mainImageUrl" :src="srvModel.mainImageUrl" :alt="srvModel.title" id="crowdfund-main-image" asp-append-version="true"/>
@ -260,7 +261,6 @@
</div>
</div>
</noscript>
<div class="text-center text-muted mt-4" v-text="`Updated ${lastUpdated}`">Updated @Model.Info.LastUpdated</div>
<b-modal title="Contribute" v-model="contributeModalOpen" size="lg" ok-only="true" ok-variant="secondary" ok-title="Close" ref="modalContribute">
<contribute v-if="contributeModalOpen"
:target-currency="srvModel.targetCurrency"
@ -271,6 +271,7 @@
</contribute>
</b-modal>
<footer class="store-footer">
<p class="text-muted" v-text="`Updated ${lastUpdated}`">Updated @Model.Info.LastUpdated</p>
<a class="store-powered-by" href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
Powered by <partial name="_StoreFooterLogo" />
</a>

View file

@ -29,7 +29,7 @@
<div id="PosCart">
<div id="content">
<div class="public-page-wrap container-xl">
<div class="public-page-wrap">
<header class="sticky-top bg-body d-flex flex-column py-3 py-lg-4 gap-3">
<div class="d-flex align-items-center justify-content-center gap-3 px-5 position-relative">
<h1 class="mb-0">@(string.IsNullOrEmpty(Model.Title) ? Model.StoreName : Model.Title)</h1>
@ -130,7 +130,7 @@
</div>
</div>
<aside id="cart" ref="cart" tabindex="-1" aria-labelledby="cartLabel">
<div class="public-page-wrap container-xl" v-cloak>
<div class="public-page-wrap" v-cloak>
<header class="sticky-top bg-tile offcanvas-header py-3 py-lg-4 d-flex align-items-baseline justify-content-center gap-3 px-5 pe-lg-0">
<h1 class="mb-0" id="cartLabel">Cart</h1>
<button id="CartClear" type="reset" v-on:click="clearCart" class="btn btn-text text-primary p-1" v-if="cartCount > 0">

View file

@ -13,7 +13,7 @@
<script src="~/pos/common.js" asp-append-version="true"></script>
<script src="~/pos/keypad.js" asp-append-version="true"></script>
}
<div class="public-page-wrap">
<div id="PosKeypad" class="public-page-wrap">
<partial name="_StatusMessage" />
<partial name="_StoreHeader" model="(string.IsNullOrEmpty(Model.Title) ? Model.StoreName : Model.Title, Model.LogoFileId)" />
@if (Context.Request.Query.ContainsKey("simple"))

View file

@ -42,7 +42,7 @@ else
<a asp-route-viewType="static" class="alert-link">Regular version</a>
</div>
}
<div id="PosPrint" class="public-page-wrap container-xl">
<div id="PosPrint" class="public-page-wrap">
<partial name="_StatusMessage" />
<partial name="_StoreHeader" model="(string.IsNullOrEmpty(Model.Title) ? Model.StoreName : Model.Title, Model.LogoFileId)" />
@if (!string.IsNullOrEmpty(Model.Description))

View file

@ -16,7 +16,7 @@
}
}
<div id="PosStatic" class="public-page-wrap container-xl">
<div id="PosStatic" class="public-page-wrap">
<partial name="_StoreHeader" model="(string.IsNullOrEmpty(Model.Title) ? Model.StoreName : Model.Title, Model.LogoFileId)" />
<main>
<partial name="_StatusMessage" />

View file

@ -1,6 +1,6 @@
@model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel
<form id="PosKeypad" method="post" asp-action="ViewPointOfSale" asp-route-appId="@Model.AppId" asp-antiforgery="false" v-on:submit="handleFormSubmit" class="d-flex flex-column gap-4 my-auto" v-cloak>
<form id="app" method="post" asp-action="ViewPointOfSale" asp-route-appId="@Model.AppId" asp-antiforgery="false" v-on:submit="handleFormSubmit" class="d-flex flex-column gap-4 my-auto" v-cloak>
<input type="hidden" name="posdata" v-model="posdata" id="posdata">
<input type="hidden" name="amount" v-model="totalNumeric">
<div ref="display" class="d-flex flex-column align-items-center px-4 mb-auto">

View file

@ -1,4 +1,3 @@
@using Microsoft.AspNetCore.Mvc.TagHelpers
@inject BTCPayServer.Services.BTCPayServerEnvironment Env
@model BTCPayServer.Forms.Models.FormViewModel
@{
@ -11,9 +10,10 @@
<partial name="LayoutHead" />
<partial name="LayoutHeadStoreBranding" model="@(Model.BrandColor, Model.CssFileId, "", "")" />
<meta name="robots" content="noindex,nofollow">
<style>#FormView { --wrap-max-width: 576px; }</style>
</head>
<body class="min-vh-100">
<div class="public-page-wrap">
<div id="FormView" class="public-page-wrap">
<partial name="_StatusMessage" model="@(new ViewDataDictionary(ViewData) { { "Margin", "mb-4" } })" />
@if (!string.IsNullOrEmpty(Model.StoreName) || !string.IsNullOrEmpty(Model.LogoFileId))
{
@ -23,14 +23,14 @@
{
<h1 class="h3 text-center mt-3">@ViewData["Title"]</h1>
}
<main class="flex-grow-1 container" style="max-width:576px">
<main class="flex-grow-1">
@if (!ViewContext.ModelState.IsValid)
{
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
}
<partial name="_FormTopMessages" model="@Model.Form" />
<div class="d-flex flex-column justify-content-center gap-4">
<div class="bg-tile p-3 p-sm-4 rounded">
<div class="tile">
@if (string.IsNullOrEmpty(Model.AspAction))
{
<form method="post" novalidate="novalidate">

View file

@ -3,7 +3,7 @@
<style>
#checkout-cheating form + form { margin-top: var(--btcpay-space-l); }
</style>
<main id="checkout-cheating" class="shadow-lg" v-cloak v-if="display">
<main id="checkout-cheating" class="tile" v-cloak v-if="display">
<section>
<p id="CheatSuccessMessage" class="alert alert-success text-break" v-if="successMessage" v-text="successMessage"></p>
<p id="CheatErrorMessage" class="alert alert-danger text-break" v-if="errorMessage" v-text="errorMessage"></p>

View file

@ -47,7 +47,7 @@
{
<partial name="_StoreHeader" model="(Model.StoreName, Model.LogoFileId)" />
}
<main class="shadow-lg">
<main class="tile">
<nav v-if="isModal">
<button type="button" v-if="isModal" id="close" v-on:click="close">
<vc:icon symbol="close"/>

View file

@ -31,6 +31,7 @@
</script>
}
<style>
#InvoiceReceipt { --wrap-max-width: 720px; }
#InvoiceSummary { gap: var(--btcpay-space-l); }
#PaymentDetails table tbody tr:first-child td { padding-top: 1rem; }
#PaymentDetails table tbody:not(:last-child) tr:last-child > th,td { padding-bottom: 1rem; }
@ -39,137 +40,134 @@
</style>
</head>
<body class="min-vh-100">
<div class="public-page-wrap">
<div id="InvoiceReceipt" class="public-page-wrap">
<main class="flex-grow-1">
<div class="container" style="max-width:720px;">
<div class="d-flex flex-column justify-content-center gap-4">
<partial name="_StoreHeader" model="(Model.StoreName, Model.LogoFileId)" />
<partial name="_StatusMessage" model="@(new ViewDataDictionary(ViewData) { { "Margin", "mb-4" } })"/>
<div class="d-flex flex-column justify-content-center gap-4">
<partial name="_StoreHeader" model="(Model.StoreName, Model.LogoFileId)" />
<div id="InvoiceSummary" class="bg-tile p-3 p-sm-4 rounded d-flex flex-wrap align-items-center justify-content-center">
@if (isProcessing)
{
<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.
</div>
}
else if (!isSettled)
{
<div class="lead text-center p-4 fw-semibold" id="invoice-unsettled">
The invoice is not settled.
</div>
}
else
{
if (Model.ReceiptOptions.ShowQR is true)
{
<vc:qr-code data="@Context.Request.GetCurrentUrl()"></vc:qr-code>
}
<dl class="d-flex flex-column gap-4 mb-0 flex-fill">
<div class="d-flex flex-column">
<div class="d-flex align-items-center justify-content-between">
<a href="?print=true" class="btn btn-link p-0 d-print-none fw-semibold order-1" target="_blank">Print</a>
<dd class="text-muted mb-0 fw-semibold">Amount Paid</dd>
</div>
<dt class="fs-2 mb-0 text-nowrap fw-semibold">@DisplayFormatter.Currency(Model.Amount, Model.Currency, DisplayFormatter.CurrencyFormat.Symbol)</dt>
</div>
<div class="d-flex flex-column">
<dd class="text-muted mb-0 fw-semibold">Date</dd>
<dt class="fs-5 mb-0 text-nowrap fw-semibold">@Model.Timestamp.ToBrowserDate()</dt>
</div>
@if (!string.IsNullOrEmpty(Model.OrderId))
{
<div class="d-flex flex-column">
<dd class="text-muted mb-0 fw-semibold">Order ID</dd>
<dt class="fs-5 mb-0 text-break fw-semibold">@Model.OrderId</dt>
</div>
}
</dl>
}
</div>
<div id="InvoiceSummary" class="tile d-flex flex-wrap align-items-center justify-content-center">
@if (isProcessing)
{
<small class="d-block text-muted text-center px-4">This page will refresh periodically until the invoice is settled.</small>
<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.
</div>
}
else if (isSettled)
else if (!isSettled)
{
if (Model.AdditionalData?.Any() is true)
{
<div id="AdditionalData" class="bg-tile p-3 p-sm-4 rounded">
<h2 class="h4 mb-3">Additional Data</h2>
<div class="table-responsive my-0">
<partial name="PosData" model="(Model.AdditionalData, 1)"/>
</div>
</div>
}
if (Model.Payments?.Any() is true)
{
<div id="PaymentDetails" class="bg-tile p-3 p-sm-4 rounded">
<h2 class="h4 mb-3">Payment Details</h2>
<div class="table-responsive my-0 d-print-none">
<table class="invoice table table-borderless">
<thead>
<tr>
<th class="fw-normal text-secondary date-col w-125px">Date</th>
<th class="fw-normal text-secondary amount-col">Paid</th>
<th class="fw-normal text-secondary amount-col w-225px">Payment</th>
</tr>
</thead>
<tbody>
@foreach (var payment in Model.Payments)
{
<tr>
<td class="date-col">@payment.ReceivedDate.ToBrowserDate()</td>
<td class="amount-col">@payment.PaidFormatted</td>
<td class="amount-col">@payment.AmountFormatted @payment.PaymentMethod</td>
</tr>
@if (!string.IsNullOrEmpty(payment.Destination))
{
<tr>
<th class="fw-normal text-nowrap text-secondary">
Destination
</th>
<td class="fw-normal" colspan="2">
<vc:truncate-center text="@payment.Destination" classes="truncate-center-id" />
</td>
</tr>
}
@if (!string.IsNullOrEmpty(payment.PaymentProof))
{
<tr>
<th class="fw-normal text-nowrap text-secondary">
Payment Proof
</th>
<td class="fw-normal" colspan="2">
<vc:truncate-center text="@payment.PaymentProof" link="@payment.Link" classes="truncate-center-id" />
</td>
</tr>
}
}
</tbody>
</table>
</div>
<div class="d-none d-print-block">
@foreach (var payment in Model.Payments)
{
<div class="mb-4">
<strong>@payment.PaidFormatted</strong> = @payment.AmountFormatted @payment.PaymentMethod, Rate: @payment.RateFormatted
@if (!string.IsNullOrEmpty(payment.PaymentProof))
{
<div>Proof: @payment.PaymentProof</div>
}
</div>
}
</div>
</div>
}
<div class="lead text-center p-4 fw-semibold" id="invoice-unsettled">
The invoice is not settled.
</div>
}
@if (!string.IsNullOrEmpty(Model.OrderUrl))
else
{
<a href="@Model.OrderUrl" class="btn btn-secondary rounded-pill mx-auto mt-3" rel="noreferrer noopener" target="_blank">Return to @(string.IsNullOrEmpty(Model.StoreName) ? "store" : Model.StoreName)</a>
if (Model.ReceiptOptions.ShowQR is true)
{
<vc:qr-code data="@Context.Request.GetCurrentUrl()"></vc:qr-code>
}
<dl class="d-flex flex-column gap-4 mb-0 flex-fill">
<div class="d-flex flex-column">
<div class="d-flex align-items-center justify-content-between gap-3">
<a href="?print=true" class="btn btn-link p-0 d-print-none fw-semibold order-1" target="_blank">Print</a>
<dd class="text-muted mb-0 fw-semibold">Amount Paid</dd>
</div>
<dt class="fs-2 mb-0 text-nowrap fw-semibold">@DisplayFormatter.Currency(Model.Amount, Model.Currency, DisplayFormatter.CurrencyFormat.Symbol)</dt>
</div>
<div class="d-flex flex-column">
<dd class="text-muted mb-0 fw-semibold">Date</dd>
<dt class="fs-5 mb-0 text-nowrap fw-semibold">@Model.Timestamp.ToBrowserDate()</dt>
</div>
@if (!string.IsNullOrEmpty(Model.OrderId))
{
<div class="d-flex flex-column">
<dd class="text-muted mb-0 fw-semibold">Order ID</dd>
<dt class="fs-5 mb-0 text-break fw-semibold">@Model.OrderId</dt>
</div>
}
</dl>
}
</div>
@if (isProcessing)
{
<small class="d-block text-muted text-center px-4">This page will refresh periodically until the invoice is settled.</small>
}
else if (isSettled)
{
if (Model.AdditionalData?.Any() is true)
{
<div id="AdditionalData" class="tile">
<h2 class="h4 mb-3">Additional Data</h2>
<div class="table-responsive my-0">
<partial name="PosData" model="(Model.AdditionalData, 1)"/>
</div>
</div>
}
if (Model.Payments?.Any() is true)
{
<div id="PaymentDetails" class="tile">
<h2 class="h4 mb-3">Payment Details</h2>
<div class="table-responsive my-0 d-print-none">
<table class="invoice table table-borderless">
<thead>
<tr>
<th class="fw-normal text-secondary date-col w-125px">Date</th>
<th class="fw-normal text-secondary amount-col">Paid</th>
<th class="fw-normal text-secondary amount-col w-225px">Payment</th>
</tr>
</thead>
@foreach (var payment in Model.Payments)
{
<tbody>
<tr>
<td class="date-col">@payment.ReceivedDate.ToBrowserDate()</td>
<td class="amount-col">@payment.PaidFormatted</td>
<td class="amount-col">@payment.AmountFormatted @payment.PaymentMethod</td>
</tr>
@if (!string.IsNullOrEmpty(payment.Destination))
{
<tr>
<th class="fw-normal text-nowrap text-secondary">
Destination
</th>
<td class="fw-normal" colspan="2">
<vc:truncate-center text="@payment.Destination" classes="truncate-center-id" />
</td>
</tr>
}
@if (!string.IsNullOrEmpty(payment.PaymentProof))
{
<tr>
<th class="fw-normal text-nowrap text-secondary">
Payment Proof
</th>
<td class="fw-normal" colspan="2">
<vc:truncate-center text="@payment.PaymentProof" link="@payment.Link" classes="truncate-center-id" />
</td>
</tr>
}
</tbody>
}
</table>
</div>
<div class="d-none d-print-block">
@foreach (var payment in Model.Payments)
{
<div class="mb-4">
<strong>@payment.PaidFormatted</strong> = @payment.Amount @payment.PaymentMethod, Rate: @payment.RateFormatted
@if (!string.IsNullOrEmpty(payment.PaymentProof))
{
<div>Proof: @payment.PaymentProof</div>
}
</div>
}
</div>
</div>
}
}
@if (!string.IsNullOrEmpty(Model.OrderUrl))
{
<a href="@Model.OrderUrl" class="btn btn-secondary rounded-pill mx-auto mt-3" rel="noreferrer noopener" target="_blank">Return to @(string.IsNullOrEmpty(Model.StoreName) ? "store" : Model.StoreName)</a>
}
</div>
</main>
<footer class="store-footer">

View file

@ -1,15 +1,9 @@
#Checkout-v2 {
--navbutton-size: .8rem;
--section-padding: 1.5rem;
--border-radius: var(--btcpay-border-radius-l);
--wrap-max-width: 400px;
}
body {
overflow-x: hidden;
}
.public-page-wrap {
max-width: var(--wrap-max-width);
}
main {
position: relative;
border-radius: var(--border-radius);
@ -35,12 +29,10 @@ nav button#close {
right: 0;
}
nav button .icon {
--navbutton-size: .8rem;
width: var(--navbutton-size);
height: var(--navbutton-size);
}
section {
padding: var(--section-padding);
}
section h4 {
margin-bottom: var(--btcpay-space-l);
font-weight: var(--btcpay-font-weight-semibold);
@ -170,12 +162,6 @@ section dl > div dd {
color: var(--btcpay-body-text-hover);
}
@media (max-width: 400px) {
main {
border-radius: 0;
}
}
/* Modal adjustments */
.checkout-modal body {
background: rgba(var(--btcpay-black-rgb), 0.85);

View file

@ -660,12 +660,12 @@ input:checked + label.btcpay-list-select-item {
min-height: 100dvh !important;
}
.tile {
--section-padding: 1.5rem;
--section-border-radius: var(--btcpay-border-radius-l);
--tile-padding: 1.5rem;
--tile-border-radius: var(--btcpay-border-radius-l);
padding: var(--section-padding);
padding: var(--tile-padding);
background: var(--btcpay-bg-tile);
border-radius: var(--section-border-radius);
border-radius: var(--tile-border-radius);
box-shadow: var(--btcpay-box-shadow-lg);
}
.tile .buttons {
@ -683,8 +683,8 @@ input:checked + label.btcpay-list-select-item {
--wrap-padding-horizontal: 0;
}
.tile {
--section-padding: 1rem;
--section-border-radius: none;
--tile-padding: 1rem;
--tile-border-radius: none;
}
}

View file

@ -3,12 +3,13 @@
}
#PosCart .public-page-wrap {
--wrap-max-width: 1320px;
padding-top: 0;
}
@media (max-width: 400px) {
#PosCart .public-page-wrap {
padding-left: var(--btcpay-space-s);
padding-right: var(--btcpay-space-s);
--wrap-padding-horizontal: var(--btcpay-space-s);
}
}

View file

@ -1,3 +1,8 @@
#PosPrint,
#PosStatic {
--wrap-max-width: 1320px;
}
.lead {
max-width: 36em;
text-align: center;

View file

@ -1,6 +1,5 @@
.public-page-wrap {
max-width: 560px;
overflow: hidden;
#PosKeypad {
--wrap-max-width: 575px;
}
/* modes */
@ -66,9 +65,9 @@
}
}
@media (max-width: 575px) {
.public-page-wrap {
padding-right: 0;
padding-left: 0;
#PosKeypad {
--wrap-padding-horizontal: 0;
overflow: hidden;
}
.keypad {
margin-left: -1px;

View file

@ -1,7 +1,7 @@
document.addEventListener("DOMContentLoaded",function () {
const displayFontSize = 64;
new Vue({
el: '#PosKeypad',
el: '#app',
mixins: [posCommon],
data () {
return {