Browse Source

Improved news system

Marcel Baumgartner 2 years ago
parent
commit
e0c9efd9a8

+ 2 - 0
Moonlight/Moonlight.csproj

@@ -62,6 +62,8 @@
     <_ContentIncludedByDefault Remove="Shared\Components\Tables\Table.razor" />
     <_ContentIncludedByDefault Remove="Shared\Views\Admin\Servers\Cleanup\Exceptions\Add.razor" />
     <_ContentIncludedByDefault Remove="Shared\Views\Admin\Servers\Cleanup\Exceptions\Edit.razor" />
+    <_ContentIncludedByDefault Remove="Shared\Components\News\NewsEditor.razor" />
+    <_ContentIncludedByDefault Remove="Shared\News\Edit.razor" />
   </ItemGroup>
 
   <ItemGroup>

+ 5 - 0
Moonlight/Shared/Components/Navigations/AdminSystemNavigation.razor

@@ -39,6 +39,11 @@
                     <TL>Discord bot</TL>
                 </a>
             </li>
+            <li class="nav-item mt-2">
+                <a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 7 ? "active" : "")" href="/admin/system/news">
+                    <TL>News</TL>
+                </a>
+            </li>
         </ul>
     </div>
 </div>

+ 0 - 98
Moonlight/Shared/Components/News/NewsEditor.razor

@@ -1,98 +0,0 @@
-@using Moonlight.App.Services
-@using Moonlight.App.Database.Entities
-@using BlazorMonaco
-
-@inject SmartTranslateService SmartTranslateService
-@inject IJSRuntime JsRuntime
-
-<div class="card mb-6">
-    <div class="card-header">
-        <h3 class="card-title w-75">
-            <input type="text" @bind="Model.Title" placeholder="@SmartTranslateService.Translate("Title...")" class="form-control form-control-flush"/>
-        </h3>
-        <div class="card-toolbar">
-            @{
-                string dateInt(int i) => i.ToString().Length < 2 ? "0" + i : i.ToString();
-                var date = Model.Date == default ? DateTime.Now : Model.Date;
-            }
-            <span class="text-gray-600 fw-semibold">@dateInt(date.Day).@dateInt(date.Month).@date.Year</span>
-        </div>
-    </div>
-    <div class="card-body">
-        <MonacoEditor CssClass="h-50" @ref="Editor" Id="vseditor" ConstructionOptions="(x) => EditorOptions"/>
-    </div>
-    <div class="card-footer">
-        <WButton CssClasses="btn btn-primary float-end" OnClick="DoSave" Text="@SmartTranslateService.Translate("Save")" WorkingText="@SmartTranslateService.Translate("Saving...")"></WButton>
-    </div>
-</div>
-
-@code {
-    // Monaco Editor
-    private MonacoEditor Editor;
-    private StandaloneEditorConstructionOptions EditorOptions;
-    
-    [Parameter]
-    public NewsEntry Model { get; set; }
-
-    [Parameter]
-    public Func<NewsEntry, Task> Save { get; set; }
-
-    protected override void OnInitialized()
-    {
-        EditorOptions = new()
-        {
-            AutomaticLayout = true,
-            Language = "plaintext",
-            Value = "Loading content",
-            Theme = "moonlight-theme",
-            Contextmenu = false,
-            Minimap = new()
-            {
-                Enabled = false
-            },
-            AutoIndent = true
-        };
-    }
-    
-    protected override async Task OnAfterRenderAsync(bool firstRender)
-    {
-        if (firstRender)
-        {
-            await JsRuntime.InvokeVoidAsync("initMonacoTheme");
-            
-            Editor.OnDidInit = new EventCallback<MonacoEditorBase>(this, async () =>
-            {
-                EditorOptions.Language = "markdown";
-        
-                var model = await Editor.GetModel();
-                await MonacoEditorBase.SetModelLanguage(model, EditorOptions.Language);
-                await Editor.SetPosition(new Position()
-                {
-                    Column = 0,
-                    LineNumber = 1
-                });
-        
-                await Editor.SetValue(string.IsNullOrWhiteSpace(Model.Markdown) ? "*enter your markdown here*" : Model.Markdown);
-        
-                await Editor.Layout(new Dimension()
-                {
-                    Height = 500,
-                    Width = 1000
-                }); 
-            });
-        }
-    }
-
-    private async Task DoSave()
-    {
-        Model.Date = Model.Date == default ? DateTime.Now : Model.Date;
-        Model.Markdown = await Editor.GetValue();
-        
-        Save?.Invoke(Model);
-    }
-
-    public async Task UpdateMonacoText()
-    {
-        await Editor.SetValue(Model.Markdown);
-    }
-}

