From 84cd929fb593d805d06a2aed95c88c310c306596 Mon Sep 17 00:00:00 2001 From: George Lemon Date: Thu, 15 Feb 2024 05:39:31 +0200 Subject: [PATCH] update Signed-off-by: George Lemon --- example/app.nim | 16 +++++++ example/preview.html | 49 +++++++++++++++++++ example/templates/layouts/base.timl | 30 ++++++++++++ example/templates/partials/btn.timl | 4 ++ example/templates/views/index.timl | 23 +++++++++ src/tim.nim | 73 +++++++++++++++++------------ src/tim/engine/compilers/html.nim | 3 +- src/tim/engine/compilers/js.nim | 7 ++- 8 files changed, 173 insertions(+), 32 deletions(-) create mode 100644 example/app.nim create mode 100644 example/preview.html create mode 100644 example/templates/layouts/base.timl create mode 100644 example/templates/partials/btn.timl create mode 100644 example/templates/views/index.timl diff --git a/example/app.nim b/example/app.nim new file mode 100644 index 0000000..e6f1d7d --- /dev/null +++ b/example/app.nim @@ -0,0 +1,16 @@ +import ../src/tim +import std/os + +var + engine = newTim( + src = "templates", + output = "storage", + basepath = currentSourcePath(), + minify = true, + indent = 2 + ) + +engine.precompile() +sleep(40) +let x = engine.render("index") +writeFile(getCurrentDir() / "example" / "preview.html", x) \ No newline at end of file diff --git a/example/preview.html b/example/preview.html new file mode 100644 index 0000000..41cbbe7 --- /dev/null +++ b/example/preview.html @@ -0,0 +1,49 @@ + + + + + + Tim Engine is Awesome + + + + +
+
+
+
+
+ Tim Engine +
+

This is Tim Engine 👋 A super fast template engine for cool kids!

+

Build sleek, dynamic websites and apps in a breeze with Tim Engine's intuitive syntax and powerful features. It's the template engine that keeps up with your creativity.

+
+ +
+

Made by Humans from OpenPeeps

+

Open Source | LGPLv3 License

+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/example/templates/layouts/base.timl b/example/templates/layouts/base.timl new file mode 100644 index 0000000..2b8a529 --- /dev/null +++ b/example/templates/layouts/base.timl @@ -0,0 +1,30 @@ +html + head + meta charset="UTF-8" + meta name="viewport" content="width=device-width, initial-scale=1" + title: "Tim Engine is Awesome" + link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" + style: " + body { + background-color: #212121; + color: whitesmoke + } + .btn-primary { + --bs-btn-color: #fff; + --bs-btn-bg: #ea4444; + --bs-btn-border-color: #ea4444; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #c73434; + --bs-btn-hover-border-color: #c73434; + --bs-btn-focus-shadow-rgb: 49,132,253; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #b62929; + --bs-btn-active-border-color: #b62929; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #0d6efd; + --bs-btn-disabled-border-color: #0d6efd; + } + " + body + @view diff --git a/example/templates/partials/btn.timl b/example/templates/partials/btn.timl new file mode 100644 index 0000000..d295c56 --- /dev/null +++ b/example/templates/partials/btn.timl @@ -0,0 +1,4 @@ +a.btn.btn-primary.btn-lg.rounded-pill.px-4.py-2 href="https://github.com/openpeeps/tim" target="_blank": + svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" class="css-i6dzq1" + path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" + span.fw-bold: "Check it on GitHub" diff --git a/example/templates/views/index.timl b/example/templates/views/index.timl new file mode 100644 index 0000000..175f67e --- /dev/null +++ b/example/templates/views/index.timl @@ -0,0 +1,23 @@ +section > div.container > div.row.vh-100.align-items-center > div#content-zone.col-lg-7.mx-auto + div.text-center > img src="https://raw.githubusercontent.com/openpeeps/tim/main/.github/timengine.png" alt="Tim Engine" width="200px" + h1.display-4.fw-bold: + "This is Tim 👋 A super fast template engine for cool kids!" + p.mb-4.h4.fw-normal.px-4 style="line-height: 1.8em": + "Build sleek, dynamic websites and apps in a breeze with Tim Engine's intuitive + syntax and powerful features. It's the template engine that keeps up with your creativity." + div.text-center + div.mb-3 + @include "btn" + div + p.mb-0: "Made by Humans from OpenPeeps" + p: "Open Source | LGPLv3 License" + +@client target="#content-zone" + // transpile to JavaScript for client-side rendering +@end + +@js + document.addEventListener('DOMContentLoaded', function() { + console.log(e) + }) +@end \ No newline at end of file diff --git a/src/tim.nim b/src/tim.nim index 11126c9..cd59f56 100755 --- a/src/tim.nim +++ b/src/tim.nim @@ -6,7 +6,8 @@ import std/json except `%*` import std/times -import pkg/[watchout, kapsis/cli] +import pkg/[watchout] +import pkg/kapsis/cli import tim/engine/[meta, parser, logging] import tim/engine/compilers/html @@ -14,7 +15,6 @@ import tim/engine/compilers/html from std/strutils import `%`, indent from std/os import `/` - const DOCKTYPE = "" defaultLayout = "base" @@ -127,6 +127,28 @@ proc precompile*(engine: TimEngine, callback: TimCallback = nil, for tpl in engine.getLayouts(): engine.compileCode(tpl) +template layoutWrapper(getViewBlock) {.dirty.} = + result = DOCKTYPE + var layoutTail: string + if not layout.jitEnabled: + # when requested layout is pre-rendered + # will use the static HTML version from disk + add result, layout.getHtml() + getViewBlock + layoutTail = layout.getTail() + else: + var data = newJObject() + data["global"] = global + data["local"] = local + var jitLayout = engine.jitCompiler(layout, data) + if likely(not jitLayout.hasError): + add result, jitLayout.getHead() + getViewBlock + layoutTail = jitLayout.getTail() + else: + jitLayout.logger.displayErrors() + add result, layoutTail + proc render*(engine: TimEngine, viewName: string, layoutName = defaultLayout, global, local = newJObject()): string = ## Renders a view based on `viewName` and `layoutName`. @@ -139,35 +161,16 @@ proc render*(engine: TimEngine, viewName: string, var layout: TimTemplate = engine.getLayout(layoutName) if not view.jitEnabled: # render a pre-compiled HTML - result = DOCKTYPE - add result, layout.getHtml() - add result, indent(view.getHtml(), layout.getViewIndent) - add result, layout.getTail() + layoutWrapper: + add result, indent(view.getHtml(), layout.getViewIndent) else: # compile and render template at runtime - var data = newJObject() - data["global"] = global - data["local"] = local - result = DOCKTYPE - var layoutTail: string - if not layout.jitEnabled: - # when requested layout is pre-rendered - # will use the static HTML version from disk - add result, layout.getHtml() - layoutTail = layout.getTail() - else: - var clayout = engine.jitCompiler(layout, data) - if likely(not clayout.hasError): - add result, clayout.getHtml() - layoutTail = clayout.getTail() + layoutWrapper: + var jitView = engine.jitCompiler(view, data) + if likely(not jitView.hasError): + add result, indent(jitView.getHtml(), layout.getViewIndent) else: - clayout.logger.displayErrors() - var cview = engine.jitCompiler(view, data) - if likely(not cview.hasError): - add result, indent(cview.getHtml(), layout.getViewIndent) - else: - cview.logger.displayErrors() - add result, layoutTail + jitView.logger.displayErrors() else: raise newException(TimError, "No layouts available") else: @@ -201,5 +204,17 @@ when defined napibuild: return %*(x) elif not isMainModule: + # Expose Tim Engine API for Nim development (as a Nimble librayr) export parser, html, json - export meta except TimEngine \ No newline at end of file + export meta except TimEngine +else: + # Build Tim Engine as a standalone CLI application + import pkg/kapsis + import ./tim/app/[runCommand] + + App: + about: + "Tim Engine CLI application" + commands: + --- "Main Commands" + $ run \ No newline at end of file diff --git a/src/tim/engine/compilers/html.nim b/src/tim/engine/compilers/html.nim index 5f6d2bf..d3a7760 100755 --- a/src/tim/engine/compilers/html.nim +++ b/src/tim/engine/compilers/html.nim @@ -905,7 +905,6 @@ proc evaluateNodes(c: var HtmlCompiler, nodes: seq[Node], c.evalConcat(nodes[i], scopetables) else: discard # todo of ntViewLoader: - # add c.output, c.getIndent(nodes[i].meta) c.head = c.output reset(c.output) of ntCall: @@ -925,7 +924,7 @@ proc evaluateNodes(c: var HtmlCompiler, nodes: seq[Node], # add c.jsComp, jsCompiler add c.jsOutput, "document.addEventListener('DOMContentLoaded', function(){" add c.jsOutput, jsCompiler.getOutput() - add c.jsOutput, "})" + add c.jsOutput, "});" else: discard # diff --git a/src/tim/engine/compilers/js.nim b/src/tim/engine/compilers/js.nim index 2a471b7..bdf0dd9 100644 --- a/src/tim/engine/compilers/js.nim +++ b/src/tim/engine/compilers/js.nim @@ -60,7 +60,6 @@ proc getAttrs(c: var JSCompiler, attrs: HtmlAttributes, elx: string): string = proc createHtmlElement(c: var JSCompiler, x: Node, elp: string) = ## Create a new HtmlElement - # c.jsClientSideOutput let elx = "el" & $(c.jsCountEl) add c.jsOutputCode, domCreateElement % [elx, x.getTag()] if x.attrs != nil: @@ -73,6 +72,12 @@ proc createHtmlElement(c: var JSCompiler, x: Node, elp: string) = else: add c.jsOutputCode, domInsertAdjacentElement % ["document.querySelector('" & c.targetElement & "')", elx] +# proc evaluatePartials(c: var HtmlCompiler, includes: seq[string], scopetables: var seq[ScopeTable]) = +# # Evaluate included partials +# for x in includes: +# if likely(c.ast.partials.hasKey(x)): +# c.evaluateNodes(c.ast.partials[x][0].nodes, scopetables) + proc evaluateNodes(c: var JSCompiler, nodes: seq[Node], elp: string = "") = for i in 0..nodes.high: case nodes[i].nt