diff --git a/src/FluentCMS.sln b/src/FluentCMS.sln index 9e301e6f7..a28f1a9b2 100644 --- a/src/FluentCMS.sln +++ b/src/FluentCMS.sln @@ -39,6 +39,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FluentCMS.Web.Plugins.Admin EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentCMS.Web.Plugins.Contents.TextHTML", "Frontend\Plugins\FluentCMS.Web.Plugins.Contents.TextHTML\FluentCMS.Web.Plugins.Contents.TextHTML.csproj", "{818F8CD0-5218-4480-A541-BD9D59416CDE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentCMS.Web.Plugins.Contents.Blogs", "Frontend\Plugins\FluentCMS.Web.Plugins.Contents.Blogs\FluentCMS.Web.Plugins.Contents.Blogs.csproj", "{9293D902-7341-4EA8-96F6-D29FFDE80AC4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -101,6 +103,10 @@ Global {818F8CD0-5218-4480-A541-BD9D59416CDE}.Debug|Any CPU.Build.0 = Debug|Any CPU {818F8CD0-5218-4480-A541-BD9D59416CDE}.Release|Any CPU.ActiveCfg = Release|Any CPU {818F8CD0-5218-4480-A541-BD9D59416CDE}.Release|Any CPU.Build.0 = Release|Any CPU + {9293D902-7341-4EA8-96F6-D29FFDE80AC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9293D902-7341-4EA8-96F6-D29FFDE80AC4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9293D902-7341-4EA8-96F6-D29FFDE80AC4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9293D902-7341-4EA8-96F6-D29FFDE80AC4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -120,6 +126,7 @@ Global {BB5FD6A0-0840-4381-AB68-AD61499368ED} = {5961A5E0-54A6-42F5-92A2-9A9E48DE2878} {70B5742E-C249-4B51-985C-2B4B7BDAB489} = {BB5FD6A0-0840-4381-AB68-AD61499368ED} {818F8CD0-5218-4480-A541-BD9D59416CDE} = {BB5FD6A0-0840-4381-AB68-AD61499368ED} + {9293D902-7341-4EA8-96F6-D29FFDE80AC4} = {BB5FD6A0-0840-4381-AB68-AD61499368ED} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2E9F4217-7A58-48A4-9850-84CD0CDA31DA} diff --git a/src/FluentCMS/FluentCMS.csproj b/src/FluentCMS/FluentCMS.csproj index 8e5fd41e9..ca893f146 100644 --- a/src/FluentCMS/FluentCMS.csproj +++ b/src/FluentCMS/FluentCMS.csproj @@ -14,6 +14,7 @@ + diff --git a/src/FluentCMS/Template/manifest.json b/src/FluentCMS/Template/manifest.json index 90bc2f8a8..225f9ce34 100644 --- a/src/FluentCMS/Template/manifest.json +++ b/src/FluentCMS/Template/manifest.json @@ -367,6 +367,26 @@ "Type": "TextHTMLEditPlugin" } ] + }, + { + "Name": "Blogs Plugin", + "Description": "", + "Assembly": "FluentCMS.Web.Plugins.Contents.Blogs.dll", + "Types": [ + { + "Name": "Blogs List", + "Type": "BlogViewPlugin", + "IsDefault": true + }, + { + "Name": "Manage Blogs", + "Type": "BlogManagePlugin" + }, + { + "Name": "Blog Detail", + "Type": "BlogDetailPlugin" + } + ] } ], "Pages": [ @@ -402,6 +422,38 @@ } ] }, + { + "Definition": "Blogs Plugin", + "Section": "Main", + "Type": "BlogContent", + "Content": [ + { + "Title": "Introduction to Responsive Web Design", + "Content": "In today's digital landscape, responsive web design is crucial for reaching users on multiple devices. This post explores the principles of responsive design and offers tips for implementation.", + "Description": "In this post You'll learn about Responsive web design" + }, + { + "Title": "Exploring the Power of C# LINQ", + "Content": "LINQ (Language-Integrated Query) in C# is a powerful tool for querying and manipulating data. This post dives into the basics of LINQ and demonstrates its usage with practical examples.", + "Description": "In this post You'll learn about LINQ" + }, + { + "Title": "Getting Started with Blazor: A Comprehensive Guide", + "Content": "

Blazor, Microsoft's innovative web framework, empowers developers to craft interactive web applications seamlessly using C#. This tutorial provides a concise overview of Blazor's core concepts, showcasing its capability to run C# code directly in the browser through WebAssembly.


Example

Let's explore a basic example: a Blazor component that implements a simple counter.

Copy code
@page \"/counter\"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class=\"btn btn-primary\" @onclick=\"IncrementCount\">Click me</button>

@code {
private int currentCount = 0;

private void IncrementCount()
{
currentCount++;
}
}

In this snippet, a Blazor component is defined to maintain and display a count. Upon clicking the button, the count increments without requiring a page refresh, demonstrating Blazor's efficient handling of user interactions and UI updates.


Conclusion

Blazor presents an enticing opportunity for .NET developers, whether seasoned or new to web development, to harness the power of C# in crafting dynamic web applications. With its seamless integration and intuitive features, Blazor streamlines the development process, making it an invaluable tool in the modern web development landscape.





", + "Description": "In this post You'll learn about blazor" + }, + { + "Title": "Mastering CSS Grid for Modern Web Layouts", + "Content": "

In the realm of web design, CSS Grid has revolutionized the way developers approach layout creation. This comprehensive guide delves into the intricacies of CSS Grid, exploring its two-dimensional grid system that allows for the creation of complex layouts with ease. We will cover the fundamental concepts such as grid containers, grid items, and grid lines, and demonstrate how to use them to build responsive and dynamic web pages.

You will learn how to define grid tracks, create grid cells, and manage grid areas. Additionally, we will explore advanced techniques like grid auto-placement, grid alignment properties, and the use of CSS Grid with media queries for responsive design. By the end of this post, you will have a solid understanding of how to leverage CSS Grid to create modern, efficient, and visually appealing web layouts.

", + "Description": "In this post You'll learn about CSS Grid" + }, + { + "Title": "Advanced JavaScript Techniques for Efficient Web Development", + "Content": "

JavaScript remains a cornerstone of modern web development, offering endless possibilities for enhancing user interaction and functionality. This post focuses on advanced JavaScript techniques that can significantly improve the efficiency and performance of your web applications. We will explore topics such as asynchronous programming with Promises and async/await, the use of modern JavaScript features like destructuring and template literals, and the importance of modularizing your code with ES6 modules.

Furthermore, we will delve into the world of JavaScript frameworks and libraries, discussing how they can streamline your development process and help you build scalable and maintainable applications. Whether you are a seasoned JavaScript developer or just starting out, this post will equip you with the knowledge and tools necessary to take your web development skills to the next level.

", + "Description": "In this post You'll learn about Advanced JavaScript Techniques" + } + ] + }, { "Definition": "TextHTML Plugin", "Section": "Main", diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogContent.cs b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogContent.cs new file mode 100644 index 000000000..12ed401c6 --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogContent.cs @@ -0,0 +1,10 @@ +namespace FluentCMS.Web.Plugins.Contents.Blogs; + +public class BlogContent : IContent +{ + public Guid Id { get; set; } + public string Title { get; set; } = String.Empty; + public string Description { get; set; } = String.Empty; + public string Content { get; set; } = String.Empty; + public string Image { get; set; } = String.Empty; +} \ No newline at end of file diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogDetailPlugin.razor b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogDetailPlugin.razor new file mode 100644 index 000000000..9a59c51e6 --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogDetailPlugin.razor @@ -0,0 +1,12 @@ +@if (Item != null) +{ +
+

@Item.Title

+

@Item.Description

+ +
+ @((MarkupString)Item.Content) +
+ +
+} \ No newline at end of file diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogDetailPlugin.razor.cs b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogDetailPlugin.razor.cs new file mode 100644 index 000000000..d96bf9990 --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogDetailPlugin.razor.cs @@ -0,0 +1,83 @@ +namespace FluentCMS.Web.Plugins.Contents.Blogs; + +public partial class BlogDetailPlugin +{ + // #region Base + + [Inject] + protected NavigationManager NavigationManager { get; set; } = default!; + + [Parameter] + public string? SectionName { get; set; } + + [Parameter] + public PluginViewState? Plugin { get; set; } = default!; + + [Inject] + protected ApiClientFactory ApiClient { get; set; } = default!; + + [Inject] + protected IHttpContextAccessor? HttpContextAccessor { get; set; } + + protected virtual void NavigateBack() + { + var url = new Uri(NavigationManager.Uri).LocalPath; + NavigateTo(url); + } + + protected virtual void NavigateTo(string path) + { + if (HttpContextAccessor?.HttpContext != null && !HttpContextAccessor.HttpContext.Response.HasStarted) + HttpContextAccessor.HttpContext.Response.Redirect(path); + else + NavigationManager.NavigateTo(path); + } + + protected virtual string GetUrl(string viewName, object? parameters = null) + { + var uri = new Uri(NavigationManager.Uri); + var oldQueryParams = HttpUtility.ParseQueryString(uri.Query); + + // this gets the page path from root without QueryString + var pagePathWithoutQueryString = uri.GetLeftPart(UriPartial.Path); + + var newQueryParams = new Dictionary() + { + { "pluginId", Plugin!.Id.ToString() }, + { "viewName", viewName } + }; + + if (parameters != null) + { + foreach (var propInfo in parameters.GetType().GetProperties()) + newQueryParams[propInfo.Name] = propInfo.GetValue(parameters)?.ToString(); + } + + foreach (var key in oldQueryParams.AllKeys) + { + if (string.IsNullOrEmpty(key) || newQueryParams.ContainsKey(key)) + continue; + + newQueryParams[key] = oldQueryParams[key]; + } + + return QueryHelpers.AddQueryString(pagePathWithoutQueryString, newQueryParams); + } + // #endregion + + [SupplyParameterFromQuery(Name = "id")] + private Guid Id { get; set; } + + private BlogContent Item { get; set; } + + protected override async Task OnInitializedAsync() + { + if (Plugin is not null) + { + var response = await ApiClient.PluginContent.GetByIdAsync(nameof(BlogContent), Plugin.Id, Id); + + if (response?.Data != null) + Item = response.Data.Data.ToContent(); + } + } +} diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogEditForm.razor b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogEditForm.razor new file mode 100644 index 000000000..aced7cea7 --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogEditForm.razor @@ -0,0 +1,24 @@ +@if (Model != null) +{ + + + + + + + + + + + + + + + + + +} \ No newline at end of file diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogEditForm.razor.cs b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogEditForm.razor.cs new file mode 100644 index 000000000..0e49cacf8 --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogEditForm.razor.cs @@ -0,0 +1,27 @@ +namespace FluentCMS.Web.Plugins.Contents.Blogs; + +public partial class BlogEditForm +{ + [Parameter] + public BlogContent Model { get; set; } + + [Parameter] + public string FormName { get; set; } + + [Parameter] + public EventCallback OnSubmit { get; set; } + + [Parameter] + public EventCallback OnCancel { get; set; } + + private async Task HandleSubmit() + { + await OnSubmit.InvokeAsync(Model); + } + + private async Task HandleCancel() + { + await OnCancel.InvokeAsync(); + } + +} \ No newline at end of file diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogManagePlugin.razor b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogManagePlugin.razor new file mode 100644 index 000000000..ab4904c2e --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogManagePlugin.razor @@ -0,0 +1,71 @@ +@rendermode InteractiveServer + +
+ + @if(CurrentState == BlogManagementState.List) + { + + + Blogs + + + + + + + + + + + + @if (Items != null) + { +
+ @foreach (var item in Items) + { +
+
+
+

@item.Title

+

@item.Description

+
+
+ + + + +
+ } +
+ } + } + else if (CurrentState == BlogManagementState.Create) + { + Create Blog Content + + + + + + + } + else if (CurrentState == BlogManagementState.Edit) + { + Edit Blog Content + + + + + + + } +
+ + + Are you sure to delete this content? + \ No newline at end of file diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogManagePlugin.razor.cs b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogManagePlugin.razor.cs new file mode 100644 index 000000000..73c7eab01 --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogManagePlugin.razor.cs @@ -0,0 +1,182 @@ +namespace FluentCMS.Web.Plugins.Contents.Blogs; + +public partial class BlogManagePlugin +{ + // #region Base + + [Inject] + protected NavigationManager NavigationManager { get; set; } = default!; + + [Parameter] + public string? SectionName { get; set; } + + [Parameter] + public PluginViewState Plugin { get; set; } = default!; + + [Inject] + protected ApiClientFactory ApiClient { get; set; } = default!; + + [Inject] + protected IHttpContextAccessor? HttpContextAccessor { get; set; } + + protected virtual void NavigateTo(string path) + { + if (HttpContextAccessor?.HttpContext != null && !HttpContextAccessor.HttpContext.Response.HasStarted) + HttpContextAccessor.HttpContext.Response.Redirect(path); + else + NavigationManager.NavigateTo(path, true); + } + + protected virtual string GetDetailUrl(string viewName, object? parameters = null) + { + var uri = new Uri(NavigationManager.Uri); + var oldQueryParams = HttpUtility.ParseQueryString(uri.Query); + + // this gets the page path from root without QueryString + var pagePathWithoutQueryString = uri.GetLeftPart(UriPartial.Path); + + var newQueryParams = new Dictionary() + { + { "pluginId", Plugin!.Id.ToString() }, + { "viewMode", "detail" }, + { "viewName", viewName } + }; + + if (parameters != null) + { + foreach (var propInfo in parameters.GetType().GetProperties()) + newQueryParams[propInfo.Name] = propInfo.GetValue(parameters)?.ToString(); + } + + foreach (var key in oldQueryParams.AllKeys) + { + if (string.IsNullOrEmpty(key) || newQueryParams.ContainsKey(key)) + continue; + + newQueryParams[key] = oldQueryParams[key]; + } + + return QueryHelpers.AddQueryString(pagePathWithoutQueryString, newQueryParams); + } + // #endregion + + public const string CONTENT_TYPE_NAME = nameof(BlogContent); + + private BlogManagementState CurrentState { get; set; } = BlogManagementState.List; + private List Items { get; set; } + private bool DeleteConfirmOpen { get; set; } = false; + + private async Task Load() + { + Console.WriteLine("Load"); + var response = await ApiClient.PluginContent.GetAllAsync(CONTENT_TYPE_NAME, Plugin.Id); + + if (response?.Data != null && response.Data.ToContentList().Any()) + Items = response.Data.ToContentList(); + } + + protected virtual async Task NavigateBack() + { + if (CurrentState == BlogManagementState.List) + { + var url = new Uri(NavigationManager.Uri).LocalPath; + NavigateTo(url + "?pageEdit=true"); + } + else + { + await Load(); + CurrentState = BlogManagementState.List; + } + } + + [SupplyParameterFromForm(FormName = CONTENT_TYPE_NAME)] + private BlogContent? Model { get; set; } + + [SupplyParameterFromQuery(Name = nameof(Id))] + private Guid? Id { get; set; } = default!; + + protected virtual string GetBackUrl() + { + return new Uri(NavigationManager.Uri).LocalPath; + } + + protected override async Task OnInitializedAsync() + { + if (Model is null) + { + if (Id != null) + { + var response = await ApiClient.PluginContent.GetByIdAsync(CONTENT_TYPE_NAME, Plugin!.Id, Id.Value); + + var content = response.Data.Data.ToContent(); + + Model = new BlogContent + { + Id = Id.Value, + Content = content.Content, + Title = content.Title, + Description = content.Description, + }; + } + else + { + Model = new BlogContent(); + } + } + + if (Items is null) + { + await Load(); + } + } + + private async Task OnDeleteItem() + { + await ApiClient.PluginContent.DeleteAsync(CONTENT_TYPE_NAME, Plugin.Id, Model.Id); + await Load(); + } + + private async Task OnConfirmClose() + { + DeleteConfirmOpen = false; + await Task.CompletedTask; + } + + private async Task OnDeleteItemClicked(BlogContent item) + { + DeleteConfirmOpen = true; + Model = item; + } + + private async Task OnEditItemClicked(BlogContent item) + { + CurrentState = BlogManagementState.Edit; + Model = item; + } + + private async Task OnAddItemClicked() + { + CurrentState = BlogManagementState.Create; + Model = new BlogContent(); + } + + private async Task OnEditBlog(BlogContent model) + { + await ApiClient.PluginContent.UpdateAsync(CONTENT_TYPE_NAME, Plugin.Id, model.Id, Model.ToDictionary()); + await NavigateBack(); + } + + private async Task OnCreateBlog(BlogContent model) + { + await ApiClient.PluginContent.CreateAsync(CONTENT_TYPE_NAME, Plugin.Id, Model.ToDictionary()); + await NavigateBack(); + } +} + +public enum BlogManagementState +{ + List, + Create, + Edit, + Delete +} diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogViewPlugin.razor b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogViewPlugin.razor new file mode 100644 index 000000000..d1649aeb2 --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogViewPlugin.razor @@ -0,0 +1,19 @@ +@if (Items != null) +{ + @foreach (var item in Items) + { +
+

@item.Title

+

@item.Description

+
+ } +} + +
+ +
\ No newline at end of file diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogViewPlugin.razor.cs b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogViewPlugin.razor.cs new file mode 100644 index 000000000..3db7bff5e --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/BlogViewPlugin.razor.cs @@ -0,0 +1,82 @@ +namespace FluentCMS.Web.Plugins.Contents.Blogs; + +public partial class BlogViewPlugin +{ + // #region Base + + [Inject] + protected NavigationManager NavigationManager { get; set; } = default!; + + [Parameter] + public string? SectionName { get; set; } + + [Parameter] + public PluginViewState? Plugin { get; set; } = default!; + + [Inject] + protected ApiClientFactory ApiClient { get; set; } = default!; + + [Inject] + protected IHttpContextAccessor? HttpContextAccessor { get; set; } + + protected virtual void NavigateBack() + { + var url = new Uri(NavigationManager.Uri).LocalPath; + NavigateTo(url); + } + + protected virtual void NavigateTo(string path) + { + if (HttpContextAccessor?.HttpContext != null && !HttpContextAccessor.HttpContext.Response.HasStarted) + HttpContextAccessor.HttpContext.Response.Redirect(path); + else + NavigationManager.NavigateTo(path); + } + + protected virtual string GetDetailUrl(string viewName, object? parameters = null) + { + var uri = new Uri(NavigationManager.Uri); + var oldQueryParams = HttpUtility.ParseQueryString(uri.Query); + + // this gets the page path from root without QueryString + var pagePathWithoutQueryString = uri.GetLeftPart(UriPartial.Path); + + var newQueryParams = new Dictionary() + { + { "pluginId", Plugin!.Id.ToString() }, + { "viewMode", "detail" }, + { "viewName", viewName } + }; + + if (parameters != null) + { + foreach (var propInfo in parameters.GetType().GetProperties()) + newQueryParams[propInfo.Name] = propInfo.GetValue(parameters)?.ToString(); + } + + foreach (var key in oldQueryParams.AllKeys) + { + if (string.IsNullOrEmpty(key) || newQueryParams.ContainsKey(key)) + continue; + + newQueryParams[key] = oldQueryParams[key]; + } + + return QueryHelpers.AddQueryString(pagePathWithoutQueryString, newQueryParams); + } + // #endregion + + private List Items { get; set; } = []; + + protected override async Task OnInitializedAsync() + { + if (Plugin is not null) + { + var response = await ApiClient.PluginContent.GetAllAsync(nameof(BlogContent), Plugin.Id); + + if (response?.Data != null && response.Data.ToContentList().Any()) + Items = response.Data.ToContentList(); + + } + } +} diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/FluentCMS.Web.Plugins.Contents.Blogs.csproj b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/FluentCMS.Web.Plugins.Contents.Blogs.csproj new file mode 100644 index 000000000..0a53eec84 --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/FluentCMS.Web.Plugins.Contents.Blogs.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + enable + + + + + + + + diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/_GlobalUsings.cs b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/_GlobalUsings.cs new file mode 100644 index 000000000..b882b57d1 --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/_GlobalUsings.cs @@ -0,0 +1,9 @@ +global using FluentCMS.Web.ApiClients; +global using Microsoft.AspNetCore.Components; +global using Microsoft.AspNetCore.Http; + +global using AutoMapper; +global using Microsoft.AspNetCore.Components.Forms; +global using Microsoft.AspNetCore.WebUtilities; +global using System.Web; + diff --git a/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/_Imports.razor b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/_Imports.razor new file mode 100644 index 000000000..bc828ca99 --- /dev/null +++ b/src/Frontend/Plugins/FluentCMS.Web.Plugins.Contents.Blogs/_Imports.razor @@ -0,0 +1,8 @@ +@using System.Web +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.JSInterop +@using FluentCMS.Web.UI.Components +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Authorization