Adapt desktop breakpoints in views (#3358)

* Add XXL breakpoint

* Unify setup guide display

* Adapt desktop breakpoints in views

* Fix POS code display

* Fix syntax in home view

* store settings + constrain update

* account settings

Co-authored-by: dstrukt <gfxdsign@gmail.com>
Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
This commit is contained in:
d11n 2022-01-27 03:56:46 +01:00 committed by GitHub
parent 4aacd0d23a
commit cbf8b23385
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 1272 additions and 488 deletions

View file

@ -1,7 +1,7 @@
@model BTCPayServer.Models.ServerViewModels.EmailsViewModel @model BTCPayServer.Models.ServerViewModels.EmailsViewModel
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<div class="d-flex align-items-center justify-content-between mb-4"> <div class="d-flex align-items-center justify-content-between mb-4">
<h3 class="mb-0">@ViewData["Title"]</h3> <h3 class="mb-0">@ViewData["Title"]</h3>
<div class="dropdown only-for-js" id="quick-fill"> <div class="dropdown only-for-js" id="quick-fill">
@ -22,7 +22,7 @@
<form method="post" autocomplete="off"> <form method="post" autocomplete="off">
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
@if (!ViewContext.ModelState.IsValid) @if (!ViewContext.ModelState.IsValid)
{ {
<div asp-validation-summary="All" class="text-danger"></div> <div asp-validation-summary="All" class="text-danger"></div>
@ -80,7 +80,7 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-xl-8 col-xxl-constrain">
<div class="form-group"> <div class="form-group">
<h3 class="mt-5 mb-3">Testing</h3> <h3 class="mt-5 mb-3">Testing</h3>
<p> <p>

View file

@ -12,7 +12,7 @@
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2> <h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<form asp-action="CreateApp"> <form asp-action="CreateApp">
<div asp-validation-summary="ModelOnly" class="text-danger"></div> <div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group"> <div class="form-group">

View file

@ -23,7 +23,7 @@
<div asp-validation-summary="ModelOnly" class="text-danger"></div> <div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<div class="form-group"> <div class="form-group">
<label asp-for="AppName" class="form-label" data-required></label> <label asp-for="AppName" class="form-label" data-required></label>
<input asp-for="AppName" class="form-control" required /> <input asp-for="AppName" class="form-control" required />
@ -40,14 +40,14 @@
<span asp-validation-for="Tagline" class="text-danger"></span> <span asp-validation-for="Tagline" class="text-danger"></span>
</div> </div>
</div> </div>
<div class="col-lg-9"> <div class="col-xl-10 col-xxl-constrain">
<div class="form-group"> <div class="form-group">
<label asp-for="Description" class="form-label" data-required></label> <label asp-for="Description" class="form-label" data-required></label>
<textarea asp-for="Description" rows="20" cols="40" class="form-control richtext"></textarea> <textarea asp-for="Description" rows="20" cols="40" class="form-control richtext"></textarea>
<span asp-validation-for="Description" class="text-danger"></span> <span asp-validation-for="Description" class="text-danger"></span>
</div> </div>
</div> </div>
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<div class="form-group"> <div class="form-group">
<label asp-for="TargetCurrency" class="form-label"></label> <label asp-for="TargetCurrency" class="form-label"></label>
<input asp-for="TargetCurrency" class="form-control" placeholder="Use store's default settings" /> <input asp-for="TargetCurrency" class="form-control" placeholder="Use store's default settings" />
@ -106,10 +106,10 @@
<div class="text-muted" hidden="@(!Model.Enabled)">The crowdfund is visible to anyone. To make it only visible to you, disable this.</div> <div class="text-muted" hidden="@(!Model.Enabled)">The crowdfund is visible to anyone. To make it only visible to you, disable this.</div>
</div> </div>
</div> </div>
<div class="col-lg-12"> <div class="col-xxl-constrain">
<partial name="TemplateEditor" model="@(nameof(Model.PerksTemplate), "Perks")" /> <partial name="TemplateEditor" model="@(nameof(Model.PerksTemplate), "Perks")" />
</div> </div>
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<div class="form-group"> <div class="form-group">
<label asp-for="PerksTemplate" class="form-label"></label> <label asp-for="PerksTemplate" class="form-label"></label>
<textarea asp-for="PerksTemplate" rows="10" cols="40" class="js-product-template form-control"></textarea> <textarea asp-for="PerksTemplate" rows="10" cols="40" class="js-product-template form-control"></textarea>

View file

@ -14,7 +14,7 @@
<div asp-validation-summary="ModelOnly" class="text-danger"></div> <div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<div class="form-group"> <div class="form-group">
<label asp-for="AppName" class="form-label" data-required></label> <label asp-for="AppName" class="form-label" data-required></label>
<input asp-for="AppName" class="form-control" required /> <input asp-for="AppName" class="form-control" required />
@ -31,14 +31,14 @@
<span asp-validation-for="Currency" class="text-danger"></span> <span asp-validation-for="Currency" class="text-danger"></span>
</div> </div>
</div> </div>
<div class="col-lg-9"> <div class="col-xl-10 col-xxl-constrain">
<div class="form-group"> <div class="form-group">
<label asp-for="Description" class="form-label"></label> <label asp-for="Description" class="form-label"></label>
<textarea asp-for="Description" rows="10" cols="40" class="form-control richtext"></textarea> <textarea asp-for="Description" rows="10" cols="40" class="form-control richtext"></textarea>
<span asp-validation-for="Description" class="text-danger"></span> <span asp-validation-for="Description" class="text-danger"></span>
</div> </div>
</div> </div>
<div class="col-lg-12"> <div class="col-xxl-constrain">
<partial name="TemplateEditor" model="@(nameof(Model.Template), "Products")" /> <partial name="TemplateEditor" model="@(nameof(Model.Template), "Products")" />
<div class="form-group"> <div class="form-group">
<label asp-for="Template" class="form-label"></label> <label asp-for="Template" class="form-label"></label>
@ -46,7 +46,7 @@
<span asp-validation-for="Template" class="text-danger"></span> <span asp-validation-for="Template" class="text-danger"></span>
</div> </div>
</div> </div>
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<h3 class="mt-5 mb-4">Appearance</h3> <h3 class="mt-5 mb-4">Appearance</h3>
<div class="form-group"> <div class="form-group">
<label asp-for="DefaultView" class="form-label" data-required></label> <label asp-for="DefaultView" class="form-label" data-required></label>
@ -113,7 +113,7 @@
</div> </div>
</section> </section>
</div> </div>
<div class="col-lg-9"> <div class="col-xl-8 col-xxl-constrain">
<h3 class="mt-5 mb-2">Additional Options</h3> <h3 class="mt-5 mb-2">Additional Options</h3>
<div class="form-group"> <div class="form-group">
<div class="accordion" id="additional"> <div class="accordion" id="additional">
@ -130,12 +130,12 @@
@if (Model.Example1 != null) @if (Model.Example1 != null)
{ {
<span>For anything with a custom amount</span> <span>For anything with a custom amount</span>
<pre><code class="html">@Model.Example1</code></pre> <pre class="p-3">@Model.Example1</pre>
} }
@if (Model.Example2 != null) @if (Model.Example2 != null)
{ {
<span>For a specific item of your template</span> <span>For a specific item of your template</span>
<pre><code class="html">@Model.Example2</code></pre> <pre class="p-3">@Model.Example2</pre>
} }
</div> </div>
</div> </div>
@ -153,7 +153,7 @@
@{ @{
var iframe = $"<iframe src='{(Url.Action("ViewPointOfSale", "UIAppsPublic", new { appId = Model.Id }, Context.Request.Scheme))}' style='max-width: 100%; border: 0;'></iframe>"; var iframe = $"<iframe src='{(Url.Action("ViewPointOfSale", "UIAppsPublic", new { appId = Model.Id }, Context.Request.Scheme))}' style='max-width: 100%; border: 0;'></iframe>";
} }
<pre><code class="html">@iframe</code></pre> <pre class="p-3">@iframe</pre>
</div> </div>
</div> </div>
</div> </div>
@ -194,7 +194,7 @@
<span asp-validation-for="NotificationUrl" class="text-danger"></span> <span asp-validation-for="NotificationUrl" class="text-danger"></span>
</div> </div>
<p>A <code>POST</code> callback will be sent to notification with the following form will be sent to <code>notificationUrl</code> once the enough is paid and once again once there is enough confirmations to the payment:</p> <p>A <code>POST</code> callback will be sent to notification with the following form will be sent to <code>notificationUrl</code> once the enough is paid and once again once there is enough confirmations to the payment:</p>
<pre><code class="json">@Model.ExampleCallback</code></pre> <pre class="p-3">@Model.ExampleCallback</pre>
<p><strong>Never</strong> trust anything but <code>id</code>, <strong>ignore</strong> the other fields completely, an attacker can spoof those, they are present only for backward compatibility reason:</p> <p><strong>Never</strong> trust anything but <code>id</code>, <strong>ignore</strong> the other fields completely, an attacker can spoof those, they are present only for backward compatibility reason:</p>
<p> <p>
<ul> <ul>

View file

@ -12,7 +12,7 @@
<input type="hidden" name="name" id="name" value="@(ViewData.ContainsKey("CredentialName") ? ViewData["CredentialName"] : string.Empty)"/> <input type="hidden" name="name" id="name" value="@(ViewData.ContainsKey("CredentialName") ? ViewData["CredentialName"] : string.Empty)"/>
</form> </form>
<div class="row"> <div class="row">
<div class="col-lg-8"> <div class="col-xl-8">
<div id="info-message" class="alert alert-info mb-3 d-none"> <div id="info-message" class="alert alert-info mb-3 d-none">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span id="spinner" class="fa fa-spinner fa-spin me-3 fido-running" style="font-size:1.5rem"></span> <span id="spinner" class="fa fa-spinner fa-spin me-3 fido-running" style="font-size:1.5rem"></span>

View file

@ -3,48 +3,21 @@
ViewData["Title"] = "BTCPay Server"; ViewData["Title"] = "BTCPay Server";
} }
@section PageHeadContent
{
<style>
.list-group-item .image {
display: flex;
flex: 0 0 1rem;
align-items: center;
justify-content: center;
}
.list-group-item .icon {
width: 1.5rem;
height: 1.5rem;
margin: 1rem;
}
.list-group-item .content {
flex: 1;
padding: 1rem 0;
}
</style>
}
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<h2>Welcome to your BTCPay Server</h2> <h2>Welcome to your BTCPay Server</h2>
@if (!Model.HasStore) @if (!Model.HasStore)
{ {
<div class="row"> <p class="lead text-secondary">To start accepting payments, set up a store.</p>
<div class="col-lg-9 col-xl-6">
<p class="lead text-secondary">To start accepting payments, set up a store.</p> <div class="list-group mt-4" id="SetupGuide">
<a asp-controller="UIUserStores" asp-action="CreateStore" id="SetupGuide-Store" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="list-group mt-4" id="SetupGuide"> <vc:icon symbol="new-store"/>
<a asp-controller="UIUserStores" asp-action="CreateStore" id="SetupGuide-Store" class="list-group-item list-group-item-action d-flex align-items-center"> <div class="content">
<vc:icon symbol="new-store"/> <h5 class="mb-0">Create your store</h5>
<div class="content">
<h5 class="mb-0">Create your store</h5>
</div>
<vc:icon symbol="caret-right"/>
</a>
</div> </div>
</div> <vc:icon symbol="caret-right"/>
</a>
</div> </div>
} }

View file

@ -30,7 +30,7 @@
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2> <h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<form asp-action="CreateInvoice" method="post" id="create-invoice-form"> <form asp-action="CreateInvoice" method="post" id="create-invoice-form">
<div asp-validation-summary="ModelOnly" class="text-danger"></div> <div asp-validation-summary="ModelOnly" class="text-danger"></div>
@if (Model.StoreId != null) @if (Model.StoreId != null)

View file

@ -43,8 +43,8 @@
<div class="invoice-details"> <div class="invoice-details">
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<div class="row mb-5"> <div class="row mb-5">
<h2 class="col-xs-12 col-lg-6 mb-4 mb-lg-0">@ViewData["Title"]</h2> <h2 class="col col-xl-6 mb-4 mb-xl-0">@ViewData["Title"]</h2>
<div class="col-xs-12 col-lg-6 mb-2 mb-lg-0 text-lg-end"> <div class="col col-xl-6 mb-2 mb-xl-0 text-xl-end">
<div class="d-inline-flex"> <div class="d-inline-flex">
@if (Model.ShowCheckout) @if (Model.ShowCheckout)
{ {

View file

@ -3,79 +3,84 @@
@{ @{
ViewData.SetActivePage(ManageNavPages.APIKeys, "API Keys"); ViewData.SetActivePage(ManageNavPages.APIKeys, "API Keys");
} }
<div class="d-flex align-items-center justify-content-between mb-3">
<h3 class="mb-0">@ViewData["Title"]</h3>
<a class="btn btn-primary" asp-action="AddApiKey" id="AddApiKey">
<span class="fa fa-plus"></span>
Generate Key
</a>
</div>
<p>
The <a asp-controller="UIHome" asp-action="SwaggerDocs" target="_blank">BTCPay Server Greenfield API</a> offers programmatic access to your instance. You can manage your BTCPay
Server (e.g. stores, invoices, users) as well as automate workflows and integrations (see <a href="https://docs.btcpayserver.org/Development/GreenFieldExample/" rel="noreferrer noopener">use case examples</a>).
For that you need the API keys, which can be generated here. Find more information in the <a href="@Url.Action("SwaggerDocs", "UIHome")#section/Authentication" target="_blank" rel="noreferrer noopener">API authentication docs</a>.
</p>
@if (Model.ApiKeyDatas.Any()) <div class="row">
{ <div class="col-xl-8 col-xxl-constrain">
<table class="table table-lg"> <div class="d-flex align-items-center justify-content-between mb-3">
<thead> <h3 class="mb-0">@ViewData["Title"]</h3>
<tr> <a class="btn btn-primary" asp-action="AddApiKey" id="AddApiKey">
<th>Label</th> <span class="fa fa-plus"></span>
<th class="w-125px">Key</th> Generate Key
<th>Permissions</th> </a>
<th class="text-end">Actions</th> </div>
</tr> <p>
</thead> The <a asp-controller="UIHome" asp-action="SwaggerDocs" target="_blank">BTCPay Server Greenfield API</a> offers programmatic access to your instance. You can manage your BTCPay
<tbody> Server (e.g. stores, invoices, users) as well as automate workflows and integrations (see <a href="https://docs.btcpayserver.org/Development/GreenFieldExample/" rel="noreferrer noopener">use case examples</a>).
@{ For that you need the API keys, which can be generated here. Find more information in the <a href="@Url.Action("SwaggerDocs", "UIHome")#section/Authentication" target="_blank" rel="noreferrer noopener">API authentication docs</a>.
var index = 0; </p>
}
@foreach (var keyData in Model.ApiKeyDatas) @if (Model.ApiKeyDatas.Any())
{ {
<tr> <table class="table table-lg">
<td>@keyData.Label</td> <thead>
<td> <tr>
<code class="hide-when-js">@keyData.Id</code> <th>Label</th>
<a class="only-for-js" data-reveal-btn>Click to reveal</a> <th class="w-125px">Key</th>
<div hidden> <th>Permissions</th>
<code data-api-key>@keyData.Id</code> <th class="text-end">Actions</th>
<a class="mt-2" data-clipboard-confirm> </tr>
Copy to clipboard </thead>
</a> <tbody>
</div> @{
</td> var index = 0;
<td> }
@{ @foreach (var keyData in Model.ApiKeyDatas)
var permissions = keyData.GetBlob().Permissions; {
} <tr>
@if (!permissions.Any()) <td>@keyData.Label</td>
{ <td>
<span class="text-warning">No permissions</span> <code class="hide-when-js">@keyData.Id</code>
} <a class="only-for-js" data-reveal-btn>Click to reveal</a>
else <div hidden>
{ <code data-api-key>@keyData.Id</code>
<ul> <a class="mt-2" data-clipboard-confirm>
@foreach (var permission in Permission.ToPermissions(permissions).Select(c => c.ToString()).Distinct().ToArray()) Copy to clipboard
{ </a>
<li> </div>
<code class="text-break">@permission</code> </td>
</li> <td>
@{
var permissions = keyData.GetBlob().Permissions;
} }
</ul> @if (!permissions.Any())
} {
</td> <span class="text-warning">No permissions</span>
<td class="text-end"> }
<a asp-action="DeleteAPIKey" asp-route-id="@keyData.Id" asp-controller="UIManage" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="Any application using the API key <strong>@(keyData.Label ?? keyData.Id)<strong> will immediately lose access." data-confirm-input="DELETE">Delete</a> else
<span>-</span> {
<button type="button" class="btn btn-link only-for-js p-0" data-qr="@index">Show QR</button> <ul>
</td> @foreach (var permission in Permission.ToPermissions(permissions).Select(c => c.ToString()).Distinct().ToArray())
</tr> {
index++; <li>
} <code class="text-break">@permission</code>
</tbody> </li>
</table> }
} </ul>
}
</td>
<td class="text-end">
<a asp-action="DeleteAPIKey" asp-route-id="@keyData.Id" asp-controller="UIManage" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="Any application using the API key <strong>@(keyData.Label ?? keyData.Id)<strong> will immediately lose access." data-confirm-input="DELETE">Delete</a>
<span>-</span>
<button type="button" class="btn btn-link only-for-js p-0" data-qr="@index">Show QR</button>
</td>
</tr>
index++;
}
</tbody>
</table>
}
</div>
</div>
<partial name="_Confirm" model="@(new ConfirmModel("Delete API key", "Any application using the API key will immediately lose access.", "Delete"))" /> <partial name="_Confirm" model="@(new ConfirmModel("Delete API key", "Any application using the API key will immediately lose access.", "Delete"))" />

View file

@ -1,6 +1,5 @@
@using BTCPayServer.Client @using BTCPayServer.Client
@using BTCPayServer.Controllers @using BTCPayServer.Controllers
@using BTCPayServer.Security.Greenfield
@model UIManageController.AddApiKeyViewModel @model UIManageController.AddApiKeyViewModel
@{ @{
@ -28,109 +27,113 @@
<h3 class="mb-3">@ViewData["Title"]</h3> <h3 class="mb-3">@ViewData["Title"]</h3>
<p>Generate a new api key to use BTCPay through its API.</p> <div class="row">
<div class="col-xl-8 col-xxl-constrain">
<form method="post" asp-action="AddApiKey"> <p>Generate a new api key to use BTCPay through its API.</p>
<div asp-validation-summary="All" class="text-danger"></div>
<form method="post" asp-action="AddApiKey">
<div class="form-group"> <div asp-validation-summary="All" class="text-danger"></div>
<label asp-for="Label" class="form-label"></label>
<input asp-for="Label" class="form-control"/> <div class="form-group">
<span asp-validation-for="Label" class="text-danger"></span> <label asp-for="Label" class="form-label"></label>
</div> <input asp-for="Label" class="form-control"/>
<span asp-validation-for="Label" class="text-danger"></span>
<h5 class="mt-4 mb-3">Permissions</h5> </div>
<div class="list-group mb-4">
@for (int i = 0; i < Model.PermissionValues.Count; i++) <h5 class="mt-4 mb-3">Permissions</h5>
{ <div class="list-group mb-4">
@if (Model.PermissionValues[i].Forbidden) @for (int i = 0; i < Model.PermissionValues.Count; i++)
{ {
<input type="hidden" asp-for="PermissionValues[i].Value" value="false" /> @if (Model.PermissionValues[i].Forbidden)
}
else
{
<div class="list-group-item py-3">
<input type="hidden" asp-for="PermissionValues[i].Permission" />
@if (Policies.IsStorePolicy(Model.PermissionValues[i].Permission))
{ {
<input type="hidden" asp-for="PermissionValues[i].StoreMode" value="@Model.PermissionValues[i].StoreMode" /> <input type="hidden" asp-for="PermissionValues[i].Value" value="false" />
@if (Model.PermissionValues[i].StoreMode == UIManageController.AddApiKeyViewModel.ApiKeyStoreMode.AllStores)
{
<div class="form-check">
<input id="@Model.PermissionValues[i].Permission" type="checkbox" asp-for="PermissionValues[i].Value" class="form-check-input ms-n4"/>
<label for="@Model.PermissionValues[i].Permission" class="h5 form-check-label me-2 mb-1">
<span class="me-lg-1">@Model.PermissionValues[i].Title</span>
<small class="text-muted text-break d-block my-2 d-lg-inline-block my-lg-0">@Model.PermissionValues[i].Permission</small>
</label>
<div>
<span asp-validation-for="PermissionValues[i].Value" class="text-danger"></span>
<div class="text-muted">@Model.PermissionValues[i].Description</div>
@if (Model.Stores.Any())
{
<button type="submit" class="btn btn-link p-0" name="command" value="@($"{Model.PermissionValues[i].Permission}:change-store-mode")">Select specific stores</button>
}
</div>
</div>
}
else
{
<h5 class="mb-1" id="@Model.PermissionValues[i].Permission">
<span class="me-lg-1">@Model.PermissionValues[i].Title</span>
<small class="text-muted text-break d-block my-2 d-lg-inline-block my-lg-0">@Model.PermissionValues[i].Permission</small>
</h5>
<div class="text-muted">@Model.PermissionValues[i].Description</div>
<button type="submit" class="btn btn-link p-0" name="command" value="@($"{Model.PermissionValues[i].Permission}:change-store-mode")">Give permission to all stores instead</button>
@if (!Model.Stores.Any())
{
<p class="text-warning mt-2 mb-0">
You currently have no stores configured.
</p>
}
@for (var index = 0; index < Model.PermissionValues[i].SpecificStores.Count; index++)
{
<div class="input-group my-3">
@if (Model.PermissionValues[i].SpecificStores[index] == null)
{
<select asp-for="PermissionValues[i].SpecificStores[index]" class="form-select w-auto flex-grow-0" asp-items="@(new SelectList(Model.Stores.Where(data => !Model.PermissionValues[i].SpecificStores.Contains(data.Id)), nameof(StoreData.Id), nameof(StoreData.StoreName)))"></select>
}
else
{
var store = Model.Stores.SingleOrDefault(data => data.Id == Model.PermissionValues[i].SpecificStores[index]);
<select asp-for="PermissionValues[i].SpecificStores[index]" class="form-select w-auto flex-grow-0" asp-items="@(new SelectList(new[] {store}, nameof(StoreData.Id), nameof(StoreData.StoreName), store.Id))"></select>
}
<span asp-validation-for="PermissionValues[i].SpecificStores[index]" class="text-danger"></span>
<button type="submit" title="Remove Store Permission" name="command" value="@($"{Model.PermissionValues[i].Permission}:remove-store:{index}")" class="btn btn-danger">
Remove
</button>
</div>
}
@if (Model.PermissionValues[i].SpecificStores.Count < Model.Stores.Length)
{
<div class="mt-3 mb-2">
<button type="submit" name="command" value="@($"{Model.PermissionValues[i].Permission}:add-store")" class="btn btn-secondary">Add another store</button>
</div>
}
}
} }
else else
{ {
<div class="form-check"> <div class="list-group-item py-3">
<input id="@Model.PermissionValues[i].Permission" type="checkbox" asp-for="PermissionValues[i].Value" class="form-check-input ms-n4" /> <input type="hidden" asp-for="PermissionValues[i].Permission" />
<label for="@Model.PermissionValues[i].Permission" class="h5 form-check-label me-2 mb-1"> @if (Policies.IsStorePolicy(Model.PermissionValues[i].Permission))
<span class="me-lg-1">@Model.PermissionValues[i].Title</span> {
<small class="text-muted text-break d-block my-2 d-lg-inline-block my-lg-0">@Model.PermissionValues[i].Permission</small> <input type="hidden" asp-for="PermissionValues[i].StoreMode" value="@Model.PermissionValues[i].StoreMode" />
</label> @if (Model.PermissionValues[i].StoreMode == UIManageController.AddApiKeyViewModel.ApiKeyStoreMode.AllStores)
<div> {
<span asp-validation-for="PermissionValues[i].Value" class="text-danger"></span> <div class="form-check">
<span class="text-muted">@Model.PermissionValues[i].Description</span> <input id="@Model.PermissionValues[i].Permission" type="checkbox" asp-for="PermissionValues[i].Value" class="form-check-input ms-n4"/>
</div> <label for="@Model.PermissionValues[i].Permission" class="h5 form-check-label me-2 mb-1">
</div> <span class="me-lg-1">@Model.PermissionValues[i].Title</span>
<small class="text-muted text-break d-block my-2 d-lg-inline-block my-lg-0">@Model.PermissionValues[i].Permission</small>
</label>
<div>
<span asp-validation-for="PermissionValues[i].Value" class="text-danger"></span>
<div class="text-muted">@Model.PermissionValues[i].Description</div>
@if (Model.Stores.Any())
{
<button type="submit" class="btn btn-link p-0" name="command" value="@($"{Model.PermissionValues[i].Permission}:change-store-mode")">Select specific stores</button>
}
</div>
</div>
}
else
{
<h5 class="mb-1" id="@Model.PermissionValues[i].Permission">
<span class="me-lg-1">@Model.PermissionValues[i].Title</span>
<small class="text-muted text-break d-block my-2 d-lg-inline-block my-lg-0">@Model.PermissionValues[i].Permission</small>
</h5>
<div class="text-muted">@Model.PermissionValues[i].Description</div>
<button type="submit" class="btn btn-link p-0" name="command" value="@($"{Model.PermissionValues[i].Permission}:change-store-mode")">Give permission to all stores instead</button>
@if (!Model.Stores.Any())
{
<p class="text-warning mt-2 mb-0">
You currently have no stores configured.
</p>
}
@for (var index = 0; index < Model.PermissionValues[i].SpecificStores.Count; index++)
{
<div class="input-group my-3">
@if (Model.PermissionValues[i].SpecificStores[index] == null)
{
<select asp-for="PermissionValues[i].SpecificStores[index]" class="form-select w-auto flex-grow-0" asp-items="@(new SelectList(Model.Stores.Where(data => !Model.PermissionValues[i].SpecificStores.Contains(data.Id)), nameof(StoreData.Id), nameof(StoreData.StoreName)))"></select>
}
else
{
var store = Model.Stores.SingleOrDefault(data => data.Id == Model.PermissionValues[i].SpecificStores[index]);
<select asp-for="PermissionValues[i].SpecificStores[index]" class="form-select w-auto flex-grow-0" asp-items="@(new SelectList(new[] {store}, nameof(StoreData.Id), nameof(StoreData.StoreName), store.Id))"></select>
}
<span asp-validation-for="PermissionValues[i].SpecificStores[index]" class="text-danger"></span>
<button type="submit" title="Remove Store Permission" name="command" value="@($"{Model.PermissionValues[i].Permission}:remove-store:{index}")" class="btn btn-danger">
Remove
</button>
</div>
}
@if (Model.PermissionValues[i].SpecificStores.Count < Model.Stores.Length)
{
<div class="mt-3 mb-2">
<button type="submit" name="command" value="@($"{Model.PermissionValues[i].Permission}:add-store")" class="btn btn-secondary">Add another store</button>
</div>
}
}
}
else
{
<div class="form-check">
<input id="@Model.PermissionValues[i].Permission" type="checkbox" asp-for="PermissionValues[i].Value" class="form-check-input ms-n4" />
<label for="@Model.PermissionValues[i].Permission" class="h5 form-check-label me-2 mb-1">
<span class="me-lg-1">@Model.PermissionValues[i].Title</span>
<small class="text-muted text-break d-block my-2 d-lg-inline-block my-lg-0">@Model.PermissionValues[i].Permission</small>
</label>
<div>
<span asp-validation-for="PermissionValues[i].Value" class="text-danger"></span>
<span class="text-muted">@Model.PermissionValues[i].Description</span>
</div>
</div>
}
</div>
} }
</div> }
} </div>
}
<button type="submit" class="btn btn-primary" id="Generate">Generate API Key</button>
</form>
</div> </div>
</div>
<button type="submit" class="btn btn-primary" id="Generate">Generate API Key</button>
</form>

View file

@ -4,7 +4,7 @@
} }
<h3 class="mb-4">@ViewData["Title"]</h3> <h3 class="mb-4">@ViewData["Title"]</h3>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-xl-8 col-xxl-constrain">
@if (!ViewContext.ModelState.IsValid) @if (!ViewContext.ModelState.IsValid)
{ {
<div asp-validation-summary="All" class="text-danger"></div> <div asp-validation-summary="All" class="text-danger"></div>

View file

@ -3,7 +3,7 @@
ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, "Enable authenticator app"); ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, "Enable authenticator app");
} }
<div> <div class="col-xl-8 col-xxl-constrain">
<h3>Enable Authenticator</h3> <h3>Enable Authenticator</h3>
<p class="my-3">To use an authenticator app go through the following steps:</p> <p class="my-3">To use an authenticator app go through the following steps:</p>
<ol class="list"> <ol class="list">
@ -36,22 +36,18 @@
Your two-factor authenticator app will provide you with a unique code. Your two-factor authenticator app will provide you with a unique code.
<br/> <br/>
Enter the code in the confirmation box below. Enter the code in the confirmation box below.
</p> </p>
<div class="row"> <form method="post">
<div class="col-md-6"> <input asp-for="AuthenticatorUri" type="hidden" />
<form method="post"> <input asp-for="SharedKey" type="hidden" />
<input asp-for="AuthenticatorUri" type="hidden" /> <div class="form-group">
<input asp-for="SharedKey" type="hidden" /> <label asp-for="Code" class="form-label">Verification Code</label>
<div class="form-group"> <input asp-for="Code" class="form-control" autocomplete="off" />
<label asp-for="Code" class="form-label">Verification Code</label> <span asp-validation-for="Code" class="text-danger"></span>
<input asp-for="Code" class="form-control" autocomplete="off" />
<span asp-validation-for="Code" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary mt-2">Verify</button>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
</form>
</div> </div>
</div> <button type="submit" class="btn btn-primary mt-2">Verify</button>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
</form>
</li> </li>
</ol> </ol>
</div> </div>

View file

@ -3,43 +3,46 @@
ViewData.SetActivePage(ManageNavPages.Index, "Update your account"); ViewData.SetActivePage(ManageNavPages.Index, "Update your account");
} }
<h3 class="mb-4">@ViewData["Title"]</h3> <h3 class="mb-4">@ViewData["Title"]</h3>
<form method="post">
@if (!ViewContext.ModelState.IsValid) <div class="col-xxl-constrain col-xl-8">
{ <form method="post">
<div asp-validation-summary="All" class="text-danger"></div> @if (!ViewContext.ModelState.IsValid)
} {
<div class="form-group row"> <div asp-validation-summary="All" class="text-danger"></div>
<div class="col-md-6 mb-3"> }
<label asp-for="Username" class="form-label"></label> <div class="form-group row">
<input asp-for="Username" class="form-control" disabled/> <div class="col-md-6 mb-3">
<label asp-for="Username" class="form-label"></label>
<input asp-for="Username" class="form-control" disabled />
</div>
</div> </div>
</div> <div class="form-group row">
<div class="form-group row"> <div class="col-md-6 mb-3">
<div class="col-md-6 mb-3"> <label asp-for="Email" class="form-label"></label>
<label asp-for="Email" class="form-label"></label> <input asp-for="Email" class="form-control" />
<input asp-for="Email" class="form-control"/> <span asp-validation-for="Email" class="text-danger"></span>
<span asp-validation-for="Email" class="text-danger"></span> </div>
<div class="col-md-6 mb-3 d-flex align-items-end">
@if (Model.IsEmailConfirmed)
{
<span class="badge bg-success p-2 my-1">
<span class="fa fa-check"></span>
confirmed
</span>
}
else
{
<button asp-action="SendVerificationEmail" class="btn btn-secondary">Send verification email</button>
}
</div>
</div> </div>
<div class="col-md-6 mb-3 d-flex align-items-end"> <button type="submit" id="save" class="btn btn-primary">Save</button>
@if (Model.IsEmailConfirmed) <h3 class="mt-5 mb-4">Delete Account</h3>
{ <div id="danger-zone">
<span class="badge bg-success p-2 my-1"> <a id="delete-user" class="btn btn-outline-danger mb-5" data-confirm-input="DELETE" data-bs-toggle="modal" data-bs-target="#ConfirmModal" asp-action="DeleteUserPost" data-description="This action will also delete all stores, invoices, apps and data associated with the user.">Delete Account</a>
<span class="fa fa-check"></span>
confirmed
</span>
}
else
{
<button asp-action="SendVerificationEmail" class="btn btn-secondary">Send verification email</button>
}
</div> </div>
</div> </form>
<button type="submit" id="save" class="btn btn-primary">Save</button> </div>
<h3 class="mt-5 mb-4">Delete Account</h3>
<div id="danger-zone">
<a id="delete-user" class="btn btn-outline-danger mb-5" data-confirm-input="DELETE" data-bs-toggle="modal" data-bs-target="#ConfirmModal" asp-action="DeleteUserPost" data-description="This action will also delete all stores, invoices, apps and data associated with the user.">Delete Account</a>
</div>
</form>
<partial name="_Confirm" <partial name="_Confirm"
model="@(new ConfirmModel("Delete user", "The user will be permanently deleted. This action will also delete all stores, invoices, apps and data associated with your user.", "Delete", actionName: nameof(BTCPayServer.Controllers.UIManageController.DeleteUserPost)))"/> model="@(new ConfirmModel("Delete user", "The user will be permanently deleted. This action will also delete all stores, invoices, apps and data associated with your user.", "Delete", actionName: nameof(BTCPayServer.Controllers.UIManageController.DeleteUserPost)))"/>

