Skip to content

Commit e4ce648

Browse files
committed
Add :applies_to: prop to admonitions
1 parent edf52c6 commit e4ce648

File tree

10 files changed

+399
-72
lines changed

10 files changed

+399
-72
lines changed

docs/syntax/admonitions.md

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -150,38 +150,53 @@ It can *span* multiple lines and supports inline formatting.
150150

151151
:::::
152152

153-
## Collapsible admonitions
153+
## Applies to information
154154

155-
:::{warning}
156-
Collapsible admonitions are deprecated. Do not use them. Use [dropdowns](./dropdowns.md) instead.
157-
:::
158-
159-
Use `:open: <bool>` to make an admonition collapsible.
155+
Admonitions support the `applies_to` property to indicate which products or versions the information applies to.
160156

161157
:::::{tab-set}
162158

163159
::::{tab-item} Output
164160

165161
:::{note}
166-
:open:
162+
:applies_to: stack: ga 9.1.0
163+
164+
This note applies to the Elastic Stack GA version 9.1.0.
165+
:::
167166

168-
Longer content can be collapsed to take less space.
167+
:::{warning}
168+
:applies_to: serverless: ga
169169

170-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
170+
This warning applies to serverless GA.
171171
:::
172172

173+
:::{tip}
174+
:applies_to: { ess:, ece: }
175+
176+
This tip applies to ECH and ECE.
177+
:::
173178

174179
::::
175180

176181
::::{tab-item} Markdown
177182

178183
```markdown
179184
:::{note}
180-
:open:
185+
:applies_to: stack: ga 9.1.0
186+
187+
This note applies to the Elastic Stack GA version 9.1.0.
188+
:::
189+
190+
:::{warning}
191+
:applies_to: serverless: ga
192+
193+
This warning applies to serverless GA.
194+
:::
181195

182-
Longer content can be collapsed to take less space.
196+
:::{tip}
197+
:applies_to: { ess:, ece: }
183198

184-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
199+
This tip applies to ECH and ECE.
185200
:::
186201
```
187202

src/Elastic.Documentation.Site/Assets/markdown/admonition.css

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,29 @@
33
@apply mt-4 rounded-sm border-1 pb-4;
44

