Skip to content

Commit 0e34817

Browse files
committed
update HTMX to fetch pages without navigation while maintaing the correct urls in history
1 parent 436f9e3 commit 0e34817

File tree

11 files changed

+99
-159
lines changed

11 files changed

+99
-159
lines changed

src/Elastic.Markdown/DocumentationGenerator.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,4 +255,11 @@ private async Task CopyFileFsAware(DocumentationFile file, IFileInfo outputFile,
255255
var pageHtml = await HtmlWriter.RenderPageHtml(markdown, ctx);
256256
return await HtmlWriter.RenderLayout(markdown, pageHtml, ctx);
257257
}
258+
259+
public async Task<string?> RenderPage(MarkdownFile markdown, Cancel ctx)
260+
{
261+
await DocumentationSet.Tree.Resolve(ctx);
262+
var pageHtml = await HtmlWriter.RenderPageHtml(markdown, ctx);
263+
return await HtmlWriter.RenderPage(markdown, pageHtml, ctx);
264+
}
258265
}

src/Elastic.Markdown/IO/MarkdownFile.cs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,31 @@ public string? NavigationTitle
7474
public string FilePath { get; }
7575
public string FileName { get; }
7676

77-
public string Url => Path.GetFileName(RelativePath) == "index.md"
78-
? $"{UrlPathPrefix}/{RelativePath.Remove(RelativePath.LastIndexOf("index.md", StringComparison.Ordinal), "index.md".Length)}"
79-
: $"{UrlPathPrefix}/{RelativePath.Remove(RelativePath.LastIndexOf(".md", StringComparison.Ordinal), 3)}";
77+
private string? _url;
78+
public string Url
79+
{
80+
get
81+
{
82+
if (_url is not null)
83+
return _url;
84+
_url = Path.GetFileName(RelativePath) == "index.md"
85+
? $"{UrlPathPrefix}/{RelativePath.Remove(RelativePath.LastIndexOf("index.md", StringComparison.Ordinal), "index.md".Length)}"
86+
: $"{UrlPathPrefix}/{RelativePath.Remove(RelativePath.LastIndexOf(".md", StringComparison.Ordinal), 3)}";
87+
return _url;
88+
}
89+
}
90+
91+
private string? _urlFetch;
92+
public string UrlFetch
93+
{
94+
get
95+
{
96+
if (_urlFetch is not null)
97+
return _urlFetch;
98+
_urlFetch = Url.TrimEnd('/') + "/index.main.html";
99+
return _urlFetch;
100+
}
101+
}
80102

81103
public int NavigationIndex { get; internal set; } = -1;
82104

