From a65e1ea845fca04553294f269f64ca3521fefed5 Mon Sep 17 00:00:00 2001 From: Ethosa Date: Sun, 9 Jun 2024 20:08:58 +0700 Subject: [PATCH 1/4] little update --- src/happyx/private/macro_utils.nim | 5 +++ src/happyx/spa/renderer.nim | 11 +++++++ src/happyx/ssr/docs/autodocs.nim | 37 +++++++++++++--------- tests/index18.html | 12 ++++++++ tests/testc2.nim | 16 ++++++++++ tests/testjs18.nim | 49 ++++++++++++++++++++++++++++++ 6 files changed, 116 insertions(+), 14 deletions(-) create mode 100644 tests/index18.html create mode 100644 tests/testjs18.nim diff --git a/src/happyx/private/macro_utils.nim b/src/happyx/private/macro_utils.nim index 0ba2f64d1..ff5773e99 100644 --- a/src/happyx/private/macro_utils.nim +++ b/src/happyx/private/macro_utils.nim @@ -1234,6 +1234,11 @@ proc buildHtmlProcedure*(root, body: NimNode, inComponent: bool = false, "is", statement[0], ident"TagRef" ), statement[0] + ), newNimNode(nnkElifBranch).add( + newCall("is", statement[0], newNimNode(nnkProcTy)), + block: + var call = newCall(statement[0]) + call ), newNimNode(nnkElse).add( newCall("initTag", newCall("$", statement[0]), newLit(true)) ))) diff --git a/src/happyx/spa/renderer.nim b/src/happyx/spa/renderer.nim index 70d4ca36a..d94317efa 100644 --- a/src/happyx/spa/renderer.nim +++ b/src/happyx/spa/renderer.nim @@ -510,6 +510,17 @@ macro buildHtml*(html: untyped): untyped = result.add(newLit(true)) +template buildHtmls*(body: untyped): seq[TagRef] = + block: + var res: seq[TagRef] + template html(b: untyped) = + res.add: + buildHtml: + b + body + res + + when enableDefaultComponents: macro buildHtmlSlot*(html: untyped, inCycle, inComponent: static[bool]): untyped = ## `buildHtml` macro provides building HTML tags with YAML-like syntax. diff --git a/src/happyx/ssr/docs/autodocs.nim b/src/happyx/ssr/docs/autodocs.nim index 8329e57ea..9ad1cce93 100644 --- a/src/happyx/ssr/docs/autodocs.nim +++ b/src/happyx/ssr/docs/autodocs.nim @@ -343,13 +343,24 @@ proc openApiDocs*(docsData: NimNode): NimNode = for m in text.findAll(re2"(?m)^\s*(\w[\w\d_]*)\s*=\s*([^\n]+)$"): pathData[text[m.group(0)]] = %text[m.group(1)] # Params + for p in route.pathParams: + let param = %*{ + "name": p.name, + "required": not p.optional, + "in": "path", + "schema": { + "type": p.paramType + } + } + pathData["parameters"].add(param) + var paramMatches: RegexMatch2 if text.find(re2"@params\s*{((\s*\w[\w\d]*\!?\s*(:\s*\w+)?[^\n]+)+)\s*}", paramMatches): - let paramText = text[paramMatches.group(1)] + let paramText = text[paramMatches.group(0)] for m in paramText.findAll( re2"(?m)^\s*(\w[\w\d_]*)(!)?\s*(:\s*\w[\w\d]*)?(\s*\-\s*[^\n]+)?" ): - pathData["parameters"].add(%*{ + let param = %*{ "name": paramText[m.group(0)], "required": m.group(1).len != 0, "description": @@ -365,18 +376,16 @@ proc openApiDocs*(docsData: NimNode): NimNode = else: "string" } - }) - - for p in route.pathParams: - let param = %*{ - "name": p.name, - "required": not p.optional, - "in": "path", - "schema": { - "type": p.paramType - } - } - pathData["parameters"].add(param) + } + var hasParam = false + for p in 0.. + + + + + +
+
+
+ + + diff --git a/tests/testc2.nim b/tests/testc2.nim index 417aac9a6..27bbad9fc 100644 --- a/tests/testc2.nim +++ b/tests/testc2.nim @@ -32,6 +32,22 @@ serve "127.0.0.1", 5000: var counter = 0 get "/{title:string}/{left:float}/{right:float}": + ## Calculate left and right. Shows title. + ## + ## @openapi { + ## operationId = calculate + ## summary = calculate left and right. + ## + ## @params { + ## title: string - just title + ## left: integer - left number + ## right: integer - right number + ## } + ## + ## @responses { + ## asdad + ## } + ## } req.answerHtml render(title, left, right) get "/": diff --git a/tests/testjs18.nim b/tests/testjs18.nim new file mode 100644 index 000000000..ab41ea5c1 --- /dev/null +++ b/tests/testjs18.nim @@ -0,0 +1,49 @@ +import ../src/happyx + + +template thunkHtml(body: untyped): proc(): TagRef = + proc(): TagRef = buildHtml: + body + +template thunkHtmls(body: untyped): seq[proc(): TagRef] = + block: + var res: seq[proc(): TagRef] + template html(b: untyped) = + res.add: + proc(): TagRef = buildHtml: + b + body + res + +let htmlProcs = thunkHtmls: + html: + tSpan: "front" + html: + tSpan: "back" + +let htmlTags = buildHtmls: + html: + tSpan: "right" + html: + tSpan: "left" + +component FormatProcHtml: + p: (proc (): TagRef) # parentheses needed in avoid "nested statements" error + html: + em(style="color:blue"): + {self.p()} + +component FormatTagHtml: + t: TagRef + html: + em(style="color:blue"): + {self.t.val} + +appRoutes("app"): + "/": + for i in 1..5: + tDiv:{$htmlProcs[0]()} + FormatProcHtml(htmlProcs[1]) + for i in 1..5: + tDiv:{$htmlTags[0]} + FormatTagHtml(htmlTags[1]) From 370dc124a292c32953abc79489c7a74ce42f43f4 Mon Sep 17 00:00:00 2001 From: Ethosa Date: Sun, 9 Jun 2024 20:49:33 +0700 Subject: [PATCH 2/4] add helpful templates (#290) --- src/happyx/spa/renderer.nim | 16 ++++++++++++++++ tests/testjs18.nim | 15 --------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/happyx/spa/renderer.nim b/src/happyx/spa/renderer.nim index d94317efa..5ae34385d 100644 --- a/src/happyx/spa/renderer.nim +++ b/src/happyx/spa/renderer.nim @@ -510,6 +510,22 @@ macro buildHtml*(html: untyped): untyped = result.add(newLit(true)) +template thunkHtml*(body: untyped): proc(): TagRef = + proc(): TagRef = buildHtml: + body + + +template thunkHtmls*(body: untyped): seq[proc(): TagRef] = + block: + var res: seq[proc(): TagRef] + template html(b: untyped) = + res.add: + proc(): TagRef = buildHtml: + b + body + res + + template buildHtmls*(body: untyped): seq[TagRef] = block: var res: seq[TagRef] diff --git a/tests/testjs18.nim b/tests/testjs18.nim index ab41ea5c1..95b05d955 100644 --- a/tests/testjs18.nim +++ b/tests/testjs18.nim @@ -1,20 +1,5 @@ import ../src/happyx - -template thunkHtml(body: untyped): proc(): TagRef = - proc(): TagRef = buildHtml: - body - -template thunkHtmls(body: untyped): seq[proc(): TagRef] = - block: - var res: seq[proc(): TagRef] - template html(b: untyped) = - res.add: - proc(): TagRef = buildHtml: - b - body - res - let htmlProcs = thunkHtmls: html: tSpan: "front" From 3c63b5b22cc2d6dac1e3fac2ec65befca4de1583 Mon Sep 17 00:00:00 2001 From: Ethosa Date: Sun, 9 Jun 2024 21:00:14 +0700 Subject: [PATCH 3/4] update website --- examples/website/src/components/about_section.nim | 7 ++----- examples/website/src/docs/introduction.nim | 8 +++++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/website/src/components/about_section.nim b/examples/website/src/components/about_section.nim index 284825837..d830f7ef7 100644 --- a/examples/website/src/components/about_section.nim +++ b/examples/website/src/components/about_section.nim @@ -3,10 +3,7 @@ import ../ui/colors -type Data = seq[tuple[name, url: string]] - - -proc AboutSection*(name: string, data: Data): TagRef = +proc AboutSection*(name: string, data: seq[tuple[name, url: string]]): TagRef = buildHtml: tDiv(class = "flex flex-col gap-8 lg:gap-4"): tP(class = "font-semibold text-2xl lg:text-base"): @@ -16,4 +13,4 @@ proc AboutSection*(name: string, data: Data): TagRef = for item in data: # Section link tA(href = item.url, class = "text-[{LinkForeground}] visited:text-[{LinkVisitedForeground}] hover:text-[{LinkActiveForeground}] translation-all"): - {name} + {item.name} diff --git a/examples/website/src/docs/introduction.nim b/examples/website/src/docs/introduction.nim index c50b203af..1a108890b 100644 --- a/examples/website/src/docs/introduction.nim +++ b/examples/website/src/docs/introduction.nim @@ -136,7 +136,7 @@ component Introduction: tH3: {translate"Contributors"} " *" - tDiv(class = "grid grid-cols-5 lg:grid-cols-10 xl:grid-cols-15 gap-x-2 gap-y-12"): + tDiv(class = "grid grid-cols-5 lg:grid-cols-10 xl:grid-cols-8 gap-x-2 gap-y-12"): Contributor("quimt", "https://github.com/quimt", "https://avatars.githubusercontent.com/u/126020181?v=4") Contributor("its5Q", "https://github.com/its5Q", "https://avatars.githubusercontent.com/u/12975646?v=4") Contributor("Lum", "https://github.com/not-lum", "https://avatars.githubusercontent.com/u/62594565?v=4") @@ -163,6 +163,12 @@ component Introduction: Contributor("Александр Старочкин", "https://github.com/levovix0", "https://avatars.githubusercontent.com/u/53170138?v=4") Contributor("MouriKogorou", "https://github.com/MouriKogorou", "https://avatars.githubusercontent.com/u/43428806?v=4") Contributor("Devon", "https://github.com/winrid", "https://avatars.githubusercontent.com/u/1733933?v=4") + Contributor("Yuriy Balyuk", "https://github.com/veksha", "https://avatars.githubusercontent.com/u/275333?v=4") + Contributor("Damian Zaręba", "https://github.com/KhazAkar", "https://avatars.githubusercontent.com/u/12693890?v=4") + Contributor("bluemax75", "https://github.com/bluemax75", "https://avatars.githubusercontent.com/u/11153375?v=4") + Contributor("svbalogh", "https://github.com/svbalogh", "https://avatars.githubusercontent.com/u/46842029?v=4") + Contributor("MelonCodeUK", "https://github.com/MelonCodeUK", "https://avatars.githubusercontent.com/u/138726110?v=4") + Contributor("baseplate-admin", "https://github.com/baseplate-admin", "https://avatars.githubusercontent.com/u/61817579?v=4") tP(class = "text-base lg:text-sm xl:text-xs pt-4"): "* " {translate"This includes all members of the HappyX community who have contributed to its development (issues and pull requests)"} From 702640cdaad39a26a6117b17206fe52730f7d689 Mon Sep 17 00:00:00 2001 From: Ethosa Date: Sun, 9 Jun 2024 23:10:27 +0700 Subject: [PATCH 4/4] add translate with arguments (#291) --- examples/website/src/pages/home.nim | 2 +- src/happyx/spa/translatable.nim | 75 ++++++++++++++++------------- tests/testjs9.nim | 13 +++-- 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/examples/website/src/pages/home.nim b/examples/website/src/pages/home.nim index e9691d95e..13079c5e7 100644 --- a/examples/website/src/pages/home.nim +++ b/examples/website/src/pages/home.nim @@ -35,7 +35,7 @@ mount Home: {translate"modern and powerful ready-to-product web framework"} tDiv(class = "cursor-pointer hover:scale-110 hover:z-10 transition-all duration-500 flex flex-col rounded-xl px-6 py-4 drop-shadow-2xl bg-gradient-to-r from-[{Background}] to-[{BackgroundSecondary}] dark:from-[{BackgroundDark}] dark:to-[{BackgroundSecondaryDark}]"): tP(class = "text-5xl lg:text-xl xl:text-3xl font-semibold"): - {translate"metaprogramming"} + "metaprogramming" tP(class = "text-3xl lg:text-base"): {translate"HappyX based on metaprogramming"} tP(class = "text-3xl lg:text-base"): diff --git a/src/happyx/spa/translatable.nim b/src/happyx/spa/translatable.nim index f335f783e..59ab90b20 100644 --- a/src/happyx/spa/translatable.nim +++ b/src/happyx/spa/translatable.nim @@ -112,33 +112,52 @@ macro translatable*(body: untyped): untyped = return translatesStatement -macro translate*(self: string): string = +macro translate*(self: string, variables: varargs[string]): string = ## Translates `self` string to current client language (SPA) or accept-language header (SSG/SSR) let language = - newNimNode(nnkIfExpr).add( - newNimNode(nnkElifBranch).add( - when defined(js): - newCall("==", newDotExpr(newDotExpr(ident"languageSettings", ident"val"), ident"lang"), newLit"auto") - else: - newCall("==", newDotExpr(ident"languageSettings", ident"lang"), newLit"auto"), - when defined(js): - newDotExpr(ident"navigator", ident"language") - else: - ident"acceptLanguage" - ), newNimNode(nnkElse).add( - when defined(js): - newDotExpr(newDotExpr(ident"languageSettings", ident"val"), ident"lang") - else: - newDotExpr(ident"languageSettings", ident"lang") - ) + newCall("[]", newCall("$", + newNimNode(nnkIfExpr).add( + newNimNode(nnkElifBranch).add( + when defined(js): + newCall("==", newDotExpr(newDotExpr(ident"languageSettings", ident"val"), ident"lang"), newLit"auto") + else: + newCall("==", newDotExpr(ident"languageSettings", ident"lang"), newLit"auto"), + when defined(js): + newDotExpr(ident"navigator", ident"language") + else: + ident"acceptLanguage" + ), newNimNode(nnkElse).add( + when defined(js): + newDotExpr(newDotExpr(ident"languageSettings", ident"val"), ident"lang") + else: + newDotExpr(ident"languageSettings", ident"lang") + ) + )), + newCall("..", newLit(0), newLit(1)) ) - source = + sourceRaw = when self is static[string]: newLit(self) else: self translations = ident"translates" + source = newCall("format", newNimNode(nnkBracketExpr).add( + newNimNode(nnkBracketExpr).add( + translations, sourceRaw + ), + language + )) + sourceDefault = newCall("format", newNimNode(nnkBracketExpr).add( + newNimNode(nnkBracketExpr).add( + translations, sourceRaw + ), + newLit"default" + )) + + for i in variables: + source.add(i) + sourceDefault.add(i) result = newNimNode(nnkIfStmt).add( newNimNode(nnkElifBranch).add( @@ -146,24 +165,14 @@ macro translate*(self: string): string = newCall( "hasKey", newNimNode(nnkBracketExpr).add( - translations, source + translations, sourceRaw ), language ) ), - newNimNode(nnkBracketExpr).add( - newNimNode(nnkBracketExpr).add( - translations, source - ), - newLit"default" - ) + sourceDefault ), newNimNode(nnkElse).add( - newNimNode(nnkBracketExpr).add( - newNimNode(nnkBracketExpr).add( - translations, source - ), - language - ) + source ) ) when not (self is static[string]): @@ -171,8 +180,8 @@ macro translate*(self: string): string = newCall("not", newCall( "hasKey", - translations, source + translations, sourceRaw ) ), - source + sourceRaw )) diff --git a/tests/testjs9.nim b/tests/testjs9.nim index 1837bff49..d291b51b1 100644 --- a/tests/testjs9.nim +++ b/tests/testjs9.nim @@ -4,21 +4,24 @@ import translatable: - "Hello": - # "Hello!" by default - "ru" -> "Привет" - "fr" -> "Bonjour" + "hello": + # "Hello, $#!" by default + "default" -> "Hello, $#!" + "ru" -> "Привет, $#!" + "fr" -> "Bonjour, $#!" +echo translates appRoutes("app"): "/": component Pure tDiv: "Hello" + {translate"nothing"} nim: var x = 0 - str = translate("Hello") + str = translate("hello", "username") tDiv(class = "flex flex-col gap-2"): while x <= 20: tDiv(class = "flex gap-2"):