View file

@ -6,37 +6,41 @@
} }
<h3 class="mb-3">@ViewData["Title"]</h3> <h3 class="mb-3">@ViewData["Title"]</h3>
<form method="post" asp-action="NotificationSettings"> <div class="row">
@if (Model.All) <div class="col-xl-8 col-xxl-constrain">
{ <form method="post" asp-action="NotificationSettings">
<div> @if (Model.All)
All notifications are disabled. {
<button type="submit" class="btn btn-primary" name="command" value="enable-all">Enable</button> <div>
</div> All notifications are disabled.
} <button type="submit" class="btn btn-primary" name="command" value="enable-all">Enable</button>
else </div>
{ }
<div class="form-group"> else
<p>Do not receive notifications for</p> {
<div class="card"> <div class="form-group">
<ul class="list-group list-group-flush"> <p>Do not receive notifications for</p>
@for (var index = 0; index < Model.DisabledNotifications.Count; index++) <div class="card">
{ <ul class="list-group list-group-flush">
var item = Model.DisabledNotifications[index]; @for (var index = 0; index < Model.DisabledNotifications.Count; index++)
<li class="list-group-item"> {
<input type="hidden" asp-for="DisabledNotifications[index].Value"/> var item = Model.DisabledNotifications[index];
<input type="checkbox" asp-for="DisabledNotifications[index].Selected" class="form-check-input form-check-inline"/> <li class="list-group-item">
<label class="mb-0 cursor-pointer" asp-for="DisabledNotifications[index].Selected"> <input type="hidden" asp-for="DisabledNotifications[index].Value"/>
@item.Text <input type="checkbox" asp-for="DisabledNotifications[index].Selected" class="form-check-input form-check-inline"/>
</label> <label class="mb-0 cursor-pointer" asp-for="DisabledNotifications[index].Selected">
</li> @item.Text
} </label>
</ul> </li>
</div> }
</div> </ul>
<div class="form-group mt-4"> </div>
<button type="submit" class="btn btn-primary" name="command" value="update">Save</button> </div>
<button type="submit" class="btn btn-secondary ms-3" name="command" value="disable-all">Disable all</button> <div class="form-group mt-4">
</div> <button type="submit" class="btn btn-primary" name="command" value="update">Save</button>
} <button type="submit" class="btn btn-secondary ms-3" name="command" value="disable-all">Disable all</button>
</form> </div>
}
</form>
</div>
</div>

