Implemented simple image upload in ArticleEditor
This commit is contained in:
parent
06ce7e995c
commit
4dac73c564
|
@ -20,17 +20,6 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</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">
|
<EditForm method="post" FormName="article-editor" Model="@Model" OnValidSubmit="OnValidSubmit">
|
||||||
<DataAnnotationsValidator/>
|
<DataAnnotationsValidator/>
|
||||||
<input type="hidden" @bind-value="@Model.Id"/>
|
<input type="hidden" @bind-value="@Model.Id"/>
|
||||||
|
@ -154,7 +143,23 @@
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</EditForm>
|
</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">
|
<SectionContent SectionName="scripts">
|
||||||
<script>
|
<script>
|
||||||
|
@ -199,6 +204,8 @@
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private const string ImageModal = "AddImage";
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Guid? Id { get; set; }
|
public Guid? Id { get; set; }
|
||||||
[Parameter]
|
[Parameter]
|
||||||
|
@ -281,6 +288,14 @@
|
||||||
|
|
||||||
Model.Categories ??= [];
|
Model.Categories ??= [];
|
||||||
context.Update(Article);
|
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>()
|
var relations = await context.Set<ArticleCategory>()
|
||||||
.IgnoreQueryFilters().IgnoreAutoIncludes()
|
.IgnoreQueryFilters().IgnoreAutoIncludes()
|
||||||
|
@ -335,6 +350,11 @@
|
||||||
Model.Categories = selected?.Select(Guid.Parse).ToArray();
|
Model.Categories = selected?.Select(Guid.Parse).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ImageAdded(ArticleImage image) {
|
||||||
|
Article.Images.Add(image);
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
private sealed class InputModel {
|
private sealed class InputModel {
|
||||||
public Guid? Id { get; set; }
|
public Guid? Id { get; set; }
|
||||||
|
|
||||||
|
@ -346,5 +366,4 @@
|
||||||
public Guid[]? Categories { get; set; }
|
public Guid[]? Categories { get; set; }
|
||||||
public DateTimeOffset? PublishDate { 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">
|
<data name="Tools_Mark_Tooltip" xml:space="preserve">
|
||||||
<value>Den selektierten Text markieren</value>
|
<value>Den selektierten Text markieren</value>
|
||||||
</data>
|
</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>
|
</root>
|
|
@ -197,4 +197,31 @@
|
||||||
<data name="Tools_Mark_Tooltip" xml:space="preserve">
|
<data name="Tools_Mark_Tooltip" xml:space="preserve">
|
||||||
<value>Mark the selected text</value>
|
<value>Mark the selected text</value>
|
||||||
</data>
|
</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>
|
</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