Implemented simple image upload in ArticleEditor
This commit is contained in:
parent
06ce7e995c
commit
4dac73c564
|
@ -20,17 +20,6 @@
|
|||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="my-3 flex flex-wrap gap-4">
|
||||
@foreach (var image in Article.Images) {
|
||||
<figure>
|
||||
<img src="/images/@(image.Id)?size=400" width="400" alt="@image.ImageDescription"/>
|
||||
<figcaption>
|
||||
@image.ImageDescription
|
||||
</figcaption>
|
||||
</figure>
|
||||
}
|
||||
</div>
|
||||
|
||||
<EditForm method="post" FormName="article-editor" Model="@Model" OnValidSubmit="OnValidSubmit">
|
||||
<DataAnnotationsValidator/>
|
||||
<input type="hidden" @bind-value="@Model.Id"/>
|
||||
|
@ -154,7 +143,23 @@
|
|||
}
|
||||
</div>
|
||||
</EditForm>
|
||||
<CategoryPicker/>
|
||||
|
||||
<ImageModal Id="@ImageModal" ImageAdded="ImageAdded" />
|
||||
<div class="my-3 flex flex-wrap gap-4 min-h-24">
|
||||
@foreach (var image in Article.Images) {
|
||||
<figure class="p-2 bg-base-200">
|
||||
<img class="w-40" src="/images/@(image.Id)?size=400" width="400"
|
||||
title="@image.ImageDescription" alt="@image.ImageDescription"/>
|
||||
<figcaption>
|
||||
<button type="button" class="btn btn-info w-full mt-3"
|
||||
onclick="navigator.clipboard.writeText('![@image.ImageDescription](@(Navigation.ToAbsoluteUri("/images/" + image.Id))?size=400)')">
|
||||
@Localizer["Image_CopyLink"]
|
||||
</button>
|
||||
</figcaption>
|
||||
</figure>
|
||||
}
|
||||
<button type="button" class="btn" onclick="@(ImageModal).showModal()">@Localizer["Image_Add_Label"]</button>
|
||||
</div>
|
||||
|
||||
<SectionContent SectionName="scripts">
|
||||
<script>
|
||||
|
@ -199,6 +204,8 @@
|
|||
</SectionContent>
|
||||
|
||||
@code {
|
||||
private const string ImageModal = "AddImage";
|
||||
|
||||
[Parameter]
|
||||
public Guid? Id { get; set; }
|
||||
[Parameter]
|
||||
|
@ -282,6 +289,14 @@
|
|||
Model.Categories ??= [];
|
||||
context.Update(Article);
|
||||
|
||||
var existingImages = await context.Set<Article>().Where(a => a.Id == Article.Id)
|
||||
.SelectMany(a => a.Images).ToListAsync();
|
||||
foreach (var image in Article.Images) {
|
||||
context.Entry(image).State =
|
||||
existingImages.Any(i => i.Id == image.Id) ?
|
||||
EntityState.Modified : EntityState.Added;
|
||||
}
|
||||
|
||||
var relations = await context.Set<ArticleCategory>()
|
||||
.IgnoreQueryFilters().IgnoreAutoIncludes()
|
||||
.Where(ac => ac.Article == Article && !Model.Categories.Contains(ac.Category.Id))
|
||||
|
@ -335,6 +350,11 @@
|
|||
Model.Categories = selected?.Select(Guid.Parse).ToArray();
|
||||
}
|
||||
|
||||
private async Task ImageAdded(ArticleImage image) {
|
||||
Article.Images.Add(image);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private sealed class InputModel {
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
|
@ -346,5 +366,4 @@
|
|||
public Guid[]? Categories { get; set; }
|
||||
public DateTimeOffset? PublishDate { get; set; }
|
||||
}
|
||||
|
||||
}
|
69
Wave/Components/Pages/Partials/ImageModal.razor
Normal file
69
Wave/Components/Pages/Partials/ImageModal.razor
Normal file
|
@ -0,0 +1,69 @@
|
|||
@using Wave.Services
|
||||
@using Wave.Data
|
||||
|
||||
@inject ImageService Images
|
||||
@inject IStringLocalizer<ArticleEditor> Localizer
|
||||
|
||||
<ModalComponent Id="@Id" ShowCloseButton="false">
|
||||
<ChildContent>
|
||||
@if (Image != null) {
|
||||
<figure>
|
||||
<img src="/images/@(Image)" alt=""/>
|
||||
</figure>
|
||||
}
|
||||
<FileUploadComponent FileUploadedCallback="FileChanged"/>
|
||||
|
||||
<InputLabelComponent LabelText="@Localizer["Image_Description_Label"]">
|
||||
<InputText class="input input-bordered w-full" maxlength="2048"
|
||||
@bind-Value="@ImageDescription"
|
||||
placeholder="@Localizer["Image_Description_Placeholder"]"
|
||||
autocomplete="off" />
|
||||
</InputLabelComponent>
|
||||
</ChildContent>
|
||||
<Actions>
|
||||
<button class="btn btn-primary" @onclick="Save">@Localizer["Image_Add_Submit"]</button>
|
||||
<form method="dialog">
|
||||
<button type="submit" class="btn btn-error" @onclick="Cancel">@Localizer["Image_Add_Abort"]</button>
|
||||
</form>
|
||||
</Actions>
|
||||
</ModalComponent>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public required string Id { get; set; }
|
||||
[Parameter]
|
||||
public required EventCallback<ArticleImage> ImageAdded { get; set; }
|
||||
|
||||
private Guid? Image { get; set; }
|
||||
private string ImageDescription { get; set; } = string.Empty;
|
||||
|
||||
private async Task FileChanged(string tempPath) {
|
||||
if (Image is { } img) {
|
||||
Image = null;
|
||||
Images.Delete(img);
|
||||
}
|
||||
|
||||
Image = await Images.StoreImageAsync(tempPath);
|
||||
}
|
||||
|
||||
private async Task Save() {
|
||||
if (Image is null) return;
|
||||
|
||||
await ImageAdded.InvokeAsync(new ArticleImage {
|
||||
Id = Image.Value,
|
||||
ImageDescription = ImageDescription
|
||||
});
|
||||
|
||||
Image = null;
|
||||
ImageDescription = string.Empty;
|
||||
}
|
||||
|
||||
private void Cancel() {
|
||||
if (Image is { } img) {
|
||||
Image = null;
|
||||
Images.Delete(img);
|
||||
}
|
||||
ImageDescription = string.Empty;
|
||||
}
|
||||
|
||||
}
|
|
@ -191,4 +191,31 @@
|
|||
<data name="Tools_Mark_Tooltip" xml:space="preserve">
|
||||
<value>Den selektierten Text markieren</value>
|
||||
</data>
|
||||
<data name="Categories_Label" xml:space="preserve">
|
||||
<value>Kategorie</value>
|
||||
</data>
|
||||
<data name="Image_Add_Label" xml:space="preserve">
|
||||
<value>Bild Hochladen</value>
|
||||
</data>
|
||||
<data name="Image_Description_Label" xml:space="preserve">
|
||||
<value>Bildbeschreibung</value>
|
||||
</data>
|
||||
<data name="Image_Description_Placeholder" xml:space="preserve">
|
||||
<value>Ein Bild eines Käsekuchen</value>
|
||||
</data>
|
||||
<data name="Image_Add_Submit" xml:space="preserve">
|
||||
<value>Hinzufügen</value>
|
||||
</data>
|
||||
<data name="Image_Add_Abort" xml:space="preserve">
|
||||
<value>Schließen</value>
|
||||
</data>
|
||||
<data name="Save_Success" xml:space="preserve">
|
||||
<value>Artikel Gespeichert</value>
|
||||
</data>
|
||||
<data name="Save_Error" xml:space="preserve">
|
||||
<value>Unbekannter fehler beim speichern des Artikels</value>
|
||||
</data>
|
||||
<data name="Image_CopyLink" xml:space="preserve">
|
||||
<value>Link Kopieren</value>
|
||||
</data>
|
||||
</root>
|
|
@ -197,4 +197,31 @@
|
|||
<data name="Tools_Mark_Tooltip" xml:space="preserve">
|
||||
<value>Mark the selected text</value>
|
||||
</data>
|
||||
<data name="Categories_Label" xml:space="preserve">
|
||||
<value>Category</value>
|
||||
</data>
|
||||
<data name="Image_Add_Label" xml:space="preserve">
|
||||
<value>Upload Image</value>
|
||||
</data>
|
||||
<data name="Image_Description_Label" xml:space="preserve">
|
||||
<value>Image Description</value>
|
||||
</data>
|
||||
<data name="Image_Description_Placeholder" xml:space="preserve">
|
||||
<value>A picture of a cheesecake</value>
|
||||
</data>
|
||||
<data name="Image_Add_Submit" xml:space="preserve">
|
||||
<value>Add</value>
|
||||
</data>
|
||||
<data name="Image_Add_Abort" xml:space="preserve">
|
||||
<value>Close</value>
|
||||
</data>
|
||||
<data name="Save_Success" xml:space="preserve">
|
||||
<value>Article Saved</value>
|
||||
</data>
|
||||
<data name="Save_Error" xml:space="preserve">
|
||||
<value>Unknown error saving article</value>
|
||||
</data>
|
||||
<data name="Image_CopyLink" xml:space="preserve">
|
||||
<value>Copy Link</value>
|
||||
</data>
|
||||
</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