Changed Added image fields for Characters and Story Assets in models, view models, repositories, services, and save flows. Added reusable avatar/initials rendering via [AvatarHelper.cs](C:/Source/PlotLine/PlotLine/Services/AvatarHelper.cs) and [_Avatar.cshtml](C:/Source/PlotLine/PlotLine/Views/Shared/_Avatar.cshtml). Added upload/remove processing through existing upload storage in [VisualIdentityImageService.cs](C:/Source/PlotLine/PlotLine/Services/VisualIdentityImageService.cs). Updated Character and Story Asset list/detail/edit views with thumbnails, initials fallback, upload, replace, and remove controls. Added styling in [site.css](C:/Source/PlotLine/PlotLine/wwwroot/css/site.css) and refreshed site.min.css. Database Added new migration [079_VisualIdentityCharacterAssetImages.sql](C:/Source/PlotLine/PlotLine/Sql/079_VisualIdentityCharacterAssetImages.sql). Adds nullable ImagePath and ThumbnailPath to Characters and StoryAssets. Applied locally and confirmed the columns exist. Stored Procedures Updated active procedure definitions only: Character_ListByProject Character_Get Character_Save Character_UpdateImage StoryAsset_ListByProject StoryAsset_Get StoryAsset_Save StoryAsset_UpdateImage
104 lines
5.1 KiB
Plaintext
104 lines
5.1 KiB
Plaintext
@model StoryAssetEditViewModel
|
|
@{
|
|
ViewData["Title"] = Model.StoryAssetID == 0 ? "New Story Asset" : "Edit Story Asset";
|
|
}
|
|
|
|
<div class="page-heading compact">
|
|
<div>
|
|
<p class="eyebrow">Story asset</p>
|
|
<h1>@ViewData["Title"] <help-icon key="storyAssets.edit" /></h1>
|
|
</div>
|
|
</div>
|
|
|
|
@if (TempData["ImageError"] is string imageError)
|
|
{
|
|
<div class="alert alert-warning">@imageError</div>
|
|
}
|
|
|
|
<form asp-action="Save" method="post" class="edit-panel" enctype="multipart/form-data">
|
|
<input asp-for="StoryAssetID" type="hidden" />
|
|
<input asp-for="ProjectID" type="hidden" />
|
|
<input asp-for="ImagePath" type="hidden" />
|
|
<input asp-for="ThumbnailPath" type="hidden" />
|
|
|
|
<div class="row g-3">
|
|
<div class="col-md-8">
|
|
<label asp-for="AssetName" class="form-label"></label>
|
|
<input asp-for="AssetName" class="form-control" />
|
|
<span asp-validation-for="AssetName" class="text-danger"></span>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label asp-for="AssetKindID" class="form-label">Kind <help-icon key="storyAssets.fields.kind" mode="inline" /></label>
|
|
<select asp-for="AssetKindID" asp-items="Model.AssetKindOptions" class="form-select"></select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="metric-slider">
|
|
<div class="metric-slider-label">
|
|
<label asp-for="Importance">Importance <help-icon key="storyAssets.fields.importance" mode="inline" /></label>
|
|
<output>@Model.Importance</output>
|
|
</div>
|
|
<input asp-for="Importance" type="range" class="form-range" min="1" max="10" oninput="this.previousElementSibling.querySelector('output').value = this.value" />
|
|
</div>
|
|
<span asp-validation-for="Importance" class="text-danger"></span>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label asp-for="CurrentStateID" class="form-label">Current state <help-icon key="storyAssets.fields.currentState" mode="inline" /></label>
|
|
<select asp-for="CurrentStateID" asp-items="Model.AssetStateOptions" class="form-select">
|
|
<option value="">No state</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label asp-for="CurrentLocationID" class="form-label">Current location <help-icon key="storyAssets.fields.currentLocation" mode="inline" /></label>
|
|
<select asp-for="CurrentLocationID" asp-items="Model.LocationOptions" class="form-select">
|
|
<option value="">No location</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-check story-asset-checkbox-field">
|
|
<input asp-for="IsResolved" class="form-check-input" />
|
|
<label asp-for="IsResolved" class="form-check-label">Resolved <help-icon key="storyAssets.fields.resolved" mode="inline" /></label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-check story-asset-checkbox-field">
|
|
<input asp-for="ShowInQuickAddBar" class="form-check-input" />
|
|
<label asp-for="ShowInQuickAddBar" class="form-check-label">Show in Quick Add Bar <help-icon key="storyAssets.fields.quickAdd" mode="inline" /></label>
|
|
<div class="form-text">Makes this item available as a draggable shortcut on the Timeline page.</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<label asp-for="Description" class="form-label"></label>
|
|
<textarea asp-for="Description" class="form-control" rows="5"></textarea>
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="visual-image-editor">
|
|
<div>
|
|
<p class="eyebrow">Asset Image</p>
|
|
<partial name="_Avatar" model="@(new AvatarViewModel { DisplayName = Model.AssetName, ImagePath = Model.ImagePath, ThumbnailPath = Model.ThumbnailPath, Size = "lg", Lazy = false })" />
|
|
</div>
|
|
<div class="visual-image-editor__controls">
|
|
<label asp-for="ImageUpload" class="form-label"></label>
|
|
<input asp-for="ImageUpload" class="form-control" type="file" accept=".jpg,.jpeg,.png,.webp,image/jpeg,image/png,image/webp" />
|
|
<div class="form-text">JPG, PNG or WebP. A 128 x 128 thumbnail is generated automatically.</div>
|
|
@if (!string.IsNullOrWhiteSpace(Model.ImagePath) || !string.IsNullOrWhiteSpace(Model.ThumbnailPath))
|
|
{
|
|
<label class="form-check mt-2">
|
|
<input asp-for="RemoveImage" class="form-check-input" />
|
|
<span class="form-check-label">Remove image</span>
|
|
</label>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="button-row mt-3">
|
|
<button class="btn btn-primary" type="submit">Save asset</button>
|
|
<a class="btn btn-outline-secondary" asp-action="Index" asp-route-projectId="@Model.ProjectID">Cancel</a>
|
|
</div>
|
|
</form>
|
|
|
|
@section Scripts {
|
|
<partial name="_ValidationScriptsPartial" />
|
|
}
|