src/Elastic.Markdown/Slices/HtmlWriter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ public async Task<string> RenderLayout(MarkdownFile markdown, string markdownHtm
4949
TitleRaw = markdown.TitleRaw ?? "[TITLE NOT SET]",
5050
MarkdownHtml = markdownHtml,
5151
PageTocItems = [.. markdown.TableOfContents.Values],
52-
Tree = DocumentationSet.Tree,
5352
CurrentDocument = markdown,
5453
PreviousDocument = previous,
5554
NextDocument = next,
@@ -73,14 +72,15 @@ public async Task<string> RenderPage(MarkdownFile markdown, string markdownHtml,
7372
var path = Path.Combine(DocumentationSet.RelativeSourcePath, markdown.RelativePath);
7473
var editUrl = $"https://github.com/elastic/{remote}/edit/{branch}/{path}";
7574

76-
var slice = Page.Create(new MainViewModel
75+
var slice = Page.Create(new IndexViewModel
7776
{
7877
Title = markdown.Title ?? "[TITLE NOT SET]",
7978
TitleRaw = markdown.TitleRaw ?? "[TITLE NOT SET]",
8079
MarkdownHtml = markdownHtml,
8180
PageTocItems = [.. markdown.TableOfContents.Values],
8281
CurrentDocument = markdown,
8382
PreviousDocument = previous,
83+
NavigationHtml = string.Empty,
8484
NextDocument = next,
8585
UrlPathPrefix = markdown.UrlPathPrefix,
8686
Applies = markdown.YamlFrontMatter?.AppliesTo,

src/Elastic.Markdown/Slices/Index.cshtml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
{
77
Title = $"Elastic Documentation: {Model.Title}",
88
PageTocItems = Model.PageTocItems.Where(i => i is { Level: 2 or 3 }).ToList(),
9-
Tree = Model.Tree,
109
CurrentDocument = Model.CurrentDocument,
1110
Previous = Model.PreviousDocument,
1211
Next = Model.NextDocument,

src/Elastic.Markdown/Slices/Layout/_Breadcrumbs.cshtml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@using Elastic.Markdown.Helpers
2-
@inherits RazorSlice<IBreadCrumbModel>
2+
@inherits RazorSlice<LayoutViewModel>
33
<ol id="breadcrumbs" class="block w-full" itemscope="" itemtype="https://schema.org/BreadcrumbList">
44
<li class="inline text-ink text-sm hover:text-ink leading-[1.2em] tracking-[-0.02em]" itemprop="itemListElement" itemscope="" itemtype="https://schema.org/ListItem">
55
<a
@@ -23,10 +23,10 @@
2323
<a
2424
itemprop="item"
2525
href="@item.Url"
26-
hx-get="@item.Url"
26+
hx-get="@(item.UrlFetch)"
27+
hx-push-url="@item.Url"
2728
hx-select-oob="@Htmx.GetHxSelectOob()"
2829
hx-swap="none"
29-
hx-push-url="true"
3030
hx-indicator="#htmx-indicator"
3131
preload="mouseover"
3232
>

src/Elastic.Markdown/Slices/Layout/_TableOfContents.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@inherits RazorSlice<ITableOfContentsModel>
1+
@inherits RazorSlice<LayoutViewModel>
22
<aside class="sidebar hidden lg:block order-3 border-l-1 border-l-gray-200 w-80">
33
<nav id="toc-nav" class="sidebar-nav pl-6">
44
<div class="pt-6 pb-20">

src/Elastic.Markdown/Slices/Layout/_TocTreeNav.cshtml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@
1010
<li class="block ml-2 pl-2 border-l-1 border-l-gray-200 group/li">
1111
<div class="flex">
1212
<a
13-
hx-get="@f.Url"
13+
href="@f.Url"
14+
hx-get="@(f.UrlFetch)"
15+
hx-push-url="@f.Url"
1416
hx-select-oob="@Htmx.GetHxSelectOob()"
1517
hx-swap="none"
16-
hx-push-url="true"
1718
hx-indicator="#htmx-indicator"
1819
preload="mouseover"
1920
class="sidebar-link my-1 ml-5 group-[.current]/li:text-blue-elastic!"
2021
id="page-@id"
21-
href="@f.Url">
22+
>
2223
@f.NavigationTitle
2324
</a>
2425
</div>
@@ -49,7 +50,8 @@
4950
>
5051
<a
5152
href="@g.Index?.Url"
52-
hx-get="@g.Index?.Url"
53+
hx-get="@(g.Index?.UrlFetch)"
54+
hx-push-url="@g.Index?.Url"
5355
hx-select-oob="@Htmx.GetHxSelectOob()"
5456
hx-swap="none"
5557
hx-push-url="true"
Lines changed: 25 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,26 @@
1-
@using Elastic.Markdown.Helpers
21
@using Markdig
3-
@inherits RazorSliceHttpResult<MainViewModel>
4-
<div class="flex flex-col items-center px-6">
5-
<div class="container flex">
6-
@await RenderPartialAsync(_PagesNav.Create(Model))
7-
@await RenderPartialAsync(_TableOfContents.Create<ITableOfContentsModel>(Model))
8-
<main class="w-full pt-6 pb-30 px-6 order-2 relative">
9-
<div class="w-full absolute top-0 left-0 right-0 htmx-indicator" id="htmx-indicator" role="status">
10-
<div class="h-[2px] w-full overflow-hidden">
11-
<div class="progress w-full h-full bg-pink-70 left-right"></div>
12-
</div>
13-
<div class="sr-only">Loading</div>
14-
</div>
15-
<div class="content-container">
16-
@await RenderPartialAsync(_Breadcrumbs.Create<IBreadCrumbModel>(Model))
17-
</div>
18-
<article id="markdown-content" class="content-container markdown-content">
19-
@* This way it's correctly rendered as <h1>text</h1> instead of <h1><p>text</p></h1> *@
20-
@(new HtmlString(Markdown.ToHtml("# " + Model.TitleRaw)))
21-
@if (Model.Applies is not null)
22-
{
23-
await RenderPartialAsync(ApplicableTo.Create(Model.Applies));
24-
}
25-
@(new HtmlString(Model.MarkdownHtml))
26-
</article>
27-
<footer id="prev-next-nav" class="content-container mt-20">
28-
<div class="flex flex-wrap lg:flex-nowrap gap-2 mt-2">
29-
<div class="w-full">
30-
@if (Model.PreviousDocument != null)
31-
{
32-
<a
33-
href="@Model.PreviousDocument.Url"
34-
hx-get="@Model.PreviousDocument.Url"
35-
hx-select-oob="@Htmx.GetHxSelectOob()"
36-
hx-swap="none"
37-
hx-push-url="true"
38-
hx-indicator="#htmx-indicator"
39-
preload="mouseover"
40-
class="flex h-full items-center text-ink-light hover:black border-1 border-gray-300 hover:border-gray-500 rounded-lg p-6 shadow-md"
41-
>
42-
<svg class="size-6 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
43-
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/>
44-
</svg>
45-
<div>
46-
<div class="text-xs lg:text-sm">Previous</div>
47-
<div class="text-base lg:text-xl text-black">@Model.PreviousDocument.NavigationTitle</div>
48-
</div>
49-
</a>
50-
}
51-
</div>
52-
<div class="w-full">
53-
@if (Model.NextDocument != null)
54-
{
55-
<a
56-
href="@Model.NextDocument.Url"
57-
hx-get="@Model.NextDocument.Url"
58-
hx-select-oob="@Htmx.GetHxSelectOob()"
59-
hx-swap="none"
60-
hx-push-url="true"
61-
hx-indicator="#htmx-indicator"
62-
preload="mouseover"
63-
class="flex h-full items-center justify-end text-ink-light hover:black border-1 border-gray-300 hover:border-gray-500 rounded-lg p-6 shadow-md text-right"
64-
>
65-
<div>
66-
<div class="text-xs lg:text-sm">Next</div>
67-
<div class="text-base lg:text-xl text-black">@Model.NextDocument.NavigationTitle</div>
68-
</div>
69-
<svg class="size-6 ml-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
70-
<path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5"/>
71-
</svg>
72-
</a>
73-
}
74-
</div>
75-
</div>
76-
</footer>
77-
</main>
78-
</div>
79-
</div>
2+
@inherits RazorSliceHttpResult<IndexViewModel>
3+
@implements IUsesLayout<Elastic.Markdown.Slices._Layout, LayoutViewModel>
4+
@functions {
5+
public LayoutViewModel LayoutModel => new()
6+
{
7+
Title = $"Elastic Documentation: {Model.Title}",
8+
PageTocItems = Model.PageTocItems.Where(i => i is { Level: 2 or 3 }).ToList(),
9+
CurrentDocument = Model.CurrentDocument,
10+
Previous = Model.PreviousDocument,
11+
Next = Model.NextDocument,
12+
NavigationHtml = string.Empty,
13+
UrlPathPrefix = Model.UrlPathPrefix,
14+
GithubEditUrl = Model.GithubEditUrl,
15+
AllowIndexing = Model.AllowIndexing,
16+
};
17+
}
18+
<section id="elastic-docs-v3">
19+
@* This way it's correctly rendered as <h1>text</h1> instead of <h1><p>text</p></h1> *@
20+
@(new HtmlString(Markdown.ToHtml("# " + Model.TitleRaw)))
21+
@if (Model.Applies is not null)
22+
{
23+
await RenderPartialAsync(ApplicableTo.Create(Model.Applies));
24+
}
25+
@(new HtmlString(Model.MarkdownHtml))
26+
</section>

src/Elastic.Markdown/Slices/_Layout.cshtml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@
1414
@(await RenderPartialAsync(_Header.Create(Model)))
1515
<div class="flex flex-col items-center px-6">
1616
<div class="container flex">
17-
@await RenderPartialAsync(_PagesNav.Create(Model))
18-
@await RenderPartialAsync(_TableOfContents.Create<ITableOfContentsModel>(Model))
17+
@if (!string.IsNullOrWhiteSpace(Model.NavigationHtml))
18+
{
19+
await RenderPartialAsync(_PagesNav.Create(Model));
20+
}
21+
@await RenderPartialAsync(_TableOfContents.Create(Model))
1922
<main class="w-full pt-6 pb-30 px-6 order-2 relative">
2023
<div class="w-full absolute top-0 left-0 right-0 htmx-indicator" id="htmx-indicator" role="status">
2124
<div class="h-[2px] w-full overflow-hidden">
@@ -24,7 +27,7 @@
2427
<div class="sr-only">Loading</div>
2528
</div>
2629
<div class="content-container">
27-
@await RenderPartialAsync(_Breadcrumbs.Create<IBreadCrumbModel>(Model))
30+
@await RenderPartialAsync(_Breadcrumbs.Create(Model))
2831
</div>
2932
<article id="markdown-content" class="content-container markdown-content">
3033
@await RenderBodyAsync()
@@ -36,10 +39,10 @@
3639
{
3740
<a
3841
href="@Model.Previous.Url"
39-
hx-get="@Model.Previous.Url"
42+
hx-get="@Model.Previous.UrlFetch"
43+
hx-push-url="@Model.Previous.Url"
4044
hx-select-oob="@Htmx.GetHxSelectOob()"
4145
hx-swap="none"
42-
hx-push-url="true"
4346
hx-indicator="#htmx-indicator"
4447
preload="mouseover"
4548
class="flex h-full items-center text-ink-light hover:black border-1 border-gray-300 hover:border-gray-500 rounded-lg p-6 shadow-md"
@@ -59,10 +62,10 @@
5962
{
6063
<a
6164
href="@Model.Next.Url"
62-
hx-get="@Model.Next.Url"
65+
hx-get="@Model.Next.UrlFetch"
66+
hx-push-url="@Model.Next.Url"
6367
hx-select-oob="@Htmx.GetHxSelectOob()"
6468
hx-swap="none"
65-
hx-push-url="true"
6669
hx-indicator="#htmx-indicator"
6770
preload="mouseover"
6871
class="flex h-full items-center justify-end text-ink-light hover:black border-1 border-gray-300 hover:border-gray-500 rounded-lg p-6 shadow-md text-right"

src/Elastic.Markdown/Slices/_ViewModels.cs

Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,53 +7,11 @@
77

88
namespace Elastic.Markdown.Slices;
99

10-
public interface IBreadCrumbModel
11-
{
12-
MarkdownFile[] Parents { get; }
13-
string? UrlPathPrefix { get; }
14-
}
15-
16-
public interface ITableOfContentsModel
17-
{
18-
IReadOnlyCollection<PageTocItem> PageTocItems { get; }
19-
string? GithubEditUrl { get; }
20-
}
21-
22-
public class MainViewModel : IBreadCrumbModel, ITableOfContentsModel
23-
{
24-
public required string Title { get; init; }
25-
public required string TitleRaw { get; init; }
26-
public required string MarkdownHtml { get; init; }
27-
public required IReadOnlyCollection<PageTocItem> PageTocItems { get; init; }
28-
public required MarkdownFile CurrentDocument { get; init; }
29-
public required MarkdownFile? PreviousDocument { get; init; }
30-
public required MarkdownFile? NextDocument { get; init; }
31-
public required string? UrlPathPrefix { get; init; }
32-
public required string? GithubEditUrl { get; init; }
33-
public required ApplicableTo? Applies { get; init; }
34-
public required bool AllowIndexing { get; init; }
35-
36-
private MarkdownFile[]? _parents;
37-
public MarkdownFile[] Parents
38-
{
39-
get
40-
{
41-
if (_parents is not null)
42-
return _parents;
43-
44-
_parents = [.. CurrentDocument.YieldParents()];
45-
return _parents;
46-
}
47-
}
48-
49-
}
50-
5110
public class IndexViewModel
5211
{
5312
public required string Title { get; init; }
5413
public required string TitleRaw { get; init; }
5514
public required string MarkdownHtml { get; init; }
56-
public required DocumentationGroup Tree { get; init; }
5715
public required IReadOnlyCollection<PageTocItem> PageTocItems { get; init; }
5816
public required MarkdownFile CurrentDocument { get; init; }
5917
public required MarkdownFile? PreviousDocument { get; init; }
@@ -65,16 +23,14 @@ public class IndexViewModel
6523
public required bool AllowIndexing { get; init; }
6624
}
6725

68-
public class LayoutViewModel : IBreadCrumbModel, ITableOfContentsModel
26+
public class LayoutViewModel
6927
{
7028
/// Used to identify the navigation for the current compilation
7129
/// We want to reset users sessionStorage every time this changes to invalidate
7230
/// the guids that no longer exist
7331
public static string CurrentNavigationId { get; } = Guid.NewGuid().ToString("N")[..8];
7432
public string Title { get; set; } = "Elastic Documentation";
75-
public string RawTitle { get; set; } = "Elastic Documentation";
7633
public required IReadOnlyCollection<PageTocItem> PageTocItems { get; init; }
77-
public required DocumentationGroup Tree { get; init; }
7834
public string[] ParentIds => [.. CurrentDocument.YieldParentGroups()];
7935
public required MarkdownFile CurrentDocument { get; init; }
8036
public required MarkdownFile? Previous { get; init; }
@@ -85,6 +41,7 @@ public class LayoutViewModel : IBreadCrumbModel, ITableOfContentsModel
8541
public required bool AllowIndexing { get; init; }
8642

8743
private MarkdownFile[]? _parents;
44+
8845
public MarkdownFile[] Parents
8946
{
9047
get

0 commit comments

Comments
 (0)