+ 0 - 8
Moonlight/Shared/Components/Partials/SidebarMenu.razor

@@ -68,14 +68,6 @@ else
             <span class="menu-title"><TL>Changelog</TL></span>
         </a>
     </div>
-    <div class="menu-item">
-        <a class="menu-link" href="/news">
-            <span class="menu-icon">
-                <i class="bx bx-news"></i>
-            </span>
-            <span class="menu-title"><TL>News</TL></span>
-        </a>
-    </div>
 
     if (User.Admin)
     {

+ 0 - 32
Moonlight/Shared/News/Edit.razor

@@ -1,32 +0,0 @@
-@page "/news/edit/{Id:int}"
-
-@using Moonlight.App.Database.Entities
-@using Moonlight.App.Repositories
-@using Moonlight.Shared.Components.News
-
-@inject NewsEntryRepository NewsEntryRepository
-@inject NavigationManager NavigationManager
-
-<OnlyAdmin>
-    <LazyLoader Load="Load">
-        <NewsEditor Model="Entry" Save="DoSave"></NewsEditor>
-    </LazyLoader>
-</OnlyAdmin>
-
-@code {
-    [Parameter]
-    public int Id { get; set; }
-
-    private NewsEntry Entry;
-
-    private async Task Load(LazyLoader loader)
-    {
-        Entry = NewsEntryRepository.Get().First(x => x.Id == Id);
-    }
-
-    private async Task DoSave(NewsEntry entry)
-    {
-        NewsEntryRepository.Update(entry);
-        NavigationManager.NavigateTo("/news");
-    }
-}

+ 78 - 0
Moonlight/Shared/Views/Admin/Sys/News/Edit.razor

@@ -0,0 +1,78 @@
+@page "/admin/system/news/edit/{Id:int}"
+
+@using Moonlight.App.Database.Entities
+@using Moonlight.App.Helpers
+@using Moonlight.App.Repositories
+@using Moonlight.App.Services
+@using Moonlight.Shared.Components.FileManagerPartials
+
+@inject SmartTranslateService SmartTranslateService
+@inject NavigationManager NavigationManager
+@inject NewsEntryRepository NewsEntryRepository
+
+<OnlyAdmin>
+    <LazyLoader Load="Load">
+        @if (Entry == null)
+        {
+            <div class="alert bg-info d-flex flex-column flex-sm-row w-100 p-5">
+                <div class="d-flex flex-column pe-0 pe-sm-10">
+                    <h4 class="fw-semibold">
+                        <TL>No entry found</TL>
+                    </h4>
+                    <span>
+                        <TL>We were not able to find the news entry with this id</TL>
+                    </span>
+                </div>
+            </div>
+        }
+        else
+        {
+            <div class="card mb-6">
+                <div class="card-header">
+                    <h3 class="card-title w-75">
+                        <input type="text" @bind="Entry.Title" placeholder="@SmartTranslateService.Translate("Title...")" class="form-control form-control-flush"/>
+                    </h3>
+                    <div class="card-toolbar">
+                        <span class="text-gray-600 fw-semibold">@(Formatter.FormatDateOnly(Entry.Date))</span>
+                    </div>
+                </div>
+                <div class="card-body">
+                    <FileEditor @ref="FileEditor" Language="markdown" HideControls="true" InitialData="@(Entry.Markdown)"/>
+                </div>
+                <div class="card-footer">
+                    <WButton CssClasses="btn btn-primary text-end"
+                             OnClick="Save"
+                             Text="@SmartTranslateService.Translate("Save")"
+                             WorkingText="@SmartTranslateService.Translate("Saving...")">
+                    </WButton>
+                </div>
+            </div>
+        }
+    </LazyLoader>
+</OnlyAdmin>
+
+@code
+{
+    [Parameter]
+    public int Id { get; set; }
+    
+    private NewsEntry? Entry;
+
+    private FileEditor FileEditor;
+
+    private async Task Save()
+    {
+        Entry!.Markdown = await FileEditor.GetData();
+        
+        NewsEntryRepository.Update(Entry);
+        
+        NavigationManager.NavigateTo("/admin/system/news");
+    }
+
+    private Task Load(LazyLoader arg)
+    {
+        Entry = NewsEntryRepository.Get().FirstOrDefault(x => x.Id == Id);
+        
+        return Task.CompletedTask;
+    }
+}

+ 84 - 0
Moonlight/Shared/Views/Admin/Sys/News/Index.razor

@@ -0,0 +1,84 @@
+@page "/admin/system/news"
+@using Moonlight.App.Repositories
+@using Moonlight.App.Database.Entities
+@using Markdig
+@using Moonlight.App.Helpers
+@using Moonlight.App.Services
+@using Moonlight.App.Services.Interop
+@using Moonlight.Shared.Components.Navigations
+@using Moonlight.Shared.Components.FileManagerPartials
+
+@inject NewsEntryRepository NewsEntryRepository
+@inject SmartTranslateService SmartTranslateService
+@inject AlertService AlertService
+
+<OnlyAdmin>
+    <AdminSystemNavigation Index="7" />
+    
+    <div class="card card-body mb-6">
+        <div class="text-end">
+            <a href="/admin/system/news/new" class="btn btn-success">
+                <TL>New entry</TL>
+            </a>
+        </div>
+    </div>
+
+    <LazyLoader @ref="LazyLoader" Load="Load">
+        @foreach (var entry in Entries)
+        {
+            <div class="card mb-6">
+                <div class="card-header">
+                    <h3 class="card-title">@entry.Title</h3>
+                    <div class="card-toolbar">
+                        <a href="/admin/system/news/edit/@(entry.Id)">
+                            <button class="btn btn-sm btn-light me-4">
+                                <TL>Edit</TL>
+                            </button>
+                        </a>
+
+                        <WButton CssClasses="btn btn-sm btn-light me-4"
+                                 Text="@SmartTranslateService.Translate("Delete")"
+                                 WorkingText="@SmartTranslateService.Translate("Deleting...")"
+                                 OnClick="() => Delete(entry)">
+                        </WButton>
+
+                        <span class="text-gray-600 fw-semibold">@(Formatter.FormatDateOnly(entry.Date))</span>
+                    </div>
+                </div>
+                <div class="card-body">
+                    @{
+                        var html = (MarkupString)Markdown.ToHtml(entry.Markdown);
+                    }
+
+                    @(html)
+                </div>
+            </div>
+        }
+    </LazyLoader>
+</OnlyAdmin>
+
+@code
+{
+    private NewsEntry[] Entries;
+
+    private LazyLoader LazyLoader;
+    private FileEditor FileEditor;
+
+    private Task Load(LazyLoader loader)
+    {
+        Entries = NewsEntryRepository.Get().OrderByDescending(x => x.Date).ToArray();
+
+        return Task.CompletedTask;
+    }
+
+    private async Task Delete(NewsEntry entry)
+    {
+        var confirm = await AlertService.ConfirmMath();
+
+        if (!confirm) return;
+
+        NewsEntryRepository.Delete(entry);
+
+        await LazyLoader.Reload();
+    }
+}

+ 52 - 0
Moonlight/Shared/Views/Admin/Sys/News/New.razor

@@ -0,0 +1,52 @@
+@page "/admin/system/news/new"
+@using Moonlight.App.Database.Entities
+@using Moonlight.App.Helpers
+@using Moonlight.App.Repositories
+@using Moonlight.App.Services
+@using Moonlight.Shared.Components.FileManagerPartials
+
+@inject SmartTranslateService SmartTranslateService
+@inject NavigationManager NavigationManager
+@inject NewsEntryRepository NewsEntryRepository
+
+<OnlyAdmin>
+    <div class="card mb-6">
+        <div class="card-header">
+            <h3 class="card-title w-75">
+                <input type="text" @bind="Model.Title" placeholder="@SmartTranslateService.Translate("Title...")" class="form-control form-control-flush"/>
+            </h3>
+            <div class="card-toolbar">
+                <span class="text-gray-600 fw-semibold">@(Formatter.FormatDateOnly(Model.Date))</span>
+            </div>
+        </div>
+        <div class="card-body">
+            <FileEditor @ref="FileEditor" Language="markdown" HideControls="true" InitialData=""/>
+        </div>
+        <div class="card-footer">
+            <WButton CssClasses="btn btn-primary text-end"
+                     OnClick="Save"
+                     Text="@SmartTranslateService.Translate("Save")"
+                     WorkingText="@SmartTranslateService.Translate("Saving...")">
+            </WButton>
+        </div>
+    </div>
+</OnlyAdmin>
+
+@code
+{
+    private NewsEntry Model = new() //TODO: Smart form model
+    {
+        Date = DateTime.UtcNow
+    };
+
+    private FileEditor FileEditor;
+
+    private async Task Save()
+    {
+        Model.Markdown = await FileEditor.GetData();
+        
+        NewsEntryRepository.Add(Model);
+        
+        NavigationManager.NavigateTo("/admin/system/news");
+    }
+}

+ 61 - 2
Moonlight/Shared/Views/Index.razor

@@ -3,14 +3,62 @@
 @using Moonlight.App.Repositories.Servers
 @using Microsoft.EntityFrameworkCore
 @using Moonlight.App.Database.Entities
+@using Moonlight.App.Helpers
 @using Moonlight.App.Repositories
 @using Moonlight.App.Repositories.Domains
+@using Markdig
 
 @inject ServerRepository ServerRepository
 @inject WebsiteRepository WebsiteRepository
 @inject DomainRepository DomainRepository
+@inject NewsEntryRepository NewsEntryRepository
 
 <LazyLoader Load="Load">
+@if (NewsEntries.Any())
+{
+    if (CurrentNewsIndex > NewsEntries.Count - 1)
+        CurrentNewsIndex = 0;
+
+    if (CurrentNewsIndex < 0)
+        CurrentNewsIndex = NewsEntries.Count - 1;
+
+    var currentEntry = NewsEntries[CurrentNewsIndex];
+
+    <div class="mb-5">
+        <div class="card">
+            <div class="card-header card-header-stretch">
+                <div class="card-title d-flex align-items-center">
+                    <span class="me-3 lh-0">
+                        <i class="bx bx-md bx-calendar"></i>
+                    </span>
+                    <h3 class="fw-bold m-0 text-gray-800">@(Formatter.FormatDateOnly(currentEntry.Date))</h3>
+                </div>
+                <div class="card-toolbar m-0">
+                    <ul class="nav nav-tabs nav-line-tabs nav-stretch fs-6 border-0 fw-bold">
+                        <li class="nav-item">
+                            <button @onclick="() => ChangeNewsIndex(-1)" class="nav-link justify-content-center text-active-gray-800">
+                                <i class="bx bx-md bx-left-arrow"></i>
+                            </button>
+                        </li>
+                        <li class="nav-item">
+                            <button @onclick="() => ChangeNewsIndex(1)" class="nav-link justify-content-center text-active-gray-800">
+                                <i class="bx bx-md bx-right-arrow"></i>
+                            </button>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+            <div class="card-body">
+                @{
+                    var html = (MarkupString)Markdown.ToHtml(currentEntry.Markdown);
+                }
+
+                @(html)
+            </div>
+        </div>
+    </div>
+}
+
 <div class="row mb-5">
     <div class="col-12 col-lg-6 col-xl">
         <a class="mt-4 card" href="/servers">
@@ -193,11 +241,14 @@
 {
     [CascadingParameter]
     public User User { get; set; }
-    
+
     private int ServerCount = 0;
     private int DomainCount = 0;
     private int WebsiteCount = 0;
 
+    private List<NewsEntry> NewsEntries;
+    private int CurrentNewsIndex = 0;
+
     private Task Load(LazyLoader lazyLoader)
     {
         ServerCount = ServerRepository
@@ -214,7 +265,15 @@
             .Get()
             .Include(x => x.Owner)
             .Count(x => x.Owner.Id == User.Id);
-        
+
+        NewsEntries = NewsEntryRepository.Get().ToList();
+
         return Task.CompletedTask;
     }
+
+    private async Task ChangeNewsIndex(int i)
+    {
+        CurrentNewsIndex += i;
+        await InvokeAsync(StateHasChanged);
+    }
 }

+ 0 - 89
Moonlight/Shared/Views/News.razor

@@ -1,89 +0,0 @@
-@page "/news"
-@using Moonlight.App.Repositories
-@using Moonlight.App.Database.Entities
-@using Markdig
-@using Moonlight.App.Services
-@using Moonlight.App.Services.Interop
-@using Moonlight.Shared.Components.News
-
-@inject NewsEntryRepository NewsEntryRepository
-@inject SmartTranslateService SmartTranslateService
-@inject NavigationManager NavigationManager
-@inject AlertService AlertService
-
-<OnlyAdmin Silent="true">
-    <NewsEditor @ref="NewPostEditor" Model="NewPost" Save="DoSaveNewPost"></NewsEditor>
-</OnlyAdmin>
-
-<LazyLoader Load="Load">
-    @foreach (var entry in Entries)
-    {
-        <div class="card mb-6">
-            <div class="card-header">
-                <h3 class="card-title">@entry.Title</h3>
-                <div class="card-toolbar">
-                    <OnlyAdmin>
-                        <a href="/news/edit/@entry.Id">
-                            <button class="btn btn-sm btn-light me-4">
-                                <TL>Edit</TL>
-                            </button>
-                        </a>
-                        
-                        <WButton CssClasses="btn btn-sm btn-light me-4" 
-                                 Text="@SmartTranslateService.Translate("Delete")"
-                                 WorkingText="@SmartTranslateService.Translate("Deleting...")"
-                                 OnClick="() => Delete(entry)"></WButton>
-                    </OnlyAdmin>
-                    
-                    @{
-                        string dateInt(int i) => i.ToString().Length < 2 ? "0" + i : i.ToString();
-                    }
-                    <span class="text-gray-600 fw-semibold">@dateInt(entry.Date.Day).@dateInt(entry.Date.Month).@entry.Date.Year</span>
-                </div>
-            </div>
-            <div class="card-body">
-                @{
-                    var html = (MarkupString)Markdown.ToHtml(entry.Markdown);
-                }
-                
-                @html
-            </div>
-        </div>
-
-    }
-</LazyLoader>
-
-@code {
-    private NewsEntry NewPost = new();
-    private NewsEditor NewPostEditor;
-    
-    private NewsEntry[] Entries;
-
-    private async Task Load(LazyLoader loader)
-    {
-        Entries = NewsEntryRepository.Get().OrderByDescending(x => x.Date).ToArray();
-    }
-
-    private async Task DoSaveNewPost(NewsEntry post)
-    {
-        NewsEntryRepository.Add(post);
-        
-        NavigationManager.NavigateTo(NavigationManager.Uri, true);
-    }
-
-    private async Task Delete(NewsEntry entry)
-    {
-        var confirm = await AlertService.YesNo(
-            SmartTranslateService.Translate("Delete post"),  
-            SmartTranslateService.Translate("Do you really want to delete the post \"") + entry.Title + "\"?", 
-            SmartTranslateService.Translate("Yes"),
-            SmartTranslateService.Translate("No")
-        );
-        
-        if(!confirm) return;
-        
-        NewsEntryRepository.Delete(entry);
-        
-        NavigationManager.NavigateTo(NavigationManager.Uri, true);
-    }
-}

+ 2 - 0
Moonlight/resources/lang/de_de.lang

@@ -563,3 +563,5 @@ You have no websites;You have no websites
 We were not able to find any websites associated with your account;We were not able to find any websites associated with your account
 Guest;Guest
 You need a domain;You need a domain
+New post;New post
+New entry;New entry