New: Working RTE and Card Style View on the index Page

This commit is contained in:
2026-02-24 10:58:53 +01:00
parent 59eb99ab23
commit f633708b57
3 changed files with 172 additions and 80 deletions

View File

@@ -8,9 +8,9 @@
@inject IBlackBoardService BlackBoardService
@inject NavigationManager NavigationManager
@inject IStringLocalizer<Edit> Localizer
@inject IReportUI ReportingComponent // TODO
@inject IReportUI ReportingComponent
<form @ref="form" class="@(validated ? " was-validated" : "needs-validation" )" novalidate>
<form @ref="form" class="@(validated ? " was-validated" : "needs-validation")" novalidate>
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="name" HelpText="Enter a name" ResourceKey="Name">Name: </Label>
@@ -19,14 +19,14 @@
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="description" HelpText="Enter a description" ResourceKey="Description">Beschreibung: </Label>
<Label Class="col-sm-3" For="image" HelpText="Enter a description" ResourceKey="Description">Beschreibung: </Label>
<div class="col-sm-9">
<FileManager AnonymizeUploadFilenames="true" UploadMultiple="false" ShowSuccess="true" FileId="@_blackBoard.ImageID" OnSelectFile="@OnFileSelected"/>
<FileManager AnonymizeUploadFilenames="true" id="image" UploadMultiple="false" ShowSuccess="true" FileId="@_blackBoard.ImageID" OnSelectFile="@OnFileSelected"/>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="" For="description" HelpText="Enter a description" ResourceKey="Description">Beschreibung: </Label>
<RichTextEditor @ref="RichTextEditorHtml" @Content="@_blackBoard.Name" Placeholder="Enter a description: "/>
<RichTextEditor @ref="RichTextEditorHtml" Content="@_blackBoard.Description" id="description" Placeholder="Enter a description: "/>
</div>
</div>
<button type="button" class="btn btn-success" @onclick="Save">@Localizer["Save"]</button>
@@ -40,7 +40,7 @@
<br/><br/>
@if (PageState.Action == "Edit")
{
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
<AuditInfo CreatedBy="@_blackBoard.CreatedBy" CreatedOn="@_blackBoard.CreatedOn" ModifiedBy="@_blackBoard.ModifiedBy" ModifiedOn="@_blackBoard.ModifiedOn"></AuditInfo>
}
</form>
@@ -53,20 +53,13 @@
public override string Title => "Manage BlackBoard";
public override List<Resource> Resources => new List<Resource>()
{
new Stylesheet("_content/SZUAbsolventenverein.Module.BlackBoard/Module.css")
};
public override List<Resource> Resources => [new Stylesheet("_content/SZUAbsolventenverein.Module.BlackBoard/Module.css")];
private RichTextEditor RichTextEditorHtml;
private ElementReference form;
private bool validated = false;
private bool validated;
private int _id;
private string _createdby;
private DateTime _createdon;
private string _modifiedby;
private DateTime _modifiedon;
// TODO
private BlackBoard _blackBoard = new BlackBoard();
@@ -82,13 +75,8 @@
_blackBoard = await BlackBoardService.GetBlackBoardAsync(_id, ModuleState.ModuleId);
if (_blackBoard != null)
{
_createdby = _blackBoard.CreatedBy;
_createdon = _blackBoard.CreatedOn;
_modifiedby = _blackBoard.ModifiedBy;
_modifiedon = _blackBoard.ModifiedOn;
_parameters = ReportingComponent.ConstructParameterList(_blackBoard, RenderModeBoundary);
}
_parameters = ReportingComponent.ConstructParameterList(_blackBoard, RenderModeBoundary);
}
}
catch (Exception ex)
@@ -113,6 +101,7 @@
var interop = new Oqtane.UI.Interop(JSRuntime);
if (await interop.FormValid(form))
{
_blackBoard.Description = await RichTextEditorHtml.GetHtml();
if (PageState.Action == "Add")
{
_blackBoard.ModuleId = ModuleState.ModuleId;
@@ -138,4 +127,5 @@
AddModuleMessage(Localizer["Message.SaveError"], MessageType.Error);
}
}
}

View File

