Skip to content
Merged
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
26 changes: 25 additions & 1 deletion docs-site/docs/reference/page-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,31 @@ matching entry in your `nav` configuration — a config `nav` title always wins
| `icon` | Navigation icon for the page (any bundled icon name, e.g. `material/key`). |
| `tags` | List of tags; collected by the [tags plugin](../plugins/tags.md). |
| `template` | Render the page with a different theme template. |
| `hide` | Awesome-pages style `hide: true` drops a folder/page from the nav. |
| `hide` | List of theme chrome to drop from the page — `toc`, `nav`, `path`. See below. |

## Hiding theme chrome

`hide` takes a list naming the parts of the page furniture to leave out:

```yaml
---
title: Support-Group ABAC Teams
hide:
- toc
---
```

| Value | Effect |
|---|---|
| `toc` | Drops the right-hand table-of-contents column, giving the content its full width. Useful for wide tables. |
| `nav` | Drops the left-hand navigation sidebar. |
| `path` | Drops the breadcrumb trail above the page title. |

A single value may be given without the list (`hide: toc`). Names are matched
case-insensitively, and unrecognised entries are ignored.

Not to be confused with `hide: true` in a directory's `.pages` file, which drops
that folder from the navigation entirely.

!!! note "Directory-wide defaults"
Repeating the same front matter on every page gets tedious. The
Expand Down
23 changes: 23 additions & 0 deletions src/Netdocs.Core/PageRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public static string Render(TemplateEngine engine, SiteContext site, Page page,
["base_url"] = BaseUrl(page.Url),
["is_homepage"] = string.IsNullOrEmpty(page.Url),
["features"] = new HashSet<string>(site.Config.Theme.Features, StringComparer.OrdinalIgnoreCase),
["hide"] = HiddenElements(page),
["highlight"] = site.Config.Theme.Highlight,
["extra"] = site.Config.Extra,
["stylesheets"] = ResolveHrefs(site.Config.ExtraCss, assets.Stylesheets),
Expand Down Expand Up @@ -108,6 +109,28 @@ public static string Render(TemplateEngine engine, SiteContext site, Page page,
private static string? FrontMatterText(Page page, string key) =>
page.FrontMatter.TryGetValue(key, out var v) && v is string s && s.Trim().Length > 0 ? s.Trim() : null;

/// <summary>Material's <c>hide:</c> front matter — the chrome a page opts out of
/// (<c>toc</c>, <c>nav</c>, <c>path</c>). Accepts a list or a single value.</summary>
internal static HashSet<string> HiddenElements(Page page)
{
var hidden = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (!page.FrontMatter.TryGetValue("hide", out var value)) return hidden;

if (value is string single)
{
hidden.Add(single.Trim());
}
else if (value is IEnumerable<object?> items)
{
foreach (var item in items)
{
if (item?.ToString()?.Trim() is { Length: > 0 } name) hidden.Add(name);
}
}

return hidden;
}

/// <summary>
/// Social meta tags must carry absolute URLs to be usable by crawlers, so a site-relative path
/// is prefixed with <c>site_url</c>. Already-absolute values are passed through untouched.
Expand Down
6 changes: 5 additions & 1 deletion src/Netdocs.Theme.Material/templates/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
{{~ end ~}}
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
{{~ if !(hide | array.contains "nav") ~}}
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
Expand All @@ -124,7 +125,8 @@
</div>
</div>
</div>
{{~ if !toc_integrate ~}}
{{~ end ~}}
{{~ if !toc_integrate && !(hide | array.contains "toc") ~}}
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
Expand All @@ -134,7 +136,9 @@
</div>
{{~ end ~}}
<div class="md-content" data-md-component="content">
{{~ if !(hide | array.contains "path") ~}}
{{ include "partials/breadcrumbs.html" }}
{{~ end ~}}
<article class="md-content__inner md-typeset">
{{ include "partials/content-actions.html" }}
{{~ if page.meta.is_post && page.meta.post_tags && (array.size page.meta.post_tags) > 0 ~}}
Expand Down
55 changes: 55 additions & 0 deletions tests/Netdocs.Core.Tests/HiddenElementsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using Netdocs.Abstractions;
using Xunit;

namespace Netdocs.Core.Tests;

/// <summary>
/// Covers Material's <c>hide:</c> front matter, which lets a page opt out of theme chrome
/// (<c>toc</c>, <c>nav</c>, <c>path</c>). Wide auto-generated tables use it to reclaim the
/// horizontal space the table-of-contents column would otherwise take.
/// </summary>
public class HiddenElementsTests
{
private static Page PageWith(object? hide)
{
var meta = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
if (hide is not null) meta["hide"] = hide;

return new Page
{
SourcePath = "x.md",
RelativePath = "x.md",
FrontMatter = meta,
};
}

[Fact]
public void NoFrontMatterHidesNothing()
{
Assert.Empty(PageRenderer.HiddenElements(PageWith(null)));
}

[Fact]
public void ListValuesAreCollected()
{
var hidden = PageRenderer.HiddenElements(PageWith(new List<object?> { "toc", "nav" }));

Assert.Contains("toc", hidden);
Assert.Contains("nav", hidden);
Assert.DoesNotContain("path", hidden);
}

[Fact]
public void SingleScalarValueIsAccepted()
{
Assert.Contains("toc", PageRenderer.HiddenElements(PageWith("toc")));
}

[Fact]
public void MatchingIsCaseInsensitiveAndTrimmed()
{
var hidden = PageRenderer.HiddenElements(PageWith(new List<object?> { " TOC " }));

Assert.Contains("toc", hidden);
}
}