From d1c63d8ac5b5d9adefc407f251c9e74471d1251b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Fri, 16 May 2025 14:07:01 +0200 Subject: [PATCH 01/22] some progress --- src/nimiSlides.nim | 267 ++++++++++++++++++++++++++++++++------------- 1 file changed, 190 insertions(+), 77 deletions(-) diff --git a/src/nimiSlides.nim b/src/nimiSlides.nim index a0e8802..bd68eb2 100644 --- a/src/nimiSlides.nim +++ b/src/nimiSlides.nim @@ -1,4 +1,4 @@ -import std/[strutils, strformat, sequtils, os] +import std/[strutils, strformat, sequtils, os, json] export os import nimib import nimib/[capture, config] @@ -56,28 +56,6 @@ proc slideOptions*(autoAnimate = false, iframeInteractive = true, colorBackgroun const reveal_version* = "5.0.4" -const document = """ - - - {{> head}} - - {{> main}} - - -""" - -const head = """ - - - {{> revealCSS }} - {{#nb_style}} - - {{/nb_style}} - -""" - const main = """
@@ -118,14 +96,95 @@ const main = """ """ -const revealCSS = """ +func revealMainToHtml*(doc: NbDoc, nb: Nb): string = + let docJson = %[] # it's unused + let renderedBlocks = nbContainerToHtml(doc, nb) + result = withNewlines: + hlHtmlF""" +
+
+ {renderedBlocks} +
+
+ """ + nb.renderPartial("revealJS", docJson) + "" + +#[ const document = """ + + + {{> head}} + + {{> main}} + + +""" ]# + +func revealNbDocToHtml*(blk: NbBlock, nb: Nb): string = + let doc = blk.NbDoc + let docJson = %[] # it's unused + result = withNewlines: + "" + """""" + nb.renderPartial("head", docJson) + "" + revealMainToHtml(doc, nb) + "" + "" + +func revealHeadToHtml*(blk: JsonNode, nb: Nb): string = + let nbStyle = nb.doc.context{"nb_style"} + result = withNewLines: + "" + """""" + nb.renderPartial("revealCSS", blk) + if nbStyle.len > 0: + fmt""" + + """ + "" + +#[ const head = """ + + + {{> revealCSS }} + {{#nb_style}} + + {{/nb_style}} + +""" ]# + +const revealCSS = hlHtml""" """ -const revealJS = """ +func revealCSSToHtml*(blk: JsonNode, nb: Nb): string = + let revealVersion = nb.doc.context{"reveal_version"}.getStr + let slidesTheme = nb.doc.context{"slidesTheme"}.getStr + result = hlHtmlF""" + + + +""" + +const revealJS = hlHtml""" @@ -134,25 +193,82 @@ const revealJS = """ {{/latex}} """ -proc useLocalReveal*(nb: var NbDoc, path: string) = - let path = nb.homeDir.string / path - let themeString = "{{{slidesTheme}}}" - nb.partials["revealCSS"] = fmt""" +func revealJSToHtml*(blk: JsonNode, nb: Nb): string = + let revealVersion = nb.doc.context{"reveal_version"}.getStr + result = withNewLines: + hlHtmlF""" + + + + """ + if nb.doc.context{"latex"}.getBool: + hlHtmlF"""""" + +proc localRevealCss*(blk: JsonNode, nb: Nb): string = + let path = nb.doc.homeDir.string / nb.doc.context{"local_reveal_path"}.getStr + result = fmt""" - + """ - - let latexStart = "{{#latex}}" - let latexEnd = "{{/latex}}" - nb.partials["revealJS"] = fmt""" + +proc localRevealJs*(blk: JsonNode, nb: Nb): string = + let path = nb.doc.homeDir.string / nb.doc.context{"local_reveal_path"}.getStr + result = withNewlines: + fmt""" -{latexStart} - -{latexEnd} - """ + """ + if nb.doc.context{"latex"}.getBool(true): + fmt"""""" + +func nimiSlidesNbCodeSourcePartial*(blk: JsonNode, nb: Nb): string = + let code = blk{"code"}.getStr + if code.len > 0: + &"
{code.highlightNim}
" + else: + "" + +func nimiSlidesNbCodeOutputPartial*(blk: JsonNode, nb: Nb): string = + let output = blk{"output"}.getStr + if output.len > 0: + #&"
{output}
" + &"
{output}
" + else: + "" + + + +newNbBlock(NbAnimateCode of NbCode): + highlightedLines: seq[seq[int]] + toHtml: + withNewLines: + nb.renderPartial("animateCodeSource", jsonutils.toJson(blk)) + nbContainerToHtml(blk, nb) + nb.renderPartial("nbCodeOutput", jsonutils.toJson(blk)) + +# "
{{&codeHighlighted}}
\n" & nb.backend.partials["nbCodeOutput"] +func highlightedLinesToString*(lines: seq[seq[int]]): string = + var linesString: string + if lines.len > 0: + linesString &= "|" + for lineBundle in lines: + for line in lineBundle: + linesString &= $line & "," + linesString &= "|" + if lines.len > 0: + linesString = linesString[0 .. ^3] + return linesString + +func nimiSlidesAnimateCodeSourcePartial*(blk: JsonNode, nb: Nb): string = + let highlightedLinesString = blk{"highlightedLines"}.to(seq[seq[int]]).highlightedLinesToString() + result = nimiSlidesNbCodeSourcePartial(blk, nb).replace("data-line-numbers", &"data-line-numbers=\"{highlightedLinesString}\"") + +proc useLocalReveal*(nb: var Nb, path: string) = + nb.doc.context["local_reveal_path"] = %path + nb.backend.partials["revealCSS"] = localRevealCss + nb.backend.partials["revealJS"] = localRevealJs template setSlidesTheme*(theme: SlidesTheme) = nb.context["slidesTheme"] = ($theme).toLower @@ -170,46 +286,50 @@ template disableVerticalCentering*() = template useScrollView*() = nb.context["useScrollView"] = true -proc addStyle*(doc: NbDoc, style: string) = - doc.context["nb_style"] = doc.context["nb_style"].vString & "\n" & style +proc addStyle*(nb: var Nb, style: string) = + nb.doc.context["nb_style"] = %(nb.doc.context{"nb_style"}.getStr & "\n" & style) + +proc revealTheme*(nb: var Nb) = + #nb.backend.partials["document"] = document + nb.backend.funcs["NbDoc"] = revealNbDocToHtml + nb.backend.partials["head"] = revealHeadToHtml + #nb.backend.partials["main"] = main + + nb.backend.partials["nbCodeSource"] = nimiSlidesNbCodeSourcePartial + nb.backend.partials["nbCodeOutput"] = nimiSlidesNbCodeOutputPartial -proc revealTheme*(doc: var NbDoc) = - doc.partials["document"] = document - doc.partials["head"] = head - doc.partials["main"] = main - doc.partials["nbCodeSource"] = "
{{&codeHighlighted}}
" - doc.partials["nbCodeOutput"] = "{{#output}}
{{output}}
{{/output}}" + nb.backend.partials["animateCodeSource"] = nimiSlidesAnimateCodeSourcePartial - doc.partials["revealCSS"] = revealCSS - doc.partials["revealJS"] = revealJS + nb.backend.partials["revealCSS"] = revealCSSToHtml + nb.backend.partials["revealJS"] = revealJSToHtml - doc.partials["animateCode"] = "
{{&codeHighlighted}}
\n" & doc.partials["nbCodeOutput"] - doc.renderPlans["animateCode"] = doc.renderPlans["nbCode"] + #[ nb.backend.partials["animateCode"] = "
{{&codeHighlighted}}
\n" & nb.backend.partials["nbCodeOutput"] + #doc.renderPlans["animateCode"] = doc.renderPlans["nbCode"] - doc.partials["fragmentStart"] = """ + nb.backend.partials["fragmentStart"] = """ {{#fragments}}
{{/fragments}} """ - doc.partials["fragmentEnd"] = """ + nb.backend.partials["fragmentEnd"] = """ {{#fragments}}
{{/fragments}} """ - doc.partials["bigText"] = """

{{&outputToHtml}}

""" - doc.renderPlans["bigText"] = doc.renderPlans["nbText"] + nb.backend.partials["bigText"] = """

{{&outputToHtml}}

""" ]# + #doc.renderPlans["bigText"] = doc.renderPlans["nbText"] - doc.context["slidesTheme"] = "black" - doc.context["nb_style"] = "" - doc.context["reveal_version"] = reveal_version + nb.doc.context["slidesTheme"] = %"black" + nb.doc.context["nb_style"] = %"" + nb.doc.context["reveal_version"] = %reveal_version try: - let slidesConfig = loadTomlSection(doc.rawCfg, "nimislides", NimiSlidesConfig) + let slidesConfig = loadTomlSection(nb.doc.rawCfg, "nimislides", NimiSlidesConfig) if slidesConfig.localReveal != "": echo "Using local Reveal.js installation specified in nimib.toml " - doc.useLocalReveal(slidesConfig.localReveal) + nb.useLocalReveal(slidesConfig.localReveal) except CatchableError: discard # if it doesn't exists, just let it be @@ -400,12 +520,6 @@ template listItem*(animation: FragmentAnimation, body: untyped) = template listItem*(body: untyped) = listItem(fadeInThenSemiOut, body) -template animateCode*(lines: string, body: untyped) = - newNbCodeBlock("animateCode", body): - nb.blk.context["highlightLines"] = lines - captureStdout(nb.blk.output): - body - template animateCode*(lines: varargs[set[range[0..65535]], toSet], body: untyped) = ## Shows code and its output just like nbCode, but highlights different lines of the code in the order specified in `lines`. ## lines: Specify which lines to highlight and in which order. The lines can be specified using either: @@ -417,19 +531,18 @@ template animateCode*(lines: varargs[set[range[0..65535]], toSet], body: untyped ## animateCode(1, 2..3, {4, 6}): body ## ``` ## This will first highlight line 1, then lines 2 and 3, and lastly line 4 and 6. - newNbCodeBlock("animateCode", body): - var linesString: string - if lines.len > 0: - linesString &= "|" - for lineBundle in lines: - for line in lineBundle: - linesString &= $line & "," - linesString &= "|" - if lines.len > 0: - linesString = linesString[0 .. ^3] - nb.blk.context["highlightLines"] = linesString - captureStdout(nb.blk.output): + var highlightedLines: seq[seq[int]] + for line in lines: + var lineSeq: seq[int] + for l in line: + lineSeq.add l + highlightedLines.add lineSeq + let blk = newNbAnimateCode(highlightedLines=highlightedLines) + blk.code = getCode(body) + nb.withContainer(blk): + captureStdout(blk.output): body + nb.add blk template newAnimateCodeBlock*(cmd: untyped, impl: untyped) = const cmdStr = astToStr(cmd) From b79ee1ea5fd4c46a5f37781491417faff4e495fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Fri, 16 May 2025 14:34:59 +0200 Subject: [PATCH 02/22] slide is ported! --- src/nimiSlides.nim | 72 ++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/src/nimiSlides.nim b/src/nimiSlides.nim index bd68eb2..5a09132 100644 --- a/src/nimiSlides.nim +++ b/src/nimiSlides.nim @@ -238,8 +238,6 @@ func nimiSlidesNbCodeOutputPartial*(blk: JsonNode, nb: Nb): string = else: "" - - newNbBlock(NbAnimateCode of NbCode): highlightedLines: seq[seq[int]] toHtml: @@ -265,6 +263,39 @@ func nimiSlidesAnimateCodeSourcePartial*(blk: JsonNode, nb: Nb): string = let highlightedLinesString = blk{"highlightedLines"}.to(seq[seq[int]]).highlightedLinesToString() result = nimiSlidesNbCodeSourcePartial(blk, nb).replace("data-line-numbers", &"data-line-numbers=\"{highlightedLinesString}\"") +newNbBlock(NbSlide of NbContainer): + options: SlideOptions + slideNumber: int + toHtml: + withNewLines: + nb.renderPartial("slideStart", jsonutils.toJson(blk)) + nbContainerToHtml(blk, nb) + nb.renderPartial("slideEnd", jsonutils.toJson(blk)) + +proc slideOptionsToAttributes*(options: SlideOptions, slideNumber: int): string = + result.add """data-nimib-slide-number="$1" """ % [$slideNumber] + if options.autoAnimate: + result.add "data-auto-animate " + if options.colorBackground.len > 0: + result.add """data-background-color="$1" """ % [options.colorBackground] + elif options.imageBackground.len > 0: + result.add """data-background-image="$1" """ % [options.imageBackground] + elif options.videoBackground.len > 0: + result.add """data-background-video="$1" """ % [options.videoBackground] + elif options.iframeBackground.len > 0: + result.add """data-background-iframe="$1" """ % [options.iframeBackground] + if options.iframeInteractive: + result.add "data-background-interactive " + elif options.gradientBackground.len > 0: + result.add """data-background-gradient="$1" """ % [options.gradientBackground] + +func nimiSlidesSlideStartPartial*(blk: JsonNode, nb: Nb): string = + let optionsStr = blk{"options"}.to(SlideOptions).slideOptionsToAttributes(blk{"slideNumber"}.getInt) + result = &"
" + +func nimiSlidesSlideEndPartial*(blk: JsonNode, nb: Nb): string = + "
" + proc useLocalReveal*(nb: var Nb, path: string) = nb.doc.context["local_reveal_path"] = %path nb.backend.partials["revealCSS"] = localRevealCss @@ -303,9 +334,9 @@ proc revealTheme*(nb: var Nb) = nb.backend.partials["revealCSS"] = revealCSSToHtml nb.backend.partials["revealJS"] = revealJSToHtml - #[ nb.backend.partials["animateCode"] = "
{{&codeHighlighted}}
\n" & nb.backend.partials["nbCodeOutput"] - #doc.renderPlans["animateCode"] = doc.renderPlans["nbCode"] - + nb.backend.partials["slideStart"] = nimiSlidesSlideStartPartial + nb.backend.partials["slideEnd"] = nimiSlidesSlideEndPartial + #[ nb.backend.partials["fragmentStart"] = """ {{#fragments}}
@@ -335,39 +366,24 @@ proc revealTheme*(nb: var Nb) = var currentFragment*, currentSlideNumber*: int -proc slideOptionsToAttributes*(options: SlideOptions): string = - result.add """data-nimib-slide-number="$1" """ % [$currentSlideNumber] - if options.autoAnimate: - result.add "data-auto-animate " - if options.colorBackground.len > 0: - result.add """data-background-color="$1" """ % [options.colorBackground] - elif options.imageBackground.len > 0: - result.add """data-background-image="$1" """ % [options.imageBackground] - elif options.videoBackground.len > 0: - result.add """data-background-video="$1" """ % [options.videoBackground] - elif options.iframeBackground.len > 0: - result.add """data-background-iframe="$1" """ % [options.iframeBackground] - if options.iframeInteractive: - result.add "data-background-interactive " - elif options.gradientBackground.len > 0: - result.add """data-background-gradient="$1" """ % [options.gradientBackground] - -template slide*(options: untyped, body: untyped): untyped = +template slide*(toptions: untyped, body: untyped): untyped = currentSlideNumber += 1 - - nbRawHtml: "
" % [slideOptionsToAttributes(options)] + let blk = newNbSlide(slideNumber=currentSlideNumber, options=toptions) + when declaredInScope(CountVarNimiSlide): when CountVarNimiSlide < 2: static: inc CountVarNimiSlide - body + nb.withContainer(blk): + body static: dec CountVarNimiSlide else: {.error: "You can only nest slides once!".} else: var CountVarNimiSlide {.inject, compileTime.} = 1 # we just entered the first level - body + nb.withContainer(blk): + body static: dec CountVarNimiSlide - nbRawHtml: "
" + nb.add blk template slide*(body: untyped) = slide(slideOptions()): From 6e8a63521b5f3043838dd68054e9c1d1936be6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Fri, 16 May 2025 16:04:28 +0200 Subject: [PATCH 03/22] fragments are working!!! --- src/nimiSlides.nim | 80 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/src/nimiSlides.nim b/src/nimiSlides.nim index 5a09132..2a34d5f 100644 --- a/src/nimiSlides.nim +++ b/src/nimiSlides.nim @@ -28,6 +28,10 @@ type highlightCurrentGreen = "highlight-current-green" highlightCurrentBlue = "highlight-current-blue" + FragmentItem* = object + classStr: string + fragIndex: int + SlidesTheme* = enum Black, Beige, Blood, Dracula, League, Moon, Night, Serif, Simple, Sky, Solarized, White @@ -296,6 +300,30 @@ func nimiSlidesSlideStartPartial*(blk: JsonNode, nb: Nb): string = func nimiSlidesSlideEndPartial*(blk: JsonNode, nb: Nb): string = "" +newNbBlock(NbFragment of NbContainer): + fragments: seq[FragmentItem] + toHtml: + withNewLines: + nb.renderPartial("fragmentStart", jsonutils.toJson(blk)) + nbContainerToHtml(blk, nb) + nb.renderPartial("fragmentEnd", jsonutils.toJson(blk)) + +func nimiSlidesFragmentStartPartial*(blk: JsonNode, nb: Nb): string = + if blk{"fragments"}.len > 0: + result = "" + for fragment in blk{"fragments"}: + let classStr = fragment{"classStr"}.getStr + let fragIndex = fragment{"fragIndex"}.getInt + result &= hlHtmlF""" +
+ """ + result &= "\n" + else: + result = "" + +func nimiSlidesFragmentEndPartial*(blk: JsonNode, nb: Nb): string = + "
\n".repeat(blk{"fragments"}.len) + proc useLocalReveal*(nb: var Nb, path: string) = nb.doc.context["local_reveal_path"] = %path nb.backend.partials["revealCSS"] = localRevealCss @@ -336,19 +364,10 @@ proc revealTheme*(nb: var Nb) = nb.backend.partials["slideStart"] = nimiSlidesSlideStartPartial nb.backend.partials["slideEnd"] = nimiSlidesSlideEndPartial - #[ - nb.backend.partials["fragmentStart"] = """ -{{#fragments}} -
-{{/fragments}} - """ - - nb.backend.partials["fragmentEnd"] = """ -{{#fragments}} -
-{{/fragments}} - """ + nb.backend.partials["fragmentStart"] = nimiSlidesFragmentStartPartial + nb.backend.partials["fragmentEnd"] = nimiSlidesFragmentEndPartial + #[ nb.backend.partials["bigText"] = """

{{&outputToHtml}}

""" ]# #doc.renderPlans["bigText"] = doc.renderPlans["nbText"] @@ -393,6 +412,23 @@ template slideAutoAnimate*(body: untyped) = slide(slideOptions(autoAnimate=true)): body +template fragmentCoreOld*(animations: openArray[seq[FragmentAnimation]], endAnimations: openArray[seq[FragmentAnimation]], indexOffset: untyped, incrementCounter: untyped, body: untyped) = + ## Creates a fragment of the content of body. Nesting works. + ## animations: each seq in animations are animations that are to be applied at the same time. The first seq's animations + ## are applied on the first button click, and the second seq's animations on the second click etc. + ## endAnimations: animations that should be applied AT THE END of block. + ## Example: + ## `fragment(@[@[fadeIn, highlightBlue], @[shrinks, semiFadeOut]]): block` will at the first click of a button fadeIn and highlightBlue + ## the content of the block. At the second click the same content will shrink and semiFadeOut. This code is also equivilent with + ## `fragment(@[@[fadeIn, highlightBlue]]): fragment(@[@[shrinks, semiFadeOut]]): block`. + ## `fragment(@[@[fadeIn]], @[@[fadeOut]]): block` will first fadeIn the entire block and perform eventual animations in nested fragments. Once + ## all of those are finished, it will run fadeOut on the entire block and its subfragments. + var fragments: seq[Table[string, string]] + fragmentStartBlock(fragments, animations, endAnimations, indexOffset, incrementCounter) + var startBlock = nb.blk # this *should* be the block created by fragmentStartBlock + body + fragmentEndBlock(fragments, animations, endAnimations, startBlock) + template fragmentStartBlock(fragments: seq[Table[string, string]], animations: openArray[seq[FragmentAnimation]], endAnimations: openArray[seq[FragmentAnimation]], indexOffset: int, incrementCounter: bool) = newNbSlimBlock("fragmentStart"): for level in animations: @@ -432,11 +468,21 @@ template fragmentCore*(animations: openArray[seq[FragmentAnimation]], endAnimati ## `fragment(@[@[fadeIn, highlightBlue]]): fragment(@[@[shrinks, semiFadeOut]]): block`. ## `fragment(@[@[fadeIn]], @[@[fadeOut]]): block` will first fadeIn the entire block and perform eventual animations in nested fragments. Once ## all of those are finished, it will run fadeOut on the entire block and its subfragments. - var fragments: seq[Table[string, string]] - fragmentStartBlock(fragments, animations, endAnimations, indexOffset, incrementCounter) - var startBlock = nb.blk # this *should* be the block created by fragmentStartBlock - body - fragmentEndBlock(fragments, animations, endAnimations, startBlock) + let blk = newNbFragment() + for level in animations: + if level.len > 1 and fadeIn in level: + # Add a fadeIn fragment at the same frame + blk.fragments.add FragmentItem(classStr: "", fragIndex: currentFragment + indexOffset) + blk.fragments.add FragmentItem(classStr: level.join(" "), fragIndex: currentFragment + indexOffset) + if incrementCounter: + currentFragment += 1 + + withContainer(nb, blk): + body + + for level in endAnimations: + blk.fragments.add FragmentItem(classStr: level.join(" "), fragIndex: currentFragment) + nb.add blk template fragmentCore*(animations: openArray[seq[FragmentAnimation]], endAnimations: openArray[seq[FragmentAnimation]], body: untyped) = fragmentCore(animations, endAnimations, 0, true, body) From 7bce18b5436e90f7eb1f159667f61a4f75b07154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Fri, 16 May 2025 16:11:01 +0200 Subject: [PATCH 04/22] bigText works --- src/nimiSlides.nim | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/nimiSlides.nim b/src/nimiSlides.nim index 2a34d5f..fddc58a 100644 --- a/src/nimiSlides.nim +++ b/src/nimiSlides.nim @@ -324,6 +324,13 @@ func nimiSlidesFragmentStartPartial*(blk: JsonNode, nb: Nb): string = func nimiSlidesFragmentEndPartial*(blk: JsonNode, nb: Nb): string = "
\n".repeat(blk{"fragments"}.len) +newNbBlock(NbBigText of NbText): + toHtml: + withNewlines: + "

" + nb.renderPartial("nbText", jsonutils.toJson(blk)) + "

" + proc useLocalReveal*(nb: var Nb, path: string) = nb.doc.context["local_reveal_path"] = %path nb.backend.partials["revealCSS"] = localRevealCss @@ -367,9 +374,6 @@ proc revealTheme*(nb: var Nb) = nb.backend.partials["fragmentStart"] = nimiSlidesFragmentStartPartial nb.backend.partials["fragmentEnd"] = nimiSlidesFragmentEndPartial - #[ - nb.backend.partials["bigText"] = """

{{&outputToHtml}}

""" ]# - #doc.renderPlans["bigText"] = doc.renderPlans["nbText"] nb.doc.context["slidesTheme"] = %"black" nb.doc.context["nb_style"] = %"" @@ -679,9 +683,9 @@ template typewriter*(textMessage: string, typeSpeed = 50, alignment = "center") discard )) -template bigText*(text: string) = - newNbSlimBlock("bigText"): - nb.blk.output = text +template bigText*(ttext: string) = + let blk = newNbBigText(text=ttext) + nb.add blk template fitImage*(src: string) = nbRawHtml: hlHtml"""""" % [src] From 17c2faee224caab317e93ffcb65978f5a0f17292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Sun, 18 May 2025 10:56:52 +0200 Subject: [PATCH 05/22] implement Pietors brilliant idea of a NbDiv block for column blocks --- src/nimiSlides.nim | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/nimiSlides.nim b/src/nimiSlides.nim index fddc58a..2f26868 100644 --- a/src/nimiSlides.nim +++ b/src/nimiSlides.nim @@ -698,39 +698,32 @@ template speakerNote*(text: string) = """ % [markdown(text)] template align*(text: string, body: untyped) = - nbRawHtml: """ -
-""" % text - body - nbRawHtml: "
" + nbDiv(styles="text-align: $1;" % text, classes=""): + body #templates can't have default args and untyped args at the same time #so we use overloading to get the same effect template columns*(columnGap: float, body: untyped) = #tempted to use fmt"", but strformat doesn't support template args in the format string - nbRawHtml: """
- """ % $columnGap - body - nbRawHtml: "
" + nbDiv(styles="display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); overflow-wrap: break-word; column-gap: $1 em;" % $columnGap, classes=""): + body template columns*(body: untyped) = columns(1.0,body) template adaptiveColumns*(columnGap: float, body: untyped) = - nbRawHtml: """
- """ % $columnGap - body - nbRawHtml: "
" + nbDiv(styles="display: grid; grid-auto-flow: column; overflow-wrap: break-word; column-gap: $1 em;" % $columnGap, classes=""): + body + template adaptiveColumns*(body: untyped) = adaptiveColumns(1.0,body) template column*(bodyInner: untyped) = ## column should always be used inside a `columns` block - nbRawHtml: "
" - bodyInner - nbRawHtml: "
" + nbDiv: + bodyInner template footer*(text: string, fontSize: int = 20, opacity: range[0.0 .. 1.0] = 0.6, rawHtml = false) = nb.context["footerFontSize"] = fontSize From c75a6c886c6b81712f0dd3e9edef840b840fd99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Fri, 29 May 2026 14:12:25 +0200 Subject: [PATCH 06/22] update deps to use nimib 0.4.0 --- nimiSlides.nimble | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nimiSlides.nimble b/nimiSlides.nimble index f528715..619bc99 100644 --- a/nimiSlides.nimble +++ b/nimiSlides.nimble @@ -1,6 +1,6 @@ # Package -version = "0.2.6" +version = "0.4.0" author = "Hugo Granström" description = "Reveal.js theme for nimib" license = "MIT" @@ -9,7 +9,7 @@ srcDir = "src" # Dependencies requires "nim >= 1.4.0" -requires "nimib >= 0.3.9" +requires "nimib >= 0.4.0" import os From 1202ac1baeba6b92955f07f9cd95b7fa58aaa191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Fri, 29 May 2026 14:15:14 +0200 Subject: [PATCH 07/22] remove Nim 1.6 from CI --- .github/workflows/valid.yml | 1 - nimiSlides.nimble | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/valid.yml b/.github/workflows/valid.yml index d7e5c2c..ddc1c74 100644 --- a/.github/workflows/valid.yml +++ b/.github/workflows/valid.yml @@ -11,7 +11,6 @@ jobs: strategy: matrix: nim: - - '1.6.x' - 'stable' - 'devel' fail-fast: false diff --git a/nimiSlides.nimble b/nimiSlides.nimble index 619bc99..c127b2b 100644 --- a/nimiSlides.nimble +++ b/nimiSlides.nimble @@ -8,7 +8,7 @@ srcDir = "src" # Dependencies -requires "nim >= 1.4.0" +requires "nim >= 2.0.0" requires "nimib >= 0.4.0" import os From 21e730d8194c967f11459f4ac1814cebd4932d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Sun, 31 May 2026 20:32:00 +0200 Subject: [PATCH 08/22] make all presntations run --- docsrc/nimconf2022.nim | 99 ++++++++---------------------------------- docsrc/showcase.nim | 2 +- src/nimiSlides.nim | 73 ++++++++++++++++--------------- 3 files changed, 56 insertions(+), 118 deletions(-) diff --git a/docsrc/nimconf2022.nim b/docsrc/nimconf2022.nim index 63092ac..a704c59 100644 --- a/docsrc/nimconf2022.nim +++ b/docsrc/nimconf2022.nim @@ -6,71 +6,6 @@ import nimiSlides nbInit(theme = revealTheme) nb.useLatex -template nbCodeDontRun*(body: untyped) = - newNbCodeBlock("nbCodeDontRun", body): - discard - -template nimibCode*(body: untyped) = - #nbText: "Nimib code:" - newNbCodeBlock("nimibCode", body): - discard - fragmentFadeIn: - nbRawHtml: "
" - #nbText: "Output:" - body - -template nimibCodeAnimate*(lines: varargs[seq[HSlice[int, int]]], body: untyped) = - ## Shows code and its output just like nbCode, but highlights different lines of the code in the order specified in `lines`. - ## lines: Specify which lines to highlight and in which order. (Must be specified as a seq[HSlice]) - ## Ex: - ## ```nim - ## animateCode(@[1..1], @[3..4, 6..6]): body - ## ``` - ## This will first highlight line 1, then lines 3, 4 and 6. - newNbCodeBlock("nimibCodeAnimate", body): - var linesString: string - if lines.len > 0: - linesString &= "|" - for lineBundle in lines: - for line in lineBundle: - linesString &= $line.a & "-" & $line.b & "," - linesString &= "|" - if lines.len > 0: - linesString = linesString[0 .. ^3] - nb.blk.context["highlightLines"] = linesString - fragmentFadeIn: - nbRawHtml: "
" - body - -template nimibCodeAnimate*(lines: varargs[HSlice[int, int], toHSlice], body: untyped) = - ## Shows code and its output just like nbCode, but highlights different lines of the code in the order specified in `lines`. - ## lines: Specify which lines to highlight and in which order. (Must be specified as a HSlice) - ## Ex: - ## ```nim - ## animateCode(1..1, 2..3, 5..5, 4..4): body - ## ``` - ## This will first highlight line 1, then lines 2 and 3, then line 5 and last line 4. - var s: seq[seq[HSlice[int, int]]] - for line in lines: - s.add @[line] - nimibCodeAnimate(s): - body - -nb.partials["nimibCode"] = nb.partials["nbCode"] -nb.renderPlans["nimibCode"] = nb.renderPlans["nbCode"] -nb.partials["nimibCodeAnimate"] = nb.partials["animateCode"] -nb.renderPlans["nimibCodeAnimate"] = nb.renderPlans["animateCode"] - -template nbCodeDontRunAnimateImpl(body: untyped) = - discard - -newAnimateCodeBlock(nbCodeDontRunAnimate, nbCodeDontRunAnimateImpl) - -nb.partials["nbCodeDontRun"] = nb.partials["nbCode"] -nb.renderPlans["nbCodeDontRun"] = nb.renderPlans["nbCode"] -nb.partials["nimibCode"] = nb.partials["nbCode"] -nb.renderPlans["nimibCode"] = nb.renderPlans["nbCode"] - template nimConfSlide(body: untyped) = slide: cornerImage("https://github.com/nim-lang/assets/raw/master/Art/logo-crown.png", UpperRight, size=100, animate=false) @@ -252,12 +187,12 @@ Text can be *italic*, **bold** or ~~crossed over~~. nimConfSlide: nbText: """### Installation""" - nbCodeDontRun: + nbCodeSkip: nimble install nimiSlides nimConfSlide: nbText: "### Setting up" - nbCodeDontRun: + nbCodeSkip: import nimib, nimiSlides nbInit(theme = revealTheme) @@ -273,7 +208,7 @@ Text can be *italic*, **bold** or ~~crossed over~~. columns: column: fragmentFadeIn: - nbCodeDontRunAnimate(1..4, 1..2, 3..4, 6..12, 6, 7..8, 9..10, 11..12): + animateCodeSkip(1..4, 1..2, 3..4, 6..12, 6, 7..8, 9..10, 11..12): slide: nbText: "1" slide: @@ -431,7 +366,7 @@ slide: listItem: nbText: "Back again" nimConfSlide: - nimibCodeAnimate(1, 2..3, 4, 5..6, 7, 9): + animateCode(1, 2..3, 4, 5..6, 7, 9): unorderedList: listItem: nbText: "First item" @@ -460,7 +395,7 @@ slide: nimConfAutoSlide: nbText: "## Columns" - nimibCodeAnimate(1, 2..3, 4..5, 6..7): + animateCode(1, 2..3, 4..5, 6..7): columns: column: nbText: "Left" @@ -509,7 +444,7 @@ slide: slide(slideOptions(colorBackground = "darkviolet")): nbText: "## Color Background" - nbCodeDontRun: + nbCodeSkip: slide(slideOptions(colorBackground = "darkviolet")): nbText: "## Color Background" @@ -518,7 +453,7 @@ slide: nimConfSlide: nbText: "## Image Background" - nbCodeDontRun: + nbCodeSkip: slide(slideOptions(imageBackground = "https://github.com/nim-lang/assets/raw/master/Art/logo-crown.png")): discard @@ -527,13 +462,13 @@ slide: nimConfSlide: nbText: "## Iframe Background" - nbCodeDontRun: + nbCodeSkip: slide(slideOptions(iframeBackground = "https://nim-lang.org/")): discard nimConfSlide: nbText: "## Video Background" - nbCodeDontRun: + nbCodeSkip: slide(slideOptions(videoBackground = "link/to/videofile.mp4")): discard fragmentFadeIn: @@ -575,7 +510,7 @@ slide: """ nimConfSlide: - nbCodeDontRunAnimate(1..4, 6..10, 12..17): + animateCodeSkip(1..4, 6..10, 12..17): slide(slideOptions(autoAnimate=true)): nbText: """ - First @@ -639,7 +574,7 @@ slide: nbText: "## Using Templates" nimConfAutoSlide: nbText: "## Using Templates" - nbCodeDontRunAnimate({1, 3, 6}): + animateCodeSkip({1, 3, 6}): slide(slideOptions(autoAnimate=true)): nbText: "## Animate header" slide(slideOptions(autoAnimate=true)): @@ -654,7 +589,7 @@ slide: nimConfAutoSlide: nbText: "## Using Templates" - nbCodeDontRunAnimate(1, 2..3, 3, 5..6): + animateCodeSkip(1, 2..3, 3, 5..6): template slideAutoAnimate(body: untyped) = slide(slideOptions(autoAnimate=true)): body @@ -667,7 +602,7 @@ slide: stackElements: fragment(fadeInThenOut): nbText: "#### Without template" - nbCodeDontRun: + nbCodeSkip: slide(slideOptions(autoAnimate=true)): nbText: "## Animate header" slide(slideOptions(autoAnimate=true)): @@ -679,7 +614,7 @@ slide: nbText: "And this" fragmentFadeIn: nbText: "#### With template" - nbCodeDontRun: + nbCodeSkip: slideAutoAnimate: nbText: "## Animate header" slideAutoAnimate: @@ -698,10 +633,10 @@ slide: nbText: "Example: Histogram of Gaussian for different N" nimConfAutoSlide: nbText: "## Loops ♻️ + Generate images 🖼️" - nbCodeDontRunAnimate(1, 2, 3, 4..7, 9, 10, 11): + animateCodeSkip(1, 2, 3, 4..7, 9, 10, 11): for n in [50, 100, 1000, 10000]: let filename = &"images/gauss-{n}.png" - let samples = newSeqWith[float](n, gauss(0.0, 1.0)) + let samples = newSeqWith(n, gauss(0.0, 1.0)) let df = toDf(samples) ggplot(df, aes("samples")) + geom_histogram(fillColor="green") + @@ -714,7 +649,7 @@ slide: slide: for n in [50, 100, 1000, 10000]: let filename = &"images/gauss-{n}.png" - let samples = newSeqWith[float](n, gauss(0.0, 1.0)) + let samples = newSeqWith(n, gauss(0.0, 1.0)) let df = toDf(samples) ggplot(df, aes("samples")) + geom_histogram(fillColor="green") + diff --git a/docsrc/showcase.nim b/docsrc/showcase.nim index 0fdaa5a..5315751 100644 --- a/docsrc/showcase.nim +++ b/docsrc/showcase.nim @@ -5,7 +5,7 @@ nbInit(theme = revealTheme) nb.useLatex() when defined(themeWhite): - nb.filename = "./showcase_white.html" + nb.doc.filename = "./showcase_white.html" setSlidesTheme(White) else: setSlidesTheme(Moon) diff --git a/src/nimiSlides.nim b/src/nimiSlides.nim index 2f26868..646a4b3 100644 --- a/src/nimiSlides.nim +++ b/src/nimiSlides.nim @@ -208,16 +208,18 @@ func revealJSToHtml*(blk: JsonNode, nb: Nb): string = if nb.doc.context{"latex"}.getBool: hlHtmlF"""""" -proc localRevealCss*(blk: JsonNode, nb: Nb): string = - let path = nb.doc.homeDir.string / nb.doc.context{"local_reveal_path"}.getStr +func localRevealCss*(blk: JsonNode, nb: Nb): string = + {.cast(noSideEffect).}: + let path = nb.doc.homeDir.string / nb.doc.context{"local_reveal_path"}.getStr result = fmt""" """ -proc localRevealJs*(blk: JsonNode, nb: Nb): string = - let path = nb.doc.homeDir.string / nb.doc.context{"local_reveal_path"}.getStr +func localRevealJs*(blk: JsonNode, nb: Nb): string = + {.cast(noSideEffect).}: + let path = nb.doc.homeDir.string / nb.doc.context{"local_reveal_path"}.getStr result = withNewlines: fmt""" @@ -331,26 +333,26 @@ newNbBlock(NbBigText of NbText): nb.renderPartial("nbText", jsonutils.toJson(blk)) "" -proc useLocalReveal*(nb: var Nb, path: string) = +func useLocalReveal*(nb: var Nb, path: string) = nb.doc.context["local_reveal_path"] = %path nb.backend.partials["revealCSS"] = localRevealCss nb.backend.partials["revealJS"] = localRevealJs template setSlidesTheme*(theme: SlidesTheme) = - nb.context["slidesTheme"] = ($theme).toLower + nb.doc.context["slidesTheme"] = %($theme).toLower template useScrollWheel*() = ## Enable using the scroll-wheel to step forward in slides. - nb.context["useScrollWheel"] = true + nb.doc.context["useScrollWheel"] = %true template showSlideNumber*() = - nb.context["showSlideNumber"] = true + nb.doc.context["showSlideNumber"] = %true template disableVerticalCentering*() = - nb.context["disableCentering"] = true + nb.doc.context["disableCentering"] = %true template useScrollView*() = - nb.context["useScrollView"] = true + nb.doc.context["useScrollView"] = %true proc addStyle*(nb: var Nb, style: string) = nb.doc.context["nb_style"] = %(nb.doc.context{"nb_style"}.getStr & "\n" & style) @@ -610,25 +612,26 @@ template animateCode*(lines: varargs[set[range[0..65535]], toSet], body: untyped body nb.add blk -template newAnimateCodeBlock*(cmd: untyped, impl: untyped) = - const cmdStr = astToStr(cmd) - - template `cmd`*(lines: varargs[set[range[0..65535]], toSet], body: untyped) = - newNbCodeBlock(cmdStr, body): - var linesString: string - if lines.len > 0: - linesString &= "|" - for lineBundle in lines: - for line in lineBundle: - linesString &= $line & "," - linesString &= "|" - if lines.len > 0: - linesString = linesString[0 .. ^3] - nb.blk.context["highlightLines"] = linesString - impl(body) - - nb.partials[cmdStr] = nb.partials["animateCode"] - nb.renderPlans[cmdStr] = nb.renderPlans["animateCode"] +template animateCodeSkip*(lines: varargs[set[range[0..65535]], toSet], body: untyped) = + ## Shows code and its output just like nbCode, but highlights different lines of the code in the order specified in `lines`. + ## lines: Specify which lines to highlight and in which order. The lines can be specified using either: + ## - An `int` (highlight single line) + ## - A slice `x..y` (highlight a range of consequative lines) + ## - A set {x, y..z} (highlight any combination of lines) + ## Ex: + ## ```nim + ## animateCode(1, 2..3, {4, 6}): body + ## ``` + ## This will first highlight line 1, then lines 2 and 3, and lastly line 4 and 6. + var highlightedLines: seq[seq[int]] + for line in lines: + var lineSeq: seq[int] + for l in line: + lineSeq.add l + highlightedLines.add lineSeq + let blk = newNbAnimateCode(highlightedLines=highlightedLines) + blk.code = getCode(body) + nb.add blk template typewriter*(textMessage: string, typeSpeed = 50, alignment = "center") = let localText = textMessage @@ -637,7 +640,7 @@ template typewriter*(textMessage: string, typeSpeed = 50, alignment = "center") # HTML and add eventlistener # check what we get back from reveal's event let fragIndex = currentFragment # important it is before fragmentFadeIn! - let id = "typewriter" & $nb.newId() + let id = "typewriter" & $nb.doc.newId() fragmentFadeIn: nbKaraxCode(id, localText, fragIndex, speed, align): import nimiSlides/revealFFI @@ -726,12 +729,12 @@ template column*(bodyInner: untyped) = bodyInner template footer*(text: string, fontSize: int = 20, opacity: range[0.0 .. 1.0] = 0.6, rawHtml = false) = - nb.context["footerFontSize"] = fontSize - nb.context["footerOpacity"] = opacity + nb.doc.context["footerFontSize"] = %fontSize + nb.doc.context["footerOpacity"] = %opacity if rawHtml: - nb.context["revealFooter"] = text + nb.doc.context["revealFooter"] = %text else: - nb.context["revealFooter"] = markdown(text, config=initGfmConfig()).dup(removeSuffix) + nb.doc.context["revealFooter"] = %markdown(text, config=initGfmConfig()).dup(removeSuffix) nbJsFromCodeGlobal: import nimiSlides/revealFFI @@ -774,7 +777,7 @@ template cornerImage*(image: string, corner: Corner, size: int = 100, animate = "transition: all 0.2s ease-out;" else: "" - let id = "cornerImage-" & $nb.newId() + let id = "cornerImage-" & $nb.doc.newId() let html = &"""""" % [image, id, $size, vertical, horizontal, animateString] let currentSlideNr = currentSlideNumber From 84033e3ede3b69eb17e5899189b60f67592abf95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Sun, 31 May 2026 20:38:59 +0200 Subject: [PATCH 09/22] update ci to newer versions --- .github/workflows/docs.yml | 4 +++- .github/workflows/valid.yml | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a2c20d9..cc0d9f1 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -12,7 +12,9 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: iffy/install-nim@v4 + - name: apt install + run: sudo apt install -y libpcre3 libblas-dev liblapack-dev + - uses: iffy/install-nim@v5 - name: Generate run: | nimble install -y diff --git a/.github/workflows/valid.yml b/.github/workflows/valid.yml index ddc1c74..fcb04f6 100644 --- a/.github/workflows/valid.yml +++ b/.github/workflows/valid.yml @@ -17,10 +17,11 @@ jobs: name: Nim ${{ matrix.nim }} steps: - uses: actions/checkout@v2 - - uses: jiro4989/setup-nim-action@v1 + - uses: jiro4989/setup-nim-action@v2.2.2 with: nim-version: ${{ matrix.nim }} repo-token: ${{ secrets.GITHUB_TOKEN }} + - run: sudo apt install libpcre3 libpcre3-dev - name: Install deps run: | nimble install -y From 4d45aec774f2732cc9d1562627c6b29434bd6415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Sun, 31 May 2026 20:52:19 +0200 Subject: [PATCH 10/22] install lapack --- .github/workflows/valid.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/valid.yml b/.github/workflows/valid.yml index fcb04f6..970bb66 100644 --- a/.github/workflows/valid.yml +++ b/.github/workflows/valid.yml @@ -21,7 +21,7 @@ jobs: with: nim-version: ${{ matrix.nim }} repo-token: ${{ secrets.GITHUB_TOKEN }} - - run: sudo apt install libpcre3 libpcre3-dev + - run: sudo apt install libpcre3 libpcre3-dev liblapack-dev - name: Install deps run: | nimble install -y From 191b3678c06bd252750bdce4adb58beefe9706ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Mon, 1 Jun 2026 20:35:01 +0200 Subject: [PATCH 11/22] add autoAnimateSlidesCustom which accepts a custom slide template --- src/nimiSlides/autoAnimation.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/nimiSlides/autoAnimation.nim b/src/nimiSlides/autoAnimation.nim index e866205..1f0b438 100644 --- a/src/nimiSlides/autoAnimation.nim +++ b/src/nimiSlides/autoAnimation.nim @@ -2,11 +2,14 @@ import std/[strutils] import nimib import ./[conversions] -template autoAnimateSlides*(nSlides: int, body: untyped) = +template autoAnimateSlidesCustom*(nSlides: int, slideTemplate: untyped, body: untyped) = for autoAnimateCounter {.inject.} in 1 .. nSlides: - slide(slideOptions(autoAnimate=true)): + slideTemplate(slideOptions(autoAnimate=true)): body +template autoAnimateSlides*(nSlides: int, body: untyped) = + autoAnimateSlidesCustom(nSlides, slide, body) + template showAt*(slideNrs: varargs[set[range[0..65535]], toSet], body: untyped) = # how to auto convert to set like in varargs? # use vararg and union all results! # This way you don't need to use the set syntax but can pass in `showOn(1, 2, 3)` instead. From fa9a73a8fa53646a34011b6840442456b8cd3c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Mon, 1 Jun 2026 20:35:31 +0200 Subject: [PATCH 12/22] start working on nimconf2026 (if you see this, congrats on finding out first ;)) --- docsrc/nimconf2026.nim | 113 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 docsrc/nimconf2026.nim diff --git a/docsrc/nimconf2026.nim b/docsrc/nimconf2026.nim new file mode 100644 index 0000000..66b4c6d --- /dev/null +++ b/docsrc/nimconf2026.nim @@ -0,0 +1,113 @@ +import std / [strutils, random, sequtils, math, strformat, json] +import nimib, nimib / [capture] +import nimiSlides + +nbInit(theme = revealTheme) +nb.useLatex + +template nimSlide(body: untyped) = + slide: + cornerImage("https://github.com/nim-lang/assets/raw/master/Art/logo-crown.png", UpperRight, size=100, animate=false) + body + +template nimSlide(options: SlideOptions, body: untyped) = + slide(options): + cornerImage("https://github.com/nim-lang/assets/raw/master/Art/logo-crown.png", UpperRight, size=100, animate=false) + body + +template nimConfTheme*() = + setSlidesTheme(Black) + let nimYellow = "#FFE953" + nb.addStyle: """ +:root { + --r-background-color: #181922; + --r-heading-color: $1; + --r-link-color: $1; + --r-selection-color: $1; + --r-link-color-dark: darken($1 , 15%) +} + +.reveal ul, .reveal ol { + display: block; + text-align: left; +} + +li::marker { + color: $1; + content: "»"; +} + +li { + padding-left: 12px; +} +""" % [nimYellow] + +nimConfTheme() + +newNbBlock(FieldSet of NbContainer): + title: string + toHtml: + let renderedBlocks = nbContainerToHtml(blk, nb) + hlHtmlF""" +
+ {blk.title} + {renderedBlocks} +
+ """ + +template fieldSet(ttitle: string, body: untyped) = + let blk = newFieldSet(title=ttitle) + nb.withContainer(blk): + body + nb.add blk + +newNbBlock(JsonShow of NbContainer): + toHtml: + let blocksSerialized = blk.blocks.toJson().fromJson().pretty() + preCodeTag("json", blocksSerialized) + +template jsonShow(body: untyped) = + let blk = newJsonShow() + nb.withContainer(blk): + body + nb.add blk + +template showJsonSerialized(body: untyped) = + let code = getCode(body) + autoAnimateSlidesCustom(3, nimSlide): + fieldSet("Nim"): + nbRawHtml: preCodeTag("nim", code) + showAt(2): + fieldSet("Rendered"): + body + showAt(3): + fieldSet("JSON"): + jsonShow: + body + +template intro = + slide: + nimSlide: + nbText: "Nimib v0.4: internals ref-actoring" + nbText: "Hugo Granström" + +template jsonShowcase = + nimSlide: + nbText: "## JSON serialization" + nimSlide: + showJsonSerialized: + nbText: "*Hello* **there**" + nimSlide: + showJsonSerialized: + nbCode: + echo "General Kenobi" + nimSlide: + showJsonSerialized: + nbDiv(classes="cool", styles="color: green"): + nbText: "This is nested" + +#intro + +jsonShowcase + +nbSave From da9d79d24eae35fe103504b7e2704b6ef909d160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Mon, 1 Jun 2026 20:39:02 +0200 Subject: [PATCH 13/22] fix bug where the nb_Style wasn't set --- src/nimiSlides.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimiSlides.nim b/src/nimiSlides.nim index 646a4b3..9ea7eb9 100644 --- a/src/nimiSlides.nim +++ b/src/nimiSlides.nim @@ -147,7 +147,7 @@ func revealNbDocToHtml*(blk: NbBlock, nb: Nb): string = "" func revealHeadToHtml*(blk: JsonNode, nb: Nb): string = - let nbStyle = nb.doc.context{"nb_style"} + let nbStyle = nb.doc.context{"nb_style"}.getStr result = withNewLines: "" """""" From 13f89ee89c442fa7b99bbeed59161f63f2bbd9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Mon, 1 Jun 2026 20:42:22 +0200 Subject: [PATCH 14/22] make some adjustments to intro page --- docsrc/nimconf2026.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docsrc/nimconf2026.nim b/docsrc/nimconf2026.nim index 66b4c6d..275e58c 100644 --- a/docsrc/nimconf2026.nim +++ b/docsrc/nimconf2026.nim @@ -88,8 +88,10 @@ template showJsonSerialized(body: untyped) = template intro = slide: nimSlide: - nbText: "Nimib v0.4: internals ref-actoring" + nbText: "## Nimib v0.4" + nbText: "## internals ref-actoring" nbText: "Hugo Granström" + nbText: "NimConf 2026" template jsonShowcase = nimSlide: @@ -106,7 +108,7 @@ template jsonShowcase = nbDiv(classes="cool", styles="color: green"): nbText: "This is nested" -#intro +intro jsonShowcase From 0665abd4cd21b925a5db67c29edb5b1410e84bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:01:14 +0200 Subject: [PATCH 15/22] Story time! --- docsrc/nimconf2026.nim | 34 ++++++++++++++++++++++++++++++-- src/nimiSlides/autoAnimation.nim | 4 ++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/docsrc/nimconf2026.nim b/docsrc/nimconf2026.nim index 275e58c..a94e7f8 100644 --- a/docsrc/nimconf2026.nim +++ b/docsrc/nimconf2026.nim @@ -44,6 +44,11 @@ li { nimConfTheme() +proc liText(s: string) = + listItem: + nbText: + s + newNbBlock(FieldSet of NbContainer): title: string toHtml: @@ -74,7 +79,7 @@ template jsonShow(body: untyped) = template showJsonSerialized(body: untyped) = let code = getCode(body) - autoAnimateSlidesCustom(3, nimSlide): + autoAnimateSlidesCustom(nimSlide, 3): fieldSet("Nim"): nbRawHtml: preCodeTag("nim", code) showAt(2): @@ -92,6 +97,31 @@ template intro = nbText: "## internals ref-actoring" nbText: "Hugo Granström" nbText: "NimConf 2026" + autoAnimateSlidesCustom(nimSlide, 3): + nbText: "## Story time" + showAt(1): + unorderedList: + liText: "Previously on Nimib" + unorderedList: + liText: "Rendering: Mustache templates" + liText: "Single NbBlock type" + showAt(2): + unorderedList: + liText: "In this episode of Nimib" + unorderedList: + liText: "Rendering: normal Nim functions" + liText: "Different type for each block" + showAt(3): + unorderedList: + liText: "Next time on Nimib" + unorderedList: + liText: "NimiSlides + NimiBook" + liText: "Static site generator" + liText: "Nimibex" + + +template defineBlockExamples = + discard template jsonShowcase = nimSlide: @@ -109,7 +139,7 @@ template jsonShowcase = nbText: "This is nested" intro - +defineBlockExamples jsonShowcase nbSave diff --git a/src/nimiSlides/autoAnimation.nim b/src/nimiSlides/autoAnimation.nim index 1f0b438..87a3572 100644 --- a/src/nimiSlides/autoAnimation.nim +++ b/src/nimiSlides/autoAnimation.nim @@ -2,13 +2,13 @@ import std/[strutils] import nimib import ./[conversions] -template autoAnimateSlidesCustom*(nSlides: int, slideTemplate: untyped, body: untyped) = +template autoAnimateSlidesCustom*(slideTemplate: untyped, nSlides: int, body: untyped) = for autoAnimateCounter {.inject.} in 1 .. nSlides: slideTemplate(slideOptions(autoAnimate=true)): body template autoAnimateSlides*(nSlides: int, body: untyped) = - autoAnimateSlidesCustom(nSlides, slide, body) + autoAnimateSlidesCustom(slide, nSlides, body) template showAt*(slideNrs: varargs[set[range[0..65535]], toSet], body: untyped) = # how to auto convert to set like in varargs? # use vararg and union all results! From 56f7c0b29e0b27ca96c8d7483ab3511649ad6626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Tue, 2 Jun 2026 22:58:18 +0200 Subject: [PATCH 16/22] usage bar example almost done --- docsrc/nimconf2026.nim | 92 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/docsrc/nimconf2026.nim b/docsrc/nimconf2026.nim index a94e7f8..847efb0 100644 --- a/docsrc/nimconf2026.nim +++ b/docsrc/nimconf2026.nim @@ -101,19 +101,21 @@ template intro = nbText: "## Story time" showAt(1): unorderedList: - liText: "Previously on Nimib" + liText: "Spirit of Nimib past" unorderedList: liText: "Rendering: Mustache templates" liText: "Single NbBlock type" showAt(2): unorderedList: - liText: "In this episode of Nimib" + liText: "Spirit of Nimib present" unorderedList: liText: "Rendering: normal Nim functions" liText: "Different type for each block" + liText: "Sugar" + liText: "JSON" showAt(3): unorderedList: - liText: "Next time on Nimib" + liText: "Spirit of Nimib future" unorderedList: liText: "NimiSlides + NimiBook" liText: "Static site generator" @@ -121,7 +123,81 @@ template intro = template defineBlockExamples = - discard + nimSlide: + nbText: "## Defining a block" + unorderedList: + liText: "Simple example - usage bar" + liText: "Container example - collapsible section" + slide: + nimSlide(slideOptions(autoAnimate = true)): + nbText: "## Usage bar" + fragment: + for i in [20, 40, 60, 80]: + nbDiv(): + nbRawHtml: hlHtml""" + + """ % [$i, $(i / 100)] + nimSlide(slideOptions(autoAnimate = true)): + nbText: "## Usage bar" + nbRawHtml: preCodeTag("html", hlHtml""" +""") + nimSlide(slideOptions(autoAnimate = true)): + nbText: "## Usage bar" + animateCode(1, 2): + newNbBlock(UsageBar): + label: string + altText: string + value: float + minValue: float + maxValue: float + toHtml: + # injects `blk: UsageBar` + &""" + +""" + + proc usageBar( + nb: var Nb, + label: string, + value: float, + altText: string = $value, + minValue: float = 0.0, + maxValue: float = 1.0 + ) = + let blk = newUsageBar( + label=label, value=value, + altText=altText, minValue=minValue, + maxValue=maxValue + ) + nb.add blk + + nimSlide(slideOptions(autoAnimate = true)): + nbText: "## Usage bar" + nbCode: + nb.usageBar( + label="Storage usage:", + value=0.8, + altText="80% of storage used" + ) + + + + + template jsonShowcase = nimSlide: @@ -138,8 +214,12 @@ template jsonShowcase = nbDiv(classes="cool", styles="color: green"): nbText: "This is nested" -intro +template outro = + discard + +#intro defineBlockExamples -jsonShowcase +#jsonShowcase +#outro nbSave From e94e5088675f6b3313d1c35edef94b268a867370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Thu, 4 Jun 2026 18:09:05 +0200 Subject: [PATCH 17/22] animate usageBar code --- docsrc/nimconf2026.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docsrc/nimconf2026.nim b/docsrc/nimconf2026.nim index 847efb0..447089d 100644 --- a/docsrc/nimconf2026.nim +++ b/docsrc/nimconf2026.nim @@ -149,7 +149,7 @@ template defineBlockExamples = """) nimSlide(slideOptions(autoAnimate = true)): nbText: "## Usage bar" - animateCode(1, 2): + animateCode(1, 2..6, 7..8, 9..19, 21..28, 29..33, 34): newNbBlock(UsageBar): label: string altText: string From a2d9ac2e53b7d2809bfbc43c874d22ba3e2f88fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Thu, 4 Jun 2026 21:02:16 +0200 Subject: [PATCH 18/22] complete container block example --- docsrc/nimconf2026.nim | 69 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/docsrc/nimconf2026.nim b/docsrc/nimconf2026.nim index 447089d..e21c271 100644 --- a/docsrc/nimconf2026.nim +++ b/docsrc/nimconf2026.nim @@ -131,15 +131,16 @@ template defineBlockExamples = slide: nimSlide(slideOptions(autoAnimate = true)): nbText: "## Usage bar" - fragment: - for i in [20, 40, 60, 80]: - nbDiv(): - nbRawHtml: hlHtml""" - - """ % [$i, $(i / 100)] + nimSlide(slideOptions(autoAnimate = true)): + nbText: "## Usage bar" + for i in [20, 40, 60, 80]: + nbDiv(): + nbRawHtml: hlHtml""" + + """ % [$i, $(i / 100)] nimSlide(slideOptions(autoAnimate = true)): nbText: "## Usage bar" nbRawHtml: preCodeTag("html", hlHtml""" @@ -193,12 +194,54 @@ template defineBlockExamples = value=0.8, altText="80% of storage used" ) + let exampleCollapsible = hlHtml""" +
+ + What is hidden inside? + + Super secret text! +
+""" + slide: + nimSlide(slideOptions(autoAnimate = true)): + nbText: "## Collapsible section" + nimSlide(slideOptions(autoAnimate = true)): + nbText: "## Collapsible section" + nbRawHtml: exampleCollapsible + nimSlide(slideOptions(autoAnimate = true)): + nbText: "## Collapsible section" + nbRawHtml: preCodeTag("html", exampleCollapsible) + nimSlide(slideOptions(autoAnimate = true)): + nbText: "## Collapsible section" + animateCode(1, 2, 3, 3..11, 13..16, 17, 18..19, 20): + newNbBlock(CollapsibleSection of NbContainer): + summary: string + toHtml: + let renderedBlocks = nbContainerToHtml(blk, nb) + &""" +
+ + {blk.summary} + + {renderedBlocks} +
""" + + template collapsibleSection( + text: string, + body: untyped + ) = + let blk = newCollapsibleSection(summary=text) + nb.withContainer(blk): + body + nb.add blk + nimSlide(slideOptions(autoAnimate = true)): + nbText: "## Collapsible section" + let secretMessage = "Never gonna give you up, never gonna let you down..." + nbCode: + collapsibleSection("Top secret"): + nbText(secretMessage) - - - - template jsonShowcase = nimSlide: nbText: "## JSON serialization" From e5ed34100114db220bde42dec6dfc5fbc34c231a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Fri, 5 Jun 2026 13:12:51 +0200 Subject: [PATCH 19/22] make typewriter work again by not using karax --- src/nimiSlides.nim | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/nimiSlides.nim b/src/nimiSlides.nim index 9ea7eb9..fd66901 100644 --- a/src/nimiSlides.nim +++ b/src/nimiSlides.nim @@ -642,9 +642,11 @@ template typewriter*(textMessage: string, typeSpeed = 50, alignment = "center") let fragIndex = currentFragment # important it is before fragmentFadeIn! let id = "typewriter" & $nb.doc.newId() fragmentFadeIn: - nbKaraxCode(id, localText, fragIndex, speed, align): + nbRawHtml: hlHTml""" +

$3

+ """ % [id, align, localText] + nbJsFromCode(id, localText, fragIndex, speed, align): import nimiSlides/revealFFI - import karax / vstyles var i = 0 var timeout: Timeout proc typewriterLocal() = @@ -654,9 +656,6 @@ template typewriter*(textMessage: string, typeSpeed = 50, alignment = "center") el.innerHtml &= $localText[i] inc i timeout = setTimeout(typewriterLocal, speed) - karaxHtml: - p(id = id, style=style(textAlign, align.kstring)): - text localText.cstring window.addEventListener("load", proc (event: Event) = echo "Loading ", fragIndex From 49df05a993821fe2c3e70776a8ff2b403ee262bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Fri, 5 Jun 2026 13:26:09 +0200 Subject: [PATCH 20/22] add newline support for typewriter --- src/nimiSlides.nim | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/nimiSlides.nim b/src/nimiSlides.nim index fd66901..c0bc599 100644 --- a/src/nimiSlides.nim +++ b/src/nimiSlides.nim @@ -653,7 +653,13 @@ template typewriter*(textMessage: string, typeSpeed = 50, alignment = "center") echo "Typing ", fragindex var el = getElementById(id.cstring) if i < localText.len: - el.innerHtml &= $localText[i] + var c = localText[i] + let s = + if c == '\n': + "
" + else: + $c + el.innerHtml &= s inc i timeout = setTimeout(typewriterLocal, speed) From dae685ffc6ca67e9a1dc020b36b0d16a42312a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Fri, 5 Jun 2026 13:26:20 +0200 Subject: [PATCH 21/22] slides are finished! --- docsrc/nimconf2026.nim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docsrc/nimconf2026.nim b/docsrc/nimconf2026.nim index e21c271..1c2bf75 100644 --- a/docsrc/nimconf2026.nim +++ b/docsrc/nimconf2026.nim @@ -258,11 +258,12 @@ template jsonShowcase = nbText: "This is nested" template outro = - discard + nimSlide: + typewriter("Thank you for watching!" & ' '.repeat(30) & "\nSee you in NimibLand!") -#intro +intro defineBlockExamples -#jsonShowcase -#outro +jsonShowcase +outro nbSave From d8092a8acd0c8fff5b4ebf5dcadeb683d63fdc8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Granstr=C3=B6m?= <5092565+HugoGranstrom@users.noreply.github.com> Date: Sat, 6 Jun 2026 10:43:36 +0200 Subject: [PATCH 22/22] fix some things I found during a repetition --- docsrc/nimconf2026.nim | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/docsrc/nimconf2026.nim b/docsrc/nimconf2026.nim index 1c2bf75..eab4784 100644 --- a/docsrc/nimconf2026.nim +++ b/docsrc/nimconf2026.nim @@ -110,7 +110,11 @@ template intro = liText: "Spirit of Nimib present" unorderedList: liText: "Rendering: normal Nim functions" + unorderedList: + liText: "Breaking change" liText: "Different type for each block" + unorderedList: + liText: "Container blocks" liText: "Sugar" liText: "JSON" showAt(3): @@ -213,7 +217,7 @@ template defineBlockExamples = nbRawHtml: preCodeTag("html", exampleCollapsible) nimSlide(slideOptions(autoAnimate = true)): nbText: "## Collapsible section" - animateCode(1, 2, 3, 3..11, 13..16, 17, 18..19, 20): + animateCode(1, 2, 3, 4, 5..11, 13..16, 17, 18..19, 20): newNbBlock(CollapsibleSection of NbContainer): summary: string toHtml: @@ -243,8 +247,19 @@ template defineBlockExamples = template jsonShowcase = - nimSlide: + autoAnimateSlidesCustom(nimSlide, 3): nbText: "## JSON serialization" + showAt(2): + unorderedList: + liText: "Uses Jsony" + liText: "Individual blocks or entire documents" + showAt(3): + animateCode(1, 2..3, 4..5): + let blk = newNbText(text="Hello JSON!") + # Serialize + echo blk.toJson() + # Deserialize + echo blk.toJson().fromJson(NbBlock).NbText.text nimSlide: showJsonSerialized: nbText: "*Hello* **there**"