@@ -4,76 +4,100 @@
@namespace SZUAbsolventenverein.Module.BlackBoard
@inherits ModuleBase
@inject IBlackBoardService BlackBoardService
@inject NavigationManager NavigationManager
@inject IStringLocalizer<Index> Localizer
@if (_BlackBoards == null)
@if (_blackBoards == null)
{
<p><em>Loading...</em></p>
<p>
<em>Loading...</em>
</p>
}
else
{
<ActionLink Action="Add" Security="SecurityAccessLevel.Edit" Text="Add BlackBoard" ResourceKey="Add" />
<br />
<br />
@if (@_BlackBoards.Count != 0)
{
<Pager Items="@_BlackBoards">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@Localizer["Name"]</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.BlackBoardId.ToString())" ResourceKey="Edit" /></td>
<td><ActionDialog Header="Delete BlackBoard" Message="Are You Sure You Wish To Delete This BlackBoard?" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" ResourceKey="Delete" Id="@context.BlackBoardId.ToString()" /></td>
<td>@context.Name</td>
</Row>
</Pager>
}
else
{
<p>@Localizer["Message.DisplayNone"]</p>
}
<ActionLink Action="Add" Security="SecurityAccessLevel.Edit" Text="Add BlackBoard" ResourceKey="Add"/>
<br/>
<br/>
@if (_blackBoards.Count != 0)
{
<div class="bb-card-grid">
@foreach (var item in _blackBoards)
{
<div class="bb-card">
@if (item.ImageID > 0)
{
<img class="bb-card-img" src="@ImageUrl(item.ImageID, 600, 400)" alt="@item.Name"/>
}
else
{
<div class="bb-card-img-placeholder">
<span>📋</span>
</div>
}
<div class="bb-card-body">
<h5>@item.Name</h5>
@if (!string.IsNullOrWhiteSpace(item.Description))
{
<div class="bb-card-desc">@((MarkupString)item.Description)</div>
}
</div>
<div class="bb-card-meta">
<AuditInfo CreatedBy="@item.CreatedBy" CreatedOn="@item.CreatedOn" ModifiedBy="@item.ModifiedBy" ModifiedOn="@item.ModifiedOn"/>
</div>
<div class="bb-card-footer">
<ActionLink Action="Edit" Parameters="@("id=" + item.BlackBoardId.ToString())" ResourceKey="Edit"/>
<ActionDialog Header="Delete BlackBoard" Message="Are You Sure You Wish To Delete This BlackBoard?" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" ConfirmClass="absolute" OnClick="@(async () => await Delete(item))" ResourceKey="Delete" Id="@item.BlackBoardId.ToString()"/>
</div>
</div>
}
</div>
}
else
{
<p>@Localizer["Message.DisplayNone"]</p>
}
}
@code {
public override string RenderMode => RenderModes.Static;
public override string RenderMode => RenderModes.Static;
public override List<Resource> Resources => new List<Resource>()
public override List<Resource> Resources =>
[
new Stylesheet("_content/SZUAbsolventenverein.Module.BlackBoard/Module.css"),
new Script("_content/SZUAbsolventenverein.Module.BlackBoard/Module.js")
];
List<BlackBoard> _blackBoards;
protected override async Task OnInitializedAsync()
{
try
{
new Stylesheet("_content/SZUAbsolventenverein.Module.BlackBoard/Module.css"),
new Script("_content/SZUAbsolventenverein.Module.BlackBoard/Module.js")
};
List<BlackBoard> _BlackBoards;
protected override async Task OnInitializedAsync()
{
try
{
_BlackBoards = await BlackBoardService.GetBlackBoardsAsync(ModuleState.ModuleId);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading BlackBoard {Error}", ex.Message);
AddModuleMessage(Localizer["Message.LoadError"], MessageType.Error);
}
_blackBoards = await BlackBoardService.GetBlackBoardsAsync(ModuleState.ModuleId);
}
private async Task Delete(BlackBoard BlackBoard)
catch (Exception ex)
{
try
{
await BlackBoardService.DeleteBlackBoardAsync(BlackBoard.BlackBoardId, ModuleState.ModuleId);
await logger.LogInformation("BlackBoard Deleted {BlackBoard}", BlackBoard);
_BlackBoards = await BlackBoardService.GetBlackBoardsAsync(ModuleState.ModuleId);
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting BlackBoard {BlackBoard} {Error}", BlackBoard, ex.Message);
AddModuleMessage(Localizer["Message.DeleteError"], MessageType.Error);
}
await logger.LogError(ex, "Error Loading BlackBoard {Error}", ex.Message);
AddModuleMessage(Localizer["Message.LoadError"], MessageType.Error);
}
}
private async Task Delete(BlackBoard blackBoard)
{
try
{
await BlackBoardService.DeleteBlackBoardAsync(blackBoard.BlackBoardId, ModuleState.ModuleId);
await logger.LogInformation("BlackBoard Deleted {BlackBoard}", blackBoard);
_blackBoards = await BlackBoardService.GetBlackBoardsAsync(ModuleState.ModuleId);
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting BlackBoard {BlackBoard} {Error}", blackBoard, ex.Message);
AddModuleMessage(Localizer["Message.DeleteError"], MessageType.Error);
}
}
}

View File

@@ -1 +1,79 @@
/* Module Custom Styles */
/* Module Custom Styles */
/* ── Blackboard Card Grid ── */
.bb-card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 1.5rem;
}
.bb-card {
display: flex;
flex-direction: column;
border: 1px solid #dee2e6;
border-radius: 0.75rem;
overflow: hidden;
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition:
box-shadow 0.2s ease,
transform 0.2s ease;
}
.bb-card:hover {
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
transform: translateY(-2px);
}
.bb-card-img {
width: 100%;
height: 200px;
object-fit: cover;
}
.bb-card-img-placeholder {
width: 100%;
height: 200px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
color: #adb5bd;
font-size: 2.5rem;
}
.bb-card-body {
padding: 1.25rem;
flex: 1 1 auto;
}
.bb-card-body h5 {
margin: 0 0 0.5rem;
font-size: 1.15rem;
font-weight: 600;
color: #212529;
}
.bb-card-desc {
font-size: 0.9rem;
color: #495057;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
line-height: 1.5;
}
.bb-card-meta {
padding: 0 1.25rem 0.75rem;
font-size: 0.8rem;
color: #6c757d;
}
.bb-card-footer {
display: flex;
gap: 0.5rem;
padding: 0.75rem 1.25rem;
border-top: 1px solid #e9ecef;
background: #f8f9fa;
}