Merge pull request #1121 from NicolasDorier/ux/login-register

Add sponsor and new design to the login and registration page
This commit is contained in:
Nicolas Dorier 2019-11-06 15:29:36 +09:00 committed by GitHub
commit d392880102
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 367 additions and 152 deletions

View file

@ -18,7 +18,7 @@ namespace BTCPayServer.Tests
[Trait("Selenium", "Selenium")]
public class CheckoutUITests
{
public const int TestTimeout = 60_000;
public const int TestTimeout = TestUtils.TestTimeout;
public CheckoutUITests(ITestOutputHelper helper)
{
Logs.Tester = new XUnitLog(helper) { Name = "Tests" };
@ -32,6 +32,7 @@ namespace BTCPayServer.Tests
using (var s = SeleniumTester.Create())
{
await s.StartAsync();
s.GoToRegister();
s.RegisterNewUser();
var store = s.CreateNewStore();
s.AddDerivationScheme("BTC");
@ -80,6 +81,7 @@ namespace BTCPayServer.Tests
using (var s = SeleniumTester.Create())
{
await s.StartAsync();
s.GoToRegister();
s.RegisterNewUser();
var store = s.CreateNewStore();
s.AddDerivationScheme("BTC");
@ -109,6 +111,7 @@ namespace BTCPayServer.Tests
using (var s = SeleniumTester.Create())
{
await s.StartAsync();
s.GoToRegister();
s.RegisterNewUser();
var store = s.CreateNewStore();
s.AddDerivationScheme("BTC");
@ -152,6 +155,7 @@ namespace BTCPayServer.Tests
using (var s = SeleniumTester.Create())
{
await s.StartAsync();
s.GoToRegister();
s.RegisterNewUser();
var store = s.CreateNewStore();
s.AddInternalLightningNode("BTC");

View file

@ -28,8 +28,11 @@ namespace BTCPayServer.Tests
try
{
Assert.NotEmpty(driver.FindElements(By.ClassName("navbar-brand")));
foreach (var dangerAlert in driver.FindElements(By.ClassName("alert-danger")))
Assert.False(dangerAlert.Displayed, "No alert should be displayed");
if (driver.PageSource.Contains("alert-danger"))
{
foreach (var dangerAlert in driver.FindElements(By.ClassName("alert-danger")))
Assert.False(dangerAlert.Displayed, "No alert should be displayed");
}
}
catch
{

View file

@ -66,7 +66,7 @@ namespace BTCPayServer.Tests
Logs.Tester.LogInformation("Selenium: Browsing to " + Server.PayTester.ServerUri);
Logs.Tester.LogInformation($"Selenium: Resolution {Driver.Manage().Window.Size}");
Driver.Manage().Timeouts().ImplicitWait = ImplicitWait;
Driver.Navigate().GoToUrl(Server.PayTester.ServerUri);
GoToRegister();
Driver.AssertNoError();
}
@ -76,10 +76,13 @@ namespace BTCPayServer.Tests
return Server.PayTester.ServerUri.AbsoluteUri.WithoutEndingSlash() + relativeLink.WithStartingSlash();
}
public void GoToRegister()
{
Driver.Navigate().GoToUrl(this.Link("/Account/Register"));
}
public string RegisterNewUser(bool isAdmin = false)
{
var usr = RandomUtils.GetUInt256().ToString().Substring(64 - 20) + "@a.com";
Driver.FindElement(By.Id("Register")).Click();
Driver.FindElement(By.Id("Email")).SendKeys(usr);
Driver.FindElement(By.Id("Password")).SendKeys("123456");
Driver.FindElement(By.Id("ConfirmPassword")).SendKeys("123456");

View file

@ -46,8 +46,7 @@ namespace BTCPayServer.Tests
var email = s.RegisterNewUser();
s.Driver.FindElement(By.Id("Logout")).Click();
s.Driver.AssertNoError();
s.Driver.FindElement(By.Id("Login")).Click();
s.Driver.AssertNoError();
Assert.Contains("Account/Login", s.Driver.Url);
s.Driver.Navigate().GoToUrl(s.Link("/invoices"));
Assert.Contains("ReturnUrl=%2Finvoices", s.Driver.Url);
@ -76,7 +75,6 @@ namespace BTCPayServer.Tests
s.Driver.AssertNoError();
//Log In With New Password
s.Driver.FindElement(By.Id("Login")).Click();
s.Driver.FindElement(By.Id("Email")).SendKeys(email);
s.Driver.FindElement(By.Id("Password")).SendKeys("abc???");
s.Driver.FindElement(By.Id("LoginButton")).Click();
@ -91,7 +89,6 @@ namespace BTCPayServer.Tests
static void LogIn(SeleniumTester s, string email)
{
s.Driver.FindElement(By.Id("Login")).Click();
s.Driver.FindElement(By.Id("Email")).SendKeys(email);
s.Driver.FindElement(By.Id("Password")).SendKeys("123456");
s.Driver.FindElement(By.Id("LoginButton")).Click();
@ -208,7 +205,7 @@ namespace BTCPayServer.Tests
Assert.Contains("ReturnUrl", s.Driver.Url);
s.Driver.Navigate().GoToUrl(invoiceUrl);
Assert.Contains("ReturnUrl", s.Driver.Url);
s.GoToRegister();
// When logged we should not be able to access store and invoice details
var bob = s.RegisterNewUser();
s.Driver.Navigate().GoToUrl(storeUrl);
@ -252,7 +249,7 @@ namespace BTCPayServer.Tests
await s.StartAsync();
s.Driver.Navigate().GoToUrl(s.Link("/api-access-request"));
Assert.Contains("ReturnUrl", s.Driver.Url);
s.GoToRegister();
var alice = s.RegisterNewUser();
var store = s.CreateNewStore().storeName;
s.AddDerivationScheme();

View file

@ -398,7 +398,9 @@ namespace BTCPayServer.Controllers
{
await _RoleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin));
await _userManager.AddToRoleAsync(user, Roles.ServerAdmin);
var settings = await _SettingsRepository.GetSettingAsync<ThemeSettings>();
settings.FirstRun = false;
await _SettingsRepository.UpdateSetting<ThemeSettings>(settings);
if(_Options.DisableRegistration)
{
// Once the admin user has been created lock subsequent user registrations (needs to be disabled for unit tests that require multiple users).

View file

@ -12,6 +12,8 @@ using Newtonsoft.Json;
using BTCPayServer.Services;
using BTCPayServer.HostedServices;
using BTCPayServer.Services.Apps;
using Microsoft.AspNetCore.Identity;
using BTCPayServer.Data;
namespace BTCPayServer.Controllers
{
@ -20,11 +22,15 @@ namespace BTCPayServer.Controllers
private readonly CssThemeManager _cachedServerSettings;
public IHttpClientFactory HttpClientFactory { get; }
SignInManager<ApplicationUser> SignInManager { get; }
public HomeController(IHttpClientFactory httpClientFactory, CssThemeManager cachedServerSettings)
public HomeController(IHttpClientFactory httpClientFactory,
CssThemeManager cachedServerSettings,
SignInManager<ApplicationUser> signInManager)
{
HttpClientFactory = httpClientFactory;
_cachedServerSettings = cachedServerSettings;
SignInManager = signInManager;
}
private async Task<ViewResult> GoToApp(string appId, AppType? appType)
@ -71,14 +77,26 @@ namespace BTCPayServer.Controllers
public async Task<IActionResult> Index()
{
if (_cachedServerSettings.FirstRun)
{
return RedirectToAction(nameof(AccountController.Register), "Account");
}
var matchedDomainMapping = _cachedServerSettings.DomainToAppMapping.FirstOrDefault(item =>
item.Domain.Equals(Request.Host.Host, StringComparison.InvariantCultureIgnoreCase));
if (matchedDomainMapping != null)
{
return await GoToApp(matchedDomainMapping.AppId, matchedDomainMapping.AppType) ?? View("Home");
return await GoToApp(matchedDomainMapping.AppId, matchedDomainMapping.AppType) ?? GoToHome();
}
return await GoToApp(_cachedServerSettings.RootAppId, _cachedServerSettings.RootAppType) ?? View("Home");
return await GoToApp(_cachedServerSettings.RootAppId, _cachedServerSettings.RootAppType) ?? GoToHome();
}
private IActionResult GoToHome()
{
if (SignInManager.IsSignedIn(User))
return View("Home");
else
return RedirectToAction(nameof(AccountController.Login), "Account");
}
[Route("translate")]

View file

@ -31,6 +31,7 @@ namespace BTCPayServer.HostedServices
_creativeStartUri = "/vendor/bootstrap4-creativestart/creative.css?v=" + DateTime.Now.Ticks;
else
_creativeStartUri = data.CreativeStartCssUri;
FirstRun = data.FirstRun;
}
private string _bootstrapUri;
@ -52,6 +53,8 @@ namespace BTCPayServer.HostedServices
public AppType? RootAppType { get; set; }
public string RootAppId { get; set; }
public bool FirstRun { get; set; }
public List<PoliciesSettings.DomainToAppMappingItem> DomainToAppMapping { get; set; } = new List<PoliciesSettings.DomainToAppMappingItem>();
internal void Update(PoliciesSettings data)

View file

@ -10,6 +10,7 @@ using BTCPayServer.Services.Stores;
using BTCPayServer.Logging;
using System.Threading;
using Npgsql;
using Microsoft.AspNetCore.Identity;
namespace BTCPayServer
{
@ -19,16 +20,19 @@ namespace BTCPayServer
private StoreRepository _StoreRepository;
private BTCPayNetworkProvider _NetworkProvider;
private SettingsRepository _Settings;
private readonly UserManager<ApplicationUser> _userManager;
public MigrationStartupTask(
BTCPayNetworkProvider networkProvider,
StoreRepository storeRepository,
ApplicationDbContextFactory dbContextFactory,
UserManager<ApplicationUser> userManager,
SettingsRepository settingsRepository)
{
_DBContextFactory = dbContextFactory;
_StoreRepository = storeRepository;
_NetworkProvider = networkProvider;
_Settings = settingsRepository;
_userManager = userManager;
}
public async Task ExecuteAsync(CancellationToken cancellationToken = default)
{
@ -72,6 +76,15 @@ namespace BTCPayServer
settings.ConvertWalletKeyPathRoots = true;
await _Settings.UpdateSetting(settings);
}
if (!settings.CheckedFirstRun)
{
var themeSettings = await _Settings.GetSettingAsync<ThemeSettings>() ?? new ThemeSettings();
var admin = await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin);
themeSettings.FirstRun = admin.Count == 0;
await _Settings.UpdateSetting(themeSettings);
settings.CheckedFirstRun = true;
await _Settings.UpdateSetting(settings);
}
}
catch (Exception ex)
{

View file

@ -13,6 +13,7 @@ namespace BTCPayServer.Services
public bool ConvertNetworkFeeProperty { get; set; }
public bool ConvertCrowdfundOldSettings { get; set; }
public bool ConvertWalletKeyPathRoots { get; set; }
public bool CheckedFirstRun { get; set; }
public override string ToString()
{
return string.Empty;

View file

@ -16,5 +16,11 @@ namespace BTCPayServer.Services
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public string CreativeStartCssUri { get; set; }
public bool FirstRun { get; set; }
public override string ToString()
{
// no logs
return string.Empty;
}
}
}

View file

@ -1,54 +1,46 @@
@model LoginViewModel
@inject SignInManager<ApplicationUser> SignInManager
@inject BTCPayServer.HostedServices.CssThemeManager themeManager
@{
ViewData["Title"] = "Log in";
Layout = "_WelcomeLayout.cshtml";
}
<section>
<div>
<div class="modal-dialog modal-login">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Sign In</h4>
</div>
<div class="modal-body">
<form asp-route-returnurl="@ViewData["ReturnUrl"]" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<label for="Email" class="input-group-text"><span class="input-group-addon fa fa-user"></span></label>
</div>
<input asp-for="Email" class="form-control" placeholder="Email" required="required" />
</div>
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<label for="Password" class="input-group-text"><span class="input-group-addon fa fa-lock"></span></label>
</div>
<input asp-for="Password" class="form-control" placeholder="Password" required="required" />
</div>
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block btn-lg" id="LoginButton">Sign in</button>
</div>
<p class="hint-text"><a asp-action="ForgotPassword">Forgot your password?</a></p>
</form>
</div>
@if (themeManager.ShowRegister)
{
<div class="modal-footer"><span>Don't have an account?&nbsp;<a asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]">Create one</a></span></div>
}
</div>
<div class="modal-dialog modal-login">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Sign In</h4>
</div>
<div class="modal-body">
<form asp-route-returnurl="@ViewData["ReturnUrl"]" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<label for="Email" class="input-group-text"><span class="input-group-addon fa fa-user"></span></label>
</div>
<input asp-for="Email" class="form-control" placeholder="Email" required="required" />
</div>
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<label for="Password" class="input-group-text"><span class="input-group-addon fa fa-lock"></span></label>
</div>
<input asp-for="Password" class="form-control" placeholder="Password" required="required" />
</div>
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block btn-lg" id="LoginButton">Sign in</button>
</div>
<p class="hint-text"><a asp-action="ForgotPassword">Forgot your password?</a></p>
</form>
</div>
@if (themeManager.ShowRegister)
{
<div class="modal-footer"><span>Don't have an account?&nbsp;<a id="Register" asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]">Create one</a></span></div>
}
</div>
</section>
@section Scripts {
@await Html.PartialAsync("_ValidationScriptsPartial")
}
</div>

View file

@ -1,62 +1,56 @@
@model RegisterViewModel
@{
ViewData["Title"] = "Register";
Layout = "_WelcomeLayout.cshtml";
}
<section>
<div>
<div class="modal-dialog modal-login">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Create account</h4>
<div class="modal-dialog modal-login">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Create account</h4>
</div>
<div class="modal-body">
<form asp-route-returnUrl="@ViewData["ReturnUrl"]" asp-route-logon="@ViewData["Logon"]" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<label for="Email" class="input-group-text"><span class="input-group-addon fa fa-user"></span></label>
</div>
<input asp-for="Email" class="form-control" placeholder="Email" required="required" />
</div>
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="modal-body">
<form asp-route-returnUrl="@ViewData["ReturnUrl"]" asp-route-logon="@ViewData["Logon"]" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<label for="Email" class="input-group-text"><span class="input-group-addon fa fa-user"></span></label>
</div>
<input asp-for="Email" class="form-control" placeholder="Email" required="required"/>
</div>
<span asp-validation-for="Email" class="text-danger"></span>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<label for="Password" class="input-group-text"><span class="input-group-addon fa fa-lock"></span></label>
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<label for="Password" class="input-group-text"><span class="input-group-addon fa fa-lock"></span></label>
</div>
<input asp-for="Password" class="form-control" placeholder="Password" required="required"/>
</div>
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<label for="ConfirmPassword" class="input-group-text"><span class="input-group-addon fa fa-lock"></span></label>
</div>
<input asp-for="ConfirmPassword" class="form-control" placeholder="Repeat password" required="required"/>
</div>
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
</div>
@if (ViewData["AllowIsAdmin"] is true)
{
<div class="form-group">
<label asp-for="IsAdmin"></label>
<input asp-for="IsAdmin" type="checkbox" class="form-check-inline"/>
<span asp-validation-for="IsAdmin" class="text-danger"></span>
</div>
}
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block btn-lg" id="RegisterButton">Create account</button>
</div>
</form>
<input asp-for="Password" class="form-control" placeholder="Password" required="required" />
</div>
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<label for="ConfirmPassword" class="input-group-text"><span class="input-group-addon fa fa-lock"></span></label>
</div>
<input asp-for="ConfirmPassword" class="form-control" placeholder="Repeat password" required="required" />
</div>
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
</div>
@if (ViewData["AllowIsAdmin"] is true)
{
<div class="form-group">
<label asp-for="IsAdmin"></label>
<input asp-for="IsAdmin" type="checkbox" class="form-check-inline" />
<span asp-validation-for="IsAdmin" class="text-danger"></span>
</div>
}
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block btn-lg" id="RegisterButton">Create account</button>
</div>
</form>
</div>
</div>
</section>
@section Scripts {
@await Html.PartialAsync("_ValidationScriptsPartial")
}
</div>

View file

@ -0,0 +1,76 @@
@model LoginViewModel
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<partial name="Header" />
<style>
.lead-title {
font-family: Montserrat;
font-style: normal;
font-weight: 600;
font-size: 40px;
line-height: 60px;
/* or 150% */
letter-spacing: 0.1em;
color: #000000;
}
.lead-login {
font-family: Montserrat;
font-style: normal;
font-weight: normal;
font-size: 18px;
line-height: 33px;
/* or 183% */
letter-spacing: 0.1em;
color: #000000;
}
.lead-h {
font-family: Montserrat;
font-style: normal;
margin-bottom: 30px;
font-weight: 600;
font-size: 14px;
line-height: 18px;
/* identical to box height, or 129% */
letter-spacing: 0.1em;
text-transform: uppercase;
color: #000000;
}
</style>
</head>
<body class="bg-light">
<section>
<!-- Dummy navbar-brand, hackish way to keep test AssertNoError passing -->
<div class="navbar-brand" style="display:none;"></div>
<div class="container">
<div class="row">
<div class="col-md-7">
<a asp-controller="Home" asp-action="Index"><img src="~/img/btcpay-logo.svg" alt="BTCPay Server" height="100" style="margin-bottom:30px;" /></a>
<h1 class="lead-title text-uppercase">Welcome to your BTCPay Server</h1>
<hr class="primary ml-0" style="margin-bottom:30px; margin-top:30px;">
<p class="lead-login" style="margin-bottom:69px;">BTCPay Server lets you process Bitcoin transactions seemlessly, enabling global and near-instant peer-to-peer payments</p>
<h3 class="lead-h">Our supporters</h3>
<div class="figure">
<a href="https://twitter.com/sqcrypto" target="_blank">
<img src="~/img/squarecrypto.svg" alt="Sponsor Square Crypto" height="100" />
</a>
<div class="figure-caption text-center">
<a href="https://twitter.com/sqcrypto" target="_blank">Square Crypto</a>
</div>
</div>
</div>
<div class="col-md-5" style="margin-top:50px;">
@RenderBody()
</div>
</div>
</div>
</section>
@await Html.PartialAsync("_ValidationScriptsPartial")
</body>
</html>

View file

@ -1,30 +1,14 @@
@model ConfirmModel
@inject BTCPayServer.HostedServices.NBXplorerDashboard dashboard
@inject BTCPayServer.HostedServices.CssThemeManager themeManager
@addTagHelper *, BundlerMinifier.TagHelpers
@{
ViewData["Title"] = Model.Title;
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="">
<meta name="author" content="">
@if (themeManager.DiscourageSearchEngines)
{
<META NAME="robots" CONTENT="noindex">
}
<title>BTCPay Server</title>
@* CSS *@
<link href="@this.Context.Request.GetRelativePathOrAbsolute(themeManager.BootstrapUri)" rel="stylesheet" />
<link href="@this.Context.Request.GetRelativePathOrAbsolute(themeManager.CreativeStartUri)" rel="stylesheet" />
<bundle name="wwwroot/bundles/main-bundle.min.css" />
@* JS *@
<bundle name="wwwroot/bundles/main-bundle.min.js" />
<partial name="Header" />
</head>
<body class="bg-light">
<div class="modal-dialog modal-dialog-centered">

View file

@ -0,0 +1,18 @@
@inject BTCPayServer.HostedServices.CssThemeManager themeManager
@addTagHelper *, BundlerMinifier.TagHelpers
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="">
<meta name="author" content="">
@if (themeManager.DiscourageSearchEngines)
{
<META NAME="robots" CONTENT="noindex">
}
<title>@ViewData["Title"]</title>
@* CSS *@
<link href="@this.Context.Request.GetRelativePathOrAbsolute(themeManager.BootstrapUri)" rel="stylesheet" />
<link href="@this.Context.Request.GetRelativePathOrAbsolute(themeManager.CreativeStartUri)" rel="stylesheet" />
<bundle name="wwwroot/bundles/main-bundle.min.css" />
@* JS *@
<bundle name="wwwroot/bundles/main-bundle.min.js" />

View file

@ -5,31 +5,11 @@
@inject BTCPayServer.HostedServices.NBXplorerDashboard dashboard
@inject BTCPayServer.HostedServices.CssThemeManager themeManager
@addTagHelper *, BundlerMinifier.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
@if (themeManager.DiscourageSearchEngines)
{
<META NAME="robots" CONTENT="noindex">
}
<title>BTCPay Server</title>
@* CSS *@
<link href="@this.Context.Request.GetRelativePathOrAbsolute(themeManager.BootstrapUri)" rel="stylesheet" />
<link href="@this.Context.Request.GetRelativePathOrAbsolute(themeManager.CreativeStartUri)" rel="stylesheet" />
<bundle name="wwwroot/bundles/main-bundle.min.css" />
@* JS *@
<bundle name="wwwroot/bundles/main-bundle.min.js" />
<partial name="Header" />
@RenderSection("HeadScripts", required: false)
@RenderSection("HeaderContent", false)

View file

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="650 0 1706.6667 1066.6667"
height="1066.6667"
width="1706.6667"
xml:space="preserve"
id="svg2"
version="1.1"
sodipodi:docname="BTCPay Server Icon.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview82"
showgrid="false"
inkscape:zoom="0.16640624"
inkscape:cx="853.33337"
inkscape:cy="533.33337"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g10" /><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
id="clipPath18"
clipPathUnits="userSpaceOnUse"><path
id="path16"
d="M 0,800 H 1280 V 0 H 0 Z" /></clipPath><clipPath
id="clipPath74"
clipPathUnits="userSpaceOnUse"><path
id="path72"
d="M 0,800 H 1280 V 0 H 0 Z" /></clipPath><clipPath
id="clipPath128"
clipPathUnits="userSpaceOnUse"><path
id="path126"
d="M 0,800 H 1280 V 0 H 0 Z" /></clipPath><clipPath
id="clipPath140"
clipPathUnits="userSpaceOnUse"><path
id="path138"
d="M 0,800 H 1280 V 0 H 0 Z" /></clipPath></defs><g
transform="matrix(1.3333333,0,0,-1.3333333,955.493,249.38967)"
id="g10"><g
transform="matrix(0.29765316,0,0,0.29765316,413.69235,44.782893)"
id="g134"><g
transform="matrix(3.6585926,0,0,3.6585926,-4809.6898,-2104.6753)"
clip-path="url(#clipPath140)"
id="g136"><g
transform="matrix(4.7732059,0,0,4.7732059,779.20458,11.551291)"
id="g146"><path
id="path148"
style="fill:#cedc21;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -4.573,0 -8.281,3.707 -8.281,8.28 v 124.622 c 0,4.573 3.708,8.281 8.281,8.281 4.573,0 8.281,-3.708 8.281,-8.281 V 8.28 C 8.281,3.707 4.573,0 0,0"
inkscape:connector-curvature="0" /></g><g
transform="matrix(4.7732059,0,0,4.7732059,779.22987,11.542212)"
id="g150"><path
id="path152"
style="fill:#51b13e;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -3.099,0 -6.069,1.746 -7.487,4.731 -1.96,4.132 -0.201,9.072 3.931,11.033 l 49.934,23.698 -51.295,37.79 c -3.682,2.713 -4.468,7.897 -1.754,11.58 2.711,3.681 7.898,4.467 11.577,1.754 L 67.347,44.583 c 2.345,-1.728 3.611,-4.56 3.331,-7.46 -0.279,-2.898 -2.06,-5.438 -4.693,-6.687 L 3.545,0.802 C 2.399,0.258 1.19,0 0,0"
inkscape:connector-curvature="0" /></g><g
transform="matrix(4.7732059,0,0,4.7732059,779.23704,245.35911)"
id="g154"><path
id="path156"
style="fill:#cedc21;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -2.542,0 -5.05,1.166 -6.673,3.369 -2.713,3.683 -1.928,8.867 1.755,11.579 L 46.376,52.739 -3.557,76.438 c -4.132,1.96 -5.891,6.899 -3.931,11.031 1.962,4.132 6.902,5.893 11.031,3.93 L 65.984,61.766 c 2.632,-1.249 4.414,-3.789 4.693,-6.688 0.279,-2.9 -0.987,-5.733 -3.332,-7.46 L 4.905,1.614 C 3.426,0.525 1.705,0 0,0"
inkscape:connector-curvature="0" /></g><g
transform="matrix(4.7732059,0,0,4.7732059,818.73005,432.0807)"
id="g158"><path
id="path160"
style="fill:#1e7a44;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 v -35.022 l 23.757,17.503 z"
inkscape:connector-curvature="0" /></g><path
id="path162"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.77320623"
d="m 818.73151,309.4809 h -79.05385 v 192.68958 h 79.05385 z"
inkscape:connector-curvature="0" /><g
transform="matrix(4.7732059,0,0,4.7732059,779.20458,685.44488)"
id="g164"><path
id="path166"
style="fill:#cedc21;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 C -4.573,0 -8.281,-3.708 -8.281,-8.281 V -112.496 H 8.281 V -8.281 C 8.281,-3.708 4.573,0 0,0"
inkscape:connector-curvature="0" /></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

@ -0,0 +1,24 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
<g>
<g>
<defs>
<path id="SVGID_1_" d="M38.001,423.401C38.001,444.72,55.283,462,76.599,462c21.319,0,38.604-17.28,38.604-38.599
c0-21.315-17.285-38.599-38.604-38.599C55.283,384.803,38.001,402.086,38.001,423.401 M192.399,384.803v77.194H418.65
c23.939,0,43.348-19.408,43.348-43.347v-33.848H192.399z M38.001,288.603h269.6v-77.198h-269.6V288.603z M384.801,250.002
c0,21.318,17.281,38.601,38.6,38.601s38.598-17.282,38.598-38.601c0-21.319-17.279-38.602-38.598-38.602
S384.801,228.683,384.801,250.002 M38.001,76.604c0,21.314,17.281,38.598,38.597,38.598c21.319,0,38.604-17.283,38.604-38.598
C115.203,55.286,97.917,38,76.599,38C55.283,38,38.001,55.286,38.001,76.604 M192.399,38v77.202h269.599V81.349
C461.998,57.411,442.59,38,418.65,38H192.399z"></path>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" overflow="visible"></use>
</clipPath>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-0.9131" y1="500" x2="1.9136" y2="500" gradientTransform="matrix(150 0 0 -150 175 75250)">
<stop offset="0" style="stop-color:#FF00FF"></stop>
<stop offset="1" style="stop-color:#0000FF"></stop>
</linearGradient>
<rect x="38.001" y="38" clip-path="url(#SVGID_2_)" fill="url(#SVGID_3_)" width="423.997" height="424"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB