I'll make an example with the Acme.BookStore project and modify the login page of the ABP Commercial MVC
template.
To replace a view/CSS with a new one, rename your new file as the original one and put it in the same directory with the original directory path.
For this example, I'll overwrite Account/Login
page.
Below is the content of my customized login view.
Create a file named Default.cshtml and put it in the folder *Acme.BookStore\src\Acme.BookStore.Web\Themes\Lepton\Layouts\Account*
Set this file as Embeded Resource
. This is needed only for the files that come from the ABP Framework and modules.
Default.cshtml
@using System.Globalization
@using Microsoft.Extensions.Localization
@using Microsoft.Extensions.Options
@using Volo.Abp.AspNetCore.MultiTenancy
@using Volo.Abp.AspNetCore.Mvc.AntiForgery
@using Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook
@using Volo.Abp.AspNetCore.Mvc.UI.Layout
@using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Bundling
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Themes.Lepton.Components.Content.Alerts
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Themes.Lepton.Components.Header.Brand
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Themes.Lepton.Components.Toolbar.LanguageSwitch
@using Volo.Abp.AspNetCore.Mvc.UI.Theming
@using Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetScripts
@using Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetStyles
@using Volo.Abp.Localization
@using Volo.Abp.MultiTenancy
@inject IAbpAntiForgeryManager AbpAntiForgeryManager
@inject IBrandingProvider BrandingProvider
@inject IPageLayout PageLayout
@inject IOptions<AbpMultiTenancyOptions> MultiTenancyOptions
@inject IOptions<AbpLocalizationOptions> LocalizationOptions
@inject ICurrentTenant CurrentTenant
@inject IStringLocalizer<AbpUiMultiTenancyResource> MultiTenancyStringLocalizer
@inject ITenantResolveResultAccessor TenantResolveResultAccessor
@{
Layout = null;
AbpAntiForgeryManager.SetCookie();
var containerClass = ViewBag.FluidLayout == true ? "container-fluid" : "container";
}
<!DOCTYPE html>
<html lang="@System.Globalization.CultureInfo.CurrentCulture.Name">
<head>
@await Component.InvokeLayoutHookAsync(LayoutHooks.Head.First, StandardLayouts.Account)
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>@(ViewBag.Title == null ? BrandingProvider.AppName : ViewBag.Title)</title>
<abp-style-bundle name="@LeptonThemeBundles.Styles.Global" />
<abp-style src="/Themes/Lepton/Layouts/Account/Default.css" />
@await Component.InvokeAsync(typeof(WidgetStylesViewComponent))
@await RenderSectionAsync("styles", false)
@await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Account)
</head>
<body class="abp-account-layout login-page-body">
@await Component.InvokeLayoutHookAsync(LayoutHooks.Body.First, StandardLayouts.Account)
<div class="loader">
<div class="indicator">
<svg width="16px" height="12px">
<polyline id="back" points="1 6 4 6 6 11 10 1 12 6 15 6"></polyline>
<polyline id="front" points="1 6 4 6 6 11 10 1 12 6 15 6"></polyline>
</svg>
</div>
</div>
<div class="container-fluid">
<div class="@containerClass responsive-image">
<h1 class="text-center title-font">Welcome to My Custom Login Page</h1>
<abp-row>
<abp-column size-md="_7" size-lg="_5" class="mx-auto">
<div class="card transparent-background mb-5">
<div class="card-header">
<h2 class="card-title d-inline-block">Please Sign In</h2>
@if (LocalizationOptions.Value.Languages.Count > 1)
{
<nav class="navbar navbar-expand p-0 pt-1 float-right">
<ul class="navbar-nav ml-auto toolbar-nav">
<li class="nav-item">
@(await Component.InvokeAsync<LanguageSwitchViewComponent>())
</li>
</ul>
</nav>
}
</div>
@if (MultiTenancyOptions.Value.IsEnabled &&
(TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(CookieTenantResolveContributor.ContributorName) == true))
{
<div class="card-header bg-light">
<div class="tenant-switch-box">
<div class="row">
<div class="col pr-1">
<h6 class="m-0">
@MultiTenancyStringLocalizer["Tenant"]
</h6>
@if (CurrentTenant.Id == null)
{
<i class="text-muted">@MultiTenancyStringLocalizer["NotSelected"]</i>
}
else
{
<span> Your tenant name <strong>@(CurrentTenant.Name ?? CurrentTenant.Id.Value.ToString())</strong></span>
}
</div>
<div class="col-auto pl-1">
<a id="AbpTenantSwitchLink" style="cursor: pointer" href="javascript:;" class="btn btn-sm btn-outline-primary float-right">@MultiTenancyStringLocalizer["Switch"]</a>
</div>
</div>
</div>
</div>
}
<div class="card-body">
@(await Component.InvokeAsync<ContentAlertsViewComponent>())
@RenderBody()
</div>
</div>
</abp-column>
</abp-row>
</div>
<div class="p-4 text-center text-muted">
@await Html.PartialAsync("~/Themes/Lepton/Layouts/Account/_Footer.cshtml")
</div>
</div>
<abp-script-bundle name="@LeptonThemeBundles.Scripts.Global" />
<script type="text/javascript" src="~/Abp/ApplicationConfigurationScript"></script>
<script type="text/javascript" src="~/Abp/ServiceProxyScript"></script>
@await Component.InvokeAsync(typeof(WidgetScriptsViewComponent))
@await RenderSectionAsync("scripts", false)
@await Component.InvokeLayoutHookAsync(LayoutHooks.Body.Last, StandardLayouts.Account)
</body>
</html>
Create your own Default.css and put it in the same folder Acme.BookStore\src\Acme.BookStore.Web\Themes\Lepton\Layouts\Account
Set this file as Embeded Resource
.
Default.css
.login-header {
height: 110px;
background-color: grey;
padding-top: 20px;
margin-right: auto;
margin-left: auto;
padding-left: 0px;
padding-right: 0px;
}
.login-page-body {
background: white;
}
.logo-container {
float: right !important;
}
.responsive-image {
background-color: bisque;
width: 100% !important;
}
.title-font {
font-size: 32px;
color: #FFFFFF;
font-weight: 300;
padding: 18px 0 44px;
text-align: center;
}
.transparent-background {
background: rgba(255, 255, 255, 0.5);
border-color: #FFFFFF;
}
.btn.btn-primary {
width: auto !important;
}
.navbar {
background-color: transparent !important;
}
.btn.btn-outline-primary {
color: #011c4c !important;
border-color: #011c4c !important;
}
a {
color: #011c4c !important;
}
Edit the existing BookStoreWebModule.cs and add the below to have 1 global CSS file. This will override the defaults:
BookStoreWebModule.cs
public override void ConfigureServices(ServiceConfigurationContext context)
{
//...
Configure<AbpBundlingOptions>(options =>
{
//add your global css files
options
.StyleBundles
.Get(StandardBundles.Styles.Global)
.AddFiles("/Pages/app.css");
});
Add the global app.css file in this directory => Acme.BookStore\src\Acme.BookStore.Web\Pages\app.css. And add some sample styles to overwrite the defaults:
.navbar {
background-color: #011C4C!important;
}
(This step is needed for v2.1.1 and older versions) Create a new file, named _ViewImports.cshtml for ABP TagHelpers and put it in the Acme.BookStore\src\Acme.BookStore.Web\Themes\Lepton\Layouts
_ViewImports.cshtml
@using System.Globalization
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling