diff --git a/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/UniqueValueRenderers.razor.cs b/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/UniqueValueRenderers.razor.cs
index a21a830..ebd0251 100644
--- a/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/UniqueValueRenderers.razor.cs
+++ b/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/UniqueValueRenderers.razor.cs
@@ -60,7 +60,7 @@ public partial class UniqueValueRenderers
["proposed"] = new SimpleLineSymbol(new MapColor(192, 192, 192), 1.5, SimpleLineSymbolStyle.Dot)
};
private readonly UniqueValueRenderer _uniqueValueRenderer = new(uniqueValueInfos: roadTypes
- .Select(r => new UniqueValueInfo(r.Key.ToUpperFirstChar().Replace("_", " "), r.Value, r.Key))
+ .Select(r => new UniqueValueInfo(string.Concat(r.Key[0].ToString().ToUpper(), r.Key.AsSpan(1)).Replace("_", " "), r.Value, r.Key))
.ToArray(),
field: "highway", defaultLabel: "Service",
legendOptions: new UniqueValueRendererLegendOptions("Route Type"));
diff --git a/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor b/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor
index a667193..6e96495 100644
--- a/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor
+++ b/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor
@@ -1,4 +1,4 @@
-
+
+
+@{
+ RenderFragment RenderNavLink(PageLink page)
+ {
+ string linkClass = $"nav-list-link{(page.Pro ? " pro" : "")}";
+ return@
+ @if (page.IconClass is not null)
+ {
+ @(page.Title)
+ }
+ else
+ {
+
@(page.Title)
+ }
+ ;
+ }
+}
diff --git a/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor.cs b/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor.cs
index b9a85f5..0b2d65d 100644
--- a/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor.cs
+++ b/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor.cs
@@ -6,6 +6,22 @@ namespace dymaptic.GeoBlazor.Core.Sample.Shared.Shared;
public partial class NavMenu
{
+ // Category name constants
+ public static class Categories
+ {
+ public const string MapsAndScenes = "Maps & Scenes";
+ public const string Layers = "Layers";
+ public const string Visualization = "Visualization";
+ public const string Widgets = "Widgets";
+ public const string Queries = "Queries";
+ public const string Interaction = "Interaction";
+ public const string Location = "Location";
+ }
+
+ protected static readonly string[] GroupOrder =
+ [Categories.MapsAndScenes, Categories.Layers, Categories.Visualization,
+ Categories.Widgets, Categories.Queries, Categories.Interaction, Categories.Location];
+
[Inject]
public required IJSRuntime JsRuntime { get; set; }
[Inject]
@@ -22,6 +38,31 @@ public partial class NavMenu
? Pages
: Pages.Where(p => p.Title.Contains(SearchText, StringComparison.OrdinalIgnoreCase));
+ protected IEnumerable
UngroupedPages => FilteredPages.Where(p => p.Category is null);
+
+ protected IEnumerable<(string GroupName, IEnumerable Pages)> GroupedFilteredPages =>
+ GroupOrder
+ .Select(g => (GroupName: g, Pages: FilteredPages.Where(p => p.Category == g)))
+ .Where(g => g.Pages.Any());
+
+ protected HashSet ExpandedGroups { get; set; } = new();
+
+ protected void ToggleGroup(string groupName)
+ {
+ if (!ExpandedGroups.Add(groupName))
+ {
+ ExpandedGroups.Remove(groupName);
+ }
+ }
+
+ protected bool IsGroupExpanded(string groupName)
+ {
+ if (!string.IsNullOrWhiteSpace(SearchText))
+ return true;
+
+ return ExpandedGroups.Contains(groupName);
+ }
+
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
@@ -39,9 +80,16 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
if (currentPage != string.Empty)
{
+ string? group = Pages.FirstOrDefault(p => p.Href == currentPage)?.Category;
+
+ if (group is not null)
+ {
+ ExpandedGroups.Add(group);
+ }
+
await JsRuntime.InvokeVoidAsync("scrollToNav", currentPage);
}
-
+
StateHasChanged();
}
@@ -84,56 +132,65 @@ await InvokeAsync(async () =>
public virtual PageLink[] Pages =>
[
new("", "Home", "oi-home"),
- new("navigation", "Navigation", "oi-compass"),
- new("drawing", "Drawing", "oi-pencil"),
- new("click-to-add", "Click to Add Point", "oi-map-marker"),
- new("many-graphics", "Many Graphics", "oi-calculator"),
- new("scene", "Scene & Attributes", "oi-globe"),
- new("widgets", "Widgets", "oi-location"),
- new("basemaps", "Basemaps", "oi-map"),
- new("feature-layers", "Feature Layers", "oi-layers"),
- new("map-image-layers", "Map Image Layers", "oi-image"),
- new("labels", "Labels", "oi-text"),
- new("popups", "Popups", "oi-chat"),
- new("popup-actions", "Popup Actions", "oi-bullhorn"),
- new("bookmarks", "Bookmarks", "oi-bookmark"),
- new("vector-layer", "Vector Layer", "oi-arrow-right"),
- new("layer-lists", "Layer Lists", "oi-list"),
- new("basemap-layer-lists", "Basemap Layer Lists", "oi-spreadsheet"),
- new("csv-layer", "CSV Layers", "oi-grid-four-up"),
- new("kmllayers", "KML Layers", "oi-excerpt"),
- new("georss-layer", "GeoRSS Layer", "oi-rss"),
- new("osm-layer", "OpenStreetMaps Layer", null, "osm.webp"),
- new("wcslayers", "WCS Layers", "oi-project"),
- new("wfslayers", "WFS Layers", null, "wfs.svg"),
- new("wmslayers", "WMS Layers", null, "wms.svg"),
- new("wmtslayers", "WMTS Layers", null, "wmts.svg"),
- new("imagerylayer", "Imagery Layers", "oi-image"),
- new("imagery-tile-layer", "Imagery Tile Layers", null, "tile.webp"),
- new("web-map", "Web Map", "oi-browser"),
- new("web-scene", "Web Scene", "oi-box"),
- new("events", "Events", "oi-flash"),
- new("reactive-utils", "Reactive Utils", "oi-wrench"),
- new("hit-tests", "Hit Tests", "oi-star"),
- new("sql-query", "SQL Query", "oi-data-transfer-download"),
- new("sql-filter-query", "SQL Filter", "oi-arrow-thick-bottom"),
- new("server-side-queries", "Server-Side Queries", "oi-question-mark"),
- new("query-related-features", "Query Related Features", "oi-people"),
- new("query-top-features", "Query Top Features", "oi-arrow-thick-top"),
- new("place-selector", "Place Selector", "oi-arrow-bottom"),
- new("service-areas", "Service Areas", "oi-comment-square"),
- new("measurement-widgets", "Measurement Widgets", null, "ruler.svg"),
- new("calculate-geometries", "Calculate Geometries", "oi-clipboard"),
- new("projection", "Display Projection", "oi-sun"),
- new("projection-tool", "Projection Tool", "oi-cog"),
- new("basemap-projections", "Basemap Projections", "oi-bullhorn"),
- new("unique-value", "Unique Renderers", "oi-eyedropper"),
- new("marker-rotation", "Marker Rotation", "oi-loop-circular"),
- new("graphic-tracking", "Graphic Tracking", "oi-move"),
- new("geometry-methods", "Geometry Methods", "oi-task"),
- new("locator-methods", "Locator Methods", "oi-task"),
- new("search-multi-source", "Search Multiple Sources", "oi-magnifying-glass"),
- new("reverse-geolocator", "GeoLocator", "oi-arrow-circle-bottom")
+ new("navigation", "Navigation", "oi-compass", Category: Categories.MapsAndScenes),
+ new("scene", "Scene & Attributes", "oi-globe", Category: Categories.MapsAndScenes),
+ new("basemaps", "Basemaps", "oi-map", Category: Categories.MapsAndScenes),
+ new("web-map", "Web Map", "oi-browser", Category: Categories.MapsAndScenes),
+ new("web-scene", "Web Scene", "oi-box", Category: Categories.MapsAndScenes),
+
+ new("feature-layers", "Feature Layers", "oi-layers", Category: Categories.Layers),
+ new("map-image-layers", "Map Image Layers", "oi-image", Category: Categories.Layers),
+ new("vector-layer", "Vector Layer", "oi-arrow-right", Category: Categories.Layers),
+ new("csv-layer", "CSV Layers", "oi-grid-four-up", Category: Categories.Layers),
+ new("kmllayers", "KML Layers", "oi-excerpt", Category: Categories.Layers),
+ new("georss-layer", "GeoRSS Layer", "oi-rss", Category: Categories.Layers),
+ new("osm-layer", "OpenStreetMaps Layer", null, "osm.webp", Category: Categories.Layers),
+ new("wcslayers", "WCS Layers", "oi-project", Category: Categories.Layers),
+ new("wfslayers", "WFS Layers", null, "wfs.svg", Category: Categories.Layers),
+ new("wmslayers", "WMS Layers", null, "wms.svg", Category: Categories.Layers),
+ new("wmtslayers", "WMTS Layers", null, "wmts.svg", Category: Categories.Layers),
+ new("imagerylayer", "Imagery Layers", "oi-image", Category: Categories.Layers),
+ new("imagery-tile-layer", "Imagery Tile Layers", null, "tile.webp", Category: Categories.Layers),
+
+ new("labels", "Labels", "oi-text", Category: Categories.Visualization),
+ new("unique-value", "Unique Renderers", "oi-eyedropper", Category: Categories.Visualization),
+ new("marker-rotation", "Marker Rotation", "oi-loop-circular", Category: Categories.Visualization),
+
+ new("widgets", "Widgets", "oi-location", Category: Categories.Widgets),
+ new("popups", "Popups", "oi-chat", Category: Categories.Widgets),
+ new("popup-actions", "Popup Actions", "oi-bullhorn", Category: Categories.Widgets),
+ new("bookmarks", "Bookmarks", "oi-bookmark", Category: Categories.Widgets),
+ new("layer-lists", "Layer Lists", "oi-list", Category: Categories.Widgets),
+ new("basemap-layer-lists", "Basemap Layer Lists", "oi-spreadsheet", Category: Categories.Widgets),
+ new("measurement-widgets", "Measurement Widgets", null, "ruler.svg", Category: Categories.Widgets),
+ new("search-multi-source", "Search Multiple Sources", "oi-magnifying-glass", Category: Categories.Widgets),
+
+ new("sql-query", "SQL Query", "oi-data-transfer-download", Category: Categories.Queries),
+ new("sql-filter-query", "SQL Filter", "oi-arrow-thick-bottom", Category: Categories.Queries),
+ new("server-side-queries", "Server-Side Queries", "oi-question-mark", Category: Categories.Queries),
+ new("query-related-features", "Query Related Features", "oi-people", Category: Categories.Queries),
+ new("query-top-features", "Query Top Features", "oi-arrow-thick-top", Category: Categories.Queries),
+
+ new("drawing", "Drawing", "oi-pencil", Category: Categories.Interaction),
+ new("click-to-add", "Click to Add Point", "oi-map-marker", Category: Categories.Interaction),
+ new("many-graphics", "Many Graphics", "oi-calculator", Category: Categories.Interaction),
+ new("events", "Events", "oi-flash", Category: Categories.Interaction),
+ new("reactive-utils", "Reactive Utils", "oi-wrench", Category: Categories.Interaction),
+ new("hit-tests", "Hit Tests", "oi-star", Category: Categories.Interaction),
+ new("graphic-tracking", "Graphic Tracking", "oi-move", Category: Categories.Interaction),
+
+ new("place-selector", "Place Selector", "oi-arrow-bottom", Category: Categories.Location),
+ new("service-areas", "Service Areas", "oi-comment-square", Category: Categories.Location),
+ new("calculate-geometries", "Calculate Geometries", "oi-clipboard", Category: Categories.Location),
+ new("projection", "Display Projection", "oi-sun", Category: Categories.Location),
+ new("projection-tool", "Projection Tool", "oi-cog", Category: Categories.Location),
+ new("basemap-projections", "Basemap Projections", "oi-bullhorn", Category: Categories.Location),
+ new("geometry-methods", "Geometry Methods", "oi-task", Category: Categories.Location),
+ new("locator-methods", "Locator Methods", "oi-task", Category: Categories.Location),
+ new("reverse-geolocator", "GeoLocator", "oi-arrow-circle-bottom", Category: Categories.Location),
];
- public record PageLink(string Href, string Title, string? IconClass, string? ImageFile = null, bool Pro = false);
+
+ public record PageLink(
+ string Href, string Title, string? IconClass,
+ string? ImageFile = null, bool Pro = false, string? Category = null);
}
\ No newline at end of file
diff --git a/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/wwwroot/css/site.css b/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/wwwroot/css/site.css
index fd39ef2..92862da 100644
--- a/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/wwwroot/css/site.css
+++ b/samples/core/dymaptic.GeoBlazor.Core.Sample.Shared/wwwroot/css/site.css
@@ -770,8 +770,10 @@ a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: var(--geoblazor-accent-emphasis);
}
-.nav-list .nav-list-item:has(.nav-list-link.active) {
- background-color: var(--background-grey-3);
+.nav-list .nav-list-item:has(> .nav-list-link.active) {
+ background-color: var(--background-grey-1);
+ border-left: 3px solid transparent;
+ border-image: var(--geoblazor-gradient-vertical) 1;
}
.nav-list .nav-list-item .nav-list-link.active {
@@ -786,26 +788,92 @@ a:not([href]):not([class]), a:not([href]):not([class]):hover {
background-image: unset;
}
+/* Pinned top-level items (Home) */
+.nav-list .nav-list-item.nav-pinned {
+ padding: 0.5rem 0.75rem;
+ margin-bottom: 0.25rem;
+ border-bottom: 1px solid var(--background-grey-3);
+ border-radius: 0;
+ padding-bottom: 0.75rem;
+}
+
+/* Group headers */
+.nav-list .nav-list-item.nav-group {
+ padding: 0;
+ margin-bottom: 0.25rem;
+ margin-top: 0.25rem;
+ background-color: transparent;
+ border-radius: 0;
+ border-top: 1px solid var(--background-grey-3);
+}
+
+.nav-list .nav-pinned + .nav-group {
+ margin-top: 0.5rem;
+}
+
+.nav-list .nav-list-item.nav-group:hover {
+ background-color: transparent;
+}
+
.nav-list .nav-list-item .nav-list-expander {
- color: var(--geoblazor-secondary);
+ color: var(--text-emphasis);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ padding: 0.75rem;
+ user-select: none;
+ border-radius: var(--box-radius);
+ background: none;
+ border: none;
+ width: 100%;
+ font: inherit;
+ text-align: left;
}
.nav-list .nav-list-item .nav-list-expander:hover {
color: var(--geoblazor-secondary-hover);
+ background-color: var(--background-grey-1);
background-image: unset;
}
-.nav-list .nav-list-item > .nav-list .nav-list-item .nav-list-link {
- color: var(--text-emphasis);
- font-size: 1rem;
+.nav-group-title {
+ font-family: 'Aller', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+ font-size: 0.8rem;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
}
.nav-list .nav-list-item .nav-list-expander svg {
+ width: 12px;
+ height: 12px;
transform: rotate(0);
+ transition: transform 0.2s ease;
+ fill: var(--geoblazor-secondary);
+ flex-shrink: 0;
}
.nav-list .nav-list-item.active .nav-list-expander svg {
transform: rotate(90deg);
+ fill: var(--geoblazor-accent);
+}
+
+/* Nested sublist */
+.nav-list .nav-sublist {
+ padding-left: 1rem;
+ padding-right: 0;
+ margin-top: 0;
+ padding-bottom: 0.25rem;
+}
+
+.nav-list .nav-sublist .nav-list-item {
+ padding: 0.4rem 0.75rem;
+ margin-bottom: 0.125rem;
+}
+
+.nav-list .nav-list-item > .nav-list .nav-list-item .nav-list-link {
+ font-size: 0.9rem;
}
.side-bar a {
@@ -1019,8 +1087,10 @@ a:not([href]):not([class]), a:not([href]):not([class]):hover {
background-color: var(--background-grey-3);
}
- .nav-list .nav-list-item:has(.nav-list-link.active) {
- background-color: var(--background-grey-4);
+ .nav-list .nav-list-item:has(> .nav-list-link.active) {
+ background-color: var(--background-grey-3);
+ border-left: 3px solid transparent;
+ border-image: var(--geoblazor-gradient-vertical) 1;
}
.oi img:not(.pro .oi img) {
diff --git a/samples/pro/dymaptic.GeoBlazor.Pro.Sample.Shared/Shared/ProNavMenu.razor b/samples/pro/dymaptic.GeoBlazor.Pro.Sample.Shared/Shared/ProNavMenu.razor
index 46659e7..4bb51c9 100644
--- a/samples/pro/dymaptic.GeoBlazor.Pro.Sample.Shared/Shared/ProNavMenu.razor
+++ b/samples/pro/dymaptic.GeoBlazor.Pro.Sample.Shared/Shared/ProNavMenu.razor
@@ -38,22 +38,53 @@
-
\ No newline at end of file
+
+
+@{
+ RenderFragment RenderNavLink(PageLink page)
+ {
+ string linkClass = $"nav-list-link{(page.Pro ? " pro" : "")}";
+ return@
+ @if (page.IconClass is not null)
+ {
+ @(page.Title)
+ }
+ else
+ {
+
@(page.Title)
+ }
+ ;
+ }
+}
diff --git a/samples/pro/dymaptic.GeoBlazor.Pro.Sample.Shared/Shared/ProNavMenu.razor.cs b/samples/pro/dymaptic.GeoBlazor.Pro.Sample.Shared/Shared/ProNavMenu.razor.cs
index 478076e..d312bf9 100644
--- a/samples/pro/dymaptic.GeoBlazor.Pro.Sample.Shared/Shared/ProNavMenu.razor.cs
+++ b/samples/pro/dymaptic.GeoBlazor.Pro.Sample.Shared/Shared/ProNavMenu.razor.cs
@@ -17,35 +17,36 @@ public partial class ProNavMenu : NavMenu
href = $"pro-{href}";
}
- return new PageLink(href, p.Title, p.IconClass, p.ImageFile);
+ return p with { Href = href };
}),
- new("imagery-group-blend", "PRO: Imagery Blend", null, "blend.svg", true),
- new("sketch-query", "PRO: Sketch Query", "oi-location", null, true),
- new("edit-feature-data", "PRO: Edit Data", "oi-map-marker", null, true),
- new("popup-edit", "PRO: Popup Edit Data", "oi-pencil", null, true),
- new("update-feature-attributes", "PRO: Update Attributes", "oi-brush", null, true),
- new("apply-edits", "PRO: Apply Edits", "oi-check", null, true),
- new("spatial-relationships", "PRO Relationships", "oi-link-intact", null, true),
- new("demographic-data", "PRO: Demographics", "oi-people", null, true),
- new("length-and-area", "PRO: Length & Area", "oi-graph", null, true),
- new("swipe", "PRO: Swipe Widget", "oi-arrow-thick-left", null, true),
- new("time-slider", "PRO: Time Slider", "oi-vertical-align-center", null, true),
- new("search-custom-source", "PRO: Custom Search", "oi-magnifying-glass", null, true),
- new("clustering", "PRO: Clustering", "oi-fullscreen-exit", null, true),
- new("clustering-popups", "PRO: Clustering Popups", "oi-fullscreen-enter", null, true),
- new("cluster-pie-charts", "PRO: Pie Chart Clusters", "oi-pie-chart", null, true),
- new("binning", "PRO: Binning", "oi-grid-three-up", null, true),
- new("routes", "PRO: Routes", "oi-transfer", null, true),
- new("graphics-legend", "PRO: Graphics Legend", "oi-list-rich", null, true),
- new("group-layers", "PRO: Group Layers", null, "groupLayer.svg", true),
- new("ogc-feature-layers", "PRO: OGC Feature Layers", "oi-layers", null, true),
- new("wfsutils", "PRO: WFS Utils", "oi-wrench", null, true),
- new("print-widget", "PRO: Print Widgets", "oi-print", null, true),
- new("custom-popup-content", "PRO: Custom Popup Content", null, "customPopup.svg", true),
- new("geojson-styles", "PRO: GeoJSON Styles", "oi-brush", null, true),
- new("web-style-symbols", "PRO: Web Style Symbols", "oi-brush", null, true),
- new("highlight-features-by-geometry", "PRO: Highlight by Geometry", "oi-target", null, true)
+ new("imagery-group-blend", "PRO: Imagery Blend", null, "blend.svg", true, Categories.Layers),
+ new("sketch-query", "PRO: Sketch Query", "oi-location", null, true, Categories.Queries),
+ new("edit-feature-data", "PRO: Edit Data", "oi-map-marker", null, true, Categories.Interaction),
+ new("popup-edit", "PRO: Popup Edit Data", "oi-pencil", null, true, Categories.Widgets),
+ new("update-feature-attributes", "PRO: Update Attributes", "oi-brush", null, true, Categories.Interaction),
+ new("apply-edits", "PRO: Apply Edits", "oi-check", null, true, Categories.Interaction),
+ new("spatial-relationships", "PRO Relationships", "oi-link-intact", null, true, Categories.Queries),
+ new("demographic-data", "PRO: Demographics", "oi-people", null, true, Categories.Location),
+ new("length-and-area", "PRO: Length & Area", "oi-graph", null, true, Categories.Location),
+ new("swipe", "PRO: Swipe Widget", "oi-arrow-thick-left", null, true, Categories.Widgets),
+ new("time-slider", "PRO: Time Slider", "oi-vertical-align-center", null, true, Categories.Widgets),
+ new("search-custom-source", "PRO: Custom Search", "oi-magnifying-glass", null, true, Categories.Widgets),
+ new("clustering", "PRO: Clustering", "oi-fullscreen-exit", null, true, Categories.Visualization),
+ new("clustering-popups", "PRO: Clustering Popups", "oi-fullscreen-enter", null, true, Categories.Visualization),
+ new("cluster-pie-charts", "PRO: Pie Chart Clusters", "oi-pie-chart", null, true, Categories.Visualization),
+ new("binning", "PRO: Binning", "oi-grid-three-up", null, true, Categories.Visualization),
+ new("routes", "PRO: Routes", "oi-transfer", null, true, Categories.Location),
+ new("graphics-legend", "PRO: Graphics Legend", "oi-list-rich", null, true, Categories.Visualization),
+ new("group-layers", "PRO: Group Layers", null, "groupLayer.svg", true, Categories.Layers),
+ new("ogc-feature-layers", "PRO: OGC Feature Layers", "oi-layers", null, true, Categories.Layers),
+ new("wfsutils", "PRO: WFS Utils", "oi-wrench", null, true, Categories.Layers),
+ new("print-widget", "PRO: Print Widgets", "oi-print", null, true, Categories.Widgets),
+ new("custom-popup-content", "PRO: Custom Popup Content", null, "customPopup.svg", true, Categories.Widgets),
+ new("geojson-styles", "PRO: GeoJSON Styles", "oi-brush", null, true, Categories.Visualization),
+ new("web-style-symbols", "PRO: Web Style Symbols", "oi-brush", null, true, Categories.Visualization),
+ new("highlight-features-by-geometry", "PRO: Highlight by Geometry", "oi-target", null, true, Categories.Interaction)
];
+
protected override bool CollapseNavMenu { get; set; } = true;
private string LowerNavMenuCssClass => _lowerNavMenuOpen ? "" : "lower-collapse";