Improved Article editor Category picker
This commit is contained in:
parent
df8399bca3
commit
4a265f30b7
|
@ -3,7 +3,7 @@
|
||||||
@using System.ComponentModel
|
@using System.ComponentModel
|
||||||
@using System.ComponentModel.DataAnnotations
|
@using System.ComponentModel.DataAnnotations
|
||||||
|
|
||||||
<label class="form-control w-full">
|
<label class="form-control w-full" @attributes="AdditionalAttributes">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
@if (Label is not null) {
|
@if (Label is not null) {
|
||||||
@Label
|
@Label
|
||||||
|
@ -32,6 +32,8 @@
|
||||||
public required RenderFragment ChildContent { get; set; }
|
public required RenderFragment ChildContent { get; set; }
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Expression<Func<object?>>? For { get; set; }
|
public Expression<Func<object?>>? For { get; set; }
|
||||||
|
[Parameter(CaptureUnmatchedValues = true)]
|
||||||
|
public Dictionary<string, object>? AdditionalAttributes { get; set; }
|
||||||
|
|
||||||
private string GetDisplayName() {
|
private string GetDisplayName() {
|
||||||
if (For is null) return string.Empty;
|
if (For is null) return string.Empty;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
@using System.Diagnostics.CodeAnalysis
|
@using System.Diagnostics.CodeAnalysis
|
||||||
@using System.Net
|
@using System.Net
|
||||||
@using System.Security.Claims
|
@using System.Security.Claims
|
||||||
|
@using Humanizer
|
||||||
@using Microsoft.AspNetCore.Identity
|
@using Microsoft.AspNetCore.Identity
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using Wave.Services
|
@using Wave.Services
|
||||||
|
@ -34,6 +35,18 @@
|
||||||
@bind-Value="@Model.Title" placeholder="@Localizer["Title_Placeholder"]" autocomplete="off"/>
|
@bind-Value="@Model.Title" placeholder="@Localizer["Title_Placeholder"]" autocomplete="off"/>
|
||||||
</InputLabelComponent>
|
</InputLabelComponent>
|
||||||
|
|
||||||
|
<InputLabelComponent class="row-span-3" LabelText="@Localizer["Categories_Label"]" For="() => Model.Categories">
|
||||||
|
<InputSelect class="select select-bordered w-full" @bind-Value="@Model.Categories" multiple size="10">
|
||||||
|
@foreach (var group in Categories.GroupBy(c => c.Color)) {
|
||||||
|
<optgroup class="font-bold not-italic my-3" label="@group.Key.Humanize()">
|
||||||
|
@foreach (var category in group) {
|
||||||
|
<option value="@category.Id" selected="@Model.Categories?.Contains(category.Id)">@category.Name</option>
|
||||||
|
}
|
||||||
|
</optgroup>
|
||||||
|
}
|
||||||
|
</InputSelect>
|
||||||
|
</InputLabelComponent>
|
||||||
|
|
||||||
<InputLabelComponent LabelText="@Localizer["Slug_Label"]" For="() => Model.Slug">
|
<InputLabelComponent LabelText="@Localizer["Slug_Label"]" For="() => Model.Slug">
|
||||||
@if (Article.Status is not ArticleStatus.Published || Article.PublishDate >= DateTimeOffset.UtcNow) {
|
@if (Article.Status is not ArticleStatus.Published || Article.PublishDate >= DateTimeOffset.UtcNow) {
|
||||||
<InputText class="input input-bordered w-full" maxlength="64"
|
<InputText class="input input-bordered w-full" maxlength="64"
|
||||||
|
@ -53,13 +66,6 @@
|
||||||
type="datetime-local" readonly value="@Article.PublishDate.ToString("yyyy-MM-dd\\THH:mm:ss")"/>
|
type="datetime-local" readonly value="@Article.PublishDate.ToString("yyyy-MM-dd\\THH:mm:ss")"/>
|
||||||
}
|
}
|
||||||
</InputLabelComponent>
|
</InputLabelComponent>
|
||||||
<InputLabelComponent LabelText="@Localizer["Categories_Label"]" For="() => Model.Categories">
|
|
||||||
<select class="select select-bordered w-full h-32" @onchange="CategorySelectionChanged" multiple>
|
|
||||||
@foreach (var category in Categories) {
|
|
||||||
<option value="@category.Id" selected="@Model.Categories?.Contains(category.Id)">@category.Name</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</InputLabelComponent>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<AdvancedMarkdownEditor Title="@Model.Title" MarkdownCallback="() => Model.Body">
|
<AdvancedMarkdownEditor Title="@Model.Title" MarkdownCallback="() => Model.Body">
|
||||||
|
@ -156,7 +162,9 @@
|
||||||
Model.Slug ??= article.Slug;
|
Model.Slug ??= article.Slug;
|
||||||
Model.Body ??= article.Body;
|
Model.Body ??= article.Body;
|
||||||
Model.PublishDate ??= article.PublishDate.LocalDateTime;
|
Model.PublishDate ??= article.PublishDate.LocalDateTime;
|
||||||
Model.Categories ??= article.Categories.Select(c => c.Id).ToArray();
|
if (Model.Categories?.Length < 1) {
|
||||||
|
Model.Categories = article.Categories.Select(c => c.Id).ToArray();
|
||||||
|
}
|
||||||
Article = article;
|
Article = article;
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
}
|
}
|
||||||
|
@ -210,7 +218,6 @@
|
||||||
await context.Set<ArticleCategory>().IgnoreQueryFilters().IgnoreAutoIncludes()
|
await context.Set<ArticleCategory>().IgnoreQueryFilters().IgnoreAutoIncludes()
|
||||||
.Where(ac => ac.Article.Id == Article.Id).LoadAsync();
|
.Where(ac => ac.Article.Id == Article.Id).LoadAsync();
|
||||||
|
|
||||||
Model.Categories ??= [];
|
|
||||||
context.Update(Article);
|
context.Update(Article);
|
||||||
|
|
||||||
var existingImages = await context.Set<Article>()
|
var existingImages = await context.Set<Article>()
|
||||||
|
@ -281,11 +288,6 @@
|
||||||
throw new ApplicationException("You do not have permissions to edit this article");
|
throw new ApplicationException("You do not have permissions to edit this article");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CategorySelectionChanged(ChangeEventArgs args) {
|
|
||||||
string[]? selected = (string[]?) args.Value;
|
|
||||||
Model.Categories = selected?.Select(Guid.Parse).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ImageAdded(ArticleImage image) {
|
private async Task ImageAdded(ArticleImage image) {
|
||||||
Article.Images.Add(image);
|
Article.Images.Add(image);
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
|
@ -306,7 +308,7 @@
|
||||||
[Required(AllowEmptyStrings = false)]
|
[Required(AllowEmptyStrings = false)]
|
||||||
public string? Body { get; set; }
|
public string? Body { get; set; }
|
||||||
|
|
||||||
public Guid[]? Categories { get; set; }
|
public Guid[]? Categories { get; set; } = [];
|
||||||
public DateTimeOffset? PublishDate { get; set; }
|
public DateTimeOffset? PublishDate { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,4 +167,10 @@
|
||||||
<data name="Image_CopyLink" xml:space="preserve">
|
<data name="Image_CopyLink" xml:space="preserve">
|
||||||
<value>Link Kopieren</value>
|
<value>Link Kopieren</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Slug_Label" xml:space="preserve">
|
||||||
|
<value>Artikel URL (autogeneriert)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Slug_Placeholder" xml:space="preserve">
|
||||||
|
<value>mein-neues-kaesekuchenrezept</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -167,4 +167,10 @@
|
||||||
<data name="Image_CopyLink" xml:space="preserve">
|
<data name="Image_CopyLink" xml:space="preserve">
|
||||||
<value>Copy Link</value>
|
<value>Copy Link</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Slug_Label" xml:space="preserve">
|
||||||
|
<value>Article Url Part (autogenerated)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Slug_Placeholder" xml:space="preserve">
|
||||||
|
<value>my-new-cheese-cake-recipe</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
2
Wave/wwwroot/css/main.min.css
vendored
2
Wave/wwwroot/css/main.min.css
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue