SF-74: Server — CustomImagesController (GET /api/CustomImages), DI registration, appsettings logo config, App.razor
This commit is contained in:
@@ -10,15 +10,58 @@
|
|||||||
<link rel="stylesheet" href="css/envelope-viewer.css" />
|
<link rel="stylesheet" href="css/envelope-viewer.css" />
|
||||||
<link rel="stylesheet" href="EnvelopeGenerator.Server.styles.css" />
|
<link rel="stylesheet" href="EnvelopeGenerator.Server.styles.css" />
|
||||||
<HeadOutlet />
|
<HeadOutlet />
|
||||||
|
<!-- Apply saved theme immediately on page load — before WASM boots.
|
||||||
|
Reads localStorage["signflow.theme"] to avoid flash of default theme. -->
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var allowed = { 'blazing-dark': true, 'blazing-berry': true, 'purple': true };
|
||||||
|
var theme = localStorage.getItem('signflow.theme');
|
||||||
|
if (!theme || !allowed[theme]) theme = 'blazing-berry';
|
||||||
|
var bsTheme = theme === 'blazing-dark' ? 'dark' : 'light';
|
||||||
|
document.documentElement.setAttribute('data-sf-theme', theme);
|
||||||
|
document.documentElement.setAttribute('data-bs-theme', bsTheme);
|
||||||
|
var link = document.createElement('link');
|
||||||
|
link.id = 'dx-theme-link';
|
||||||
|
link.rel = 'stylesheet';
|
||||||
|
link.href = '_content/DevExpress.Blazor.Themes/' + theme + '.bs5.min.css';
|
||||||
|
document.head.appendChild(link);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<!-- WASM boot loading overlay — hidden once Blazor circuit connects -->
|
||||||
|
<div id="sf-boot-overlay">
|
||||||
|
<div class="sf-boot-spinner">
|
||||||
|
<div class="sf-boot-ring"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Routes />
|
<Routes />
|
||||||
<script src="_content/DevExpress.Blazor.Resources/js/preload-script.js"></script>
|
<script src="_content/DevExpress.Blazor.Resources/js/preload-script.js"></script>
|
||||||
<script src="js/typed.umd.js"></script>
|
<script src="js/typed.umd.js"></script>
|
||||||
<script src="js/receiver-signature.js?v=9"></script>
|
<script src="js/receiver-signature.js?v=9"></script>
|
||||||
<script src="js/signflow-theme.js"></script>
|
<script src="js/signflow-theme.js"></script>
|
||||||
<script src="_framework/blazor.web.js"></script>
|
<script src="_framework/blazor.web.js"></script>
|
||||||
|
<script>
|
||||||
|
// Remove the boot overlay once Blazor has started and enhanced navigation is active.
|
||||||
|
Blazor.addEventListener('enhancedload', function onFirstLoad() {
|
||||||
|
var overlay = document.getElementById('sf-boot-overlay');
|
||||||
|
if (overlay) overlay.style.opacity = '0';
|
||||||
|
setTimeout(function () { if (overlay) overlay.remove(); }, 250);
|
||||||
|
Blazor.removeEventListener('enhancedload', onFirstLoad);
|
||||||
|
});
|
||||||
|
// Also remove when WASM circuit is ready (for non-enhanced pages like /sender)
|
||||||
|
document.addEventListener('blazor-circuit-connected', function () {
|
||||||
|
var overlay = document.getElementById('sf-boot-overlay');
|
||||||
|
if (overlay) { overlay.style.opacity = '0'; setTimeout(function () { if (overlay) overlay.remove(); }, 250); }
|
||||||
|
}, { once: true });
|
||||||
|
// Fallback: remove after 4s regardless
|
||||||
|
setTimeout(function () {
|
||||||
|
var overlay = document.getElementById('sf-boot-overlay');
|
||||||
|
if (overlay) overlay.remove();
|
||||||
|
}, 4000);
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
|
using EnvelopeGenerator.Server.Models;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Server.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exposes the CustomImages configuration (signFLOW logo + company logo) to WASM clients.
|
||||||
|
/// Values are sourced from appsettings.json "CustomImages" section via Options Pattern.
|
||||||
|
///
|
||||||
|
/// To change logos per deployment: update "CustomImages.App.Src", "App.Height",
|
||||||
|
/// "Company.Src", "Company.Height" in appsettings.json — no code change required.
|
||||||
|
/// </summary>
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[Authorize(Policy = AuthPolicy.SenderOrReceiver)]
|
||||||
|
public class CustomImagesController(IOptions<CustomImagesOptions> options) : ControllerBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the signFLOW app logo and company logo configuration.
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet]
|
||||||
|
public ActionResult<CustomImagesOptions> Get() => Ok(options.Value);
|
||||||
|
}
|
||||||
@@ -326,12 +326,17 @@ try
|
|||||||
// User Preferences (theme, dark mode, grid layouts — stored in TBDD_CACHE)
|
// User Preferences (theme, dark mode, grid layouts — stored in TBDD_CACHE)
|
||||||
// Registration handled by Infrastructure DependencyInjection (AddEnvelopeGeneratorInfrastructureServices)
|
// Registration handled by Infrastructure DependencyInjection (AddEnvelopeGeneratorInfrastructureServices)
|
||||||
|
|
||||||
|
// CustomImages — logo sources and heights, configurable per deployment via appsettings.json
|
||||||
|
builder.Services.Configure<EnvelopeGenerator.Server.Models.CustomImagesOptions>(
|
||||||
|
config.GetSection(EnvelopeGenerator.Server.Models.CustomImagesOptions.SectionName));
|
||||||
|
|
||||||
// Client-side services that MainLayout depends on must also be registered here
|
// Client-side services that MainLayout depends on must also be registered here
|
||||||
// so that Blazor Auto prerender (SSR pass) can resolve them on the server.
|
// so that Blazor Auto prerender (SSR pass) can resolve them on the server.
|
||||||
// ThemeService.InitializeAsync() uses IJSRuntime but is only called in OnAfterRenderAsync
|
// ThemeService.InitializeAsync() uses IJSRuntime but is only called in OnAfterRenderAsync
|
||||||
// (never during prerender), so registering it server-side is safe.
|
// (never during prerender), so registering it server-side is safe.
|
||||||
builder.Services.AddScoped<EnvelopeGenerator.Server.Client.Services.UserPreferencesService>();
|
builder.Services.AddScoped<EnvelopeGenerator.Server.Client.Services.UserPreferencesService>();
|
||||||
builder.Services.AddScoped<EnvelopeGenerator.Server.Client.Services.ThemeService>();
|
builder.Services.AddScoped<EnvelopeGenerator.Server.Client.Services.ThemeService>();
|
||||||
|
builder.Services.AddScoped<EnvelopeGenerator.Server.Client.Services.CustomImagesService>();
|
||||||
|
|
||||||
// Business Services (Server specific)
|
// Business Services (Server specific)
|
||||||
builder.Services.AddScoped<DocumentService>();
|
builder.Services.AddScoped<DocumentService>();
|
||||||
|
|||||||
@@ -145,15 +145,17 @@
|
|||||||
"CustomImages": {
|
"CustomImages": {
|
||||||
"App": {
|
"App": {
|
||||||
"Src": "/img/DD_signFLOW_LOGO.png",
|
"Src": "/img/DD_signFLOW_LOGO.png",
|
||||||
|
"Height": "28px",
|
||||||
"Classes": {
|
"Classes": {
|
||||||
"Main": "signFlow-logo"
|
"Main": "signflow-app-logo"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Company": {
|
"Company": {
|
||||||
"Src": "/img/digital_data.svg",
|
"Src": "/img/digital_data.svg",
|
||||||
|
"Height": "33px",
|
||||||
"Classes": {
|
"Classes": {
|
||||||
"Show": "dd-show-logo",
|
"Show": "signflow-company-logo",
|
||||||
"Locked": "dd-locked-logo"
|
"Locked": "signflow-company-logo"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user