55
.admonition-title {
6-
@apply flex items-center gap-2 rounded-t-sm px-4 py-2 font-bold;
7-
svg {
8-
@apply size-6;
6+
@apply flex items-center gap-3 rounded-t-sm px-4 py-2 font-bold;
7+
}
8+
9+
.admonition-title__text {
10+
@apply text-sm tracking-wider uppercase;
11+
}
12+
13+
.applies-admonition {
14+
@apply flex items-center gap-1 font-normal;
15+
color: inherit;
16+
.applicable-info {
17+
@apply border-none bg-transparent p-0;
18+
&:not(:last-child):after {
19+
@apply text-sm;
20+
content: ',';
21+
}
22+
}
23+
.applicable-name,
24+
.applicable-meta {
25+
@apply text-sm;
26+
}
27+
.applicable-separator {
28+
mix-blend-mode: multiply;
929
}
1030
}
1131
.admonition-content {

src/Elastic.Markdown/Myst/Directives/Admonition/AdmonitionBlock.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Elastic.Markdown.Myst.Directives.Admonition;
99

1010
public class DropdownBlock(DirectiveBlockParser parser, ParserContext context) : AdmonitionBlock(parser, "dropdown", context);
1111

12-
public class AdmonitionBlock : DirectiveBlock, IBlockTitle
12+
public class AdmonitionBlock : DirectiveBlock, IBlockTitle, IBlockAppliesTo
1313
{
1414
public AdmonitionBlock(DirectiveBlockParser parser, string admonition, ParserContext context) : base(parser, context)
1515
{
@@ -65,6 +65,7 @@ public override void FinalizeAndValidate(ParserContext context)
6565
catch
6666
{
6767
// If parsing fails, return null
68+
// Note: Error handling is done in the YamlSerialization.Deserialize method
6869
return null;
6970
}
7071
}

src/Elastic.Markdown/Myst/Directives/Admonition/AdmonitionView.cshtml

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,19 @@
1+
@using Elastic.Markdown.Myst.Components
12
@inherits RazorSlice<Elastic.Markdown.Myst.Directives.Admonition.AdmonitionViewModel>
23
<div class="admonition @Model.Directive @Model.Classes" id="@Model.CrossReferenceName" open="@Model.Open">
34
<div class="admonition-title">
4-
5-
@{
6-
switch (Model.Directive)
7-
{
8-
case "tip":
9-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
10-
<path stroke-linecap="round" stroke-linejoin="round" d="M12 18v-5.25m0 0a6.01 6.01 0 0 0 1.5-.189m-1.5.189a6.01 6.01 0 0 1-1.5-.189m3.75 7.478a12.06 12.06 0 0 1-4.5 0m3.75 2.383a14.406 14.406 0 0 1-3 0M14.25 18v-.192c0-.983.658-1.823 1.508-2.316a7.5 7.5 0 1 0-7.517 0c.85.493 1.509 1.333 1.509 2.316V18"/>
11-
</svg>
12-
break;
13-
case "warning":
14-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
15-
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"/>
16-
</svg>
17-
break;
18-
case "note":
19-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
20-
<path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" />
21-
</svg>
22-
break;
23-
case "important":
24-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
25-
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z"/>
26-
</svg>
27-
break;
28-
default:
29-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
30-
<path stroke-linecap="round" stroke-linejoin="round" d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 0 1 .865-.501 48.172 48.172 0 0 0 3.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z" />
31-
</svg>
32-
break;
33-
}
5+
@if (Model.AppliesTo is not null)
6+
{
7+
<span class="applies applies-admonition">
8+
@await RenderPartialAsync(ApplicableToComponent.Create(new ApplicableToViewModel
9+
{
10+
AppliesTo = Model.AppliesTo,
11+
Inline = true,
12+
ShowTooltip = false,
13+
VersionsConfig = Model.BuildContext.VersionsConfiguration
14+
}))
15+
</span>
16+
<span class="admonition-title__separator"></span>
3417
}
3518
<span>@Model.Title</span>
3619
</div>

src/Elastic.Markdown/Myst/Directives/DirectiveBlock.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public interface IBlockTitle
1818
string Title { get; }
1919
}
2020

21+
public interface IBlockAppliesTo
22+
{
23+
string? AppliesToDefinition { get; }
24+
}
25+
2126
public interface IBlockExtension : IBlock
2227
{
2328
BuildContext Build { get; }

src/Elastic.Markdown/Myst/Renderers/LlmMarkdown/LlmBlockRenderers.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,13 @@ protected override void Write(LlmMarkdownRenderer renderer, DirectiveBlock obj)
383383
break;
384384
}
385385

386+
switch (obj)
387+
{
388+
case IBlockAppliesTo appliesBlock when !string.IsNullOrEmpty(appliesBlock.AppliesToDefinition):
389+
renderer.Writer.Write($" applies-to=\"{appliesBlock.AppliesToDefinition}\"");
390+
break;
391+
}
392+
386393
renderer.WriteLine(">");
387394
renderer.EnsureLine();
388395

tests/Elastic.Markdown.Tests/Directives/AdmonitionTests.cs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,163 @@ public void ParsesAppliesToWithComplexValue()
236236
Block!.AppliesTo.Should().NotBeNull();
237237
}
238238
}
239+
240+
public class NoteAppliesToTests(ITestOutputHelper output) : DirectiveTest<AdmonitionBlock>(output,
241+
"""
242+
:::{note}
243+
:applies_to: stack: ga
244+
This is a note with applies_to information
245+
:::
246+
A regular paragraph.
247+
"""
248+
)
249+
{
250+
[Fact]
251+
public void SetsCorrectAdmonitionType() => Block!.Admonition.Should().Be("note");
252+
253+
[Fact]
254+
public void SetsTitle() => Block!.Title.Should().Be("Note");
255+
256+
[Fact]
257+
public void SetsAppliesToDefinition() => Block!.AppliesToDefinition.Should().Be("stack: ga");
258+
259+
[Fact]
260+
public void ParsesAppliesTo() => Block!.AppliesTo.Should().NotBeNull();
261+
262+
[Fact]
263+
public void RendersAppliesToInHtml()
264+
{
265+
var html = Html;
266+
html.Should().Contain("applies applies-admonition");
267+
html.Should().Contain("admonition-title__separator");
268+
html.Should().Contain("applicable-info");
269+
}
270+
}
271+
272+
public class WarningAppliesToTests(ITestOutputHelper output) : DirectiveTest<AdmonitionBlock>(output,
273+
"""
274+
:::{warning}
275+
:applies_to: stack: ga
276+
This is a warning with applies_to information
277+
:::
278+
A regular paragraph.
279+
"""
280+
)
281+
{
282+
[Fact]
283+
public void SetsCorrectAdmonitionType() => Block!.Admonition.Should().Be("warning");
284+
285+
[Fact]
286+
public void SetsTitle() => Block!.Title.Should().Be("Warning");
287+
288+
[Fact]
289+
public void SetsAppliesToDefinition() => Block!.AppliesToDefinition.Should().Be("stack: ga");
290+
291+
[Fact]
292+
public void ParsesAppliesTo() => Block!.AppliesTo.Should().NotBeNull();
293+
294+
[Fact]
295+
public void RendersAppliesToInHtml()
296+
{
297+
var html = Html;
298+
html.Should().Contain("applies applies-admonition");
299+
html.Should().Contain("admonition-title__separator");
300+
html.Should().Contain("applicable-info");
301+
}
302+
}
303+
304+
public class TipAppliesToTests(ITestOutputHelper output) : DirectiveTest<AdmonitionBlock>(output,
305+
"""
306+
:::{tip}
307+
:applies_to: stack: ga
308+
This is a tip with applies_to information
309+
:::
310+
A regular paragraph.
311+
"""
312+
)
313+
{
314+
[Fact]
315+
public void SetsCorrectAdmonitionType() => Block!.Admonition.Should().Be("tip");
316+
317+
[Fact]
318+
public void SetsTitle() => Block!.Title.Should().Be("Tip");
319+
320+
[Fact]
321+
public void SetsAppliesToDefinition() => Block!.AppliesToDefinition.Should().Be("stack: ga");
322+
323+
[Fact]
324+
public void ParsesAppliesTo() => Block!.AppliesTo.Should().NotBeNull();
325+
326+
[Fact]
327+
public void RendersAppliesToInHtml()
328+
{
329+
var html = Html;
330+
html.Should().Contain("applies applies-admonition");
331+
html.Should().Contain("admonition-title__separator");
332+
html.Should().Contain("applicable-info");
333+
}
334+
}
335+
336+
public class ImportantAppliesToTests(ITestOutputHelper output) : DirectiveTest<AdmonitionBlock>(output,
337+
"""
338+
:::{important}
339+
:applies_to: stack: ga
340+
This is an important notice with applies_to information
341+
:::
342+
A regular paragraph.
343+
"""
344+
)
345+
{
346+
[Fact]
347+
public void SetsCorrectAdmonitionType() => Block!.Admonition.Should().Be("important");
348+
349+
[Fact]
350+
public void SetsTitle() => Block!.Title.Should().Be("Important");
351+
352+
[Fact]
353+
public void SetsAppliesToDefinition() => Block!.AppliesToDefinition.Should().Be("stack: ga");
354+
355+
[Fact]
356+
public void ParsesAppliesTo() => Block!.AppliesTo.Should().NotBeNull();
357+
358+
[Fact]
359+
public void RendersAppliesToInHtml()
360+
{
361+
var html = Html;
362+
html.Should().Contain("applies applies-admonition");
363+
html.Should().Contain("admonition-title__separator");
364+
html.Should().Contain("applicable-info");
365+
}
366+
}
367+
368+
public class AdmonitionAppliesToTests(ITestOutputHelper output) : DirectiveTest<AdmonitionBlock>(output,
369+
"""
370+
:::{admonition} Custom Admonition
371+
:applies_to: stack: ga
372+
This is a custom admonition with applies_to information
373+
:::
374+
A regular paragraph.
375+
"""
376+
)
377+
{
378+
[Fact]
379+
public void SetsCorrectAdmonitionType() => Block!.Admonition.Should().Be("admonition");
380+
381+
[Fact]
382+
public void SetsCustomTitle() => Block!.Title.Should().Be("Custom Admonition");
383+
384+
[Fact]
385+
public void SetsAppliesToDefinition() => Block!.AppliesToDefinition.Should().Be("stack: ga");
386+
387+
[Fact]
388+
public void ParsesAppliesTo() => Block!.AppliesTo.Should().NotBeNull();
389+
390+
[Fact]
391+
public void RendersAppliesToInHtml()
392+
{
393+
var html = Html;
394+
html.Should().Contain("applies applies-admonition");
395+
html.Should().Contain("admonition-title__separator");
396+
html.Should().Contain("applicable-info");
397+
}
398+
}

0 commit comments

Comments
 (0)