Skip to content

Commit 609837b

Browse files
authored
Add stepper directive (#1092)
* Add stepper directive * Add description * Tweak description * Run prettier * Change syntax * Use appropriate tag * Move stepper in docset * Run prettier
1 parent bf46642 commit 609837b

File tree

10 files changed

+342
-0
lines changed

10 files changed

+342
-0
lines changed

docs/_docset.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ toc:
8989
- file: links.md
9090
- file: passthrough.md
9191
- file: sidebars.md
92+
- file: stepper.md
9293
- file: substitutions.md
9394
- file: sundries.md
9495
- file: tables.md

docs/syntax/stepper.md

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# Stepper
2+
3+
Steppers provide a visual representation of sequential steps, commonly used in tutorials or guides
4+
to break down processes into manageable stages.
5+
6+
By default every step title is a link with a generated anchor.
7+
But you can override the default anchor by adding the `:anchor:` option to the step.
8+
9+
## Basic Stepper
10+
11+
:::::::{tab-set}
12+
::::::{tab-item} Output
13+
:::::{stepper}
14+
15+
:::::{stepper}
16+
17+
::::{step} Install
18+
First install the dependencies.
19+
```shell
20+
npm install
21+
```
22+
::::
23+
24+
::::{step} Build
25+
Then build the project.
26+
```shell
27+
npm run build
28+
```
29+
::::
30+
31+
::::{step} Test
32+
Finally run the tests.
33+
```shell
34+
npm run test
35+
```
36+
::::
37+
38+
::::{step} Done
39+
::::
40+
41+
:::::
42+
43+
:::::
44+
::::::
45+
46+
::::::{tab-item} Markdown
47+
````markdown
48+
:::::{stepper}
49+
50+
::::{step} Install
51+
First install the dependencies.
52+
```shell
53+
npm install
54+
```
55+
::::
56+
57+
::::{step} Build
58+
Then build the project.
59+
```shell
60+
npm run build
61+
```
62+
::::
63+
64+
::::{step} Test
65+
Finally run the tests.
66+
```shell
67+
npm run test
68+
```
69+
::::
70+
71+
::::{step} Done
72+
::::
73+
74+
:::::
75+
````
76+
::::::
77+
78+
:::::::
79+
80+
## Advanced Example
81+
82+
:::::::{tab-set}
83+
84+
::::::{tab-item} Output
85+
86+
:::::{stepper}
87+
88+
::::{step} Create an index
89+
90+
Create a new index named `books`:
91+
92+
```console
93+
PUT /books
94+
```
95+
96+
The following response indicates the index was created successfully.
97+
98+
:::{dropdown} Example response
99+
```console-result
100+
{
101+
"acknowledged": true,
102+
"shards_acknowledged": true,
103+
"index": "books"
104+
}
105+
```
106+
:::
107+
108+
::::
109+
110+
::::{step} Add data to your index
111+
:anchor: add-data
112+
113+
:::{tip}
114+
This tutorial uses Elasticsearch APIs, but there are many other ways to [add data to Elasticsearch](#).
115+
:::
116+
117+
You add data to Elasticsearch as JSON objects called documents. Elasticsearch stores these documents in searchable indices.
118+
::::
119+
120+
::::{step} Define mappings and data types
121+
122+
When using dynamic mapping, Elasticsearch automatically creates mappings for new fields by default.
123+
The documents we’ve added so far have used dynamic mapping, because we didn’t specify a mapping when creating the index.
124+
125+
To see how dynamic mapping works, add a new document to the `books` index with a field that doesn’t appear in the existing documents.
126+
127+
```console
128+
POST /books/_doc
129+
{
130+
"name": "The Great Gatsby",
131+
"author": "F. Scott Fitzgerald",
132+
"release_date": "1925-04-10",
133+
"page_count": 180,
134+
"language": "EN" <1>
135+
}
136+
```
137+
1. The new field.
138+
::::
139+
140+
:::::
141+
142+
::::::
143+
144+
::::::{tab-item} Markdown
145+
146+
````markdown
147+
:::::{stepper}
148+
149+
::::{step} Create an index
150+
151+
Create a new index named `books`:
152+
153+
```console
154+
PUT /books
155+
```
156+
157+
The following response indicates the index was created successfully.
158+
159+
:::{dropdown} Example response
160+
```console-result
161+
{
162+
"acknowledged": true,
163+
"shards_acknowledged": true,
164+
"index": "books"
165+
}
166+
```
167+
:::
168+
169+
::::
170+
171+
::::{step} Add data to your index
172+
:anchor: add-data
173+
174+
:::{tip}
175+
This tutorial uses Elasticsearch APIs, but there are many other ways to [add data to Elasticsearch](#).
176+
:::
177+
178+
You add data to Elasticsearch as JSON objects called documents. Elasticsearch stores these documents in searchable indices.
179+
::::
180+
181+
::::{step} Define mappings and data types
182+
183+
When using dynamic mapping, Elasticsearch automatically creates mappings for new fields by default.
184+
The documents we’ve added so far have used dynamic mapping, because we didn’t specify a mapping when creating the index.
185+
186+
To see how dynamic mapping works, add a new document to the `books` index with a field that doesn’t appear in the existing documents.
187+
188+
```console
189+
POST /books/_doc
190+
{
191+
"name": "The Great Gatsby",
192+
"author": "F. Scott Fitzgerald",
193+
"release_date": "1925-04-10",
194+
"page_count": 180,
195+
"language": "EN" <1>
196+
}
197+
```
198+
1. The new field.
199+
::::
200+
201+
:::::
202+
`````
203+
::::::
204+
205+
:::::::
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
.markdown-content {
2+
.stepper {
3+
.step {
4+
@apply not-first:mt-8;
5+
}
6+
7+
.title {
8+
@apply font-sans text-2xl font-semibold text-black no-underline hover:text-black;
9+
}
10+
11+
& > ol {
12+
@apply ml-0;
13+
counter-reset: stepper;
14+
15+
ol {
16+
list-style-type: decimal;
17+
}
18+
ol > li > ol {
19+
list-style-type: lower-alpha;
20+
}
21+
ol > li > ol > li > ol {
22+
list-style-type: lower-roman;
23+
}
24+
ol > li > ol > li > ol > li > ol {
25+
list-style-type: decimal;
26+
}
27+
ol > li > ol > li > ol > li > ol > li > ol {
28+
list-style-type: lower-alpha;
29+
}
30+
ol > li > ol > li > ol > li > ol > li > ol > li > ol {
31+
list-style-type: lower-roman;
32+
}
33+
}
34+
& > ol > li {
35+
@apply relative list-none pl-12;
36+
counter-increment: stepper;
37+
position: relative;
38+
&::before {
39+
@apply bg-grey-20 absolute top-8 -bottom-10 block w-[1px];
40+
content: '';
41+
left: calc(var(--spacing) * 4 - 1px);
42+
}
43+
&:last-child::before {
44+
@apply bottom-0;
45+
}
46+
&::after {
47+
@apply border-grey-20 bg-grey-10 absolute top-0 left-0 flex size-8 items-center justify-center rounded-full border-1 text-sm text-black;
48+
content: counter(stepper);
49+
}
50+
}
51+
}
52+
}

src/Elastic.Markdown/Assets/styles.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
@import './markdown/images.css';
1414
@import './modal.css';
1515
@import './archive.css';
16+
@import './markdown/stepper.css';
1617

1718
:root {
1819
--outline-size: max(2px, 0.08em);

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ protected override DirectiveBlock CreateFencedBlock(BlockProcessor processor)
119119
return new VersionBlock(this, version, context);
120120
}
121121

122+
if (info.IndexOf("{stepper}") > 0)
123+
return new StepperBlock(this, context);
124+
125+
if (info.IndexOf("{step}") > 0)
126+
return new StepBlock(this, context);
127+
122128
return new UnknownDirectiveBlock(this, info.ToString(), context);
123129
}
124130

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ protected override void Write(HtmlRenderer renderer, DirectiveBlock directiveBlo
6565
case SettingsBlock settingsBlock:
6666
WriteSettingsBlock(renderer, settingsBlock, markdownParser);
6767
return;
68+
case StepperBlock stepperBlock:
69+
WriteStepperBlock(renderer, stepperBlock, markdownParser);
70+
return;
71+
case StepBlock stepBlock:
72+
WriteStepBlock(renderer, stepBlock, markdownParser);
73+
return;
6874
default:
6975
// if (!string.IsNullOrEmpty(directiveBlock.Info) && !directiveBlock.Info.StartsWith('{'))
7076
// WriteCode(renderer, directiveBlock);
@@ -111,6 +117,22 @@ private static void WriteImage(HtmlRenderer renderer, ImageBlock block)
111117
RenderRazorSlice(slice, renderer, block);
112118
}
113119

120+
private static void WriteStepperBlock(HtmlRenderer renderer, StepperBlock block, MarkdownParser _)
121+
{
122+
var slice = Stepper.Create(new StepperViewModel());
123+
RenderRazorSlice(slice, renderer, block);
124+
}
125+
126+
private static void WriteStepBlock(HtmlRenderer renderer, StepBlock block, MarkdownParser _)
127+
{
128+
var slice = Step.Create(new StepViewModel
129+
{
130+
Title = block.Title,
131+
Anchor = block.Anchor
132+
});
133+
RenderRazorSlice(slice, renderer, block);
134+
}
135+
114136
private static void WriteFigure(HtmlRenderer renderer, ImageBlock block)
115137
{
116138
var imageUrl = block.ImageUrl != null &&
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using Elastic.Markdown.Helpers;
6+
7+
namespace Elastic.Markdown.Myst.Directives;
8+
9+
public class StepperBlock(DirectiveBlockParser parser, ParserContext context) : DirectiveBlock(parser, context)
10+
{
11+
public override string Directive => "stepper";
12+
13+
public override void FinalizeAndValidate(ParserContext context)
14+
{
15+
}
16+
}
17+
18+
public class StepBlock(DirectiveBlockParser parser, ParserContext context) : DirectiveBlock(parser, context)
19+
{
20+
public override string Directive => "step";
21+
public string Title { get; private set; } = string.Empty;
22+
public string Anchor { get; private set; } = string.Empty;
23+
24+
public override void FinalizeAndValidate(ParserContext context)
25+
{
26+
Title = Arguments ?? string.Empty;
27+
Anchor = Prop("anchor") ?? Title.Slugify();
28+
}
29+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@inherits RazorSlice<StepViewModel>
2+
<li class="step">
3+
@if (!string.IsNullOrEmpty(Model.Title))
4+
{
5+
<p id="@Model.Anchor">
6+
<a class="title" href="#@Model.Anchor">
7+
@Model.Title
8+
</a>
9+
</p>
10+
}
11+
[CONTENT]
12+
</li>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@inherits RazorSlice<StepperViewModel>
2+
<div class="stepper">
3+
<ol>
4+
[CONTENT]
5+
</ol>
6+
</div>

src/Elastic.Markdown/Slices/Directives/_ViewModels.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,11 @@ public class SettingsViewModel
8181
}
8282

8383
public class MermaidViewModel;
84+
85+
public class StepperViewModel;
86+
87+
public class StepViewModel
88+
{
89+
public required string Title { get; init; }
90+
public required string Anchor { get; init; }
91+
}

0 commit comments

Comments
 (0)