├── LICENSE ├── README.md ├── docs ├── css │ └── sidebar.css └── index.html ├── input.md ├── md-to-bootstrap5.lua ├── media ├── accordion.gif ├── alertdanger.png ├── alertinfo.png ├── button.png ├── buttonsuccess.png ├── card.png ├── carousel.gif ├── carouselquiz.gif ├── icon.png ├── jumbotron.png ├── quiz.gif ├── tabs.gif └── youtube.png ├── template ├── README.md └── bs5.template.html └── test ├── bs5.bat ├── css └── sidebar.css └── result-v2.html /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright © 2021–2022 François PARLANT and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pandoc Lua filter : Markdown To Bootstrap 2 | 3 | This pandoc Lua filter converts markdown to Bootstrap components. 4 | 5 | *Useful for rapidly creating visually attractive Moodle courses* 6 | 7 | # USAGE 8 | 9 | 10 | ``` 11 | pandoc sample.md --lua-filter bootstrap.lua -o expected.html -f markdown+inline_code_attributes 12 | ``` 13 | 14 | Or with a template to add the bootstrap headers and navbar with Table of content. 15 | ``` 16 | pandoc sample.md --lua-filter bootstrap.lua -o result.html --template bs5.template.html -f markdown+inline_code_attributes 17 | ``` 18 | 19 | # COMPONENTS 20 | 21 | 22 | ## Header block (jumbotron) 23 | 24 | 25 | 26 | 27 | 40 | 45 |
Simply type this: Get that:
28 | 29 | ``` 30 | ::: jumbotron 31 | # Markdown to Bootstrap 32 | Discovert how some simple Mardown can 33 | be converted 34 | 35 | Here is an implementation with pandoc 36 | and Lua filter 37 | ::: 38 | ``` 39 | 41 | 42 | ![jumbotron](/media/jumbotron.png) 43 | 44 |
46 | 47 | 48 | 49 | ## Simple Quiz 50 | 51 | 52 | 53 | 54 | 70 | 75 |
Simply type the question and proposals: And get that :
55 | 56 | ``` 57 | ::: quiz 58 | # This is the question? 59 | 60 | * First proposition 61 | * Explanation about first 62 | * Second proposition 63 | * Third proposition 64 | * Fourth proposition 65 | * Explanation about fourth 66 | 67 | ::: 68 | ``` 69 | 71 | 72 | ![jumbotron](/media/quiz.gif) 73 | 74 |
76 | 77 | 78 | 79 | ## Carousel 80 | 81 | 82 | 83 | 84 | 103 | 108 |
Type simply the slide content: And get that:
85 | 86 | ``` 87 | ::: carousel carouselId 88 | 89 | # first slide 90 | Some content for first slide 91 | 92 | # Second slide 93 | Some content for second slide 94 | 95 | # Third slide 96 | Some content for third slide 97 | 98 | ::: 99 | 100 | ``` 101 | 102 | 104 | 105 | ![jumbotron](/media/carousel.gif) 106 | 107 |
109 | 110 | 111 | 112 | 113 | 114 | ## Accordion 115 | 116 | 117 | 118 | 119 | 139 | 144 |
Simply type the content of the toggle: And get that:
120 | 121 | ``` 122 | ::: accordion accordionId 123 | 124 | # first toggle link 125 | Content of the first toggle 126 | 127 | # Second toggle link 128 | Content of the second toggle 129 | 130 | # Third toggle link 131 | Content of the third toggle 132 | 133 | ::: 134 | 135 | ``` 136 | 137 | 138 | 140 | 141 | ![jumbotron](/media/accordion.gif) 142 | 143 |
145 | 146 | 147 | 148 | 149 | ## Tabs 150 | 151 | 152 | 153 | 154 | 155 | 173 | 178 |
Type simply this: Get that
156 | 157 | ``` 158 | ::: tabs 159 | 160 | # Choice 1 161 | Some content for first choice 162 | 163 | # Choice 2 164 | Some content for second choice 165 | 166 | # Choice 3 167 | Some content for third choice 168 | 169 | ::: 170 | 171 | ``` 172 | 174 | 175 | ![jumbotron](/media/tabs.gif) 176 | 177 |
179 | 180 | 181 | 182 | 183 | 184 | 185 | ## Alerts 186 | 187 | 188 | 189 | 190 | 199 | 204 | 213 | 218 | 219 |
Type simply this: Get that
191 | 192 | ``` 193 | ::: info 194 | This is an info alert 195 | ::: 196 | ``` 197 | 198 | 200 | 201 | ![jumbotron](/media/alertinfo.png) 202 | 203 |
205 | 206 | ``` 207 | ::: danger 208 | This is an danger alert 209 | ::: 210 | ``` 211 | 212 | 214 | 215 | ![jumbotron](/media/alertdanger.png) 216 | 217 |
220 | 221 | 222 | 223 | 224 | ## Cards 225 | 226 | 227 | 228 | 229 | 252 | 257 |
Type simply the card content: Get that
230 | 231 | ``` 232 | ::: card 233 | 234 | ::: header (optional) 235 | text of the header 236 | ::: 237 | 238 | # a title in the body 239 | 240 | Paragraph one of the body 241 | Paragraph two of the body 242 | 243 | :::footer (optional) 244 | text of the footer 245 | ::: 246 | 247 | ::: 248 | 249 | ``` 250 | 251 | 253 | 254 | ![jumbotron](/media/card.png) 255 | 256 |
258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | ## Buttons 266 | 267 | 268 | 269 | 278 | 283 | 292 | 297 | 298 |
Type simply this: Get that
270 | 271 | ``` 272 | 273 | You can [Click me](https://github.com/pandoc) 274 | 275 | ``` 276 | 277 | 279 | 280 | ![jumbotron](/media/button.png) 281 | 282 |
284 | 285 | ``` 286 | 287 | You can [Click me](https://github.com/pandoc){.success} 288 | 289 | ``` 290 | 291 | 293 | 294 | ![jumbotron](/media/buttonsuccess.png) 295 | 296 |
299 | 300 | 301 | 302 | ## Media link 303 | 304 | 305 | 306 | 307 | 316 | 321 |
Type simply this: Get that
308 | 309 | ``` 310 | 311 | [Bootstrap design](https://www.youtube.com/watch?v=Uz7XbIxHf-4) 312 | 313 | ``` 314 | 315 | 317 | 318 | ![youtube embed](/media/youtube.png) 319 | 320 |
322 | 323 | 324 | 325 | ## Icons 326 | 327 | 328 | 329 | 330 | 337 | 342 |
Simply type this: And get that:
331 | 332 | ``` 333 | [](.bi-bootstrap) 334 | ``` 335 | 336 | 338 | 339 | ![jumbotron](/media/icon.png) 340 | 341 |
343 | 344 | # Other tools included 345 | This filter comes with a template to include: 346 | 347 | * [x] Table of content for the sidebar 348 | 349 | Another filter can be used to insert social network blocks: 350 | 351 | * [x] [Social-snetwork](https://github.com/fxpar/social-networks-pandoc-lua-filter) filter to create recommandation blocks 352 | 353 | 354 | 355 | # ROADMAP 356 | 357 | Here is what is already done and which components are planned: 358 | 359 | * [x] Jumbotrons 360 | * [x] Accordions 361 | * [x] Alerts 362 | * [x] Tabs 363 | * [x] Carousel 364 | * [x] Buttons 365 | * [ ] Carddeck 366 | * [ ] ButtonGroups 367 | * [ ] Dropdowns 368 | * [x] YouTube Embeds 369 | 370 | 371 | 372 | ## Swyping Quiz 373 | 374 | 375 | 376 | 377 | 410 | 415 |
Type simply this: And get that:
378 | 379 | ``` 380 | ::: carousel 381 | 382 | ::: quiz 383 | 384 | # Check your level 385 | 386 | A little quiz for you! 387 | 388 | # Question 1 389 | 390 | * proposition 1 391 | * feedback for proposition 1 392 | * proposition 2 393 | * proposition c 394 | * proposition d 395 | 396 | 397 | # Question 2 398 | 399 | * Prop A 400 | * Prop B 401 | * Prop C 402 | * feedback prop C 403 | * prop D 404 | ::: 405 | 406 | ::: 407 | ``` 408 | 409 | 411 | 412 | ![jumbotron](/media/carouselquiz.gif) 413 | 414 |
416 | 417 | # Creator 418 | 419 | François Parlant 420 | * [Github fxpar](https://github.com/fxpar/) 421 | * [Linkedin François Parlant](https://linkedin.com/in/francois-parlant/) 422 | 423 | Thanks to [Tarleb](https://stackoverflow.com/users/2425163/tarleb) for his helpful answers about Lua on stackoveflow 👍 424 | 425 | -------------------------------------------------------------------------------- /docs/css/sidebar.css: -------------------------------------------------------------------------------- 1 | body { 2 | min-height: 100vh; 3 | min-height: -webkit-fill-available; 4 | } 5 | 6 | html { 7 | height: -webkit-fill-available; 8 | } 9 | 10 | main { 11 | display: flex; 12 | flex-wrap: nowrap; 13 | height: 100vh; 14 | height: -webkit-fill-available; 15 | max-height: 100vh; 16 | overflow-x: auto; 17 | overflow-y: hidden; 18 | } 19 | 20 | .b-example-divider { 21 | flex-shrink: 0; 22 | width: 1.5rem; 23 | height: 100vh; 24 | background-color: rgba(0, 0, 0, .1); 25 | border: solid rgba(0, 0, 0, .15); 26 | border-width: 1px 0; 27 | box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15); 28 | } 29 | 30 | .bi { 31 | vertical-align: -.125em; 32 | pointer-events: none; 33 | fill: currentColor; 34 | } 35 | 36 | .dropdown-toggle { outline: 0; } 37 | 38 | .nav-flush .nav-link { 39 | border-radius: 0; 40 | } 41 | 42 | .btn-toggle { 43 | display: inline-flex; 44 | align-items: center; 45 | padding: .25rem .5rem; 46 | font-weight: 600; 47 | color: rgba(0, 0, 0, .65); 48 | background-color: transparent; 49 | border: 0; 50 | } 51 | .btn-toggle:hover, 52 | .btn-toggle:focus { 53 | color: rgba(0, 0, 0, .85); 54 | background-color: #d2f4ea; 55 | } 56 | 57 | .btn-toggle::before { 58 | width: 1.25em; 59 | line-height: 0; 60 | content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e"); 61 | transition: transform .35s ease; 62 | transform-origin: .5em 50%; 63 | } 64 | 65 | .btn-toggle[aria-expanded="true"] { 66 | color: rgba(0, 0, 0, .85); 67 | } 68 | .btn-toggle[aria-expanded="true"]::before { 69 | transform: rotate(90deg); 70 | } 71 | 72 | .btn-toggle-nav a { 73 | display: inline-flex; 74 | padding: .1875rem .5rem; 75 | margin-top: .125rem; 76 | margin-left: 1.25rem; 77 | text-decoration: none; 78 | } 79 | .btn-toggle-nav a:hover, 80 | .btn-toggle-nav a:focus { 81 | background-color: #d2f4ea; 82 | } 83 | 84 | .scrollarea { 85 | overflow-y: auto; 86 | } 87 | 88 | .fw-semibold { font-weight: 600; } 89 | .lh-tight { line-height: 1.25; } 90 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Markdown to Bootstrap 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 65 | 66 | 72 | 73 |
74 |
75 |
Markdown to Bootstrap
76 | 77 |
78 |
79 | 80 | 113 | 114 |
115 |
116 | 117 | 118 | 119 | 120 | 121 | 122 |
123 |

