mirror of
https://github.com/alexhopeoconnor/dnsmasq-webui.git
synced 2026-10-04 04:18:13 +10:00
EffectiveConfig section CSS/panel updates; add ConfigFileList components
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
@namespace DnsmasqWebUI.Components.Dnsmasq
|
||||
@using DnsmasqWebUI.Models.Dnsmasq
|
||||
@using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig
|
||||
|
||||
<div class="config-file-list">
|
||||
@{
|
||||
var configFileList = Status.ConfigFiles?.Count > 0 ? Status.ConfigFiles : ConfigSet?.Files;
|
||||
var hasList = configFileList != null && configFileList.Count > 0;
|
||||
var mainEntry = hasList ? configFileList![0] : null;
|
||||
var hasMoreThanOne = hasList && configFileList!.Count > 1;
|
||||
var fileCount = hasList ? configFileList!.Count : 2;
|
||||
var showToggle = hasMoreThanOne || (!hasList && Status.ManagedFilePath != null);
|
||||
}
|
||||
<p class="config-file-list-title mb-0">Config files (load order)</p>
|
||||
<div class="config-file-list-content-row">
|
||||
<div class="config-file-list-list">
|
||||
<ul class="list-unstyled config-file-list-main">
|
||||
@if (hasList)
|
||||
{
|
||||
<ConfigFileListItem Entry="@mainEntry" Status="Status" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<li><strong>Main config:</strong> @(Status.MainConfigPath ?? "—") @(Status.MainConfigPathExists ? "✓" : "(missing)")</li>
|
||||
}
|
||||
</ul>
|
||||
@if (showToggle)
|
||||
{
|
||||
<div class="config-file-list-expandable @(_expanded ? "expanded" : null)">
|
||||
<div class="config-file-list-expandable-inner">
|
||||
<ul class="list-unstyled">
|
||||
@if (hasList)
|
||||
{
|
||||
@foreach (var f in configFileList!.Skip(1))
|
||||
{
|
||||
<ConfigFileListItem Entry="f" Status="Status" />
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<li><strong>Managed file:</strong> @(Status.ManagedFilePath ?? "—") @(Status.ManagedFilePathExists ? "✓" : "(not created yet)")</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@if (showToggle)
|
||||
{
|
||||
<button type="button"
|
||||
class="config-file-list-toggle"
|
||||
@onclick="ToggleExpanded"
|
||||
aria-expanded="@_expanded"
|
||||
aria-label="@(_expanded ? "Show only main config" : "Show all config files")">
|
||||
<i class="bi @(_expanded ? "bi-chevron-up" : "bi-chevron-down")" aria-hidden="true"></i>
|
||||
<span>@(_expanded ? "Show less" : $"Show all ({fileCount} files)")</span>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter, EditorRequired]
|
||||
public DnsmasqServiceStatus Status { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public DnsmasqConfigSet? ConfigSet { get; set; }
|
||||
|
||||
private bool _expanded;
|
||||
|
||||
private void ToggleExpanded() => _expanded = !_expanded;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/* Config file list: card-style block with expandable list */
|
||||
.config-file-list {
|
||||
--cfl-radius: var(--app-radius, 0.375rem);
|
||||
--cfl-spacing: var(--app-spacing-md, 1rem);
|
||||
--cfl-border: 1px solid #e9ecef;
|
||||
--cfl-bg: #f8f9fa;
|
||||
--cfl-bg-hover: #e9ecef;
|
||||
}
|
||||
|
||||
.config-file-list {
|
||||
border-radius: var(--cfl-radius);
|
||||
border: var(--cfl-border);
|
||||
background: var(--cfl-bg);
|
||||
padding: var(--cfl-spacing);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.config-file-list .config-file-list-title {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 600;
|
||||
color: #212529;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.config-file-list ul {
|
||||
margin: 0;
|
||||
padding-left: 1.25rem;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.6;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.config-file-list ul li {
|
||||
padding: 0.2rem 0;
|
||||
}
|
||||
|
||||
/* Content and toggle on one row: list grows, toggle at bottom-right */
|
||||
.config-file-list-content-row {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.config-file-list-list {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.config-file-list .config-file-list-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
flex-shrink: 0;
|
||||
padding: 0.35rem 0.5rem;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
color: #0d6efd;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: var(--cfl-radius);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease, color 0.15s ease;
|
||||
}
|
||||
|
||||
.config-file-list .config-file-list-toggle:hover {
|
||||
background: var(--cfl-bg-hover);
|
||||
color: #0a58ca;
|
||||
}
|
||||
|
||||
.config-file-list .config-file-list-toggle:focus-visible {
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
|
||||
.config-file-list .config-file-list-toggle .bi {
|
||||
font-size: 0.875rem;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
/* Expandable section: animate height with grid 0fr → 1fr */
|
||||
.config-file-list-expandable {
|
||||
display: grid;
|
||||
grid-template-rows: 0fr;
|
||||
transition: grid-template-rows 0.25s ease-out;
|
||||
}
|
||||
|
||||
.config-file-list-expandable.expanded {
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
|
||||
.config-file-list-expandable-inner {
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.config-file-list-expandable-inner ul {
|
||||
padding-top: 0.15rem;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
@namespace DnsmasqWebUI.Components.Dnsmasq
|
||||
@using DnsmasqWebUI.Models.Dnsmasq
|
||||
@using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig
|
||||
|
||||
<li>
|
||||
@if (Entry.IsManaged)
|
||||
{
|
||||
<StatusBadge Kind="StatusBadgeKind.Managed" Text="managed" Class="me-1" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<StatusBadge Kind="StatusBadgeKind.SourceMain" Text="@(Entry.Source.ToString().ToLowerInvariant())" Class="me-1" />
|
||||
}
|
||||
@Entry.Path
|
||||
@{
|
||||
var isMain = string.Equals(Entry.Path, Status.MainConfigPath, StringComparison.Ordinal);
|
||||
var isManaged = Entry.IsManaged;
|
||||
var exists = isMain ? Status.MainConfigPathExists : (isManaged ? Status.ManagedFilePathExists : (bool?)null);
|
||||
}
|
||||
@if (exists == true) { <text> ✓</text> }
|
||||
@if (exists == false) { <text> @(isManaged ? "(not created yet)" : "(missing)")</text> }
|
||||
</li>
|
||||
|
||||
@code {
|
||||
[Parameter, EditorRequired]
|
||||
public DnsmasqConfigSetEntry Entry { get; set; } = null!;
|
||||
|
||||
[Parameter, EditorRequired]
|
||||
public DnsmasqServiceStatus Status { get; set; } = null!;
|
||||
}
|
||||
+16
@@ -125,6 +125,22 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Animated expand/collapse: grid 0fr → 1fr */
|
||||
::deep .ec-section-collapse {
|
||||
display: grid;
|
||||
grid-template-rows: 0fr;
|
||||
transition: grid-template-rows 0.25s ease-out;
|
||||
}
|
||||
|
||||
::deep .ec-section-collapse-open {
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
|
||||
::deep .ec-section-collapse-inner {
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
::deep .ec-section-body {
|
||||
padding: 0.25rem 1rem 0.5rem 1rem;
|
||||
padding-left: 1rem;
|
||||
|
||||
+4
-2
@@ -8,8 +8,9 @@
|
||||
<span class="ec-section-title fw-bold">@Title</span>
|
||||
<i class="bi @(IsOpen ? "bi-chevron-down" : "bi-chevron-right") ec-section-chevron" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="collapse @(IsOpen ? "show" : "")">
|
||||
<div class="ec-section-body">
|
||||
<div class="ec-section-collapse @(IsOpen ? "ec-section-collapse-open" : "")">
|
||||
<div class="ec-section-collapse-inner">
|
||||
<div class="ec-section-body">
|
||||
<ul class="list-unstyled mb-0">
|
||||
@foreach (var f in Descriptors)
|
||||
{
|
||||
@@ -18,6 +19,7 @@
|
||||
IsEditMode="@IsEditMode" IsActive="@(ActiveFieldKey == fieldKey)" />
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user