Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="top-row navbar">
<div class="top-row navbar">
<div class="container-fluid">
<div class="navbar__logo" aria-label="GeoBlazor Logo"></div>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
Expand All @@ -9,21 +9,52 @@
<hr>
<div id="nav-container" @ref="Navbar" class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<ul class="nav-list">
@foreach (PageLink page in FilteredPages)
@foreach (PageLink page in UngroupedPages)
{
string linkClass = $"nav-list-link{(page.Pro ? " pro" : "")}";
<li class="nav-list-item" @onclick="@(() => NavigateTo(page.Href))">
<NavLink class="@linkClass" href="@(page.Href)" @onclick:preventDefault="true" Match="NavLinkMatch.All">
@if (page.IconClass is not null)
{
<text><span class="oi @(page.IconClass)" aria-hidden="true"></span><span class="nav-item-title">@(page.Title)</span></text>
}
else
{
<text><span class="oi"><img src="_content/dymaptic.GeoBlazor.Core.Sample.Shared/images/@(page.ImageFile)" alt="@(page.Title)" /></span><span class="nav-item-title">@(page.Title)</span></text>
}
</NavLink>
<li class="nav-list-item nav-pinned" @onclick="@(() => NavigateTo(page.Href))">
@RenderNavLink(page)
</li>
}

@foreach (var (groupName, pages) in GroupedFilteredPages)
{
bool expanded = IsGroupExpanded(groupName);
<li class="nav-list-item nav-group @(expanded ? "active" : "")">
<button type="button" class="nav-list-expander" aria-expanded="@expanded" @onclick="@(() => ToggleGroup(groupName))" @onclick:stopPropagation="true">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true">
<path d="M6.22 3.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L9.94 8 6.22 4.28a.75.75 0 0 1 0-1.06Z" />
</svg>
<span class="nav-group-title">@groupName</span>
</button>
@if (expanded)
{
<ul class="nav-list nav-sublist">
@foreach (PageLink page in pages)
{
<li class="nav-list-item" @onclick="@(() => NavigateTo(page.Href))">
@RenderNavLink(page)
</li>
}
</ul>
}
</li>
}
</ul>
</div>
</div>

@{
RenderFragment RenderNavLink(PageLink page)
{
string linkClass = $"nav-list-link{(page.Pro ? " pro" : "")}";
return@<NavLink class="@linkClass" href="@(page.Href)" @onclick:preventDefault="true" Match="NavLinkMatch.All">
Comment thread
magmoe marked this conversation as resolved.
@if (page.IconClass is not null)
{
<text><span class="oi @(page.IconClass)" aria-hidden="true"></span><span class="nav-item-title">@(page.Title)</span></text>
}
else
{
<text><span class="oi"><img src="_content/dymaptic.GeoBlazor.Core.Sample.Shared/images/@(page.ImageFile)" alt="@(page.Title)" /></span><span class="nav-item-title">@(page.Title)</span></text>
}
</NavLink>;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -22,6 +38,31 @@ public partial class NavMenu
? Pages
: Pages.Where(p => p.Title.Contains(SearchText, StringComparison.OrdinalIgnoreCase));

protected IEnumerable<PageLink> UngroupedPages => FilteredPages.Where(p => p.Category is null);

protected IEnumerable<(string GroupName, IEnumerable<PageLink> Pages)> GroupedFilteredPages =>
GroupOrder
.Select(g => (GroupName: g, Pages: FilteredPages.Where(p => p.Category == g)))
.Where(g => g.Pages.Any());

protected HashSet<string> 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);
Expand All @@ -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();
}

Expand Down Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Comment thread
magmoe marked this conversation as resolved.
Expand All @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down
Loading