Markdown to Bootstrap

124 |

Discover how some simple markdown can be converted

125 |
126 |

Here is an implementation with pandoc and Lua filter

127 | Check the projet on Github 128 |
129 | 130 |


131 |


132 | 133 |

Simple Quiz

134 |

Click on the propositions

135 |
136 |
137 |
This is the question?
138 | 139 |
140 | 141 | 160 | 163 | 164 |
165 | 166 | 167 | 168 |
169 |

Jumbotron

170 | 171 | 172 |
173 |

This is a big header

174 |

This is what a jumbotron (bootrap4) or a header (bs5) looks like.

175 |
176 |

It should be created automatically from the markdown code below.

177 | 178 |
179 |
It should be simply created from this code:
180 |

181 | ::: jumbotron
182 | # This is a big header
183 | This is what a jumbotron (bootrap4) or a header (bs5) looks like.
184 | 
185 | It should be created automatically from the markdown code below.
186 | :::
187 | 
188 | 
189 | 190 |
191 | 192 |

ALERTS

193 | 196 | 197 |
It should be created from this code:
198 | 199 |

200 | 
201 | ::: danger
202 | This is a danger alert
203 | :::
204 | 
205 | 
206 | 207 |
208 | 209 | 210 | 213 | 214 |
It should be created from this code:
215 | 216 |

