diff --git a/src/BirthList.Web/Components/Pages/RegistryAdmin.razor.cs b/src/BirthList.Web/Components/Pages/RegistryAdmin.razor.cs
index fa7cea4..d46679f 100644
--- a/src/BirthList.Web/Components/Pages/RegistryAdmin.razor.cs
+++ b/src/BirthList.Web/Components/Pages/RegistryAdmin.razor.cs
@@ -5,6 +5,7 @@ using BirthList.Web.Services;
using Blazored.TextEditor;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;
@@ -55,6 +56,7 @@ public partial class RegistryAdmin : ComponentBase
protected string? InviteLink { get; private set; }
protected BlazoredTextEditor? TextEditor { get; set; }
protected string ActiveTab { get; set; } = "items";
+ protected string? HeroImageUploadMessage { get; set; }
protected RenderFragment ToolbarContent => builder =>
{
builder.AddMarkupContent(0, @"
");
@@ -805,4 +807,48 @@ public partial class RegistryAdmin : ComponentBase
return false;
}
}
+
+ protected async Task OnHeroImageSelectedAsync(InputFileChangeEventArgs e)
+ {
+ HeroImageUploadMessage = null;
+
+ try
+ {
+ const long maxFileSize = 10 * 1024 * 1024; // 10 MB
+ var file = e.File;
+
+ if (file.Size > maxFileSize)
+ {
+ HeroImageUploadMessage = $"File size exceeds maximum of 10 MB";
+ return;
+ }
+
+ if (!file.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
+ {
+ HeroImageUploadMessage = "Only image files are allowed";
+ return;
+ }
+
+ using var memoryStream = new MemoryStream();
+ await file.OpenReadStream(maxFileSize).CopyToAsync(memoryStream).ConfigureAwait(false);
+
+ SettingsModel.HeroImageBase64 = Convert.ToBase64String(memoryStream.ToArray());
+ SettingsModel.HeroImageContentType = file.ContentType;
+
+ HeroImageUploadMessage = "Image uploaded successfully. Click 'Save Settings' to apply.";
+ }
+ catch (Exception ex)
+ {
+ HeroImageUploadMessage = $"Error uploading image: {ex.Message}";
+ }
+ }
+
+ protected Task RemoveHeroImageAsync()
+ {
+ SettingsModel.HeroImageBase64 = string.Empty;
+ SettingsModel.HeroImageContentType = null;
+ HeroImageUploadMessage = "Image will be removed when you save settings.";
+ return Task.CompletedTask;
+ }
}
+
diff --git a/src/BirthList.Web/Components/Pages/RegistryPublic.razor b/src/BirthList.Web/Components/Pages/RegistryPublic.razor
index 608e076..0c45bea 100644
--- a/src/BirthList.Web/Components/Pages/RegistryPublic.razor
+++ b/src/BirthList.Web/Components/Pages/RegistryPublic.razor
@@ -12,6 +12,13 @@
else
{
+ @if (!string.IsNullOrWhiteSpace(Registry.HeroImageBase64))
+ {
+
+

+
+ }
+
@(string.IsNullOrWhiteSpace(Registry.BabyName) ? Registry.Title : Registry.BabyName)
@if (!string.IsNullOrWhiteSpace(Registry.HeaderContentHtml))
diff --git a/src/BirthList.Web/Components/Pages/RegistryPublic.razor.css b/src/BirthList.Web/Components/Pages/RegistryPublic.razor.css
index 0a91bd5..10153a3 100644
--- a/src/BirthList.Web/Components/Pages/RegistryPublic.razor.css
+++ b/src/BirthList.Web/Components/Pages/RegistryPublic.razor.css
@@ -4,6 +4,20 @@
gap: 1rem;
}
+.hero-image-container {
+ margin: 0 -1rem;
+ max-height: 400px;
+ overflow: hidden;
+ border-radius: 8px;
+}
+
+.hero-image {
+ object-fit: cover;
+ object-position: center;
+ max-height: 400px;
+ border-radius: 8px;
+}
+
.item-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
diff --git a/src/BirthList.Web/Features/Registries/RegistryModels.cs b/src/BirthList.Web/Features/Registries/RegistryModels.cs
index 73daa0e..e4c7254 100644
--- a/src/BirthList.Web/Features/Registries/RegistryModels.cs
+++ b/src/BirthList.Web/Features/Registries/RegistryModels.cs
@@ -53,6 +53,8 @@ public sealed class RegistrySettingsEditModel
{
public string? BabyName { get; set; }
public DateOnly? BirthDate { get; set; }
+ public string? HeroImageBase64 { get; set; }
+ public string? HeroImageContentType { get; set; }
public string? HeaderContentHtml { get; set; }
public string? ShippingAddress { get; set; }
public string CurrencyCode { get; set; } = "€";
@@ -80,6 +82,8 @@ public sealed class RegistryPublicViewModel
public string Title { get; init; } = string.Empty;
public string PublicLinkCode { get; init; } = string.Empty;
public string? BabyName { get; init; }
+ public string? HeroImageBase64 { get; init; }
+ public string? HeroImageContentType { get; init; }
public string? HeaderContentHtml { get; init; }
public string? ShippingAddress { get; init; }
public string CurrencyCode { get; init; } = "€";
diff --git a/src/BirthList.Web/Features/Registries/RegistryService.cs b/src/BirthList.Web/Features/Registries/RegistryService.cs
index bc4d043..5a93929 100644
--- a/src/BirthList.Web/Features/Registries/RegistryService.cs
+++ b/src/BirthList.Web/Features/Registries/RegistryService.cs
@@ -299,6 +299,8 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli
Title = registry.Title,
PublicLinkCode = registry.PublicLinkCode,
BabyName = registry.BabyName,
+ HeroImageBase64 = registry.HeroImageData != null ? Convert.ToBase64String(registry.HeroImageData) : null,
+ HeroImageContentType = registry.HeroImageContentType,
HeaderContentHtml = registry.HeaderContentHtml,
ShippingAddress = registry.ShippingAddress,
CurrencyCode = registry.CurrencyCode,
@@ -336,6 +338,8 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli
{
BabyName = registry.BabyName,
BirthDate = registry.BirthDate,
+ HeroImageBase64 = registry.HeroImageData != null ? Convert.ToBase64String(registry.HeroImageData) : null,
+ HeroImageContentType = registry.HeroImageContentType,
HeaderContentHtml = registry.HeaderContentHtml,
ShippingAddress = registry.ShippingAddress,
CurrencyCode = registry.CurrencyCode,
@@ -372,6 +376,18 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli
registry.BabyName = string.IsNullOrWhiteSpace(model.BabyName) ? null : model.BabyName.Trim();
registry.BirthDate = model.BirthDate;
+
+ if (!string.IsNullOrWhiteSpace(model.HeroImageBase64))
+ {
+ registry.HeroImageData = Convert.FromBase64String(model.HeroImageBase64);
+ registry.HeroImageContentType = model.HeroImageContentType;
+ }
+ else if (string.IsNullOrWhiteSpace(model.HeroImageBase64) && model.HeroImageBase64 == string.Empty)
+ {
+ registry.HeroImageData = null;
+ registry.HeroImageContentType = null;
+ }
+
registry.HeaderContentHtml = string.IsNullOrWhiteSpace(model.HeaderContentHtml) ? null : model.HeaderContentHtml;
registry.ShippingAddress = string.IsNullOrWhiteSpace(model.ShippingAddress) ? null : model.ShippingAddress.Trim();
registry.CurrencyCode = NormalizeCurrencySymbol(model.CurrencyCode);
diff --git a/src/BirthList.Web/Resources/SharedResources.fr-FR.resx b/src/BirthList.Web/Resources/SharedResources.fr-FR.resx
index 7ec44a5..46041ef 100644
--- a/src/BirthList.Web/Resources/SharedResources.fr-FR.resx
+++ b/src/BirthList.Web/Resources/SharedResources.fr-FR.resx
@@ -175,6 +175,10 @@
Moderne
Adresse de livraison
Les sauts de ligne seront conservés
+
Image héros
+
Télécharger une image
+
Supprimer l'image héros
+
Image héros actuelle
Contenu d'en-tête
Texte d'accueil
Paramètres du compte bancaire
diff --git a/src/BirthList.Web/Resources/SharedResources.nl-BE.resx b/src/BirthList.Web/Resources/SharedResources.nl-BE.resx
index 06d39c0..61ce07c 100644
--- a/src/BirthList.Web/Resources/SharedResources.nl-BE.resx
+++ b/src/BirthList.Web/Resources/SharedResources.nl-BE.resx
@@ -175,6 +175,10 @@
Modern
Leveringsadres
Regeleinden blijven behouden
+
Hero-afbeelding
+
Afbeelding uploaden
+
Hero-afbeelding verwijderen
+
Huidige hero-afbeelding
Bovenste inhoud
Welkomsttekst
Bankrekeninginstellingen
diff --git a/src/BirthList.Web/Resources/SharedResources.qps-Ploc.resx b/src/BirthList.Web/Resources/SharedResources.qps-Ploc.resx
index 2f7d222..7b733e6 100644
--- a/src/BirthList.Web/Resources/SharedResources.qps-Ploc.resx
+++ b/src/BirthList.Web/Resources/SharedResources.qps-Ploc.resx
@@ -501,6 +501,18 @@
[[Line breaks will be preserved]]
+
+ [[Hero image]]
+
+
+ [[Upload image]]
+
+
+ [[Remove hero image]]
+
+
+ [[Current hero image]]
+
[[Top content]]
diff --git a/src/BirthList.Web/Resources/SharedResources.resx b/src/BirthList.Web/Resources/SharedResources.resx
index 8408099..e3d78de 100644
--- a/src/BirthList.Web/Resources/SharedResources.resx
+++ b/src/BirthList.Web/Resources/SharedResources.resx
@@ -182,6 +182,10 @@
Modern
Shipping address
Line breaks will be preserved
+
Hero image
+
Upload image
+
Remove hero image
+
Current hero image
Top content
Welcome text
Bank Account Settings