mirror of https://github.com/abpframework/abp.git
33 changed files with 487 additions and 296 deletions
@ -1,4 +1,4 @@ |
|||
@page "/authentication/{action}" |
|||
@page "/authentication/{action}" |
|||
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication |
|||
<RemoteAuthenticatorView Action="@Action" /> |
|||
|
|||
@ -1,18 +1,29 @@ |
|||
@inherits LayoutComponentBase |
|||
@using Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic |
|||
|
|||
<div class="sidebar"> |
|||
<NavMenu /> |
|||
</div> |
|||
|
|||
<div class="main"> |
|||
<div class="top-row px-4 auth"> |
|||
<LanguageSwitch/> |
|||
<LoginDisplay/> |
|||
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> |
|||
</div> |
|||
|
|||
<div class="content px-4"> |
|||
@Body |
|||
<nav class="navbar navbar-expand-md navbar-dark bg-dark shadow-sm flex-column flex-md-row mb-4" id="main-navbar" style="min-height: 4rem;"> |
|||
<div class="container"> |
|||
<a class="navbar-brand" href="~/">My Application (TODO)</a> |
|||
<button class="navbar-toggler" type="button" data-toggle="collapse" |
|||
data-target="#main-navbar-collapse" aria-controls="main-navbar-collapse" |
|||
aria-expanded="false" aria-label="Toggle navigation"> |
|||
<span class="navbar-toggler-icon"></span> |
|||
</button> |
|||
<div class="collapse navbar-collapse" id="main-navbar-collapse"> |
|||
<ul class="navbar-nav mx-auto"> |
|||
<NavMenu/> |
|||
</ul> |
|||
<ul class="navbar-nav"> |
|||
<li class="nav-item"> |
|||
<LanguageSwitch/> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<LoginDisplay/> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</nav> |
|||
<div class="container"> |
|||
@Body |
|||
</div> |
|||
|
|||
@ -1,37 +1,7 @@ |
|||
<div class="top-row pl-4 navbar navbar-dark"> |
|||
<a class="navbar-brand" href="">MyProjectName</a> |
|||
<button class="navbar-toggler" @onclick="ToggleNavMenu"> |
|||
<span class="navbar-toggler-icon"></span> |
|||
</button> |
|||
</div> |
|||
|
|||
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu"> |
|||
<ul class="nav flex-column"> |
|||
<li class="nav-item px-3"> |
|||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All"> |
|||
<i class="fas fa-home" aria-hidden="true"></i> Home |
|||
</NavLink> |
|||
</li> |
|||
<li class="nav-item px-3"> |
|||
<NavLink class="nav-link" href="identity/users"> |
|||
<i class="fas fa-users" aria-hidden="true"></i> Users |
|||
</NavLink> |
|||
</li> |
|||
<li class="nav-item px-3"> |
|||
<NavLink class="nav-link" href="identity/roles"> |
|||
<i class="fas fa-user-tag" aria-hidden="true"></i> Roles |
|||
</NavLink> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
|
|||
@code { |
|||
private bool collapseNavMenu = true; |
|||
|
|||
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null; |
|||
|
|||
private void ToggleNavMenu() |
|||
@if (Menu != null) |
|||
{ |
|||
foreach (var menuItem in Menu.Items) |
|||
{ |
|||
collapseNavMenu = !collapseNavMenu; |
|||
<NavMenuItem MenuItem="@menuItem" /> |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,27 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Components; |
|||
using Volo.Abp.UI.Navigation; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic |
|||
{ |
|||
public partial class NavMenu |
|||
{ |
|||
[Inject] protected IMenuManager MenuManager { get; set; } |
|||
|
|||
protected ApplicationMenu Menu { get; set; } |
|||
|
|||
private bool collapseNavMenu = true; |
|||
|
|||
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null; |
|||
|
|||
protected override async Task OnInitializedAsync() |
|||
{ |
|||
Menu = await MenuManager.GetAsync(StandardMenus.Main); |
|||
} |
|||
|
|||
private void ToggleNavMenu() |
|||
{ |
|||
collapseNavMenu = !collapseNavMenu; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
@using Volo.Abp.UI.Navigation |
|||
@{ |
|||
var elementId = MenuItem.ElementId ?? "MenuItem_" + MenuItem.Name.Replace(".", "_"); |
|||
var cssClass = string.IsNullOrEmpty(MenuItem.CssClass) ? string.Empty : MenuItem.CssClass; |
|||
var url = string.IsNullOrEmpty(MenuItem.Url) ? "#" : MenuItem.Url; |
|||
} |
|||
@if (MenuItem.IsLeaf) |
|||
{ |
|||
if (MenuItem.Url != null) |
|||
{ |
|||
<li class="nav-item @cssClass" disabled="@MenuItem.IsDisabled"> |
|||
<NavLink class="nav-link" href="@url" id="@elementId"> |
|||
@if (MenuItem.Icon != null) |
|||
{ |
|||
if (MenuItem.Icon.StartsWith("fa")) |
|||
{ |
|||
<i class="@MenuItem.Icon"></i> |
|||
} |
|||
} |
|||
@MenuItem.DisplayName |
|||
</NavLink> |
|||
</li> |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
<li class="nav-item"> |
|||
<div class="dropdown"> |
|||
<a class="nav-link dropdown-toggle" href="#" id="@elementId" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
|||
@if (MenuItem.Icon != null) |
|||
{ |
|||
if (MenuItem.Icon.StartsWith("fa")) |
|||
{ |
|||
<i class="@MenuItem.Icon"></i> |
|||
} |
|||
} |
|||
@MenuItem.DisplayName |
|||
</a> |
|||
<div class="dropdown-menu border-0 shadow-sm" aria-labelledby="@elementId"> |
|||
@foreach (var childMenuItem in MenuItem.Items) |
|||
{ |
|||
<NavMenuItem MenuItem="@childMenuItem" /> |
|||
} |
|||
</div> |
|||
</div> |
|||
</li> |
|||
|
|||
} |
|||
@code { |
|||
[Parameter] |
|||
public ApplicationMenuItem MenuItem { get; set; } |
|||
} |
|||
@ -0,0 +1,105 @@ |
|||
|
|||
#main-navbar-tools a.dropdown-toggle { |
|||
text-decoration: none; |
|||
color: #fff; |
|||
} |
|||
|
|||
.navbar .dropdown-submenu { |
|||
position: relative; |
|||
} |
|||
.navbar .dropdown-menu { |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
.navbar .dropdown-menu a { |
|||
font-size: .9em; |
|||
padding: 10px 15px; |
|||
display: block; |
|||
min-width: 210px; |
|||
text-align: left; |
|||
border-radius: 0.25rem; |
|||
min-height: 44px; |
|||
} |
|||
.navbar .dropdown-submenu a::after { |
|||
transform: rotate(-90deg); |
|||
position: absolute; |
|||
right: 16px; |
|||
top: 18px; |
|||
} |
|||
.navbar .dropdown-submenu .dropdown-menu { |
|||
top: 0; |
|||
left: 100%; |
|||
} |
|||
|
|||
.card-header .btn { |
|||
padding: 2px 6px; |
|||
} |
|||
.card-header h5 { |
|||
margin: 0; |
|||
} |
|||
.container > .card { |
|||
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; |
|||
} |
|||
|
|||
@media screen and (min-width: 768px) { |
|||
.navbar .dropdown:hover > .dropdown-menu { |
|||
display: block; |
|||
} |
|||
|
|||
.navbar .dropdown-submenu:hover > .dropdown-menu { |
|||
display: block; |
|||
} |
|||
} |
|||
.input-validation-error { |
|||
border-color: #dc3545; |
|||
} |
|||
.field-validation-error { |
|||
font-size: 0.8em; |
|||
} |
|||
|
|||
.dataTables_scrollBody { |
|||
min-height: 248px; |
|||
} |
|||
|
|||
div.dataTables_wrapper div.dataTables_info { |
|||
padding-top: 11px; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
div.dataTables_wrapper div.dataTables_length label { |
|||
padding-top: 10px; |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
.rtl .dropdown-menu-right { |
|||
right: auto; |
|||
left: 0; |
|||
} |
|||
|
|||
.rtl .dropdown-menu-right a { |
|||
text-align: right; |
|||
} |
|||
|
|||
.rtl .navbar .dropdown-menu a { |
|||
text-align: right; |
|||
} |
|||
.rtl .navbar .dropdown-submenu .dropdown-menu { |
|||
top: 0; |
|||
left: auto; |
|||
right: 100%; |
|||
} |
|||
|
|||
/* TEMP */ |
|||
|
|||
.navbar-dark .navbar-nav .nav-link { |
|||
color: #000 !important; |
|||
} |
|||
|
|||
.navbar-nav > .nav-item > .nav-link, |
|||
.navbar-nav > .nav-item > .dropdown > .nav-link { |
|||
color: #fff !important; |
|||
} |
|||
|
|||
.navbar-nav>.nav-item>div>button{ |
|||
color:#fff; |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
$(function () { |
|||
$('.dropdown-menu a.dropdown-toggle').on('click', function (e) { |
|||
if (!$(this).next().hasClass('show')) { |
|||
$(this).parents('.dropdown-menu').first().find('.show').removeClass("show"); |
|||
} |
|||
|
|||
var $subMenu = $(this).next(".dropdown-menu"); |
|||
$subMenu.toggleClass('show'); |
|||
|
|||
$(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function (e) { |
|||
$('.dropdown-submenu .show').removeClass("show"); |
|||
}); |
|||
|
|||
return false; |
|||
}); |
|||
}); |
|||
@ -0,0 +1,17 @@ |
|||
using Volo.Abp.BlazoriseUI; |
|||
using Volo.Abp.Http.Client.IdentityModel.WebAssembly; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.UI.Navigation; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpBlazoriseUIModule), |
|||
typeof(AbpHttpClientIdentityModelWebAssemblyModule), |
|||
typeof(AbpUiNavigationModule) |
|||
)] |
|||
public class AbpAspNetCoreComponentsWebAssemblyThemingModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,17 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk.Razor"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.1</TargetFramework> |
|||
<RazorLangVersion>3.0</RazorLangVersion> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.Abp.BlazoriseUI\Volo.Abp.BlazoriseUI.csproj" /> |
|||
<ProjectReference Include="..\Volo.Abp.Http.Client.IdentityModel.WebAssembly\Volo.Abp.Http.Client.IdentityModel.WebAssembly.csproj" /> |
|||
<ProjectReference Include="..\Volo.Abp.UI.Navigation\Volo.Abp.UI.Navigation.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,40 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Identity.Localization; |
|||
using Volo.Abp.UI.Navigation; |
|||
|
|||
namespace Volo.Abp.Identity.Blazor |
|||
{ |
|||
public class AbpIdentityWebMainMenuContributor : IMenuContributor |
|||
{ |
|||
public virtual async Task ConfigureMenuAsync(MenuConfigurationContext context) |
|||
{ |
|||
if (context.Menu.Name != StandardMenus.Main) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var hasRolePermission = await context.IsGrantedAsync(IdentityPermissions.Roles.Default); |
|||
var hasUserPermission = await context.IsGrantedAsync(IdentityPermissions.Users.Default); |
|||
|
|||
if (hasRolePermission || hasUserPermission) |
|||
{ |
|||
var administrationMenu = context.Menu.GetAdministration(); |
|||
|
|||
var l = context.GetLocalizer<IdentityResource>(); |
|||
|
|||
var identityMenuItem = new ApplicationMenuItem(IdentityMenuNames.GroupName, l["Menu:IdentityManagement"], icon: "fa fa-id-card-o"); |
|||
administrationMenu.AddItem(identityMenuItem); |
|||
|
|||
if (hasRolePermission) |
|||
{ |
|||
identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Roles, l["Roles"], url: "/identity/roles")); |
|||
} |
|||
|
|||
if (hasUserPermission) |
|||
{ |
|||
identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Users, l["Users"], url: "/identity/users")); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
namespace Volo.Abp.Identity.Blazor |
|||
{ |
|||
public class IdentityMenuNames |
|||
{ |
|||
public const string GroupName = "AbpIdentity"; |
|||
|
|||
public const string Roles = GroupName + ".Roles"; |
|||
public const string Users = GroupName + ".Users"; |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.UI.Navigation; |
|||
|
|||
namespace MyCompanyName.MyProjectName.Blazor |
|||
{ |
|||
public class MyProjectNameMenuContributor : IMenuContributor |
|||
{ |
|||
public Task ConfigureMenuAsync(MenuConfigurationContext context) |
|||
{ |
|||
context.Menu.AddItem(new ApplicationMenuItem("Test", "Test", "/test")); |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
@ -1,185 +0,0 @@ |
|||
html, body { |
|||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; |
|||
} |
|||
|
|||
a, .btn-link { |
|||
color: #0366d6; |
|||
} |
|||
|
|||
.btn-primary { |
|||
color: #fff; |
|||
background-color: #1b6ec2; |
|||
border-color: #1861ac; |
|||
} |
|||
|
|||
app { |
|||
position: relative; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.top-row { |
|||
height: 3.5rem; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.main { |
|||
flex: 1; |
|||
} |
|||
|
|||
.main .top-row { |
|||
background-color: #f7f7f7; |
|||
border-bottom: 1px solid #d6d5d5; |
|||
justify-content: flex-end; |
|||
} |
|||
|
|||
.main .top-row > a, .main .top-row .btn-link { |
|||
white-space: nowrap; |
|||
margin-left: 1.5rem; |
|||
} |
|||
|
|||
.main .top-row a:first-child { |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
|
|||
.sidebar { |
|||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); |
|||
} |
|||
|
|||
.sidebar .top-row { |
|||
background-color: rgba(0,0,0,0.4); |
|||
} |
|||
|
|||
.sidebar .navbar-brand { |
|||
font-size: 1.1rem; |
|||
} |
|||
|
|||
.sidebar .oi { |
|||
width: 2rem; |
|||
font-size: 1.1rem; |
|||
vertical-align: text-top; |
|||
top: -2px; |
|||
} |
|||
|
|||
.sidebar .nav-item { |
|||
font-size: 0.9rem; |
|||
padding-bottom: 0.5rem; |
|||
} |
|||
|
|||
.sidebar .nav-item:first-of-type { |
|||
padding-top: 1rem; |
|||
} |
|||
|
|||
.sidebar .nav-item:last-of-type { |
|||
padding-bottom: 1rem; |
|||
} |
|||
|
|||
.sidebar .nav-item a { |
|||
color: #d7d7d7; |
|||
border-radius: 4px; |
|||
height: 3rem; |
|||
display: flex; |
|||
align-items: center; |
|||
line-height: 3rem; |
|||
} |
|||
|
|||
.sidebar .nav-item a.active { |
|||
background-color: rgba(255,255,255,0.25); |
|||
color: white; |
|||
} |
|||
|
|||
.sidebar .nav-item a:hover { |
|||
background-color: rgba(255,255,255,0.1); |
|||
color: white; |
|||
} |
|||
|
|||
.content { |
|||
padding-top: 1.1rem; |
|||
} |
|||
|
|||
.navbar-toggler { |
|||
background-color: rgba(255, 255, 255, 0.1); |
|||
} |
|||
|
|||
.valid.modified:not([type=checkbox]) { |
|||
outline: 1px solid #26b050; |
|||
} |
|||
|
|||
.invalid { |
|||
outline: 1px solid red; |
|||
} |
|||
|
|||
.validation-message { |
|||
color: red; |
|||
} |
|||
|
|||
#blazor-error-ui { |
|||
background: lightyellow; |
|||
bottom: 0; |
|||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); |
|||
display: none; |
|||
left: 0; |
|||
padding: 0.6rem 1.25rem 0.7rem 1.25rem; |
|||
position: fixed; |
|||
width: 100%; |
|||
z-index: 1000; |
|||
} |
|||
|
|||
#blazor-error-ui .dismiss { |
|||
cursor: pointer; |
|||
position: absolute; |
|||
right: 0.75rem; |
|||
top: 0.5rem; |
|||
} |
|||
|
|||
.nav .nav-item .nav-link i { |
|||
margin: 5px; |
|||
} |
|||
|
|||
@media (max-width: 767.98px) { |
|||
.main .top-row:not(.auth) { |
|||
display: none; |
|||
} |
|||
|
|||
.main .top-row.auth { |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.main .top-row a, .main .top-row .btn-link { |
|||
margin-left: 0; |
|||
} |
|||
} |
|||
|
|||
@media (min-width: 768px) { |
|||
app { |
|||
flex-direction: row; |
|||
} |
|||
|
|||
.sidebar { |
|||
width: 250px; |
|||
height: 100vh; |
|||
position: sticky; |
|||
top: 0; |
|||
} |
|||
|
|||
.main .top-row { |
|||
position: sticky; |
|||
top: 0; |
|||
} |
|||
|
|||
.main > div { |
|||
padding-left: 2rem !important; |
|||
padding-right: 1.5rem !important; |
|||
} |
|||
|
|||
.navbar-toggler { |
|||
display: none; |
|||
} |
|||
|
|||
.sidebar .collapse { |
|||
/* Never collapse the sidebar for wide screens */ |
|||
display: block; |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
#blazor-error-ui { |
|||
background: lightyellow; |
|||
bottom: 0; |
|||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); |
|||
display: none; |
|||
left: 0; |
|||
padding: 0.6rem 1.25rem 0.7rem 1.25rem; |
|||
position: fixed; |
|||
width: 100%; |
|||
z-index: 1000; |
|||
} |
|||
|
|||
#blazor-error-ui .dismiss { |
|||
cursor: pointer; |
|||
position: absolute; |
|||
right: 0.75rem; |
|||
top: 0.5rem; |
|||
} |
|||
Loading…
Reference in new issue