Hi,
Most of the problems came from Perfect Scrollbar on Blazor, because in the Blazor Logic, DOM is updated at runtime without page refresh. So PS can't handle it.
We removed the perfect scrollbar from Blazor UI in the LeptonX version 3.1 (compatible to ABP v8.1.0) and the native scrollbar will be visible in the newer versions.
Hi,
You can override the following sections to make it fit to your conditions:
Probably you're familiar with this but if you struggle in any topic you can follow Overriding Services steps to override services in your application.
Menu items are added in here:
https://github.com/abpframework/abp/blob/73cd37f06717d1f920d224e00c1e4380a1244cf3/modules/cms-kit/src/Volo.CmsKit.Public.Web/Menus/CmsKitPublicMenuContributor.cs#L32-L41
But as a better single-point approach you can override MenuItemPublicAppService and add Host menu items always.
https://github.com/abpframework/abp/blob/73cd37f06717d1f920d224e00c1e4380a1244cf3/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs#L40
Even you show menu items from host, CMS Kit pages or blog post won't be opened, you should override PagePublicAppService and modify logic and make it includes Host entities too:
https://github.com/abpframework/abp/blob/dev/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PagePublicAppService.cs
And same for BlogPostPublicAppService
https://github.com/abpframework/abp/blob/dev/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs
You can use Disabling Data Filters feature for disabling
IMultiTenantfeature in the queries.
Hi, AbpApplication can't be initialized without retrieving application-configuration. So, it's not possible to initialize the same application without application configuration. Here are 2 ways to go:
1 ) You can cache application-configuration once it's retrieved and read application-configuration from local storage if it's not available, and you have to implement offline cases on each page. It's tough and complex way.
2 ) You can handle it if the backend isn't reachable and show the error page. (In that way application can't be opened without restarting when backend is available again)
Here the steps to show error in your application:
MauiProgram.cs, find the following code block and remove itapp.Services.GetRequiredService<IAbpApplicationWithExternalServiceProvider>().Initialize(app.Services);
App.xaml.cs and initialize it in here and show an error page when it can't be initialized. Change the MainPage = serviceProvider.GetRequiredService<AppShell>() section in theconstructor with the following pattern: try
{
serviceProvider.GetRequiredService<IAbpApplicationWithExternalServiceProvider>().Initialize(serviceProvider);
// Regular scenario, everything is fine:
MainPage = serviceProvider.GetRequiredService<AppShell>();
}
catch (Exception ex)
{
MainPage = new ContentPage { Content = new Label { Text = ex.Message } };
// Log the exception with your tracking tool, AppCenter, Sentry, etc.
// Crashes.TrackError(exception);
}
It seems the previous bug has been solved with the latest patch release.
Since it was a bug, your credit has been refunded
Can you check if overriding LogoUrl and LogoReverseUrl works or not?
In the LeptonX both of them should be defined at the same time since it supports client-side dark/light changes.
A default BrandingProvider should be included in your project by default.
[Dependency(ReplaceServices = true)]
public class MyProjectBrandingProvider : DefaultBrandingProvider
{
public override string LogoUrl => "/logo.png";
public override string LogoReverseUrl=> "/logo-dark.png";
}
Hi,
Confirmed that menu overflow it a bug of leptonx and we'll work on it.
For rest of the features;
Have you updated your blazor wasm bundles after switching between layouts with abp bundle command?
Try updating them cleanly, run abp clean first and then execute abp bundle command inside your blazor wasm project.
Yes, you need to add view imports to work that cshtml file work properly. Then, you'll be overridden the default logic page, you can make any changes according to LeptonX HTML demo
Can you check if abp-script tags are colored (Tag helpers are imported)
If not, you can crate a_ViewImports.cshtml file in the same folder with following imports:
@using System.Globalization
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
_(Or you can add them into the same file, but creating ViewImports is suggested.)
Sorry, my bad. You're right.
In the LeptonX, it'll beThemes/LeptonX/Layouts/Account/Default.cshtml
You can override this file for Account layout of LeptonX and existing content is below:
@using Microsoft.Extensions.Localization
@using Microsoft.Extensions.Options
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX
@using Volo.Abp.LeptonX.Shared.Localization;
@using Volo.Abp.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Bundling
@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.Ui.Branding
@using Volo.Abp.AspNetCore.Mvc.AntiForgery
@using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Localization
@using Volo.Abp.AspNetCore.MultiTenancy
@using Volo.Abp.MultiTenancy
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Themes.LeptonX.Components.Common.PageAlerts
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Themes.LeptonX.Components.SideMenu.Toolbar.LanguageSwitch
@using Microsoft.AspNetCore.Http.Extensions
@using Volo.Abp.Ui.LayoutHooks
@inject IAbpAntiForgeryManager AbpAntiForgeryManager
@inject IBrandingProvider BrandingProvider
@inject LeptonXStyleProvider LeptonXStyleProvider
@inject IStringLocalizer<AbpUiMultiTenancyResource> MultiTenancyStringLocalizer
@inject IStringLocalizer<LeptonXResource> L
@inject ITenantResolveResultAccessor TenantResolveResultAccessor
@inject IOptions<AbpMultiTenancyOptions> MultiTenancyOptions
@inject ICurrentTenant CurrentTenant
@inject ThemeLanguageInfoProvider ThemeLanguageInfoProvider
@inject Volo.Abp.AspNetCore.Mvc.UI.Layout.IPageLayout PageLayout
@{
AbpAntiForgeryManager.SetCookie();
var langDir = CultureHelper.IsRtl ? "rtl" : string.Empty;
var title = $"{ViewBag.Title ?? PageLayout.Content.Title} | {BrandingProvider.AppName}".Trim('|', ' ');
var languageInfo = await ThemeLanguageInfoProvider.GetLanguageSwitchViewComponentModel();
var returnUrl = System.Net.WebUtility.UrlEncode(Context.Request.GetEncodedPathAndQuery());
var logoUrl = BrandingProvider.LogoUrl == null ? null : "--lpx-logo: url(" + BrandingProvider.LogoUrl + ");";
var logoReverseUrl = BrandingProvider.LogoReverseUrl == null ? null : "--lpx-logo: url(" + BrandingProvider.LogoReverseUrl + ");";
var selectedStyle = await LeptonXStyleProvider.GetSelectedStyleAsync();
var selectedStyleFileName = CultureHelper.IsRtl ? selectedStyle + ".rtl" : selectedStyle;
}
<!DOCTYPE html>
<html lang="@CultureInfo.CurrentCulture.Name" dir="@langDir">
<head>
@await Component.InvokeLayoutHookAsync(LayoutHooks.Head.First, StandardLayouts.Account)
<title>@title</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<meta charset="UTF-8" />
<meta name="description" content="@ViewBag.MetaDescription">
<link rel="icon" href="~/favicon.svg" type="image/svg+xml">
<abp-style-bundle name="@LeptonXThemeBundles.Styles.Global" />
<link href="~/Themes/LeptonX/Global/side-menu/css/bootstrap-@(selectedStyleFileName).css" type="text/css"
rel="stylesheet" id="lpx-theme-bootstrap-@selectedStyle" />
<link href="~/Themes/LeptonX/Global/side-menu/css/@(selectedStyleFileName).css" type="text/css" rel="stylesheet"
id="lpx-theme-color-@selectedStyle" />
@await Component.InvokeAsync(typeof(WidgetStylesViewComponent))
@await RenderSectionAsync("styles", false)
@await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Account)
<style>
.lpx-login-bg {
background-image: url('/LeptonX/images/login-pages/login-bg-img-@(selectedStyle).svg') !important;
}
:root .lpx-theme-light {
@logoUrl
}
:root .lpx-theme-dark {
@logoReverseUrl
}
:root .lpx-theme-dim {
@logoReverseUrl
}
</style>
</head>
<body class="abp-account-layout lpx-theme-@selectedStyle">
@await Component.InvokeLayoutHookAsync(LayoutHooks.Body.First, StandardLayouts.Account)
<div class="container-fluid p-0 overflow-hidden">
@await Component.InvokeLayoutHookAsync(LayoutHooks.PageContent.First, StandardLayouts.Account)
<div class="lpx-login-area">
<div class="lpx-login-bg">
<div class="d-flex flex-column justify-content-center min-vh-100">
<div class="row">
<div class="col-xxl-5 col-lg-7 col-md-8 col-11 mx-auto position-relative py-4">
@if (BrandingProvider.LogoUrl.IsNullOrEmpty())
{
<div class="lpx-logo-container lpx-login-brand-text">
<div class="lpx-brand-logo lpx-login-logo mx-auto"></div>
<div class="lpx-brand-name lpx-login-name mx-auto">@BrandingProvider.AppName</div>
</div>
}
else
{
<div class="lpx-brand-logo lpx-login-logo mb-3 mx-auto"></div>
}
<div class="card mx-auto" style="max-width: 30rem;">
<div class="card-body p-3 p-sm-4">
<div class="align-items-start d-flex justify-content-between mb-2">
<h2 class="lpx-main-title lpx-login-title m-0 me-auto"> @PageLayout.Content.Title @* TODO: Find a better text here. *@</h2>
<div class="dropdown btn-group ms-auto" aria-labelledby="languageDropdown">
<button class="btn btn-sm btn-light dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-translate me-1"></i> @languageInfo.CurrentLanguage.DisplayName
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownMenuButton1" style="">
@foreach (var language in languageInfo.Languages)
{
var twoLetterLanguageName = new CultureInfo(language.CultureName).TwoLetterISOLanguageName.ToUpperInvariant();
var url = Url.Content($"~/Abp/Languages/Switch?culture={language.CultureName}&uiCulture={language.UiCultureName}&returnUrl={returnUrl}");
<li>
<a href="@url" class="dropdown-item" data-lpx-language-option="@twoLetterLanguageName">@language.DisplayName / @twoLetterLanguageName</a>
</li>
}
</ul>
</div>
</div>
<hr />
@await Component.InvokeAsync(typeof(PageAlertsViewComponent))
@if (MultiTenancyOptions.Value.IsEnabled &&
(TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(CookieTenantResolveContributor.ContributorName)
== true ||
TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(QueryStringTenantResolveContributor.ContributorName)
== true))
{
<div>
<div class="row">
<div class="col">
<span style="font-size: .8em;"
class="text-uppercase text-muted">@MultiTenancyStringLocalizer["Tenant"]</span><br />
<h6 class="m-0 d-inline-block">
@if (CurrentTenant.Id == null)
{
<span>
@MultiTenancyStringLocalizer["NotSelected"]
</span>
}
else
{
<strong>
@(CurrentTenant.Name ??
CurrentTenant.Id.Value.ToString())
</strong>
}
</h6>
</div>
<div class="col-auto">
<a id="AbpTenantSwitchLink" href="#"
class="btn btn-sm btn-outline-primary">@MultiTenancyStringLocalizer["Switch"]</a>
</div>
</div>
</div>
<hr />
}
@RenderBody()
</div>
@* @await Html.PartialAsync("~/Themes/LeptonX/Layouts/Account/_Footer.cshtml") *@
</div>
</div>
</div>
</div>
</div>
</div>
@await Component.InvokeLayoutHookAsync(LayoutHooks.PageContent.Last, StandardLayouts.Account)
</div>
<abp-script-bundle name="@LeptonXThemeBundles.Scripts.Global" />
<abp-script src="~/Abp/ApplicationLocalizationScript?cultureName=@CultureInfo.CurrentUICulture.Name"/>
<abp-script src="~/Abp/ApplicationConfigurationScript"/>
<abp-script src="~/Abp/ServiceProxyScript"/>
@await Component.InvokeAsync(typeof(WidgetScriptsViewComponent))
@await RenderSectionAsync("scripts", false)
@await Component.InvokeLayoutHookAsync(LayoutHooks.Body.Last, StandardLayouts.Account)
</body>
</html>
Hi,
LeptonX HTML demo shows you only possibilities with LeptonX theme. C# packages don't include all the variations inside them. If you need to customize a page, you should override it in your project and make changes by following Overriding a razor page documentation.
In your case, you'll need to customize Account Layout in your project. And since Account layout is implemented inMVC, you'll need to override .cshtml file.
Themes/LeptonXLite/Layouts/Account.cshtml file in your project.@using System.Globalization
@using Microsoft.Extensions.Localization
@using Microsoft.Extensions.Options
@using Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook
@using Volo.Abp.AspNetCore.Mvc.UI.Layout
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Themes.LeptonXLite.Components.PageAlerts
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Bundling
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Themes.LeptonXLite.Components.Brand
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Themes.LeptonXLite.Components.BreadCrumbs
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Toolbars
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Themes.LeptonXLite.Components.MainToolbar
@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.Ui.Branding
@using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Localization
@using Volo.Abp.AspNetCore.MultiTenancy
@using Volo.Abp.MultiTenancy
@using Volo.Abp.Ui.LayoutHooks
@inject IBrandingProvider BrandingProvider
@inject IPageLayout PageLayout
@inject IStringLocalizer<AbpUiMultiTenancyResource> MultiTenancyStringLocalizer
@inject ITenantResolveResultAccessor TenantResolveResultAccessor
@inject IOptions<AbpMultiTenancyOptions> MultiTenancyOptions
@inject ICurrentTenant CurrentTenant
@{
Layout = null;
var pageTitle = ViewBag.Title == null ? BrandingProvider.AppName : ViewBag.Title; //TODO: Discard to get from Title
if (PageLayout.Content.Title != null)
{
if (!string.IsNullOrWhiteSpace(pageTitle))
{
pageTitle = " | " + pageTitle;
}
pageTitle = PageLayout.Content.Title + pageTitle;
}
var rtl = CultureHelper.IsRtl ? "rtl" : string.Empty;
}
<!DOCTYPE html>
<html lang="@CultureInfo.CurrentCulture.Name" dir="@rtl">
<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>@pageTitle</title>
<link rel="icon" href="~/favicon.svg" type="image/svg+xml">
<abp-style-bundle name="@LeptonXLiteThemeBundles.Styles.Global" />
@await Component.InvokeAsync(typeof(WidgetStylesViewComponent))
@await RenderSectionAsync("styles", false)
@await Component.InvokeLayoutHookAsync(LayoutHooks.Head.Last, StandardLayouts.Account)
</head>
<body class="abp-account-layout @rtl">
@await Component.InvokeLayoutHookAsync(LayoutHooks.Body.First, StandardLayouts.Account)
<div class="lpx-scroll-container">
<div id="lpx-wrapper">
<div class="lpx-mobile-navbar-container">
<header class="lpx-mobile-navbar">
<div class="lpx-logo-container">
@await Component.InvokeAsync(typeof(MainNavbarBrandViewComponent))
</div>
<div class="user-menu">
<i class="lpx-icon bi bi-person lpx-toggle" data-lpx-toggle="mobile-user-menu-group" aria-hidden="true"></i>
</div>
</header>
<div class="user-menu-groups d-none" id="mobile-user-menu-group">
@await Component.InvokeAsync(typeof(ToolbarItemsViewComponent), new { Name = LeptonXLiteToolbars.MainMobile })
</div>
</div>
<div class="lpx-content-container m-0">
<div class="lpx-topbar-container">
<div class="lpx-topbar rounded-0">
<nav aria-label="breadcrumb" class="lpx-breadcrumb-container">
@await Component.InvokeAsync(typeof(BreadCrumbsViewComponent))
</nav>
<div class="lpx-topbar-content">
@await Component.InvokeAsync(typeof(ToolbarItemsViewComponent), new { Name = LeptonXLiteToolbars.Main})
</div>
</div>
</div>
<div class="lpx-content">
@await Component.InvokeLayoutHookAsync(LayoutHooks.PageContent.First, StandardLayouts.Account)
<div class="container">
<div class="row">
<div class="col-md-8 col-lg-5 mx-auto">
@await Component.InvokeAsync(typeof(PageAlertsViewComponent))
@if (MultiTenancyOptions.Value.IsEnabled &&
(TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(CookieTenantResolveContributor.ContributorName) == true ||
TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(QueryStringTenantResolveContributor.ContributorName) == true))
{
<abp-card>
<abp-card-body>
<div class="row">
<div class="col">
<span style="font-size: .8em;"
class="text-uppercase text-muted">@MultiTenancyStringLocalizer["Tenant"]</span><br />
<h6 class="m-0 d-inline-block">
@if (CurrentTenant.Id == null)
{
<span>
@MultiTenancyStringLocalizer["NotSelected"]
</span>
}
else
{
<strong>@(CurrentTenant.Name ??
CurrentTenant.Id.Value.ToString())</strong>
}
</h6>
</div>
<div class="col-auto">
<a id="AbpTenantSwitchLink" href="#"
class="btn btn-sm btn-outline-primary">@MultiTenancyStringLocalizer["Switch"]</a>
</div>
</div>
</abp-card-body>
</abp-card>
<hr />
}
@RenderBody()
@*<UiMessageAlert />
<UiNotificationAlert />
<UiPageProgress />*@
@await Component.InvokeLayoutHookAsync(LayoutHooks.PageContent.Last, StandardLayouts.Account)
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<abp-script-bundle name="@LeptonXLiteThemeBundles.Scripts.Global" />
<abp-script src="~/Abp/ApplicationLocalizationScript?cultureName=@CultureInfo.CurrentUICulture.Name"/>
<abp-script type="text/javascript" src="~/Abp/ApplicationConfigurationScript"/>
<abp-script type="text/javascript" src="~/Abp/ServiceProxyScript"/>
@await Component.InvokeAsync(typeof(WidgetScriptsViewComponent))
@await RenderSectionAsync("scripts", false)
@await Component.InvokeLayoutHookAsync(LayoutHooks.Body.Last, StandardLayouts.Account)
</body>
</html>
When you do that, this file will be being used as account layout. You can make changes in this file according to your desired login page from https://x.leptontheme.com/side-menu/login-pages/login-2