View file

@ -6,7 +6,7 @@
<h3 class="mb-3">@ViewData["Title"]</h3> <h3 class="mb-3">@ViewData["Title"]</h3>
<div class="row"> <div class="row">
<div class="col-lg-10 col-xl-8"> <div class="col-xl-8 col-xxl-constrain">
<p> <p>
Two-Factor Authentication (2FA) is an additional measure to protect your account. Two-Factor Authentication (2FA) is an additional measure to protect your account.
In addition to your password you will be asked for a second proof on login. In addition to your password you will be asked for a second proof on login.

View file

@ -21,7 +21,7 @@
<form method="post" action="@Url.Action("EditPaymentRequest", "UIPaymentRequest", new { storeId = Model.StoreId, payReqId = Model.Id }, Context.Request.Scheme)"> <form method="post" action="@Url.Action("EditPaymentRequest", "UIPaymentRequest", new { storeId = Model.StoreId, payReqId = Model.Id }, Context.Request.Scheme)">
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<div asp-validation-summary="ModelOnly" class="text-danger"></div> <div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group"> <div class="form-group">
<label asp-for="Title" class="form-label" data-required></label> <label asp-for="Title" class="form-label" data-required></label>
@ -66,13 +66,14 @@
</p> </p>
</div> </div>
</div> </div>
<div class="col-lg-9"> <div class="col-xl-10 col-xxl-constrain">
<div class="form-group"> <div class="form-group">
<label asp-for="Description" class="form-label"></label> <label asp-for="Description" class="form-label"></label>
<textarea asp-for="Description" class="form-control richtext"></textarea> <textarea asp-for="Description" class="form-control richtext"></textarea>
<span asp-validation-for="Description" class="text-danger"></span> <span asp-validation-for="Description" class="text-danger"></span>
</div> </div>
</div>
<div class="col-xl-8 col-xxl-constrain">
<h4 class="mt-5 mb-2">Additional Options</h4> <h4 class="mt-5 mb-2">Additional Options</h4>
<div class="form-group"> <div class="form-group">
<div class="accordion" id="additional"> <div class="accordion" id="additional">

View file

@ -7,7 +7,7 @@
<h3 class="mb-4">@ViewData["Title"]</h3> <h3 class="mb-4">@ViewData["Title"]</h3>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
@if (!ViewContext.ModelState.IsValid) @if (!ViewContext.ModelState.IsValid)
{ {
<div asp-validation-summary="All" class="text-danger"></div> <div asp-validation-summary="All" class="text-danger"></div>

View file

@ -6,7 +6,7 @@
<h3 class="mb-4">@ViewData["Title"]</h3> <h3 class="mb-4">@ViewData["Title"]</h3>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-xl-6 col-xxl-constrain">
<form method="post" asp-action="CreateUser"> <form method="post" asp-action="CreateUser">
<div asp-validation-summary="ModelOnly" class="text-danger"></div> <div asp-validation-summary="ModelOnly" class="text-danger"></div>

View file

@ -6,7 +6,7 @@
<h3 class="mb-4">@ViewData["Title"]</h3> <h3 class="mb-4">@ViewData["Title"]</h3>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<form method="post"> <form method="post">
<div class="form-group"> <div class="form-group">
<label asp-for="ContainerName" class="form-label"></label> <label asp-for="ContainerName" class="form-label"></label>

View file

@ -6,7 +6,7 @@
<h3 class="mb-4">@ViewData["Title"]</h3> <h3 class="mb-4">@ViewData["Title"]</h3>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<form method="post"> <form method="post">
<div class="form-group"> <div class="form-group">
<label asp-for="ContainerName" class="form-label">Container Name</label> <label asp-for="ContainerName" class="form-label">Container Name</label>

View file

@ -7,7 +7,7 @@
<p>Any uploaded files are being saved on the same machine that hosts BTCPay; please pay attention to your storage space.</p> <p>Any uploaded files are being saved on the same machine that hosts BTCPay; please pay attention to your storage space.</p>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<a asp-action="Storage" asp-route-forceChoice="true">Change Storage provider</a> <a asp-action="Storage" asp-route-forceChoice="true">Change Storage provider</a>
</div> </div>
</div> </div>

View file

@ -6,7 +6,7 @@
<h3 class="mb-4">@ViewData["Title"]</h3> <h3 class="mb-4">@ViewData["Title"]</h3>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<form method="post"> <form method="post">
<div class="form-group"> <div class="form-group">
<label asp-for="ContainerName" class="form-label">Container Name</label> <label asp-for="ContainerName" class="form-label">Container Name</label>

View file

@ -136,11 +136,10 @@
@foreach (var plugin in Model.Installed) @foreach (var plugin in Model.Installed)
{ {
var matchedAvailable = Model.Available.Where(availablePlugin => availablePlugin.Identifier == plugin.Identifier && availablePlugin.Version > plugin.Version).OrderByDescending(availablePlugin => availablePlugin.Version).ToArray(); var matchedAvailable = Model.Available.Where(availablePlugin => availablePlugin.Identifier == plugin.Identifier && availablePlugin.Version > plugin.Version).OrderByDescending(availablePlugin => availablePlugin.Version).ToArray();
var x = matchedAvailable.FirstOrDefault(availablePlugin => DependenciesMet(availablePlugin.Dependencies)) ?? matchedAvailable.FirstOrDefault(); var x = matchedAvailable.FirstOrDefault(availablePlugin => DependenciesMet(availablePlugin.Dependencies)) ?? matchedAvailable.FirstOrDefault();
var updateAvailable = !plugin.SystemPlugin && matchedAvailable.Any(); var updateAvailable = !plugin.SystemPlugin && matchedAvailable.Any();
var tabId = plugin.Identifier.ToLowerInvariant().Replace(".", "_"); var tabId = plugin.Identifier.ToLowerInvariant().Replace(".", "_");
<div class="col col-12 col-lg-6 mb-4"> <div class="col col-12 col-md-6 col-lg-12 col-xl-6 col-xxl-4 mb-4">
<div class="card h-100"> <div class="card h-100">
<div class="card-body"> <div class="card-body">
<h4 class="card-title d-inline-block" title="@plugin.Identifier" data-bs-toggle="tooltip">@plugin.Name</h4> <h4 class="card-title d-inline-block" title="@plugin.Identifier" data-bs-toggle="tooltip">@plugin.Name</h4>
@ -257,11 +256,10 @@
<div class="row mb-4"> <div class="row mb-4">
@foreach (var plugin in availableAndNotInstalled) @foreach (var plugin in availableAndNotInstalled)
{ {
var recommended = BTCPayServerOptions.RecommendedPlugins.Contains(plugin.Identifier.ToLowerInvariant()); var recommended = BTCPayServerOptions.RecommendedPlugins.Contains(plugin.Identifier.ToLowerInvariant());
var disabled = Model.Disabled?.Contains(plugin.Identifier) ?? false; var disabled = Model.Disabled?.Contains(plugin.Identifier) ?? false;
<div class="col col-12 col-lg-6 mb-4"> <div class="col col-12 col-md-6 col-lg-12 col-xl-6 col-xxl-4 mb-4">
<div class="card h-100"> <div class="card h-100">
<div class="card-body"> <div class="card-body">
<h4 class="card-title d-inline-block" data-bs-toggle="tooltip" title="@plugin.Identifier">@plugin.Name</h4> <h4 class="card-title d-inline-block" data-bs-toggle="tooltip" title="@plugin.Identifier">@plugin.Name</h4>
@ -338,7 +336,7 @@
Upload Plugin Upload Plugin
</button> </button>
<div class="row collapse" id="manual-upload"> <div class="row collapse" id="manual-upload">
<div class="col col-12 col-lg-6 mb-4"> <div class="col col-xl-6 mb-4">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<h4 class="card-title">Add plugin manually</h4> <h4 class="card-title">Add plugin manually</h4>

View file

@ -7,7 +7,7 @@
<form method="post"> <form method="post">
<div class="row mb-5"> <div class="row mb-5">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<h4 class="mb-2">Domain name</h4> <h4 class="mb-2">Domain name</h4>
<p>You can change the domain name of your server by following <a href="https://docs.btcpayserver.org/Deployment/ChangeDomain/" target="_blank" rel="noreferrer noopener">this guide</a>.</p> <p>You can change the domain name of your server by following <a href="https://docs.btcpayserver.org/Deployment/ChangeDomain/" target="_blank" rel="noreferrer noopener">this guide</a>.</p>

View file

@ -1,4 +1,3 @@
@using BTCPayServer.Storage.Models
@model BTCPayServer.Storage.ViewModels.ChooseStorageViewModel @model BTCPayServer.Storage.ViewModels.ChooseStorageViewModel
@{ @{
ViewData.SetActivePage(ServerNavPages.Services, "Storage"); ViewData.SetActivePage(ServerNavPages.Services, "Storage");
@ -6,15 +5,14 @@
<h3 class="mb-4">@ViewData["Title"]</h3> <h3 class="mb-4">@ViewData["Title"]</h3>
@if (Model.ShowChangeWarning)
{
<div class="alert alert-danger mb-4">
If you change your configured storage provider, your current files will become inaccessible.
</div>
}
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
@if (Model.ShowChangeWarning)
{
<div class="alert alert-danger mb-4">
If you change your configured storage provider, your current files will become inaccessible.
</div>
}
<form method="post"> <form method="post">
@if (!ViewContext.ModelState.IsValid) @if (!ViewContext.ModelState.IsValid)
{ {
@ -22,7 +20,7 @@
} }
<div class="form-group"> <div class="form-group">
<label asp-for="Provider" class="form-label"></label> <label asp-for="Provider" class="form-label"></label>
<select asp-for="Provider" asp-items="@Model.ProvidersList" class="form-select"></select> <select asp-for="Provider" asp-items="@Model.ProvidersList" class="form-select w-auto"></select>
</div> </div>
<button type="submit" class="btn btn-primary mt-2" name="command" value="Save">Next</button> <button type="submit" class="btn btn-primary mt-2" name="command" value="Save">Next</button>
</form> </form>

View file

@ -10,7 +10,7 @@
<h3 class="mb-4">@ViewData["Title"]</h3> <h3 class="mb-4">@ViewData["Title"]</h3>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<form method="post"> <form method="post">
<h4 class="mb-3">Custom theme</h4> <h4 class="mb-3">Custom theme</h4>
<p>Use the default Light or Dark Themes, or provide a CSS theme file below.</p> <p>Use the default Light or Dark Themes, or provide a CSS theme file below.</p>

View file

@ -10,7 +10,7 @@
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2> <h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-xl-8 col-xxl-constrain">
<form method="post" <form method="post"
asp-route-walletId="@Context.GetRouteValue("walletId")" asp-route-walletId="@Context.GetRouteValue("walletId")"
asp-action="NewPullPayment"> asp-action="NewPullPayment">

View file

@ -6,7 +6,7 @@
} }
<div class="row"> <div class="row">
<div class="col-lg-8"> <div class="col-xxl-constrain col-xl-8">
<form method="post"> <form method="post">
@if (!ViewContext.ModelState.IsValid) @if (!ViewContext.ModelState.IsValid)
{ {

View file

@ -6,7 +6,7 @@
ViewBag.ShowStores = ViewBag.ShowStores ?? false; ViewBag.ShowStores = ViewBag.ShowStores ?? false;
} }
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xxl-constrain col-xl-8">
<h3 class="mb-4">@ViewData["Title"]</h3> <h3 class="mb-4">@ViewData["Title"]</h3>
<form method="post"> <form method="post">
<div class="form-group"> <div class="form-group">

View file

@ -4,29 +4,6 @@
var isReady = Model.WalletEnabled || Model.LightningEnabled; var isReady = Model.WalletEnabled || Model.LightningEnabled;
} }
@section PageHeadContent
{
<style>
.list-group-item .image {
display: flex;
flex: 0 0 1rem;
align-items: center;
justify-content: center;
}
.list-group-item .icon {
width: 1.5rem;
height: 1.5rem;
margin: 1rem;
}
.list-group-item .content {
flex: 1;
padding: 1rem 0;
}
</style>
}
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<h2 class="mt-1 mb-3">@ViewData["Title"]</h2> <h2 class="mt-1 mb-3">@ViewData["Title"]</h2>
@ -40,79 +17,75 @@ else
<p class="lead text-secondary">To start accepting payments, set up a wallet or a Lightning node.</p> <p class="lead text-secondary">To start accepting payments, set up a wallet or a Lightning node.</p>
} }
<div class="row"> <div class="list-group" id="SetupGuide">
<div class="col-md-7 col-xl-5"> <div class="list-group-item d-flex align-items-center" id="SetupGuide-StoreDone">
<div class="list-group" id="SetupGuide"> <vc:icon symbol="done"/>
<div class="list-group-item d-flex align-items-center" id="SetupGuide-StoreDone"> <div class="content">
<vc:icon symbol="done"/> <h5 class="mb-0 text-success">Create your store</h5>
<div class="content">
<h5 class="mb-0 text-success">Create your store</h5>
</div>
</div>
@if (!Model.WalletEnabled)
{
if (!Model.AltcoinsBuild)
{
<a asp-controller="UIStores" asp-action="SetupWallet" asp-route-storeId="@Model.StoreId" asp-route-cryptoCode="BTC" id="SetupGuide-Wallet" class="list-group-item list-group-item-action d-flex align-items-center order-1">
<vc:icon symbol="new-wallet"/>
<div class="content">
<h5 class="mb-0">Set up a wallet</h5>
</div>
<vc:icon symbol="caret-right"/>
</a>
}
else
{
<a asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Model.StoreId" id="SetupGuide-Wallet" class="list-group-item list-group-item-action d-flex align-items-center order-1">
<vc:icon symbol="new-wallet"/>
<div class="content">
<h5 class="mb-0">Set up a wallet</h5>
</div>
<vc:icon symbol="caret-right"/>
</a>
}
}
else
{
<div class="list-group-item d-flex align-items-center" id="SetupGuide-WalletDone">
<vc:icon symbol="done"/>
<div class="content">
<h5 class="mb-0 text-success">Set up a wallet</h5>
</div>
</div>
}
@if (!Model.LightningEnabled)
{
if (!Model.AltcoinsBuild)
{
<a asp-controller="UIStores" asp-action="SetupLightningNode" asp-route-storeId="@Model.StoreId" asp-route-cryptoCode="BTC" id="SetupGuide-Lightning" class="list-group-item list-group-item-action d-flex align-items-center order-1">
<vc:icon symbol="new-wallet"/>
<div class="content">
<h5 class="mb-0">Set up a Lightning node</h5>
</div>
<vc:icon symbol="caret-right"/>
</a>
}
else
{
<a asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Model.StoreId" id="SetupGuide-Lightning" class="list-group-item list-group-item-action d-flex align-items-center order-1">
<vc:icon symbol="new-wallet"/>
<div class="content">
<h5 class="mb-0">Set up a Lightning node</h5>
</div>
<vc:icon symbol="caret-right"/>
</a>
}
}
else
{
<div class="list-group-item d-flex align-items-center" id="SetupGuide-LightningDone">
<vc:icon symbol="done"/>
<div class="content">
<h5 class="mb-0 text-success">Set up a Lightning node</h5>
</div>
</div>
}
</div> </div>
</div> </div>
@if (!Model.WalletEnabled)
{
if (!Model.AltcoinsBuild)
{
<a asp-controller="UIStores" asp-action="SetupWallet" asp-route-storeId="@Model.StoreId" asp-route-cryptoCode="BTC" id="SetupGuide-Wallet" class="list-group-item list-group-item-action d-flex align-items-center order-1">
<vc:icon symbol="new-wallet"/>
<div class="content">
<h5 class="mb-0">Set up a wallet</h5>
</div>
<vc:icon symbol="caret-right"/>
</a>
}
else
{
<a asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Model.StoreId" id="SetupGuide-Wallet" class="list-group-item list-group-item-action d-flex align-items-center order-1">
<vc:icon symbol="new-wallet"/>
<div class="content">
<h5 class="mb-0">Set up a wallet</h5>
</div>
<vc:icon symbol="caret-right"/>
</a>
}
}
else
{
<div class="list-group-item d-flex align-items-center" id="SetupGuide-WalletDone">
<vc:icon symbol="done"/>
<div class="content">
<h5 class="mb-0 text-success">Set up a wallet</h5>
</div>
</div>
}
@if (!Model.LightningEnabled)
{
if (!Model.AltcoinsBuild)
{
<a asp-controller="UIStores" asp-action="SetupLightningNode" asp-route-storeId="@Model.StoreId" asp-route-cryptoCode="BTC" id="SetupGuide-Lightning" class="list-group-item list-group-item-action d-flex align-items-center order-1">
<vc:icon symbol="new-wallet"/>
<div class="content">
<h5 class="mb-0">Set up a Lightning node</h5>
</div>
<vc:icon symbol="caret-right"/>
</a>
}
else
{
<a asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Model.StoreId" id="SetupGuide-Lightning" class="list-group-item list-group-item-action d-flex align-items-center order-1">
<vc:icon symbol="new-wallet"/>
<div class="content">
<h5 class="mb-0">Set up a Lightning node</h5>
</div>
<vc:icon symbol="caret-right"/>
</a>
}
}
else
{
<div class="list-group-item d-flex align-items-center" id="SetupGuide-LightningDone">
<vc:icon symbol="done"/>
<div class="content">
<h5 class="mb-0 text-success">Set up a Lightning node</h5>
</div>
</div>
}
</div> </div>

View file

@ -5,7 +5,7 @@
} }
<div class="row"> <div class="row">
<div class="col-lg-10 col-xl-8"> <div class="col-xxl-constrain col-xl-8">
@if (!ViewContext.ModelState.IsValid) @if (!ViewContext.ModelState.IsValid)
{ {
<div asp-validation-summary="All" class="text-danger"></div> <div asp-validation-summary="All" class="text-danger"></div>
@ -45,7 +45,7 @@
<a href="https://docs.btcpayserver.org/FAQ/Stores/#add-network-fee-to-invoice-vary-with-mining-fees" target="_blank" rel="noreferrer noopener"> <a href="https://docs.btcpayserver.org/FAQ/Stores/#add-network-fee-to-invoice-vary-with-mining-fees" target="_blank" rel="noreferrer noopener">
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span> <span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
</a> </a>
<select asp-for="NetworkFeeMode" class="form-select"> <select asp-for="NetworkFeeMode" class="form-select w-auto">
<option value="MultiplePaymentsOnly">... only if the customer makes more than one payment for the invoice</option> <option value="MultiplePaymentsOnly">... only if the customer makes more than one payment for the invoice</option>
<option value="Always">... on every payment</option> <option value="Always">... on every payment</option>
<option value="Never">Never add network fee</option> <option value="Never">Never add network fee</option>

View file

@ -5,7 +5,7 @@
} }
<div class="row"> <div class="row">
<div class="col-lg-8"> <div class="col-xl-8 col-xxl-constrain">
<h3 class="mb-0 mb-4">@ViewData["Title"]</h3> <h3 class="mb-0 mb-4">@ViewData["Title"]</h3>
@if (!ViewContext.ModelState.IsValid) @if (!ViewContext.ModelState.IsValid)
{ {

View file

@ -16,7 +16,7 @@
} }
<div class="row"> <div class="row">
<div class="col-lg-8"> <div class="col-xxl-constrain col-xl-8">
<div class="d-flex align-items-center justify-content-between mb-3"> <div class="d-flex align-items-center justify-content-between mb-3">
<h3 class="mb-0">@ViewData["Title"]</h3> <h3 class="mb-0">@ViewData["Title"]</h3>
<a id="CreateNewToken" asp-action="CreateToken" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")"> <a id="CreateNewToken" asp-action="CreateToken" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")">

View file

@ -13,7 +13,7 @@
} }
<div class="row"> <div class="row">
<div class="col-lg-8"> <div class="col-xxl-constrain col-xl-8">
<form method="post"> <form method="post">
<h3 class="mb-3">@ViewData["Title"]</h3> <h3 class="mb-3">@ViewData["Title"]</h3>
<div class="form-group"> <div class="form-group">

View file

@ -130,36 +130,34 @@
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2> <h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<div class="alert alert-warning alert-dismissible mb-4" role="alert">
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
<vc:icon symbol="close" />
</button>
<p><strong>Warning:</strong> This feature should not be activated on a BTCPay Server store processing commercial transactions.</p>
<p>By activating this feature, a malicious user can trick you into thinking an order has been processed by creating a new invoice, reusing the same Order Id of another valid order but different amount or currency.</p>
<p>If this store process commercial transactions, we advise you to <a asp-controller="UIUserStores" asp-action="CreateStore">create a separate store</a> before using the payment button.</p>
<form asp-action="DisableAnyoneCanCreateInvoice" asp-route-storeId="@Context.GetRouteValue("storeId")" method="post">
<button name="command" id="disable-pay-button" type="submit" class="btn btn-danger mt-0" value="Save">Disable payment button</button>
</form>
</div>
<div id="payButtonCtrl"> <div id="payButtonCtrl">
<div class="row"> <div class="row">
<div class="col-lg-7"> <div class="col-xl-8">
<div class="row"> <div class="alert alert-warning alert-dismissible mb-4" role="alert">
<p>Configure your Pay Button, and the generated code will be displayed at the bottom of the page to copy into your project.</p> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
<h4 class="mt-3 mb-3">General Settings</h4> <vc:icon symbol="close" />
<div class="form-group col-md-8"> </button>
<label class="form-label" for="price">Price</label> <p><strong>Warning:</strong> This feature should not be activated on a BTCPay Server store processing commercial transactions.</p>
<input name="price" type="text" class="form-control" id="price" <p>By activating this feature, a malicious user can trick you into thinking an order has been processed by creating a new invoice, reusing the same Order Id of another valid order but different amount or currency.</p>
v-model="srvModel.price" v-on:change="inputChanges" <p>If this store process commercial transactions, we advise you to <a asp-controller="UIUserStores" asp-action="CreateStore">create a separate store</a> before using the payment button.</p>
v-validate="'decimal|min_value:0'" :class="{'is-invalid': errors.has('price') }"> <form asp-action="DisableAnyoneCanCreateInvoice" asp-route-storeId="@Context.GetRouteValue("storeId")" method="post">
<small class="text-danger">{{ errors.first('price') }}</small> <button name="command" id="disable-pay-button" type="submit" class="btn btn-danger mt-0" value="Save">Disable payment button</button>
</div> </form>
<div class="form-group col-md-4" v-if="!srvModel.appIdEndpoint"> </div>
<label class="form-label" for="currency">Currency</label> <p>Configure your Pay Button, and the generated code will be displayed at the bottom of the page to copy into your project.</p>
<input name="currency" type="text" class="form-control" id="currency" <h4 class="mt-3 mb-3">General Settings</h4>
v-model="srvModel.currency" v-on:change="inputChanges" <div class="form-group col-md-8">
:class="{'is-invalid': errors.has('currency') }"> <label class="form-label" for="price">Price</label>
</div> <input name="price" type="text" class="form-control" id="price"
v-model="srvModel.price" v-on:change="inputChanges"
v-validate="'decimal|min_value:0'" :class="{'is-invalid': errors.has('price') }">
<small class="text-danger">{{ errors.first('price') }}</small>
</div>
<div class="form-group col-md-4" v-if="!srvModel.appIdEndpoint">
<label class="form-label" for="currency">Currency</label>
<input name="currency" type="text" class="form-control" id="currency"
v-model="srvModel.currency" v-on:change="inputChanges"
:class="{'is-invalid': errors.has('currency') }">
</div> </div>
<div class="form-group" v-if="!srvModel.appIdEndpoint"> <div class="form-group" v-if="!srvModel.appIdEndpoint">
<label class="form-label" for="description">Checkout Description</label> <label class="form-label" for="description">Checkout Description</label>
@ -176,7 +174,7 @@
<h4 class="mt-5 mb-3">Display Options</h4> <h4 class="mt-5 mb-3">Display Options</h4>
<div class="row"> <div class="row">
<div class="col-lg-7"> <div class="col-xl-8 col-xxl-constrain">
<div class="form-group"> <div class="form-group">
<div class="form-check" v-if="!srvModel.appIdEndpoint"> <div class="form-check" v-if="!srvModel.appIdEndpoint">
<input id="useModal" type="checkbox" v-model="srvModel.useModal" v-on:change="inputChanges" class="form-check-input"/> <input id="useModal" type="checkbox" v-model="srvModel.useModal" v-on:change="inputChanges" class="form-check-input"/>
@ -275,7 +273,7 @@
</div> </div>
</template> </template>
</div> </div>
<div class="col-lg-4 mt-4 mt-lg-0"> <div class="col-xl-4 mt-4 mt-xl-0">
<h5 class="mb-3">Preview</h5> <h5 class="mb-3">Preview</h5>
<div id="preview"></div> <div id="preview"></div>
<div v-show="!srvModel.appIdEndpoint"> <div v-show="!srvModel.appIdEndpoint">
@ -287,7 +285,7 @@
<h4 class="mt-5 mb-3">Payment Notifications</h4> <h4 class="mt-5 mb-3">Payment Notifications</h4>
<div class="row"> <div class="row">
<div class="col-lg-7"> <div class="col-xl-8 col-xxl-constrain">
<div class="form-group"> <div class="form-group">
<label class="form-label" for="server-ipn">Server IPN</label> <label class="form-label" for="server-ipn">Server IPN</label>
<input name="serverIpn" type="text" class="form-control" id="server-ipn" <input name="serverIpn" type="text" class="form-control" id="server-ipn"
@ -324,7 +322,7 @@
<h4 class="mt-5 mb-3">Advanced Options</h4> <h4 class="mt-5 mb-3">Advanced Options</h4>
<div class="row" v-if="!srvModel.appIdEndpoint"> <div class="row" v-if="!srvModel.appIdEndpoint">
<div class="col-lg-7"> <div class="col-xl-8 col-xxl-constrain">
<p> <p>
Specify additional query string parameters that should be appended to the checkout page once the invoice is created. Specify additional query string parameters that should be appended to the checkout page once the invoice is created.
For example, <code>lang=da-DK</code> would load the checkout page in Danish by default. For example, <code>lang=da-DK</code> would load the checkout page in Danish by default.
@ -340,7 +338,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-7"> <div class="col-xl-8 col-xxl-constrain">
<p>Link this Pay Button to an app instead. Some features are disabled due to the different endpoint capabilities. You can set which perk/item this button should be targeting.</p> <p>Link this Pay Button to an app instead. Some features are disabled due to the different endpoint capabilities. You can set which perk/item this button should be targeting.</p>
<div class="form-group"> <div class="form-group">
<label class="form-label" for="app-as-endpoint">Use App As Endpoint</label> <label class="form-label" for="app-as-endpoint">Use App As Endpoint</label>
@ -363,7 +361,7 @@
<h4 class="mt-5 mb-3">Generated Code</h4> <h4 class="mt-5 mb-3">Generated Code</h4>
<div class="row" v-show="!errors.any()"> <div class="row" v-show="!errors.any()">
<div class="col-lg-12"> <div class="col-xxl-8">
<pre><code id="mainCode" class="html"></code></pre> <pre><code id="mainCode" class="html"></code></pre>
<button class="btn btn-primary" data-clipboard-target="#mainCode"> <button class="btn btn-primary" data-clipboard-target="#mainCode">
<i class="fa fa-copy"></i> Copy Code <i class="fa fa-copy"></i> Copy Code
@ -371,7 +369,7 @@
</div> </div>
</div> </div>
<div class="row" v-show="errors.any()"> <div class="row" v-show="errors.any()">
<div class="col-lg-12 text-danger"> <div class="col-xl-8 col-xxl-constrain text-danger">
Please fix errors shown in order for code generation to successfully execute. Please fix errors shown in order for code generation to successfully execute.
</div> </div>
</div> </div>

