diff --git a/src/OrchardCore.Modules/OrchardCore.Admin/Drivers/VisitSiteNavbarDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Admin/Drivers/VisitSiteNavbarDisplayDriver.cs new file mode 100644 index 00000000000..8a330c67d4e --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Admin/Drivers/VisitSiteNavbarDisplayDriver.cs @@ -0,0 +1,14 @@ +using OrchardCore.Admin.Models; +using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.DisplayManagement.Views; + +namespace OrchardCore.Admin.Drivers; + +public class VisitSiteNavbarDisplayDriver : DisplayDriver +{ + public override IDisplayResult Display(Navbar model) + { + return View("VisitSiteNavbarItem", model) + .Location("DetailAdmin", "Content:20"); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs index 0c71bfcbbd1..7d08f46eabb 100644 --- a/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs @@ -55,6 +55,7 @@ public override void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddSingleton(); + services.AddScoped, VisitSiteNavbarDisplayDriver>(); services.Configure(_configuration.GetSection("OrchardCore_Admin")); } diff --git a/src/OrchardCore.Modules/OrchardCore.Admin/Views/Navbar.DetailAdmin.cshtml b/src/OrchardCore.Modules/OrchardCore.Admin/Views/Navbar.DetailAdmin.cshtml new file mode 100644 index 00000000000..68e040fe58b --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Admin/Views/Navbar.DetailAdmin.cshtml @@ -0,0 +1,8 @@ +@if (Model.Content == null) +{ + return; +} + + diff --git a/src/OrchardCore.Modules/OrchardCore.Admin/Views/Navbar.cshtml b/src/OrchardCore.Modules/OrchardCore.Admin/Views/Navbar.cshtml new file mode 100644 index 00000000000..91b5f1d422d --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Admin/Views/Navbar.cshtml @@ -0,0 +1,8 @@ +@if (Model.Content == null) +{ + return; +} + + diff --git a/src/OrchardCore.Themes/TheAdmin/Views/NavbarLink.cshtml b/src/OrchardCore.Modules/OrchardCore.Admin/Views/VisitSiteNavbarItem.cshtml similarity index 100% rename from src/OrchardCore.Themes/TheAdmin/Views/NavbarLink.cshtml rename to src/OrchardCore.Modules/OrchardCore.Admin/Views/VisitSiteNavbarItem.cshtml diff --git a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Drivers/ContentCulturePickerNavbarDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Drivers/ContentCulturePickerNavbarDisplayDriver.cs new file mode 100644 index 00000000000..a8ed26a24a0 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Drivers/ContentCulturePickerNavbarDisplayDriver.cs @@ -0,0 +1,42 @@ +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Localization; +using OrchardCore.Admin.Models; +using OrchardCore.ContentLocalization.ViewModels; +using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.DisplayManagement.Views; +using OrchardCore.Localization; + +namespace OrchardCore.ContentLocalization.Drivers; + +public class ContentCulturePickerNavbarDisplayDriver : DisplayDriver +{ + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly ILocalizationService _localizationService; + + public ContentCulturePickerNavbarDisplayDriver( + IHttpContextAccessor httpContextAccessor, + ILocalizationService localizationService) + { + _httpContextAccessor = httpContextAccessor; + _localizationService = localizationService; + } + + public override async Task DisplayAsync(Navbar model, BuildDisplayContext context) + { + var supportedCultures = (await _localizationService.GetSupportedCulturesAsync()).Select(c => CultureInfo.GetCultureInfo(c)); + + return Initialize("ContentCulturePicker", model => + { + model.SupportedCultures = supportedCultures; + model.CurrentCulture = _httpContextAccessor + .HttpContext + .Features + .Get()?.RequestCulture?.Culture ?? CultureInfo.CurrentUICulture; + + }).RenderWhen(() => Task.FromResult(supportedCultures.Count() > 1)) + .Location("Detail", "Content:5"); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Startup.cs b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Startup.cs index 0c0e61071ff..3509ae86a06 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Startup.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using OrchardCore.Admin; +using OrchardCore.Admin.Models; using OrchardCore.ContentLocalization.Controllers; using OrchardCore.ContentLocalization.Drivers; using OrchardCore.ContentLocalization.Indexing; @@ -82,6 +83,7 @@ public ContentPickerStartup(IShellConfiguration shellConfiguration) public override void ConfigureServices(IServiceCollection services) { + services.AddScoped, ContentCulturePickerNavbarDisplayDriver>(); services.AddLiquidFilter("switch_culture_url"); services.AddScoped(); services.AddScoped(); diff --git a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/ViewModels/CulturePickerViewModel.cs b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/ViewModels/CulturePickerViewModel.cs new file mode 100644 index 00000000000..cebdc69654f --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/ViewModels/CulturePickerViewModel.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Globalization; +using Microsoft.AspNetCore.Mvc.ModelBinding; + +namespace OrchardCore.ContentLocalization.ViewModels; + +public class CulturePickerViewModel +{ + [BindNever] + public CultureInfo CurrentCulture { get; set; } + + [BindNever] + public IEnumerable SupportedCultures { get; set; } +} diff --git a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Views/ContentCulturePicker.cshtml b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Views/ContentCulturePicker.cshtml index ca00c652727..6f25b695e5b 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Views/ContentCulturePicker.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Views/ContentCulturePicker.cshtml @@ -1,12 +1,17 @@ -@using System.Globalization -@using Microsoft.AspNetCore.Localization -@inject OrchardCore.Localization.ILocalizationService localizationService - -@{ - var currentCulture = Context.Features.Get()?.RequestCulture?.Culture ?? CultureInfo.CurrentUICulture; - var supportedCultures = (await localizationService.GetSupportedCulturesAsync()).Select(c => CultureInfo.GetCultureInfo(c)); -} -@await DisplayAsync(await New.ContentCulturePickerContainer( - CurrentCulture: currentCulture, - SupportedCultures: supportedCultures -)) + diff --git a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Views/ContentCulturePickerContainer.cshtml b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Views/ContentCulturePickerContainer.cshtml deleted file mode 100644 index 40ef9550efe..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Views/ContentCulturePickerContainer.cshtml +++ /dev/null @@ -1,19 +0,0 @@ - diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/AdminCulturePickerShapes.cs b/src/OrchardCore.Modules/OrchardCore.Localization/AdminCulturePickerShapes.cs deleted file mode 100644 index cac80bf2002..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Localization/AdminCulturePickerShapes.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using OrchardCore.Admin; -using OrchardCore.DisplayManagement; -using OrchardCore.DisplayManagement.Descriptors; -using OrchardCore.DisplayManagement.Zones; -using OrchardCore.Modules; - -namespace OrchardCore.Localization; - -[Feature("OrchardCore.Localization.AdminCulturePicker")] -public class AdminCulturePickerShapes : IShapeTableProvider -{ - public void Discover(ShapeTableBuilder builder) - { - builder.Describe("Layout") - .OnCreated(async context => - { - if (context.Shape is IZoneHolding layout) - { - var httpContextAccessor = context.ServiceProvider.GetRequiredService(); - if (!AdminAttribute.IsApplied(httpContextAccessor.HttpContext)) - { - return; - } - - var shapeFactory = context.ServiceProvider.GetRequiredService(); - var culturePickerShape = await shapeFactory.CreateAsync("AdminCulturePicker"); - - await layout.Zones["NavbarTop"].AddAsync(culturePickerShape); - } - }); - } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/Drivers/AdminCulturePickerNavbarDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Localization/Drivers/AdminCulturePickerNavbarDisplayDriver.cs new file mode 100644 index 00000000000..f4855ec7568 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Localization/Drivers/AdminCulturePickerNavbarDisplayDriver.cs @@ -0,0 +1,41 @@ +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Localization; +using OrchardCore.Admin.Models; +using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.DisplayManagement.Views; +using OrchardCore.Localization.ViewModels; + +namespace OrchardCore.Localization.Drivers; + +public class AdminCulturePickerNavbarDisplayDriver : DisplayDriver +{ + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly ILocalizationService _localizationService; + + public AdminCulturePickerNavbarDisplayDriver( + IHttpContextAccessor httpContextAccessor, + ILocalizationService localizationService) + { + _httpContextAccessor = httpContextAccessor; + _localizationService = localizationService; + } + + public override async Task DisplayAsync(Navbar model, BuildDisplayContext context) + { + var supportedCultures = (await _localizationService.GetSupportedCulturesAsync()).Select(c => CultureInfo.GetCultureInfo(c)); + + return Initialize("AdminCulturePicker", model => + { + model.SupportedCultures = supportedCultures; + model.CurrentCulture = _httpContextAccessor + .HttpContext + .Features + .Get()?.RequestCulture?.Culture ?? CultureInfo.CurrentUICulture; + + }).RenderWhen(() => Task.FromResult(supportedCultures.Count() > 1)) + .Location("DetailAdmin", "Content:5"); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs index 545688365b2..8c825301c3d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/Startup.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using OrchardCore.Admin; -using OrchardCore.DisplayManagement.Descriptors; +using OrchardCore.Admin.Models; using OrchardCore.DisplayManagement.Handlers; using OrchardCore.Environment.Shell; using OrchardCore.Localization.Drivers; @@ -92,7 +92,7 @@ public CulturePickerStartup(IOptions adminOptions, ShellSettings s public override void ConfigureServices(IServiceCollection services) { - services.AddScoped(); + services.AddScoped, AdminCulturePickerNavbarDisplayDriver>(); services.Configure(options => options.AddInitialRequestCultureProvider(new AdminCookieCultureProvider(_shellSettings, _adminOptions))); diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/ViewModels/AdminCulturePickerViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Localization/ViewModels/AdminCulturePickerViewModel.cs new file mode 100644 index 00000000000..f14655bd046 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Localization/ViewModels/AdminCulturePickerViewModel.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Globalization; +using Microsoft.AspNetCore.Mvc.ModelBinding; + +namespace OrchardCore.Localization.ViewModels; + +public class AdminCulturePickerViewModel +{ + [BindNever] + public CultureInfo CurrentCulture { get; set; } + + [BindNever] + public IEnumerable SupportedCultures { get; set; } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/Views/AdminCulturePicker.cshtml b/src/OrchardCore.Modules/OrchardCore.Localization/Views/AdminCulturePicker.cshtml index f8b99729782..15662d87770 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/Views/AdminCulturePicker.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Localization/Views/AdminCulturePicker.cshtml @@ -1,16 +1,42 @@ -@using System.Globalization -@using Microsoft.AspNetCore.Localization -@inject OrchardCore.Localization.ILocalizationService localizationService +@using OrchardCore.Localization +@using OrchardCore.Environment.Shell + +@model AdminCulturePickerViewModel + +@inject ShellSettings ShellSettings @{ - var currentCulture = Context.Features.Get()?.RequestCulture?.Culture ?? CultureInfo.CurrentUICulture; - var supportedCultures = (await localizationService.GetSupportedCulturesAsync()).Select(c => CultureInfo.GetCultureInfo(c)); + var cookieName = AdminCookieCultureProvider.MakeCookieName(ShellSettings); + var cookiePath = AdminCookieCultureProvider.MakeCookiePath(Context); + var selectedCultureName = Model.CurrentCulture.Name; } -@if (supportedCultures.Count() > 1) -{ - @await DisplayAsync(await New.AdminCulturePickerContainer( - CurrentCulture: currentCulture, - SupportedCultures: supportedCultures - )); -} + + + diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/Views/AdminCulturePickerContainer.cshtml b/src/OrchardCore.Modules/OrchardCore.Localization/Views/AdminCulturePickerContainer.cshtml deleted file mode 100644 index 62155cfb3c6..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Localization/Views/AdminCulturePickerContainer.cshtml +++ /dev/null @@ -1,40 +0,0 @@ -@using OrchardCore.Localization -@using OrchardCore.Environment.Shell - -@inject ShellSettings ShellSettings - -@{ - var cookieName = AdminCookieCultureProvider.MakeCookieName(ShellSettings); - var cookiePath = AdminCookieCultureProvider.MakeCookiePath(Context); - var selectedCultureName = Model.CurrentCulture.Name; -} - - - - diff --git a/src/OrchardCore.Modules/OrchardCore.Notifications/Drivers/NotificationNavbarDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Notifications/Drivers/NotificationNavbarDisplayDriver.cs new file mode 100644 index 00000000000..4d9ae05fa2e --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Notifications/Drivers/NotificationNavbarDisplayDriver.cs @@ -0,0 +1,51 @@ +using System.Linq; +using System.Security.Claims; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using OrchardCore.Admin.Models; +using OrchardCore.DisplayManagement.Handlers; +using OrchardCore.DisplayManagement.Views; +using OrchardCore.Notifications.Indexes; +using OrchardCore.Notifications.ViewModels; +using YesSql; + +namespace OrchardCore.Notifications.Drivers; + +public class NotificationNavbarDisplayDriver : DisplayDriver +{ + // TODO, make this part of a configurable of NotificationOptions + private const int MaxVisibleNotifications = 10; + + private readonly IAuthorizationService _authorizationService; + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly YesSql.ISession _session; + + public NotificationNavbarDisplayDriver( + IAuthorizationService authorizationService, + IHttpContextAccessor httpContextAccessor, + YesSql.ISession session) + { + _authorizationService = authorizationService; + _httpContextAccessor = httpContextAccessor; + _session = session; + } + + public override IDisplayResult Display(Navbar model) + { + return Initialize("UserNotificationNavbar", async model => + { + var userId = _httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier); + var notifications = (await _session.Query(x => x.UserId == userId && !x.IsRead, collection: NotificationConstants.NotificationCollection) + .OrderByDescending(x => x.CreatedAtUtc) + .Take(MaxVisibleNotifications + 1) + .ListAsync()).ToList(); + + model.Notifications = notifications; + model.MaxVisibleNotifications = MaxVisibleNotifications; + model.TotalUnread = notifications.Count; + + }).Location("Detail", "Content:9") + .Location("DetailAdmin", "Content:9") + .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User, NotificationPermissions.ManageNotifications)); + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Notifications/Filters/NotificationResultFilter.cs b/src/OrchardCore.Modules/OrchardCore.Notifications/Filters/NotificationResultFilter.cs deleted file mode 100644 index ee598546a2b..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Notifications/Filters/NotificationResultFilter.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Security.Claims; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc.Filters; -using OrchardCore.DisplayManagement; -using OrchardCore.DisplayManagement.Layout; -using OrchardCore.DisplayManagement.ModelBinding; -using OrchardCore.DisplayManagement.Views; -using OrchardCore.Notifications.Indexes; -using OrchardCore.Notifications.ViewModels; -using YesSql; - -namespace OrchardCore.Notifications.Filters; - -public class NotificationResultFilter : IAsyncResultFilter -{ - // TODO, make this part of a configurable of NotificationOptions - private const int MaxVisibleNotifications = 10; - - private readonly ILayoutAccessor _layoutAccessor; - private readonly IAuthorizationService _authorizationService; - private readonly IDisplayManager _notificationDisplayDriver; - private readonly IUpdateModelAccessor _updateModelAccessor; - private readonly ISession _session; - - public NotificationResultFilter(ILayoutAccessor layoutAccessor, - IAuthorizationService authorizationService, - IDisplayManager notificationDisplayDriver, - IUpdateModelAccessor updateModelAccessor, - ISession session) - { - _layoutAccessor = layoutAccessor; - _authorizationService = authorizationService; - _notificationDisplayDriver = notificationDisplayDriver; - _updateModelAccessor = updateModelAccessor; - _session = session; - } - - public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) - { - if (!context.IsViewOrPageResult() - || !await _authorizationService.AuthorizeAsync(context.HttpContext.User, NotificationPermissions.ManageNotifications)) - { - await next(); - - return; - } - - var userId = context.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier); - var notifications = await _session.Query(x => x.UserId == userId && !x.IsRead, collection: NotificationConstants.NotificationCollection) - .OrderByDescending(x => x.CreatedAtUtc) - .Take(MaxVisibleNotifications + 1) - .ListAsync(); - - var shapes = new List(); - - foreach (var notification in notifications) - { - dynamic shape = await _notificationDisplayDriver.BuildDisplayAsync(notification, _updateModelAccessor.ModelUpdater, "Header"); - shape.Notification = notification; - - shapes.Add(shape); - } - - var viewModel = new UserNotificationCollectionViewModel() - { - TotalUnread = notifications.Count(), - MaxVisibleNotifications = MaxVisibleNotifications, - Notifications = shapes, - }; - - var layout = await _layoutAccessor.GetLayoutAsync(); - var contentZone = layout.Zones["NavbarTop"]; - - await contentZone.AddAsync(new ShapeViewModel("UserNotificationCollection", viewModel)); - - await next(); - } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Notifications/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Notifications/Startup.cs index 4a3b4367b44..b98f7087790 100644 --- a/src/OrchardCore.Modules/OrchardCore.Notifications/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Notifications/Startup.cs @@ -1,10 +1,10 @@ using System; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using OrchardCore.Admin; +using OrchardCore.Admin.Models; using OrchardCore.Data; using OrchardCore.Data.Migration; using OrchardCore.DisplayManagement.Handlers; @@ -14,7 +14,6 @@ using OrchardCore.Notifications.Activities; using OrchardCore.Notifications.Controllers; using OrchardCore.Notifications.Drivers; -using OrchardCore.Notifications.Filters; using OrchardCore.Notifications.Handlers; using OrchardCore.Notifications.Indexes; using OrchardCore.Notifications.Migrations; @@ -68,11 +67,7 @@ public override void ConfigureServices(IServiceCollection services) services.AddTransient, NotificationOptionsConfiguration>(); services.AddScoped, UserNotificationPreferencesPartDisplayDriver>(); - - services.Configure((options) => - { - options.Filters.Add(typeof(NotificationResultFilter)); - }); + services.AddScoped, NotificationNavbarDisplayDriver>(); } public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) diff --git a/src/OrchardCore.Modules/OrchardCore.Notifications/ViewModels/UserNotificationCollectionViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Notifications/ViewModels/UserNotificationNavbarViewModel.cs similarity index 64% rename from src/OrchardCore.Modules/OrchardCore.Notifications/ViewModels/UserNotificationCollectionViewModel.cs rename to src/OrchardCore.Modules/OrchardCore.Notifications/ViewModels/UserNotificationNavbarViewModel.cs index f424ec0a624..aa52a2c04ca 100644 --- a/src/OrchardCore.Modules/OrchardCore.Notifications/ViewModels/UserNotificationCollectionViewModel.cs +++ b/src/OrchardCore.Modules/OrchardCore.Notifications/ViewModels/UserNotificationNavbarViewModel.cs @@ -2,11 +2,11 @@ namespace OrchardCore.Notifications.ViewModels; -public class UserNotificationCollectionViewModel +public class UserNotificationNavbarViewModel { public int TotalUnread { get; set; } public int MaxVisibleNotifications { get; set; } - public List Notifications { get; set; } + public List Notifications { get; set; } } diff --git a/src/OrchardCore.Modules/OrchardCore.Notifications/Views/UserNotificationCollection.cshtml b/src/OrchardCore.Modules/OrchardCore.Notifications/Views/UserNotificationNavbar.cshtml similarity index 66% rename from src/OrchardCore.Modules/OrchardCore.Notifications/Views/UserNotificationCollection.cshtml rename to src/OrchardCore.Modules/OrchardCore.Notifications/Views/UserNotificationNavbar.cshtml index 924701f50ed..50f95ac4f69 100644 --- a/src/OrchardCore.Modules/OrchardCore.Notifications/Views/UserNotificationCollection.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Notifications/Views/UserNotificationNavbar.cshtml @@ -1,20 +1,24 @@ @using Microsoft.AspNetCore.Mvc.Localization +@using OrchardCore.DisplayManagement.ModelBinding + +@inject IDisplayManager NotificationDisplayDriver +@inject IUpdateModelAccessor UpdateModelAccessor + +@model UserNotificationNavbarViewModel -@model ShapeViewModel - - - - diff --git a/src/OrchardCore.Themes/TheTheme/Views/UserNotificationNavbar.cshtml b/src/OrchardCore.Themes/TheTheme/Views/UserNotificationNavbar.cshtml new file mode 100644 index 00000000000..16a68e96da5 --- /dev/null +++ b/src/OrchardCore.Themes/TheTheme/Views/UserNotificationNavbar.cshtml @@ -0,0 +1,70 @@ +@using Microsoft.AspNetCore.Mvc.Localization +@using OrchardCore.DisplayManagement.ModelBinding +@using OrchardCore.DisplayManagement +@using OrchardCore.Notifications +@using OrchardCore.Notifications.ViewModels + +@inject IDisplayManager NotificationDisplayDriver +@inject IUpdateModelAccessor UpdateModelAccessor + +@model UserNotificationNavbarViewModel + + + + + + diff --git a/src/OrchardCore/OrchardCore.Admin.Abstractions/Models/Navbar.cs b/src/OrchardCore/OrchardCore.Admin.Abstractions/Models/Navbar.cs new file mode 100644 index 00000000000..130614a7411 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Admin.Abstractions/Models/Navbar.cs @@ -0,0 +1,7 @@ +using OrchardCore.Entities; + +namespace OrchardCore.Admin.Models; + +public class Navbar : Entity +{ +} diff --git a/src/OrchardCore/OrchardCore.Admin.Abstractions/OrchardCore.Admin.Abstractions.csproj b/src/OrchardCore/OrchardCore.Admin.Abstractions/OrchardCore.Admin.Abstractions.csproj index 74faf853dba..4b90a1b6cae 100644 --- a/src/OrchardCore/OrchardCore.Admin.Abstractions/OrchardCore.Admin.Abstractions.csproj +++ b/src/OrchardCore/OrchardCore.Admin.Abstractions/OrchardCore.Admin.Abstractions.csproj @@ -18,6 +18,7 @@ + diff --git a/src/docs/reference/modules/Admin/README.md b/src/docs/reference/modules/Admin/README.md index 189c75b0861..f190ca5d0b3 100644 --- a/src/docs/reference/modules/Admin/README.md +++ b/src/docs/reference/modules/Admin/README.md @@ -49,4 +49,44 @@ Here are samples using logo and favicon from media module. @Site.SiteName + ``` + + +## Navbar Shape + +The navigation bar shape is available in two display types `Detail` for the frontend and `DetailAdmin` for the backend admin. If you wish to add a menu item to the navigation bar, simply create a display driver for `Navbar`. + +As an illustration, we inject the Visit Site link into `DetailAdmin` display type using a display driver as outlined below: + +```csharp +public class VisitSiteNavbarDisplayDriver : DisplayDriver +{ + public override IDisplayResult Display(Navbar model) + { + return View("VisitSiteNavbarItem", model) + .Location("DetailAdmin", "Content:20"); + } +} +``` + +You can change it by overriding 'VisitSiteNavbarItem' shape, either from a [custom admin theme](../../../guides/create-admin-theme/README.md) or using Admin Templates feature. + +=== "Liquid" + + ``` liquid + + ``` + +=== "Razor" + + ``` html + ``` \ No newline at end of file diff --git a/src/docs/reference/modules/ContentLocalization/README.md b/src/docs/reference/modules/ContentLocalization/README.md index 63f69e1e1b6..c9d5043feda 100644 --- a/src/docs/reference/modules/ContentLocalization/README.md +++ b/src/docs/reference/modules/ContentLocalization/README.md @@ -16,7 +16,6 @@ Enabling this feature results in - A `ContentRequestCultureProvider` being added as the first method used to determine the current thread culture. This Provider will set the thread culture based on the ContentItem that matches the current url. -- 2 shapes (described below) are available to the frontend theme. The `ContentCulturePicker` selects the url to redirect using the following rules @@ -47,77 +46,6 @@ The cookie can be set during recipes using the settings step. Here is a sample s }, ``` -### Shapes - -#### `ContentCulturePicker` - -The `ContentCulturePicker` shape loads data for the `ContentCulturePickerContainer` shape. -You should always render this shape in your theme: - -=== "Liquid" - - ``` liquid - {% shape "ContentCulturePicker" %} - ``` - -=== "Razor" - - ``` html - - ``` - -#### `ContentCulturePickerContainer` - -The `ContentCulturePickerContainer` shape is used to render the `ContentCulturePicker`. -You should override this shape in your theme. - -| Property | Description | -| ------------------------- | ----------------------------------------------------------- | -| `Model.CurrentCulture` | CultureViewModel {Name, DisplayName} representing the current thread culture. | -| `Model.SupportedCultures` | A list of CultureViewModel objects for all supported cultures. | - -##### ContentCulturePickerContainer Example - -=== "Liquid" - - ``` liquid - - ``` - -=== "Razor" - - ``` html - - ``` - ## Liquid filters ### `switch_culture_url` diff --git a/src/docs/releases/1.8.0.md b/src/docs/releases/1.8.0.md index fc27b8d98a5..5962e509335 100644 --- a/src/docs/releases/1.8.0.md +++ b/src/docs/releases/1.8.0.md @@ -16,5 +16,35 @@ The `TheAdmin` theme was upgraded to Bootstrap 5.3.2. Here is a list of the brea - The `DarkModeService.cs` was replaced with `ThemeTogglerService`. - The property named `DisplayDarkMode` in `AdminSettings` was replaced with `DisplayThemeToggler`. - Bootstrap is no longer compiled in `TheAdmin.css`. Bootstrap assets are loaded independently for performance and maintainability reasons. - + + ### Navbar + + The `NavbarTop` zone is no longer used in the `TheAdmin` or `TheTheme` themes. Follow the Navbar details below on how to inject custom menu items in the navbar. + ## Change Logs + +### TheTheme Theme + +The `TheTheme` theme was upgraded to Bootstrap 5.3.2. New `light` and `dark` modes were added. + +### Navbar + +The upper navigation bar has been transformed into a customizable shape, allowing for easy integration of items. The `NavbarTop` zone is no longer used in the `TheAdmin` or `TheTheme` themes. If you wish to add a menu item to the navigation bar, simply create a display driver for `Navbar`. + +As an illustration, we inject the theme toggler into both `Detail` and `DetailAdmin` display type using a display driver as outlined below: + +```csharp +public class ToggleThemeNavbarDisplayDriver : DisplayDriver +{ + public override IDisplayResult Display(Navbar model) + { + return View("ToggleTheme", model) + .Location("Detail", "Content:10") + .Location("DetailAdmin", "Content:10"); + } +} +``` + + Additionally, the follow shapes have been removed + - `ContentCulturePickerContainer` + - `AdminCulturePickerContainer`