From 5f187451d3e0c1ee484554a0c5bde6dadaaf1470 Mon Sep 17 00:00:00 2001 From: Jan Calanog Date: Tue, 14 Jan 2025 12:54:18 +0100 Subject: [PATCH 1/3] Fix tab groups --- docs/source/syntax/tabs.md | 125 +++++++++++++++++- .../Myst/Directives/DirectiveHtmlRenderer.cs | 4 +- .../Myst/Directives/TabSetBlock.cs | 11 +- .../Slices/Directives/TabItem.cshtml | 4 +- .../Slices/Directives/TabSet.cshtml | 2 +- .../Slices/Directives/_ViewModels.cs | 3 +- .../Directives/TabTests.cs | 73 ++++++++++ 7 files changed, 213 insertions(+), 9 deletions(-) diff --git a/docs/source/syntax/tabs.md b/docs/source/syntax/tabs.md index e9950d894..265db23ae 100644 --- a/docs/source/syntax/tabs.md +++ b/docs/source/syntax/tabs.md @@ -4,7 +4,11 @@ title: Tabs Tabbed content is created using the `tab-set` directive with individual `tab-item` blocks for each tab's content. You can embed other directives, like admonitions directly in tabs. -## Syntax +## Tabs Simple + +### Example + +#### Syntax ```markdown ::::{tab-set} @@ -20,6 +24,8 @@ This is where the content for tab #2 goes. :::: ``` +#### Example + ::::{tab-set} :::{tab-item} Tab #1 title @@ -32,6 +38,120 @@ This is where the content for tab #2 goes. :::: +--- + +## Tab Groups + +Tabs can be grouped together by setting the `group` attribute to the same value for each `tab-set`. +This allows for multiple sets of tabs to be controlled together. + +You need to set both the `group` and `sync` attributes to the same value for each `tab-item` to sync the tabs. + +This means tabs with the same group and the same sync value will be selected together. + +### Example + +In the following example we have three tab sets, but only the first two are grouped together. +Hence, the first two tab sets will be in sync, but the third tab set will not be in sync with the first two. + +#### Syntax +```markdown +::::{tab-set} +:group: languages // This is the group name +:::{tab-item} Java +:sync: java // This is the sync name +Content for Java tab +::: + +:::{tab-item} Golang +:sync: golang +Content for Golang tab +::: + +:::{tab-item} C# +:sync: csharp +Content for C# tab +::: + +:::: + +::::{tab-set} +:group: languages +:::{tab-item} Java +:sync: java +Content for Java tab +::: + +:::{tab-item} Golang +:sync: golang +Content for Golang tab +::: + +:::{tab-item} C# +:sync: csharp +Content for C# tab +::: + +:::: +``` + +#### Result + +::::{tab-set} +:group: languages +:::{tab-item} Java +:sync: java +Content for Java tab +::: + +:::{tab-item} Golang +:sync: golang +Content for Golang tab +::: + +:::{tab-item} C# +:sync: csharp +Content for C# tab +::: + +:::: + +::::{tab-set} +:group: languages +:::{tab-item} Java +:sync: java +Other content for Java tab +::: + +:::{tab-item} Golang +:sync: golang +Other content for Golang tab +::: + +:::{tab-item} C# +:sync: csharp +Other content for C# tab +::: +:::: + +::::{tab-set} +:::{tab-item} Java +:sync: java +Other content for Java tab that is not in the same group +::: + +:::{tab-item} Golang +:sync: golang +Other content for Golang tab that is not in the same group +::: + +:::{tab-item} C# +:sync: csharp +Other content for Golang tab that is not in the same group +::: + +:::: + ## Asciidoc syntax `````asciidoc @@ -79,4 +199,5 @@ This is where the content for tab #1 goes. This is where the content for tab #2 goes. // end::reg-config[] ---- -``` \ No newline at end of file +``` +````` diff --git a/src/Elastic.Markdown/Myst/Directives/DirectiveHtmlRenderer.cs b/src/Elastic.Markdown/Myst/Directives/DirectiveHtmlRenderer.cs index 1815f0f02..fc6a89691 100644 --- a/src/Elastic.Markdown/Myst/Directives/DirectiveHtmlRenderer.cs +++ b/src/Elastic.Markdown/Myst/Directives/DirectiveHtmlRenderer.cs @@ -191,7 +191,9 @@ private void WriteTabItem(HtmlRenderer renderer, TabItemBlock block) { Index = block.Index, Title = block.Title, - TabSetIndex = block.TabSetIndex + TabSetIndex = block.TabSetIndex, + SyncKey = block.SyncKey, + TabSetGroupKey = block.TabSetGroupKey }); RenderRazorSlice(slice, renderer, block); } diff --git a/src/Elastic.Markdown/Myst/Directives/TabSetBlock.cs b/src/Elastic.Markdown/Myst/Directives/TabSetBlock.cs index 06069f10b..c35939e32 100644 --- a/src/Elastic.Markdown/Myst/Directives/TabSetBlock.cs +++ b/src/Elastic.Markdown/Myst/Directives/TabSetBlock.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information using Elastic.Markdown.Diagnostics; +using Elastic.Markdown.Slices.Directives; namespace Elastic.Markdown.Myst.Directives; @@ -12,6 +13,8 @@ public class TabSetBlock(DirectiveBlockParser parser, ParserContext context) public override string Directive => "tab-set"; public int Index { get; set; } + public string? GetGroupKey() => Prop("group"); + public override void FinalizeAndValidate(ParserContext context) => Index = FindIndex(); private int _index = -1; @@ -32,7 +35,7 @@ public class TabItemBlock(DirectiveBlockParser parser, ParserContext context) public string Title { get; private set; } = default!; public int Index { get; private set; } public int TabSetIndex { get; private set; } - + public string? TabSetGroupKey { get; private set; } public string? SyncKey { get; private set; } public bool Selected { get; private set; } @@ -43,7 +46,11 @@ public override void FinalizeAndValidate(ParserContext context) Title = Arguments ?? "{undefined}"; Index = Parent!.IndexOf(this); - TabSetIndex = Parent is TabSetBlock tb ? tb.FindIndex() : -1; + + var tabSet = Parent as TabSetBlock; + + TabSetIndex = tabSet?.FindIndex() ?? -1; + TabSetGroupKey = tabSet?.GetGroupKey(); // ?? "default" SyncKey = Prop("sync"); Selected = PropBool("selected"); diff --git a/src/Elastic.Markdown/Slices/Directives/TabItem.cshtml b/src/Elastic.Markdown/Slices/Directives/TabItem.cshtml index fea4cb398..181a101c9 100644 --- a/src/Elastic.Markdown/Slices/Directives/TabItem.cshtml +++ b/src/Elastic.Markdown/Slices/Directives/TabItem.cshtml @@ -1,6 +1,6 @@ @inherits RazorSlice - - + +
[CONTENT]
diff --git a/src/Elastic.Markdown/Slices/Directives/TabSet.cshtml b/src/Elastic.Markdown/Slices/Directives/TabSet.cshtml index c63698e3e..d11bb9532 100644 --- a/src/Elastic.Markdown/Slices/Directives/TabSet.cshtml +++ b/src/Elastic.Markdown/Slices/Directives/TabSet.cshtml @@ -1,4 +1,4 @@ @inherits RazorSlice
[CONTENT] -
\ No newline at end of file + diff --git a/src/Elastic.Markdown/Slices/Directives/_ViewModels.cs b/src/Elastic.Markdown/Slices/Directives/_ViewModels.cs index de3cde0cf..853596226 100644 --- a/src/Elastic.Markdown/Slices/Directives/_ViewModels.cs +++ b/src/Elastic.Markdown/Slices/Directives/_ViewModels.cs @@ -36,8 +36,9 @@ public class TabItemViewModel public required int Index { get; init; } public required int TabSetIndex { get; init; } public required string Title { get; init; } + public required string? SyncKey { get; init; } + public required string? TabSetGroupKey { get; init; } } - public class IncludeViewModel { public required string Html { get; init; } diff --git a/tests/Elastic.Markdown.Tests/Directives/TabTests.cs b/tests/Elastic.Markdown.Tests/Directives/TabTests.cs index a4f7dbdb5..69d4915c3 100644 --- a/tests/Elastic.Markdown.Tests/Directives/TabTests.cs +++ b/tests/Elastic.Markdown.Tests/Directives/TabTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information using Elastic.Markdown.Myst.Directives; using FluentAssertions; +using Markdig; using Xunit.Abstractions; namespace Elastic.Markdown.Tests.Directives; @@ -92,3 +93,75 @@ public void ParsesMultipleTabSets() } } } + +public class GroupTabTests(ITestOutputHelper output) : DirectiveTest(output, + """ + ::::{tab-set} + :group: languages + :::{tab-item} Java + :sync: java + Content for Java tab + ::: + + :::{tab-item} Golang + :sync: golang + Content for Golang tab + ::: + + :::{tab-item} C# + :sync: csharp + Content for C# tab + ::: + + :::: + + ::::{tab-set} + :group: languages + :::{tab-item} Java + :sync: java + Content for Java tab + ::: + + :::{tab-item} Golang + :sync: golang + Content for Golang tab + ::: + + :::{tab-item} C# + :sync: csharp + Content for C# tab + ::: + + :::: + """ +) +{ + [Fact] + public void ParsesMultipleTabSets() + { + var sets = Document.OfType().ToArray(); + sets.Length.Should().Be(2); + for (var s = 0; s < sets.Length; s++) + { + var items = sets[s].OfType().ToArray(); + items.Should().NotBeNull().And.HaveCount(3); + for (var i = 0; i < items.Length; i++) + { + items[i].Index.Should().Be(i); + items[i].TabSetIndex.Should().Be(s); + } + } + } + + [Fact] + public void ParsesGroup() + { + var sets = Document.OfType().ToArray(); + sets.Length.Should().Be(2); + + foreach (var t in sets) + { + t.GetGroupKey().Should().Be("languages"); + } + } +} From 183bcc24c8c7fa46d783e42d32002cdeaa754b1d Mon Sep 17 00:00:00 2001 From: Jan Calanog Date: Tue, 14 Jan 2025 12:57:23 +0100 Subject: [PATCH 2/3] cleanup --- src/Elastic.Markdown/Myst/Directives/TabSetBlock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Elastic.Markdown/Myst/Directives/TabSetBlock.cs b/src/Elastic.Markdown/Myst/Directives/TabSetBlock.cs index c35939e32..f884844dc 100644 --- a/src/Elastic.Markdown/Myst/Directives/TabSetBlock.cs +++ b/src/Elastic.Markdown/Myst/Directives/TabSetBlock.cs @@ -50,7 +50,7 @@ public override void FinalizeAndValidate(ParserContext context) var tabSet = Parent as TabSetBlock; TabSetIndex = tabSet?.FindIndex() ?? -1; - TabSetGroupKey = tabSet?.GetGroupKey(); // ?? "default" + TabSetGroupKey = tabSet?.GetGroupKey(); SyncKey = Prop("sync"); Selected = PropBool("selected"); From e63ef1e0be9557b092fb1c0748e88cb26983ac1b Mon Sep 17 00:00:00 2001 From: Jan Calanog Date: Tue, 14 Jan 2025 13:10:09 +0100 Subject: [PATCH 3/3] Enhance docs and test --- docs/source/syntax/tabs.md | 4 ++++ tests/Elastic.Markdown.Tests/Directives/TabTests.cs | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/docs/source/syntax/tabs.md b/docs/source/syntax/tabs.md index 265db23ae..eb143b31c 100644 --- a/docs/source/syntax/tabs.md +++ b/docs/source/syntax/tabs.md @@ -97,6 +97,8 @@ Content for C# tab #### Result +##### Grouped Tabs + ::::{tab-set} :group: languages :::{tab-item} Java @@ -134,6 +136,8 @@ Other content for C# tab ::: :::: +##### Ungrouped Tabs + ::::{tab-set} :::{tab-item} Java :sync: java diff --git a/tests/Elastic.Markdown.Tests/Directives/TabTests.cs b/tests/Elastic.Markdown.Tests/Directives/TabTests.cs index 69d4915c3..735f8f997 100644 --- a/tests/Elastic.Markdown.Tests/Directives/TabTests.cs +++ b/tests/Elastic.Markdown.Tests/Directives/TabTests.cs @@ -164,4 +164,15 @@ public void ParsesGroup() t.GetGroupKey().Should().Be("languages"); } } + + [Fact] + public void ParsesSyncKey() + { + var set = Document.OfType().First(); + var items = set.OfType().ToArray(); + items.Should().HaveCount(3); + items[0].SyncKey.Should().Be("java"); + items[1].SyncKey.Should().Be("golang"); + items[2].SyncKey.Should().Be("csharp"); + } }