View file

@ -5,7 +5,7 @@
} }
<div class="row"> <div class="row">
<div class="col-lg-8"> <div class="col-xxl-constrain col-xl-8">
<h3 class="mb-3">@ViewData["Title"]</h3> <h3 class="mb-3">@ViewData["Title"]</h3>
@if (!ViewContext.ModelState.IsValid) @if (!ViewContext.ModelState.IsValid)
{ {

View file

@ -5,7 +5,7 @@
} }
<div class="row"> <div class="row">
<div class="col-lg-8"> <div class="col-xxl-constrain col-xl-8">
<h3 class="mb-3">@ViewData["Title"]</h3> <h3 class="mb-3">@ViewData["Title"]</h3>
<p> <p>
Give other registered BTCPay Server users access to your store.<br /> Give other registered BTCPay Server users access to your store.<br />

View file

@ -4,7 +4,7 @@
ViewData.SetActivePage(StoreNavPages.Webhooks, "Webhooks", Context.GetStoreData().Id); ViewData.SetActivePage(StoreNavPages.Webhooks, "Webhooks", Context.GetStoreData().Id);
} }
<div class="row"> <div class="row">
<div class="col-lg-8"> <div class="col-xl-8 col-xxl-constrain">
<div class="d-flex align-items-center justify-content-between mb-3"> <div class="d-flex align-items-center justify-content-between mb-3">
<h3 class="mb-0">@ViewData["Title"]</h3> <h3 class="mb-0">@ViewData["Title"]</h3>
<a id="CreateWebhook" asp-action="NewWebhook" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")"> <a id="CreateWebhook" asp-action="NewWebhook" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")">

View file

@ -11,7 +11,7 @@
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2> <h2 class="mt-1 mb-4">@ViewData["Title"]</h2>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-xl-8 col-xxl-constrain">
<form asp-action="CreateStore"> <form asp-action="CreateStore">
<div asp-validation-summary="ModelOnly" class="text-danger"></div> <div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group"> <div class="form-group">

View file

