Install script, static assets, UI and release workflow updates

- install.sh: default dirs, --update/--service/--uninstall/--purge, in-dir dnsmasq-webui symlink, ContentRootPath note
- UseStaticFiles instead of MapStaticAssets (fix 0-byte assets)
- Program: ContentRootPath when not Development for symlink/CWD
- App.razor: direct asset paths
- Dnsmasq page: remove redundant status pre, margin above Reload button
- Sidebar: logo 64px via app.css, hamburger vertically centered, toggler inside top-row
- ApplicationTitle documented in README
- publish/release: RIDs, Docker build for glibc
This commit is contained in:
2026-02-05 02:00:36 +10:00
parent 4ff9c552eb
commit 2f049feed2
13 changed files with 228 additions and 63 deletions
+4 -5
View File
@@ -6,11 +6,10 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/" />
<link rel="stylesheet" href="@Assets["lib/bootstrap/dist/css/bootstrap.min.css"]" />
<link rel="stylesheet" href="@Assets["lib/bootstrap-icons/bootstrap-icons.min.css"]" />
<link rel="stylesheet" href="@Assets["app.css"]" />
<link rel="stylesheet" href="@Assets["DnsmasqWebUI.styles.css"]" />
<ImportMap />
<link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="lib/bootstrap-icons/bootstrap-icons.min.css" />
<link rel="stylesheet" href="app.css" />
<link rel="stylesheet" href="DnsmasqWebUI.styles.css" />
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16.png" />
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32.png" />
<link rel="icon" type="image/png" sizes="48x48" href="favicon-48.png" />
@@ -4,14 +4,13 @@
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid d-flex align-items-center">
<a class="navbar-brand d-flex align-items-center gap-2" href="" aria-label="@AppTitle home">
<img src="logo.webp" alt="" class="brand-logo" />
<span class="brand-logo-wrap"><img src="logo.webp" alt="" class="brand-logo" /></span>
<span>@AppTitle</span>
</a>
</div>
<input type="checkbox" title="Navigation menu" class="navbar-toggler" id="nav-toggler" aria-label="Toggle navigation" />
</div>
<input type="checkbox" title="Navigation menu" class="navbar-toggler" id="nav-toggler" aria-label="Toggle navigation" />
<div class="nav-scrollable" onclick="document.getElementById('nav-toggler')?.click()">
<nav class="nav flex-column" aria-label="Main navigation">
<div class="nav-item px-3">
@@ -5,8 +5,9 @@
height: 2.5rem;
color: white;
position: absolute;
top: 0.5rem;
top: 50%;
right: 1rem;
transform: translateY(-50%);
border: 1px solid rgba(255, 255, 255, 0.1);
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
}
@@ -16,6 +17,7 @@
}
.top-row {
position: relative;
min-height: 3.5rem;
background-color: rgba(0,0,0,0.4);
}
@@ -31,13 +33,7 @@
color: white !important;
}
.brand-logo {
display: block;
flex-shrink: 0;
height: 1.75rem;
width: auto;
vertical-align: middle;
}
/* Logo size/alignment: see app.css .sidebar .navbar-brand .brand-logo-wrap / .brand-logo */
/* Bootstrap Icons in nav: white, sized to match link text */
.nav-item .nav-icon {
@@ -48,13 +48,9 @@ else if (_status != null)
</ul>
}
<EffectiveConfigSection Status="_status" />
@if (_status.DnsmasqStatus != "active" && (_status.StatusCommandStdout != null || _status.StatusCommandStderr != null))
{
<pre class="pre-block mt-2 mb-0" style="max-height: 12rem;">@(_status.StatusCommandStdout != null ? _status.StatusCommandStdout : "")@(_status.StatusCommandStdout != null && _status.StatusCommandStderr != null ? "\n" : "")@(_status.StatusCommandStderr ?? "")</pre>
}
@if (_status.ReloadCommandConfigured)
{
<div class="d-flex align-items-center gap-2 flex-wrap">
<div class="d-flex align-items-center gap-2 flex-wrap mt-3">
<button class="btn btn-primary btn-sm" @onclick="ReloadDnsmasq" disabled="@_reloading">
@if (_reloading)
{
+3
View File
@@ -4,6 +4,9 @@
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Avoid pre-compressed .br/.gz so MapStaticAssets serves uncompressed files (fixes 0-byte/empty response bug). -->
<DisableBuildCompression>true</DisableBuildCompression>
<PublishCompressionFormats></PublishCompressionFormats>
</PropertyGroup>
<ItemGroup>
+7 -2
View File
@@ -3,7 +3,11 @@ using DnsmasqWebUI.Extensions;
using DnsmasqWebUI.Configuration;
using Microsoft.Extensions.Options;
var builder = WebApplication.CreateBuilder(args);
// When not in Development, use the app's directory (not CWD) so static assets work when run via symlink or from any CWD.
var isDevelopment = string.Equals(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"), "Development", StringComparison.OrdinalIgnoreCase);
var builder = isDevelopment
? WebApplication.CreateBuilder(args)
: WebApplication.CreateBuilder(new WebApplicationOptions { ContentRootPath = AppContext.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), Args = args });
// ---- Application options (title, etc.) ----
builder.Services.AddOptions<ApplicationOptions>()
@@ -55,7 +59,8 @@ app.UseAntiforgery();
// ---- Endpoints ----
app.MapControllers();
app.MapStaticAssets();
// UseStaticFiles: MapStaticAssets returns 0-byte responses for fingerprinted assets (known bug). Serve from wwwroot directly.
app.UseStaticFiles();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
+18
View File
@@ -209,3 +209,21 @@ h1:focus {
.bi-gear-sm {
font-size: 1.125rem;
}
/* Sidebar brand logo – 64px, header stays 3.5rem min-height */
.sidebar .navbar-brand .brand-logo-wrap {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 4rem; /* 64px */
height: 4rem;
}
.sidebar .navbar-brand .brand-logo {
display: block;
height: 4rem;
width: auto;
object-fit: contain;
vertical-align: middle;
}