217 | 
218 | ::: info
219 | This is an info alert
220 | :::
221 | 
222 | 
223 | 224 | 225 |
226 | 227 |

CARDS

228 |
229 |
230 | text of the header 231 |
232 |
233 |
a title in the body
234 |

Paragraph one of the body

235 |

Paragraph two of the body

236 |
237 | 240 |
241 |

242 |
It should be simply created from this code:
243 | 244 |

245 | 
246 | ::: card
247 | 
248 | ::: header (optional)
249 | text of the header
250 | :::
251 | 
252 | # a title in the body
253 | 
254 | Paragraph one of the body
255 | Paragraph two of the body
256 | 
257 | ::: footer (optional)
258 | text of the footer
259 | :::
260 | 
261 | :::
262 | 
263 | 
264 | 265 | 266 | 267 |
268 | 269 |

CAROUSEL

270 | 271 | 311 | 312 |


313 | Should be created from 314 |

315 | 
316 | ::: carousel 
317 | 
318 | # First slide title
319 | Some content for the first slide.
320 | 
321 | # Second slide title
322 | Some content for the second slide.
323 | 
324 | # Third slide title
325 | Some content for the third slide.
326 | 
327 | :::
328 | 
329 | 
330 | 331 | 332 | 333 | 334 | 335 |
336 | 337 |

ACCORDION

338 |
Click on each drawer title to unfold the level of the accordion.
339 |


340 |
341 |
342 |

343 | 346 |

347 |
348 |
349 | Content of the first accordion 350 |
351 |
352 |
353 |
354 |

355 | 358 |

359 |
360 |
361 | Content of the second accordion 362 |
363 |
364 |
365 |
366 |

367 | 370 |

371 |
372 |
373 | Content of the third accordion 374 |
375 |
376 |
377 |
378 | 379 | 380 |


381 |
Should be created from:
382 | 383 |

384 | 
385 | ::: accordion
386 | 
387 | # Accordion Item #1
388 | First accordion content
389 | 
390 | # Accordion Item #2
391 | Second accordion content
392 | 
393 | # Accordion Item #3
394 | Third accordion content
395 | 
396 | :::
397 | 
398 | 
399 | 400 | 401 | 402 | 403 |
404 | 405 |