@ -606,7 +606,8 @@ progress {
.container-sm, .container-sm,
.container-md, .container-md,
.container-lg, .container-lg,
.container-xl { .container-xl,
.container-xxl {
width: 100%; width: 100%;
padding-right: var(--btcpay-gutter-x, 0.75rem); padding-right: var(--btcpay-gutter-x, 0.75rem);
padding-left: var(--btcpay-gutter-x, 0.75rem); padding-left: var(--btcpay-gutter-x, 0.75rem);
@ -638,6 +639,12 @@ progress {
} }
} }
@media (min-width: 1400px) {
.container, .container-sm, .container-md, .container-lg, .container-xl, .container-xxl {
max-width: 1320px;
}
}
.row { .row {
--btcpay-gutter-x: 1.5rem; --btcpay-gutter-x: 1.5rem;
--btcpay-gutter-y: 0; --btcpay-gutter-y: 0;
@ -1545,6 +1552,176 @@ progress {
} }
} }
@media (min-width: 1400px) {
.col-xxl {
flex: 1 0 0%;
}
.row-cols-xxl-auto > * {
flex: 0 0 auto;
width: auto;
}
.row-cols-xxl-1 > * {
flex: 0 0 auto;
width: 100%;
}
.row-cols-xxl-2 > * {
flex: 0 0 auto;
width: 50%;
}
.row-cols-xxl-3 > * {
flex: 0 0 auto;
width: 33.33333%;
}
.row-cols-xxl-4 > * {
flex: 0 0 auto;
width: 25%;
}
.row-cols-xxl-5 > * {
flex: 0 0 auto;
width: 20%;
}
.row-cols-xxl-6 > * {
flex: 0 0 auto;
width: 16.66667%;
}
.col-xxl-auto {
flex: 0 0 auto;
width: auto;
}
.col-xxl-1 {
flex: 0 0 auto;
width: 8.33333%;
}
.col-xxl-2 {
flex: 0 0 auto;
width: 16.66667%;
}
.col-xxl-3 {
flex: 0 0 auto;
width: 25%;
}
.col-xxl-4 {
flex: 0 0 auto;
width: 33.33333%;
}
.col-xxl-5 {
flex: 0 0 auto;
width: 41.66667%;
}
.col-xxl-6 {
flex: 0 0 auto;
width: 50%;
}
.col-xxl-7 {
flex: 0 0 auto;
width: 58.33333%;
}
.col-xxl-8 {
flex: 0 0 auto;
width: 66.66667%;
}
.col-xxl-9 {
flex: 0 0 auto;
width: 75%;
}
.col-xxl-10 {
flex: 0 0 auto;
width: 83.33333%;
}
.col-xxl-11 {
flex: 0 0 auto;
width: 91.66667%;
}
.col-xxl-12 {
flex: 0 0 auto;
width: 100%;
}
.offset-xxl-0 {
margin-left: 0;
}
.offset-xxl-1 {
margin-left: 8.33333%;
}
.offset-xxl-2 {
margin-left: 16.66667%;
}
.offset-xxl-3 {
margin-left: 25%;
}
.offset-xxl-4 {
margin-left: 33.33333%;
}
.offset-xxl-5 {
margin-left: 41.66667%;
}
.offset-xxl-6 {
margin-left: 50%;
}
.offset-xxl-7 {
margin-left: 58.33333%;
}
.offset-xxl-8 {
margin-left: 66.66667%;
}
.offset-xxl-9 {
margin-left: 75%;
}
.offset-xxl-10 {
margin-left: 83.33333%;
}
.offset-xxl-11 {
margin-left: 91.66667%;
}
.g-xxl-0,
.gx-xxl-0 {
--btcpay-gutter-x: 0;
}
.g-xxl-0,
.gy-xxl-0 {
--btcpay-gutter-y: 0;
}
.g-xxl-1,
.gx-xxl-1 {
--btcpay-gutter-x: 0.25rem;
}
.g-xxl-1,
.gy-xxl-1 {
--btcpay-gutter-y: 0.25rem;
}
.g-xxl-2,
.gx-xxl-2 {
--btcpay-gutter-x: 0.5rem;
}
.g-xxl-2,
.gy-xxl-2 {
--btcpay-gutter-y: 0.5rem;
}
.g-xxl-3,
.gx-xxl-3 {
--btcpay-gutter-x: 1rem;
}
.g-xxl-3,
.gy-xxl-3 {
--btcpay-gutter-y: 1rem;
}
.g-xxl-4,
.gx-xxl-4 {
--btcpay-gutter-x: 1.5rem;
}
.g-xxl-4,
.gy-xxl-4 {
--btcpay-gutter-y: 1.5rem;
}
.g-xxl-5,
.gx-xxl-5 {
--btcpay-gutter-x: 3rem;
}
.g-xxl-5,
.gy-xxl-5 {
--btcpay-gutter-y: 3rem;
}
}
.table { .table {
--btcpay-table-bg: transparent; --btcpay-table-bg: transparent;
--btcpay-table-accent-bg: transparent; --btcpay-table-accent-bg: transparent;
@ -1748,6 +1925,13 @@ progress {
} }
} }
@media (max-width: 1399.98px) {
.table-responsive-xxl {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
}
.form-label { .form-label {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
color: var(--btcpay-form-text-label); color: var(--btcpay-form-text-label);
@ -3408,6 +3592,23 @@ fieldset:disabled .btn {
} }
} }
@media (min-width: 1400px) {
.dropdown-menu-xxl-start {
--bs-position: start;
}
.dropdown-menu-xxl-start[data-bs-popper] {
right: auto;
left: 0;
}
.dropdown-menu-xxl-end {
--bs-position: end;
}
.dropdown-menu-xxl-end[data-bs-popper] {
right: 0;
left: auto;
}
}
.dropup .dropdown-menu[data-bs-popper] { .dropup .dropdown-menu[data-bs-popper] {
top: auto; top: auto;
bottom: 100%; bottom: 100%;
@ -3807,7 +4008,7 @@ fieldset:disabled .btn {
} }
.navbar > .container, .navbar > .container,
.navbar > .container-fluid, .navbar > .container-sm, .navbar > .container-md, .navbar > .container-lg, .navbar > .container-xl { .navbar > .container-fluid, .navbar > .container-sm, .navbar > .container-md, .navbar > .container-lg, .navbar > .container-xl, .navbar > .container-xxl {
display: flex; display: flex;
flex-wrap: inherit; flex-wrap: inherit;
align-items: center; align-items: center;
@ -4105,6 +4306,60 @@ fieldset:disabled .btn {
} }
} }
@media (min-width: 1400px) {
.navbar-expand-xxl {
flex-wrap: nowrap;
justify-content: flex-start;
}
.navbar-expand-xxl .navbar-nav {
flex-direction: row;
}
.navbar-expand-xxl .navbar-nav .dropdown-menu {
position: absolute;
}
.navbar-expand-xxl .navbar-nav .nav-link {
padding-right: 0.5rem;
padding-left: 0.5rem;
}
.navbar-expand-xxl .navbar-nav-scroll {
overflow: visible;
}
.navbar-expand-xxl .navbar-collapse {
display: flex !important;
flex-basis: auto;
}
.navbar-expand-xxl .navbar-toggler {
display: none;
}
.navbar-expand-xxl .offcanvas-header {
display: none;
}
.navbar-expand-xxl .offcanvas {
position: inherit;
bottom: 0;
z-index: 1000;
flex-grow: 1;
visibility: visible !important;
background-color: transparent;
border-right: 0;
border-left: 0;
transition: none;
transform: none;
}
.navbar-expand-xxl .offcanvas-top,
.navbar-expand-xxl .offcanvas-bottom {
height: auto;
border-top: 0;
border-bottom: 0;
}
.navbar-expand-xxl .offcanvas-body {
display: flex;
flex-grow: 0;
padding: 0;
overflow-y: visible;
}
}
.navbar-expand { .navbar-expand {
flex-wrap: nowrap; flex-wrap: nowrap;
justify-content: flex-start; justify-content: flex-start;
@ -5040,6 +5295,31 @@ fieldset:disabled .btn {
} }
} }
@media (min-width: 1400px) {
.list-group-horizontal-xxl {
flex-direction: row;
}
.list-group-horizontal-xxl > .list-group-item:first-child {
border-bottom-left-radius: var(--btcpay-border-radius);
border-top-right-radius: 0;
}
.list-group-horizontal-xxl > .list-group-item:last-child {
border-top-right-radius: var(--btcpay-border-radius);
border-bottom-left-radius: 0;
}
.list-group-horizontal-xxl > .list-group-item.active {
margin-top: 0;
}
.list-group-horizontal-xxl > .list-group-item + .list-group-item {
border-top-width: 1px;
border-left-width: 0;
}
.list-group-horizontal-xxl > .list-group-item + .list-group-item.active {
margin-left: -1px;
border-left-width: 1px;
}
}
.list-group-flush { .list-group-flush {
border-radius: 0; border-radius: 0;
} }
@ -5544,6 +5824,29 @@ fieldset:disabled .btn {
} }
} }
@media (max-width: 1399.98px) {
.modal-fullscreen-xxl-down {
width: 100vw;
max-width: none;
height: 100%;
margin: 0;
}
.modal-fullscreen-xxl-down .modal-content {
height: 100%;
border: 0;
border-radius: 0;
}
.modal-fullscreen-xxl-down .modal-header {
border-radius: 0;
}
.modal-fullscreen-xxl-down .modal-body {
overflow-y: auto;
}
.modal-fullscreen-xxl-down .modal-footer {
border-radius: 0;
}
}
.tooltip { .tooltip {
position: absolute; position: absolute;
z-index: 1080; z-index: 1080;
@ -6384,6 +6687,15 @@ fieldset:disabled .btn {
} }
} }
@media (min-width: 1400px) {
.sticky-xxl-top {
position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 1020;
}
}
.hstack { .hstack {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -9759,6 +10071,503 @@ fieldset:disabled .btn {
} }
} }
@media (min-width: 1400px) {
.float-xxl-start {
float: left !important;
}
.float-xxl-end {
float: right !important;
}
.float-xxl-none {
float: none !important;
}
.d-xxl-inline {
display: inline !important;
}
.d-xxl-inline-block {
display: inline-block !important;
}
.d-xxl-block {
display: block !important;
}
.d-xxl-grid {
display: grid !important;
}
.d-xxl-table {
display: table !important;
}
.d-xxl-table-row {
display: table-row !important;
}
.d-xxl-table-cell {
display: table-cell !important;
}
.d-xxl-flex {
display: flex !important;
}
.d-xxl-inline-flex {
display: inline-flex !important;
}
.d-xxl-none {
display: none !important;
}
.flex-xxl-fill {
flex: 1 1 auto !important;
}
.flex-xxl-row {
flex-direction: row !important;
}
.flex-xxl-column {
flex-direction: column !important;
}
.flex-xxl-row-reverse {
flex-direction: row-reverse !important;
}
.flex-xxl-column-reverse {
flex-direction: column-reverse !important;
}
.flex-xxl-grow-0 {
flex-grow: 0 !important;
}
.flex-xxl-grow-1 {
flex-grow: 1 !important;
}
.flex-xxl-shrink-0 {
flex-shrink: 0 !important;
}
.flex-xxl-shrink-1 {
flex-shrink: 1 !important;
}
.flex-xxl-wrap {
flex-wrap: wrap !important;
}
.flex-xxl-nowrap {
flex-wrap: nowrap !important;
}
.flex-xxl-wrap-reverse {
flex-wrap: wrap-reverse !important;
}
.gap-xxl-0 {
gap: 0 !important;
}
.gap-xxl-1 {
gap: 0.25rem !important;
}
.gap-xxl-2 {
gap: 0.5rem !important;
}
.gap-xxl-3 {
gap: 1rem !important;
}
.gap-xxl-4 {
gap: 1.5rem !important;
}
.gap-xxl-5 {
gap: 3rem !important;
}
.justify-content-xxl-start {
justify-content: flex-start !important;
}
.justify-content-xxl-end {
justify-content: flex-end !important;
}
.justify-content-xxl-center {
justify-content: center !important;
}
.justify-content-xxl-between {
justify-content: space-between !important;
}
.justify-content-xxl-around {
justify-content: space-around !important;
}
.justify-content-xxl-evenly {
justify-content: space-evenly !important;
}
.align-items-xxl-start {
align-items: flex-start !important;
}
.align-items-xxl-end {
align-items: flex-end !important;
}
.align-items-xxl-center {
align-items: center !important;
}
.align-items-xxl-baseline {
align-items: baseline !important;
}
.align-items-xxl-stretch {
align-items: stretch !important;
}
.align-content-xxl-start {
align-content: flex-start !important;
}
.align-content-xxl-end {
align-content: flex-end !important;
}
.align-content-xxl-center {
align-content: center !important;
}
.align-content-xxl-between {
align-content: space-between !important;
}
.align-content-xxl-around {
align-content: space-around !important;
}
.align-content-xxl-stretch {
align-content: stretch !important;
}
.align-self-xxl-auto {
align-self: auto !important;
}
.align-self-xxl-start {
align-self: flex-start !important;
}
.align-self-xxl-end {
align-self: flex-end !important;
}
.align-self-xxl-center {
align-self: center !important;
}
.align-self-xxl-baseline {
align-self: baseline !important;
}
.align-self-xxl-stretch {
align-self: stretch !important;
}
.order-xxl-first {
order: -1 !important;
}
.order-xxl-0 {
order: 0 !important;
}
.order-xxl-1 {
order: 1 !important;
}
.order-xxl-2 {
order: 2 !important;
}
.order-xxl-3 {
order: 3 !important;
}
.order-xxl-4 {
order: 4 !important;
}
.order-xxl-5 {
order: 5 !important;
}
.order-xxl-last {
order: 6 !important;
}
.m-xxl-0 {
margin: 0 !important;
}
.m-xxl-1 {
margin: 0.25rem !important;
}
.m-xxl-2 {
margin: 0.5rem !important;
}
.m-xxl-3 {
margin: 1rem !important;
}
.m-xxl-4 {
margin: 1.5rem !important;
}
.m-xxl-5 {
margin: 3rem !important;
}
.m-xxl-auto {
margin: auto !important;
}
.mx-xxl-0 {
margin-right: 0 !important;
margin-left: 0 !important;
}
.mx-xxl-1 {
margin-right: 0.25rem !important;
margin-left: 0.25rem !important;
}
.mx-xxl-2 {
margin-right: 0.5rem !important;
margin-left: 0.5rem !important;
}
.mx-xxl-3 {
margin-right: 1rem !important;
margin-left: 1rem !important;
}
.mx-xxl-4 {
margin-right: 1.5rem !important;
margin-left: 1.5rem !important;
}
.mx-xxl-5 {
margin-right: 3rem !important;
margin-left: 3rem !important;
}
.mx-xxl-auto {
margin-right: auto !important;
margin-left: auto !important;
}
.my-xxl-0 {
margin-top: 0 !important;
margin-bottom: 0 !important;
}
.my-xxl-1 {
margin-top: 0.25rem !important;
margin-bottom: 0.25rem !important;
}
.my-xxl-2 {
margin-top: 0.5rem !important;
margin-bottom: 0.5rem !important;
}
.my-xxl-3 {
margin-top: 1rem !important;
margin-bottom: 1rem !important;
}
.my-xxl-4 {
margin-top: 1.5rem !important;
margin-bottom: 1.5rem !important;
}
.my-xxl-5 {
margin-top: 3rem !important;
margin-bottom: 3rem !important;
}
.my-xxl-auto {
margin-top: auto !important;
margin-bottom: auto !important;
}
.mt-xxl-0 {
margin-top: 0 !important;
}
.mt-xxl-1 {
margin-top: 0.25rem !important;
}
.mt-xxl-2 {
margin-top: 0.5rem !important;
}
.mt-xxl-3 {
margin-top: 1rem !important;
}
.mt-xxl-4 {
margin-top: 1.5rem !important;
}
.mt-xxl-5 {
margin-top: 3rem !important;
}
.mt-xxl-auto {
margin-top: auto !important;
}
.me-xxl-0 {
margin-right: 0 !important;
}
.me-xxl-1 {
margin-right: 0.25rem !important;
}
.me-xxl-2 {
margin-right: 0.5rem !important;
}
.me-xxl-3 {
margin-right: 1rem !important;
}
.me-xxl-4 {
margin-right: 1.5rem !important;
}
.me-xxl-5 {
margin-right: 3rem !important;
}
.me-xxl-auto {
margin-right: auto !important;
}
.mb-xxl-0 {
margin-bottom: 0 !important;
}
.mb-xxl-1 {
margin-bottom: 0.25rem !important;
}
.mb-xxl-2 {
margin-bottom: 0.5rem !important;
}
.mb-xxl-3 {
margin-bottom: 1rem !important;
}
.mb-xxl-4 {
margin-bottom: 1.5rem !important;
}
.mb-xxl-5 {
margin-bottom: 3rem !important;
}
.mb-xxl-auto {
margin-bottom: auto !important;
}
.ms-xxl-0 {
margin-left: 0 !important;
}
.ms-xxl-1 {
margin-left: 0.25rem !important;
}
.ms-xxl-2 {
margin-left: 0.5rem !important;
}
.ms-xxl-3 {
margin-left: 1rem !important;
}
.ms-xxl-4 {
margin-left: 1.5rem !important;
}
.ms-xxl-5 {
margin-left: 3rem !important;
}
.ms-xxl-auto {
margin-left: auto !important;
}
.p-xxl-0 {
padding: 0 !important;
}
.p-xxl-1 {
padding: 0.25rem !important;
}
.p-xxl-2 {
padding: 0.5rem !important;
}
.p-xxl-3 {
padding: 1rem !important;
}
.p-xxl-4 {
padding: 1.5rem !important;
}
.p-xxl-5 {
padding: 3rem !important;
}
.px-xxl-0 {
padding-right: 0 !important;
padding-left: 0 !important;
}
.px-xxl-1 {
padding-right: 0.25rem !important;
padding-left: 0.25rem !important;
}
.px-xxl-2 {
padding-right: 0.5rem !important;
padding-left: 0.5rem !important;
}
.px-xxl-3 {
padding-right: 1rem !important;
padding-left: 1rem !important;
}
.px-xxl-4 {
padding-right: 1.5rem !important;
padding-left: 1.5rem !important;
}
.px-xxl-5 {
padding-right: 3rem !important;
padding-left: 3rem !important;
}
.py-xxl-0 {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
.py-xxl-1 {
padding-top: 0.25rem !important;
padding-bottom: 0.25rem !important;
}
.py-xxl-2 {
padding-top: 0.5rem !important;
padding-bottom: 0.5rem !important;
}
.py-xxl-3 {
padding-top: 1rem !important;
padding-bottom: 1rem !important;
}
.py-xxl-4 {
padding-top: 1.5rem !important;
padding-bottom: 1.5rem !important;
}
.py-xxl-5 {
padding-top: 3rem !important;
padding-bottom: 3rem !important;
}
.pt-xxl-0 {
padding-top: 0 !important;
}
.pt-xxl-1 {
padding-top: 0.25rem !important;
}
.pt-xxl-2 {
padding-top: 0.5rem !important;
}
.pt-xxl-3 {
padding-top: 1rem !important;
}
.pt-xxl-4 {
padding-top: 1.5rem !important;
}
.pt-xxl-5 {
padding-top: 3rem !important;
}
.pe-xxl-0 {
padding-right: 0 !important;
}
.pe-xxl-1 {
padding-right: 0.25rem !important;
}
.pe-xxl-2 {
padding-right: 0.5rem !important;
}
.pe-xxl-3 {
padding-right: 1rem !important;
}
.pe-xxl-4 {
padding-right: 1.5rem !important;
}
.pe-xxl-5 {
padding-right: 3rem !important;
}
.pb-xxl-0 {
padding-bottom: 0 !important;
}
.pb-xxl-1 {
padding-bottom: 0.25rem !important;
}
.pb-xxl-2 {
padding-bottom: 0.5rem !important;
}
.pb-xxl-3 {
padding-bottom: 1rem !important;
}
.pb-xxl-4 {
padding-bottom: 1.5rem !important;
}
.pb-xxl-5 {
padding-bottom: 3rem !important;
}
.ps-xxl-0 {
padding-left: 0 !important;
}
.ps-xxl-1 {
padding-left: 0.25rem !important;
}
.ps-xxl-2 {
padding-left: 0.5rem !important;
}
.ps-xxl-3 {
padding-left: 1rem !important;
}
.ps-xxl-4 {
padding-left: 1.5rem !important;
}
.ps-xxl-5 {
padding-left: 3rem !important;
}
.text-xxl-start {
text-align: left !important;
}
.text-xxl-end {
text-align: right !important;
}
.text-xxl-center {
text-align: center !important;
}
}
@media (min-width: 1200px) { @media (min-width: 1200px) {
.fs-1 { .fs-1 {
font-size: 2.1875rem !important; font-size: 2.1875rem !important;
@ -10386,5 +11195,6 @@ html[data-devenv]:before {
@media (min-width: 576px) and (max-width: 767px) { html[data-devenv]:before { content: 'SM'; } } @media (min-width: 576px) and (max-width: 767px) { html[data-devenv]:before { content: 'SM'; } }
@media (min-width: 768px) and (max-width: 991px) { html[data-devenv]:before { content: 'MD'; } } @media (min-width: 768px) and (max-width: 991px) { html[data-devenv]:before { content: 'MD'; } }
@media (min-width: 992px) and (max-width: 1199px) { html[data-devenv]:before { content: 'LG'; } } @media (min-width: 992px) and (max-width: 1199px) { html[data-devenv]:before { content: 'LG'; } }
@media (min-width: 1200px) { html[data-devenv]:before { content: 'XL'; } } @media (min-width: 1200px) and (max-width: 1399px) { html[data-devenv]:before { content: 'XL'; } }
@media (min-width: 1400px) { html[data-devenv]:before { content: 'XXL'; } }
@media print { html[data-devenv]:before { content: none; } } @media print { html[data-devenv]:before { content: none; } }

View file

@ -59,6 +59,12 @@ hr.primary {
} }
} }
@media (min-width: 1400px) {
.col-xxl-constrain {
max-width: 800px;
}
}
/* Info icons in main headline */ /* Info icons in main headline */
h2 small .fa-question-circle-o { h2 small .fa-question-circle-o {
position: relative; position: relative;
@ -200,3 +206,19 @@ svg.icon-note {
.services-list .service h6 { .services-list .service h6 {
margin: var(--btcpay-space-m) 0 0 0; margin: var(--btcpay-space-m) 0 0 0;
} }
/* Setup Guide */
#SetupGuide {
max-width: 30em;
}
#SetupGuide .list-group-item .icon {
width: 1.5rem;
height: 1.5rem;
margin: 1rem;
}
#SetupGuide .list-group-item .content {
flex: 1;
padding: 1rem 0;
}