TABS

406 |
Click on each "tab" to see the content of the card change
407 | 408 | 409 | 410 |


411 |
412 | 424 |
425 | 426 |
427 | 428 | 432 | 436 | 440 | 441 |
442 | 443 | 444 | 445 |


446 |
Should be created from
447 | 448 |

449 | 
450 | ::: tabs
451 | 
452 | # Linux
453 | ## Support for Linux users
454 | Create a shell script
455 | 
456 | # Mac
457 | ## Support for Mac users
458 | Do it with Cmd.
459 | 
460 | # Windows
461 | ## Support for windows users
462 | Do it with Ctrl
463 | 
464 | :::
465 | 
466 | 
467 | 468 | 469 | 470 | 471 |


472 |


473 |


474 | 475 |
476 |

Swyping quiz

477 | 478 | 479 |
480 | 562 | 563 |


564 |


565 |


566 |


567 |


568 |


569 | It should simply be created from this code 570 | 571 |

572 | ::: quiz carousel
573 | 
574 | # 2 most frequent questions
575 | Earn points for the exam
576 | 
577 | 
578 | # Which bootstrap component can be swyped?
579 | * Carousel
580 |   * Perfect! yes the carousel has controls to swype on mobile and click on desktop.
581 | * Accordion
582 | * Alert
583 | * Carddeck
584 | 
585 | # Which language takes indentation very seriously?
586 | * javascript
587 | * Php
588 | * Python
589 |   * yes in Python indenting code is very important
590 | 
591 | 
592 | :::
593 | 
594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 |
602 | 603 |

Buttons

604 | Links are converted to buttons by default 605 |

606 | 607 |

You can Click me

608 | 609 |
Is created from the code
610 |

611 | [Pandoc repository](https://github.com/pandoc)
612 | 
613 | 
614 | 615 | 616 | Pandoc repository 617 | 618 |
Is created from the code
619 |

620 | [Pandoc repository](https://github.com/pandoc){.success}
621 | 
622 | 
623 | 624 | 625 | 626 |
627 | 628 |

Embeds

629 | YouTube video are turned into embed 630 | 631 |

632 | [Moodle Bootstrap Design](https://www.youtube.com/watch?v=Uz7XbIxHf-4) 633 |

634 | 635 |
636 | 637 |
638 | 639 | 640 |
641 | 642 |

Icons

643 | 644 | 645 | 646 |
Should be created from:
647 | 648 |

649 | {.bi-bootstrap}
650 | 
651 |
Or even:
652 |

653 | (.bi-bootstrap)
654 | 
655 | 656 |
But currently requires the full syntax to work:
657 | 658 |

659 | 
660 | []{.bi .bi-bootstrap}
661 | 
662 | 
663 | 664 | 665 | 666 | 667 | 668 |
669 | 670 | 671 | -------------------------------------------------------------------------------- /input.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown to Bootstrap 3 | author: François Parlant 4 | description: Pandoc Lua filter to convert markdown code into Beautiful Bootstrap components (carousel, accordion, cards, jumbotrons...) 5 | url: https://fxpar.github.io/Pandoc-Lua-Markdown-Bootstrap/ 6 | iconprefix: bi 7 | --- 8 | 9 | 10 | # JUMBOTRON 11 | 12 | ::: jumbotron 13 | 14 | # Learn Markdown 15 | 16 | Lead text for this header block 17 | 18 | Description part for this jumbotron 19 | 20 | ::: 21 | 22 | 23 | # JUMBOTRON COLORED 24 | 25 | ::: {.jumbotron .bg-success .text-white} 26 | 27 | # Learn Boostrap 28 | 29 | Lead text for this header block 30 | 31 | Description part for this jumbotron 32 | 33 | ::: 34 | 35 | 36 | 37 | # ALERTS 38 | 39 | ::: danger 40 | 41 | You must do this to be safe 42 | 43 | ::: 44 | 45 | 46 | 47 | ::: info 48 | 49 | This is an information 50 | 51 | ::: 52 | 53 | 54 | ::: warning 55 | 56 | []{.bi .bi-bug} This is an information 57 | 58 | ::: 59 | 60 | 61 | 62 | # CARD 63 | 64 | ::: card :::::::: 65 | 66 | ::: header 67 | 68 | text of the header 69 | 70 | ::: 71 | 72 | # a title in the body 73 | 74 | Paragraph one of the body 75 | Paragraph two of the body 76 | 77 | ::: footer 78 | 79 | text of the footer 80 | 81 | ::: 82 | 83 | :::::::::::::::::: 84 | 85 | 86 | 87 | 88 | 89 | # ACCORDION 90 | 91 | 92 | ::: accordion 93 | 94 | # Accordion Item #1 95 | First toggle content 96 | 97 | # Accordion Item #2 98 | Second toggle content 99 | 100 | # Accordion Item #3 101 | Third toggle content 102 | 103 | ::: 104 | 105 | 106 | 107 | 108 | 109 | # CAROUSEL 110 | 111 | ::: carousel 112 | 113 | # First slide label 114 | Some representative placeholder content for the first slide. 115 | 116 | # Second slide label 117 | Some representative placeholder content for the second slide. 118 | 119 | # Third slide label 120 | Some representative placeholder content for the third slide. 121 | 122 | ::: 123 | 124 | 125 | 126 | 127 | 128 | # TABS 129 | 130 | ::: tabs 131 | 132 | # Linux 133 | 134 | ## Support for Linux users 135 | 136 | Create a shell script 137 | 138 | # Mac 139 | 140 | ## Support for Mac users 141 | 142 | Do it with Cmd. 143 | 144 | # Windows 145 | 146 | ## Support for windows users 147 | 148 | Do it with Ctrl 149 | 150 | ::: 151 | 152 | 153 | 154 | ::: quiz 155 | 156 | # this is the question? 157 | 158 | * at the start 159 | * something else 160 | * feedback for this 161 | * the end 162 | 163 | ::: 164 | 165 | 166 | 167 | 168 | ::: {.quiz .carousel} 169 | 170 | # 2 most frequent questions 171 | Earn points for the exam 172 | 173 | 174 | # Which bootstrap component can be swyped? 175 | * Carousel 176 | * Perfect! yes the carousel has controls to swype on mobile and click on desktop. 177 | Second paragraph of feedback 178 | * Accordion 179 | * Alert 180 | * Carddeck 181 | 182 | # Which language takes indentation very seriously? 183 | * javascript 184 | * Php 185 | * Python 186 | * yes in Python indenting code is very important 187 | 188 | 189 | ::: 190 | 191 | 192 | # BUTTONS 193 | 194 | [Pandoc repository](https://github.com/pandoc) 195 | 196 | [Pandoc repository](https://github.com/pandoc){.success} 197 | 198 | 199 | # EMBEDS 200 | 201 | [Moodle Bootstrap Design](https://www.youtube.com/watch?v=Uz7XbIxHf-4) 202 | 203 | 204 | [Youtube video with sharing links](https://www.youtube.com/watch?v=JdeyVMi2W8U){.social} 205 | 206 | 207 | # Icons 208 | 209 | I love []{.bi .bi-bootstrap} with markdown. 210 | 211 | 212 | 213 | # normal chapter 214 | * a normal list 215 | * with items 216 | * or more 217 | * to finish -------------------------------------------------------------------------------- /md-to-bootstrap5.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | -- title: Markdown to Bootstrap Lua filter for Pandoc 3 | -- author: François Parlant 4 | -- with lots of help from tarleb 5 | -- version: 0.1 6 | --]] 7 | 8 | -- TODO mytoc 9 | local filter_class, normal_filter, special_filter, carousel_filter, tabs_filter, accordion_filter, card_filter, carddeck_filter, alert_filter, jumbotron_filter, quiz_filter 10 | local mytoc='' 11 | local num = 1 12 | local section_num = 0 13 | local paranum = 0 14 | local tabs_title_list = '' 15 | local tabs_h1_num =0 16 | local accordion_h1_num =0 17 | local carousel_h1_num =0 18 | local icon_prefix ='bi' 19 | 20 | 21 | 22 | -- jumbo 23 | -- TODO stop section to add "Display-4" from title or stop section 24 | jumbotron_filter = { 25 | traverse = 'topdown', 26 | Header = function(el) 27 | local mytitle = pandoc.utils.stringify(el) 28 | el.classes = {'display-4'} 29 | -- print(make_id(pandoc.Inlines (pandoc.utils.stringify(el)))) 30 | return el 31 | end, 32 | Para = function (para) 33 | paranum = paranum + 1 34 | if paranum == 1 then 35 | 36 | 37 | return pandoc.Plain( 38 | {pandoc.RawInline('html', '

')} .. 39 | para.content .. 40 | {pandoc.RawInline('html', '

\n
')} 41 | ) 42 | else 43 | return para 44 | end 45 | end 46 | 47 | } 48 | 49 | -- alert 50 | alert_filter = { 51 | traverse = 'topdown', 52 | print("ALERT") 53 | } 54 | 55 | 56 | -- card 57 | -- TODO put a card-body div around the content 58 | card_filter = { 59 | traverse = 'topdown', 60 | Header = function(el) 61 | local mytitle = pandoc.utils.stringify(el) 62 | el.classes = {'specialHeader'} 63 | print(make_id(pandoc.Inlines (pandoc.utils.stringify(el)))) 64 | return el 65 | end, 66 | Div = function (el) 67 | print('CARD:::'..el.classes[1]) 68 | if el.classes[1] == 'header' then 69 | -- mylist = mylist .. '\n' 70 | el.classes = {'card-header'} 71 | return el 72 | elseif el.classes[1] == 'footer' then 73 | el.classes = {'card-footer'} 74 | return el 75 | else 76 | return el 77 | end 78 | end 79 | } 80 | 81 | -- cardddeck 82 | -- NOT DONE 83 | carddeck_filter = { 84 | traverse = 'topdown', 85 | Header = function(el) 86 | local mytitle = pandoc.utils.stringify(el) 87 | el.classes = {'specialHeader'} 88 | print(make_id(pandoc.Inlines (pandoc.utils.stringify(el)))) 89 | return el 90 | end, 91 | BulletList = function (el) 92 | local mylist ='\n' 100 | return pandoc.RawInline('html', mylist) 101 | end 102 | } 103 | 104 | 105 | 106 | 107 | -- carousel 108 | carousel_filter = { 109 | traverse = 'topdown', 110 | Header = function(el) 111 | if el.level==1 then 112 | local active ='active' 113 | local before ='' 114 | carousel_h1_num = carousel_h1_num + 1 115 | if carousel_h1_num == 1 then 116 | active = 'active' 117 | before = '' 118 | else 119 | active='' 120 | before ='' 121 | end 122 | -- TODO add the num of the carousel in case 123 | -- there are more than one in the document 124 | local pre =pandoc.RawBlock('html',before..[[ 125 | ' 159 | end 160 | -- TODO add the num of the accordion in case 161 | -- there are more than one in the document 162 | local pre =pandoc.RawBlock('html',before..[[ 163 | 164 |
165 |

166 | 169 |

170 |
171 |
172 | 173 | ]]) 174 | local post =pandoc.RawBlock('html','') 175 | local content = el.content 176 | table.insert(content,1,pre) 177 | table.insert(content, post) 178 | return content 179 | else 180 | return el 181 | end 182 | 183 | end 184 | } 185 | 186 | 187 | 188 | -- Tabs 189 | tabs_filter = { 190 | traverse = 'topdown', 191 | Header = function(el) 192 | -- we need to process twice the level 1 headings 193 | -- once to create the card header 194 | -- once to process the content 195 | if el.level==1 then 196 | print("TABS_TITLE_1") 197 | -- create the tab header 198 | local show = '' 199 | -- we want to add the "show active" class only to the first h1 200 | tabs_h1_num = tabs_h1_num + 1 201 | if tabs_h1_num == 1 then show = 'show active' end 202 | tabs_title_list = tabs_title_list .. '' 203 | show ='' 204 | 205 | -- create the tab content 206 | local active = '' 207 | local pre ='' 208 | 209 | if tabs_h1_num == 1 then 210 | active = '' 211 | -- we close the tab header and we add active 212 | pre = pandoc.RawBlock('html','
\n\n
\n\t
') 447 | table.insert(content,1,pre) 448 | table.insert(content, post) 449 | -- reset accordion_h1_num for another tab in document 450 | accordion_h1_num = 0 451 | return content 452 | end 453 | 454 | 455 | 456 | 457 | 458 | function make_carousel(div) 459 | section_id = section_num + 1 460 | filter = carousel_filter 461 | local content = pandoc.walk_block(div,carousel_filter).content 462 | local pre = pandoc.RawBlock('html',' 465 | 469 | 473 |
]]) 474 | table.insert(content,1,pre) 475 | table.insert(content, post) 476 | -- reset carousel_h1_num for another tab in document 477 | carousel_h1_num = 0 478 | return content 479 | end 480 | 481 | function make_tabs(div) 482 | -- filter = tabs_filter 483 | -- we need to insert the tab header 484 | -- before we add the content 485 | local content = pandoc.walk_block(div,tabs_filter).content 486 | local pre = pandoc.RawBlock('html','
') 487 | -- we close last menu and content 488 | local post = pandoc.RawBlock('html','
') 489 | table.insert(content,1,pre) 490 | table.insert(content, post) 491 | -- reset tabs_h1_num for another tab in document 492 | tabs_h1_num = 0 493 | return content 494 | 495 | end 496 | 497 | 498 | function make_id (inlines, via) 499 | local via = via or 'html' 500 | local heading = pandoc.Header(1, inlines) 501 | local temp_doc = pandoc.Pandoc{heading} 502 | local roundtripped_doc = pandoc.read(pandoc.write(temp_doc, via), via) 503 | return roundtripped_doc.blocks[1].identifier 504 | end 505 | 506 | function sanitize_string(source) 507 | return source:gsub("%W", function(ch) 508 | return string.gsub(string.format("%%%02X", ch:byte())," ","") 509 | end) 510 | end 511 | 512 | function addToToc(el) 513 | print("TOC: "..pandoc.utils.stringify(el)) 514 | mytoc = mytoc ..'
  • '.. pandoc.utils.stringify(el).."
  • " 515 | num = num + 1 516 | return true 517 | end 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | function make_social(el, includelink, result) 526 | -- local post = make_social(el) 527 | local content=pandoc.utils.stringify(el.content) 528 | local content_e = urlencode(content) 529 | local target = el.target 530 | local target_e = urlencode(target) 531 | -- local mysocial = 'finished' 532 | local mysocial = [[ 533 | 534 | 535 |
  • Facebook
  • 536 | 537 | 538 |
  • Twitter
  • 539 | 540 |
  • LinkedIn
  • 541 | 542 |
  • Whatsapp
  • 543 | 544 |
  • Telegram
  • 545 | 546 |
  • Mail
  • 548 | 549 | 550 | ]] 551 | 552 | local post = pandoc.RawInline('html',mysocial) 553 | -- print(el.content) 554 | if result == 'string' then return mysocial end 555 | if includelink == false then 556 | return post 557 | else 558 | return {el, post} 559 | end 560 | end 561 | 562 | -- we need to modify the doc AT THE END to add the toc 563 | function makeTOC(doc) 564 | doc.meta.toc = pandoc.RawInline('html',"\n"..mytoc) 565 | return doc 566 | end 567 | 568 | 569 | --used to create the social links url with special chars converted to hex 570 | function urlencode (str) 571 | str = string.gsub (str, "([^0-9a-zA-Z!'()*._~-])", -- locale independent 572 | function (c) return string.format ("%%%02X", string.byte(c)) end) 573 | --str = string.gsub (str, " ", "+") 574 | return str 575 | end 576 | 577 | 578 | 579 | 580 | 581 | 582 | -------------------------------------------------------------------------------- /media/accordion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/accordion.gif -------------------------------------------------------------------------------- /media/alertdanger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/alertdanger.png -------------------------------------------------------------------------------- /media/alertinfo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/alertinfo.png -------------------------------------------------------------------------------- /media/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/button.png -------------------------------------------------------------------------------- /media/buttonsuccess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/buttonsuccess.png -------------------------------------------------------------------------------- /media/card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/card.png -------------------------------------------------------------------------------- /media/carousel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/carousel.gif -------------------------------------------------------------------------------- /media/carouselquiz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/carouselquiz.gif -------------------------------------------------------------------------------- /media/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/icon.png -------------------------------------------------------------------------------- /media/jumbotron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/jumbotron.png -------------------------------------------------------------------------------- /media/quiz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/quiz.gif -------------------------------------------------------------------------------- /media/tabs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/tabs.gif -------------------------------------------------------------------------------- /media/youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter/0c2d7a23872bec52c35df3eae282848ff64ea7f6/media/youtube.png -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | # Bootstrap Template for pandoc 2 | 3 | A template to add some basic bootstrap architecture around a document. 4 | 5 | 6 | * meta 7 | * title 8 | * author 9 | * description 10 | * base 11 | * css 12 | * bootstrap 5 min 13 | * bootstrap icons 14 | * sidebar (for turning chevrons) 15 | * scripts 16 | * bootstrap 5 min 17 | * sidebar 18 | * table of content 19 | 20 | 21 | ## Usage 22 | 23 | This template can be applied to other formats than markdown. 24 | 25 | pandoc input.md --template bs5.template.html -o output.html 26 | 27 | 28 | 29 | ## Markdown 30 | 31 | ``` 32 | --- 33 | title: Markdown to Bootstrap 34 | author: François Parlant 35 | description: Pandoc Lua filter to convert markdown code into Beautiful Bootstrap components (carousel, accordion, cards, jumbotrons...) 36 | 37 | --- 38 | 39 | # title one of the document 40 | 41 | Some introduction text 42 | 43 | ## A level 2 title 44 | 45 | Some text 46 | 47 | # another level 1 title 48 | 49 | More text 50 | 51 | ``` 52 | 53 | ## References 54 | 55 | * Used by the [markdown to bootstrap](https://github.com/fxpar/markdown-to-bootstrap-pandoc-lua-filter) components filter 56 | -------------------------------------------------------------------------------- /template/bs5.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $if(author)$ $endif$ 6 | $if(title)$ $title$ $endif$ 7 | 8 | 9 | 10 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
    28 | 29 | 30 | 53 | 54 |
    55 |
    56 |
    $if(title)$ $title$ $endif$
    57 | 58 |
    59 |
    60 | 61 |
      62 |
    • 63 | $if(toc)$ 64 |
    • 65 | 66 | 73 |
    • 74 |
    • 75 | 76 | $endif$ 77 | 78 |
    • 79 | 80 |
      81 | 89 |
      90 |
    • 91 |
    • 92 |
    • François Parlant
    • 93 |
    94 | 95 |
    96 |
    97 | $if(title)$

    $title$

    $endif$ 98 | 99 | $for(include-before)$ 100 | $include-before$ 101 | $endfor$ 102 | 103 | $body$ 104 | 105 | $for(include-after)$ 106 | $include-after$ 107 | $endfor$ 108 |
    109 | 110 | -------------------------------------------------------------------------------- /test/bs5.bat: -------------------------------------------------------------------------------- 1 | pandoc input.md --lua-filter ..\docs\md-to-bootstrap5.lua --template ..\template\bs5.template.html -o result-v2.html 2 | 3 | 4 | pandoc sample.md --lua-filter bootstrap.lua -o result.html --template bs5.template.html -f markdown+inline_code_attributes 5 | 6 | 7 | 8 | 9 | 10 | -f commonmark+attributes 11 | 12 | ou 13 | 14 | -f markdown+raw_attribute 15 | -f markdown+inline_code_attributes 16 | 17 | -f gsm+task_lists 18 | -------------------------------------------------------------------------------- /test/css/sidebar.css: -------------------------------------------------------------------------------- 1 | body { 2 | min-height: 100vh; 3 | min-height: -webkit-fill-available; 4 | } 5 | 6 | html { 7 | height: -webkit-fill-available; 8 | } 9 | 10 | main { 11 | display: flex; 12 | flex-wrap: nowrap; 13 | height: 100vh; 14 | height: -webkit-fill-available; 15 | max-height: 100vh; 16 | overflow-x: auto; 17 | overflow-y: hidden; 18 | } 19 | 20 | .b-example-divider { 21 | flex-shrink: 0; 22 | width: 1.5rem; 23 | height: 100vh; 24 | background-color: rgba(0, 0, 0, .1); 25 | border: solid rgba(0, 0, 0, .15); 26 | border-width: 1px 0; 27 | box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15); 28 | } 29 | 30 | .bi { 31 | vertical-align: -.125em; 32 | pointer-events: none; 33 | fill: currentColor; 34 | } 35 | 36 | .dropdown-toggle { outline: 0; } 37 | 38 | .nav-flush .nav-link { 39 | border-radius: 0; 40 | } 41 | 42 | .btn-toggle { 43 | display: inline-flex; 44 | align-items: center; 45 | padding: .25rem .5rem; 46 | font-weight: 600; 47 | color: rgba(0, 0, 0, .65); 48 | background-color: transparent; 49 | border: 0; 50 | } 51 | .btn-toggle:hover, 52 | .btn-toggle:focus { 53 | color: rgba(0, 0, 0, .85); 54 | background-color: #d2f4ea; 55 | } 56 | 57 | .btn-toggle::before { 58 | width: 1.25em; 59 | line-height: 0; 60 | content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e"); 61 | transition: transform .35s ease; 62 | transform-origin: .5em 50%; 63 | } 64 | 65 | .btn-toggle[aria-expanded="true"] { 66 | color: rgba(0, 0, 0, .85); 67 | } 68 | .btn-toggle[aria-expanded="true"]::before { 69 | transform: rotate(90deg); 70 | } 71 | 72 | .btn-toggle-nav a { 73 | display: inline-flex; 74 | padding: .1875rem .5rem; 75 | margin-top: .125rem; 76 | margin-left: 1.25rem; 77 | text-decoration: none; 78 | } 79 | .btn-toggle-nav a:hover, 80 | .btn-toggle-nav a:focus { 81 | background-color: #d2f4ea; 82 | } 83 | 84 | .scrollarea { 85 | overflow-y: auto; 86 | } 87 | 88 | .fw-semibold { font-weight: 600; } 89 | .lh-tight { line-height: 1.25; } 90 | -------------------------------------------------------------------------------- /test/result-v2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Markdown to Bootstrap 7 | 8 | 9 | 10 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
    28 | 29 | 30 | 68 | 69 |
    70 |
    71 |
    Markdown to 72 | Bootstrap
    73 | 74 |
    75 |
    76 | 77 | 109 | 110 |
    111 |
    112 |

    Markdown to Bootstrap

    113 | 114 | 115 | 116 |

    JUMBOTRON

    117 |
    118 |

    Learn Markdown

    119 |

    Lead text for this header block

    120 |
    121 |

    Description part for this jumbotron

    122 |
    123 |

    JUMBOTRON COLORED

    124 |
    125 |

    Learn Boostrap

    126 |

    Lead text for this header block

    127 |
    128 |

    Description part for this jumbotron

    129 |
    130 |

    ALERTS

    131 |
    132 |

    You must do this to be safe

    133 |
    134 |
    135 |

    This is an information

    136 |
    137 |
    138 |

    This is an information

    139 |
    140 |

    CARD

    141 |
    142 |
    143 |

    text of the header

    144 |
    145 |

    a title in the 146 | body

    147 |

    Paragraph one of the body Paragraph two of the body

    148 | 151 |
    152 |

    ACCORDION

    153 |
    154 | 155 |
    156 |

    157 | 159 |

    160 |
    161 |
    162 | 163 | 164 | Accordion 165 | 166 | Item 167 | 168 | #1 169 | 170 |

    First toggle content

    171 |
    172 |
    173 |

    174 | 176 |

    177 |
    178 |
    179 | 180 | 181 | Accordion 182 | 183 | Item 184 | 185 | #2 186 | 187 |

    Second toggle content

    188 |
    189 |
    190 |

    191 | 193 |

    194 |
    195 |
    196 | 197 | 198 | Accordion 199 | 200 | Item 201 | 202 | #3 203 | 204 |

    Third toggle content

    205 |
    206 |

    CAROUSEL

    207 | 250 |

    TABS

    251 |
    252 |
    253 | 254 |
    255 |
    271 |
    272 |

    special chapter

    273 | 278 | 279 |
    280 | 304 |

    BUTTONS

    305 |

    Pandoc repository

    307 |

    Pandoc repository

    309 |

    EMBEDS

    310 |

    311 |

    312 | 313 |
    314 | 315 | 316 |

    317 |

    318 |

    319 | 320 |
    321 |
    322 | 325 | 343 |
    344 | 345 | 346 |

    347 |

    Icons

    348 |

    I love with markdown.

    349 |

    normal chapter

    350 | 356 | 357 |
    358 | 359 | --------------------------------------------------------------------------------