From dc22440b428193b28f062f5e3c79406a6fef804d Mon Sep 17 00:00:00 2001 From: array-in-a-matrix Date: Thu, 7 Sep 2023 08:55:05 -0400 Subject: [PATCH 1/8] handle error code --- src/articles/test.html | 3 +-- src/main.nim | 7 ++++++- src/templates/index.nimja | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/articles/test.html b/src/articles/test.html index 74c2399..d249cf3 100644 --- a/src/articles/test.html +++ b/src/articles/test.html @@ -3296,5 +3296,4 @@ $$

Please see the donation page for information on how to support the development of Joplin.

- - \ No newline at end of file + \ No newline at end of file diff --git a/src/main.nim b/src/main.nim index 509e9d8..8766580 100644 --- a/src/main.nim +++ b/src/main.nim @@ -8,6 +8,10 @@ templateFolder("templates") proc renderPage(title: string): string = renderTemplate("index.nimja") +type httpErrors = object + code: string + # description: string + # ? Serve at http://127.0.0.1:5000 serve("127.0.0.1", 5000): @@ -21,7 +25,8 @@ serve("127.0.0.1", 5000): echo req notfound: - return renderPage("404") + let error = httpErrors(code: "404") + return renderPage(error.code) # make base articles and assets publicly accessible staticDir "src/articles" diff --git a/src/templates/index.nimja b/src/templates/index.nimja index 859a92f..ac71f4a 100644 --- a/src/templates/index.nimja +++ b/src/templates/index.nimja @@ -69,9 +69,9 @@ {% if title == "" %} {% elif title == "404" %} - does not exist + Page does not exist. {% else %} - + {% endif %} -- 2.49.0 From aec9ca279920852e4f05f3579d8cbfa05b8d8aa4 Mon Sep 17 00:00:00 2001 From: array-in-a-matrix Date: Thu, 7 Sep 2023 10:36:11 -0400 Subject: [PATCH 2/8] add oneko --- src/main.nim | 1 + src/scripts/oneko.gif | Bin 0 -> 3316 bytes src/scripts/oneko.js | 210 ++++++++++++++++++++++++++++++++++++++ src/templates/index.nimja | 2 +- 4 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 src/scripts/oneko.gif create mode 100644 src/scripts/oneko.js diff --git a/src/main.nim b/src/main.nim index 8766580..491d048 100644 --- a/src/main.nim +++ b/src/main.nim @@ -31,3 +31,4 @@ serve("127.0.0.1", 5000): # make base articles and assets publicly accessible staticDir "src/articles" staticDir "src/public" + staticDir "src/scripts" \ No newline at end of file diff --git a/src/scripts/oneko.gif b/src/scripts/oneko.gif new file mode 100644 index 0000000000000000000000000000000000000000..a009c2cc19c96b001ac76e96f27e5fa1a9e56577 GIT binary patch literal 3316 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 yo73M10028!@k;#w literal 0 HcmV?d00001 diff --git a/src/scripts/oneko.js b/src/scripts/oneko.js new file mode 100644 index 0000000..08c0584 --- /dev/null +++ b/src/scripts/oneko.js @@ -0,0 +1,210 @@ +// oneko.js: https://github.com/adryd325/oneko.js + +(function oneko() { + const nekoEl = document.createElement("div"); + let nekoPosX = 32; + let nekoPosY = 32; + let mousePosX = 0; + let mousePosY = 0; + const isReduced = window.matchMedia(`(prefers-reduced-motion: reduce)`) === true || window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true; + if (isReduced) { + return; + } + + let frameCount = 0; + let idleTime = 0; + let idleAnimation = null; + let idleAnimationFrame = 0; + const nekoSpeed = 10; + const spriteSets = { + idle: [[-3, -3]], + alert: [[-7, -3]], + scratchSelf: [ + [-5, 0], + [-6, 0], + [-7, 0], + ], + scratchWallN: [ + [0, 0], + [0, -1], + ], + scratchWallS: [ + [-7, -1], + [-6, -2], + ], + scratchWallE: [ + [-2, -2], + [-2, -3], + ], + scratchWallW: [ + [-4, 0], + [-4, -1], + ], + tired: [[-3, -2]], + sleeping: [ + [-2, 0], + [-2, -1], + ], + N: [ + [-1, -2], + [-1, -3], + ], + NE: [ + [0, -2], + [0, -3], + ], + E: [ + [-3, 0], + [-3, -1], + ], + SE: [ + [-5, -1], + [-5, -2], + ], + S: [ + [-6, -3], + [-7, -2], + ], + SW: [ + [-5, -3], + [-6, -1], + ], + W: [ + [-4, -2], + [-4, -3], + ], + NW: [ + [-1, 0], + [-1, -1], + ], + }; + + function create() { + nekoEl.id = "oneko"; + nekoEl.style.width = "32px"; + nekoEl.style.height = "32px"; + nekoEl.style.position = "fixed"; + nekoEl.style.pointerEvents = "none"; + nekoEl.style.backgroundImage = "url('/src/scripts/oneko.gif')"; + nekoEl.style.imageRendering = "pixelated"; + nekoEl.style.left = `${nekoPosX - 16}px`; + nekoEl.style.top = `${nekoPosY - 16}px`; + nekoEl.style.zIndex = Number.MAX_VALUE; + + document.body.appendChild(nekoEl); + + document.addEventListener("mousemove",function(){ + mousePosX = event.clientX; + mousePosY = event.clientY; + }); + + window.onekoInterval = setInterval(frame, 100); + } + + function setSprite(name, frame) { + const sprite = spriteSets[name][frame % spriteSets[name].length]; + nekoEl.style.backgroundPosition = `${sprite[0] * 32}px ${sprite[1] * 32}px`; + } + + function resetIdleAnimation() { + idleAnimation = null; + idleAnimationFrame = 0; + } + + function idle() { + idleTime += 1; + + // every ~ 20 seconds + if ( + idleTime > 10 && + Math.floor(Math.random() * 200) == 0 && + idleAnimation == null + ) { + let avalibleIdleAnimations = ["sleeping", "scratchSelf"]; + if (nekoPosX < 32) { + avalibleIdleAnimations.push("scratchWallW"); + } + if (nekoPosY < 32) { + avalibleIdleAnimations.push("scratchWallN"); + } + if (nekoPosX > window.innerWidth - 32) { + avalibleIdleAnimations.push("scratchWallE"); + } + if (nekoPosY > window.innerHeight - 32) { + avalibleIdleAnimations.push("scratchWallS"); + } + idleAnimation = + avalibleIdleAnimations[ + Math.floor(Math.random() * avalibleIdleAnimations.length) + ]; + } + + switch (idleAnimation) { + case "sleeping": + if (idleAnimationFrame < 8) { + setSprite("tired", 0); + break; + } + setSprite("sleeping", Math.floor(idleAnimationFrame / 4)); + if (idleAnimationFrame > 192) { + resetIdleAnimation(); + } + break; + case "scratchWallN": + case "scratchWallS": + case "scratchWallE": + case "scratchWallW": + case "scratchSelf": + setSprite(idleAnimation, idleAnimationFrame); + if (idleAnimationFrame > 9) { + resetIdleAnimation(); + } + break; + default: + setSprite("idle", 0); + return; + } + idleAnimationFrame += 1; + } + + function frame() { + frameCount += 1; + const diffX = nekoPosX - mousePosX; + const diffY = nekoPosY - mousePosY; + const distance = Math.sqrt(diffX ** 2 + diffY ** 2); + + if (distance < nekoSpeed || distance < 48) { + idle(); + return; + } + + idleAnimation = null; + idleAnimationFrame = 0; + + if (idleTime > 1) { + setSprite("alert", 0); + // count down after being alerted before moving + idleTime = Math.min(idleTime, 7); + idleTime -= 1; + return; + } + + let direction; + direction = diffY / distance > 0.5 ? "N" : ""; + direction += diffY / distance < -0.5 ? "S" : ""; + direction += diffX / distance > 0.5 ? "W" : ""; + direction += diffX / distance < -0.5 ? "E" : ""; + setSprite(direction, frameCount); + + nekoPosX -= (diffX / distance) * nekoSpeed; + nekoPosY -= (diffY / distance) * nekoSpeed; + + nekoPosX = Math.min(Math.max(16, nekoPosX), window.innerWidth - 16); + nekoPosY = Math.min(Math.max(16, nekoPosY), window.innerHeight - 16); + + nekoEl.style.left = `${nekoPosX - 16}px`; + nekoEl.style.top = `${nekoPosY - 16}px`; + } + + create(); +})(); diff --git a/src/templates/index.nimja b/src/templates/index.nimja index ac71f4a..29279aa 100644 --- a/src/templates/index.nimja +++ b/src/templates/index.nimja @@ -65,8 +65,8 @@
+

Blog in a Matrix

- {% if title == "" %} {% elif title == "404" %} Page does not exist. -- 2.49.0 From dd1cb29d2f54036a478077a88328f43a1ebceca3 Mon Sep 17 00:00:00 2001 From: array-in-a-matrix Date: Thu, 21 Dec 2023 16:41:06 -0500 Subject: [PATCH 3/8] rewrite as SPA --- .gitignore | 3 +- README.md | 18 +- happyx.cfg | 10 +- src/articles/test.html | 3299 --------------------------------- src/components/navigation.nim | 13 + src/index.html | 12 + src/main.nim | 43 +- src/path_params.nim | 5 + src/scripts/oneko.gif | Bin 3316 -> 0 bytes src/scripts/oneko.js | 210 --- src/templates/index.nimja | 81 - 11 files changed, 51 insertions(+), 3643 deletions(-) delete mode 100644 src/articles/test.html create mode 100644 src/components/navigation.nim create mode 100644 src/index.html create mode 100644 src/path_params.nim delete mode 100644 src/scripts/oneko.gif delete mode 100644 src/scripts/oneko.js delete mode 100644 src/templates/index.nimja diff --git a/.gitignore b/.gitignore index c7182c0..96acba8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,10 @@ # Nimcache nimcache/ cache/ +build/ # Garbage *.exe +*.js *.log *.lg -main diff --git a/README.md b/README.md index 0fa0eab..c93b1f5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # [Blog in a Matrix](https://bloginamatrix.xyz) -New server side rendered blog site written in Nim. +New single page blog site application written in Nim. Articles/blogs written in markdown using [Joplin](https://github.com/laurent22/joplin/ "The best notes app/markdown editor ever made.") then exported as `HTML` to the `/src/public` directory. Joplin has support for [the extended markdown syntax](https://github.com/laurent22/joplin/blob/dev/readme/markdown.md), [KaTeX](https://khan.github.io/KaTeX/), and [Mermaid.js](https://mermaidjs.github.io/) out of the box. The syntax can be farther extended with [plugins](https://github.com/joplin/plugins/) (e.g. [music sheet notation](https://github.com/joplin/plugin-abc-sheet-music)). @@ -18,20 +18,8 @@ Install Nim dependencies: nimble install happyx ``` -Build website: +Development server: ```sh -nim c "src/main.nim" -``` - -Run HTTP server: - -```sh -./main -``` - -Build debug site and run server using a single command: - -```sh -nim c -d:debug -r "src/main.nim" +npx dev --reload ``` diff --git a/happyx.cfg b/happyx.cfg index e610ab6..ba16cc8 100644 --- a/happyx.cfg +++ b/happyx.cfg @@ -2,7 +2,9 @@ [Main] projectName = Blog in a Matrix -projectType = SSR -mainFile = main # main script filename (without extension) -srcDir = src # source directory -assetsDir = public +projectType = SPA +mainFile = main # main script filename (without extension) that should be launched with hpx dev command +srcDir = src # source directory in project root +buildDir = build # build directory in project root +assetsDir = public # assets directory in srcDir, will copied into build/public +language = nim # programming language diff --git a/src/articles/test.html b/src/articles/test.html deleted file mode 100644 index d249cf3..0000000 --- a/src/articles/test.html +++ /dev/null @@ -1,3299 +0,0 @@ - - - - - - - - 4. Tips - - -
4. Tips
- -

Tips

-

The first few notes should have given you an overview of the main functionalities of Joplin, but there's more it can do. See below for some of these features and how to get more help using the app:

-

Web clipper

-

-

The Web Clipper is a browser extension that allows you to save web pages and screenshots from your browser. To start using it, open the Joplin desktop application, go to the Web Clipper Options and follow the instructions.

-

More info on the official website: https://joplinapp.org/clipper/

-

Plugins

-

Joplin supports many plugins that allows you to add new features to the app, such as tabs, a table of content for your notes, a way to manage favourite notes, and many other ones. To add a plugin, go to the "Plugins" section in the config screen. From there you can search and install plugins, as well as search or update plugins.

-

Attachments

-

Any kind of file can be attached to a note. In Markdown, links to these files are represented as an ID. In the note viewer, these files, if they are images, will be displayed or, if they are other files (PDF, text files, etc.) they will be displayed as links. Clicking on this link will open the file in the default application.

-

Images can be attached either by clicking on "Attach file" or by pasting (with Ctrl+V or Cmd+V) an image directly in the editor, or by drag and dropping an image.

-

More info about attachments: https://joplinapp.org/help/#attachments

- -

Joplin supports advanced search queries, which are fully documented on the official website: https://joplinapp.org/help/#searching

-

Alarms

-

An alarm can be associated with any to-do. It will be triggered at the given time by displaying a notification. To use this feature, see the documentation: https://joplinapp.org/help/#notifications

-

Markdown advanced tips

-

Joplin uses and renders Github-flavoured Markdown with a few variations and additions.

-

For example, tables are supported:

- - - - - - - - - - - - - - - - - - - - - - - - - -
TablesAreCool
col 3 isright-aligned$1600
col 2 iscentered$12
zebra stripesare neat$1
-

You can also create lists of checkboxes. These checkboxes can be ticked directly in the viewer, or by adding an "x" inside:

-
    -
  • -
  • -
  • -
-

Math expressions can be added using the KaTeX notation:

-
f(x) = \int_{-\infty}^\infty
-    \hat f(\xi)\,e^{2 \pi i \xi x}
-    \,d\xi
-
f(x)=f^(ξ)e2πiξxdξf(x) = \int_{-\infty}^\infty - \hat f(\xi)\,e^{2 \pi i \xi x} - \,d\xi -
-

Various other tricks are possible, such as using HTML, or customising the CSS. See the Markdown documentation for more info - https://joplinapp.org/markdown/

-

Community and further help

-
    -
  • For general discussion about Joplin, user support, software development questions, and to discuss new features, go to the Joplin Forum. It is possible to login with your GitHub account.
  • -
  • The latest news are posted on the Patreon page.
  • -
  • For bug reports and feature requests, go to the GitHub Issue Tracker.
  • -
-

Donations

-

Donations to Joplin support the development of the project. Developing quality applications mostly takes time, but there are also some expenses, such as digital certificates to sign the applications, app store fees, hosting, etc. Most of all, your donation will make it possible to keep up the current development standard.

-

Please see the donation page for information on how to support the development of Joplin.

-
- - \ No newline at end of file diff --git a/src/components/navigation.nim b/src/components/navigation.nim new file mode 100644 index 0000000..d989842 --- /dev/null +++ b/src/components/navigation.nim @@ -0,0 +1,13 @@ +# Import HappyX +import happyx + + +# Declare component +component Nav: + # Declare HTML template + `template`: + # tDiv(class = "", id=""): + tNav(class="nav"): + "Hello, world!" + `script`: + echo "Start coding!" diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..9ebcf9a --- /dev/null +++ b/src/index.html @@ -0,0 +1,12 @@ + + + + Blog in a Matrix + + + + +
+ + + \ No newline at end of file diff --git a/src/main.nim b/src/main.nim index 491d048..e217507 100644 --- a/src/main.nim +++ b/src/main.nim @@ -1,34 +1,11 @@ -from os import fileExists -import happyx +# Import HappyX +import + happyx, + path_params, + components/[navigation] -# Declare template folder -templateFolder("templates") - -# ? Renders template and returns HTML string -proc renderPage(title: string): string = - renderTemplate("index.nimja") - -type httpErrors = object - code: string - # description: string - -# ? Serve at http://127.0.0.1:5000 -serve("127.0.0.1", 5000): - - get "/": - req.answerHtml renderPage("") - - get "/{article}": - req.answerHtml renderPage(article) - - middleware: - echo req - - notfound: - let error = httpErrors(code: "404") - return renderPage(error.code) - -# make base articles and assets publicly accessible - staticDir "src/articles" - staticDir "src/public" - staticDir "src/scripts" \ No newline at end of file +# Declare application with ID "app" +appRoutes("app"): + "/": + # Component usage + component Nav \ No newline at end of file diff --git a/src/path_params.nim b/src/path_params.nim new file mode 100644 index 0000000..5e4166c --- /dev/null +++ b/src/path_params.nim @@ -0,0 +1,5 @@ +import happyx + + +pathParams: + id int diff --git a/src/scripts/oneko.gif b/src/scripts/oneko.gif deleted file mode 100644 index a009c2cc19c96b001ac76e96f27e5fa1a9e56577..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3316 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 yo73M10028!@k;#w diff --git a/src/scripts/oneko.js b/src/scripts/oneko.js deleted file mode 100644 index 08c0584..0000000 --- a/src/scripts/oneko.js +++ /dev/null @@ -1,210 +0,0 @@ -// oneko.js: https://github.com/adryd325/oneko.js - -(function oneko() { - const nekoEl = document.createElement("div"); - let nekoPosX = 32; - let nekoPosY = 32; - let mousePosX = 0; - let mousePosY = 0; - const isReduced = window.matchMedia(`(prefers-reduced-motion: reduce)`) === true || window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true; - if (isReduced) { - return; - } - - let frameCount = 0; - let idleTime = 0; - let idleAnimation = null; - let idleAnimationFrame = 0; - const nekoSpeed = 10; - const spriteSets = { - idle: [[-3, -3]], - alert: [[-7, -3]], - scratchSelf: [ - [-5, 0], - [-6, 0], - [-7, 0], - ], - scratchWallN: [ - [0, 0], - [0, -1], - ], - scratchWallS: [ - [-7, -1], - [-6, -2], - ], - scratchWallE: [ - [-2, -2], - [-2, -3], - ], - scratchWallW: [ - [-4, 0], - [-4, -1], - ], - tired: [[-3, -2]], - sleeping: [ - [-2, 0], - [-2, -1], - ], - N: [ - [-1, -2], - [-1, -3], - ], - NE: [ - [0, -2], - [0, -3], - ], - E: [ - [-3, 0], - [-3, -1], - ], - SE: [ - [-5, -1], - [-5, -2], - ], - S: [ - [-6, -3], - [-7, -2], - ], - SW: [ - [-5, -3], - [-6, -1], - ], - W: [ - [-4, -2], - [-4, -3], - ], - NW: [ - [-1, 0], - [-1, -1], - ], - }; - - function create() { - nekoEl.id = "oneko"; - nekoEl.style.width = "32px"; - nekoEl.style.height = "32px"; - nekoEl.style.position = "fixed"; - nekoEl.style.pointerEvents = "none"; - nekoEl.style.backgroundImage = "url('/src/scripts/oneko.gif')"; - nekoEl.style.imageRendering = "pixelated"; - nekoEl.style.left = `${nekoPosX - 16}px`; - nekoEl.style.top = `${nekoPosY - 16}px`; - nekoEl.style.zIndex = Number.MAX_VALUE; - - document.body.appendChild(nekoEl); - - document.addEventListener("mousemove",function(){ - mousePosX = event.clientX; - mousePosY = event.clientY; - }); - - window.onekoInterval = setInterval(frame, 100); - } - - function setSprite(name, frame) { - const sprite = spriteSets[name][frame % spriteSets[name].length]; - nekoEl.style.backgroundPosition = `${sprite[0] * 32}px ${sprite[1] * 32}px`; - } - - function resetIdleAnimation() { - idleAnimation = null; - idleAnimationFrame = 0; - } - - function idle() { - idleTime += 1; - - // every ~ 20 seconds - if ( - idleTime > 10 && - Math.floor(Math.random() * 200) == 0 && - idleAnimation == null - ) { - let avalibleIdleAnimations = ["sleeping", "scratchSelf"]; - if (nekoPosX < 32) { - avalibleIdleAnimations.push("scratchWallW"); - } - if (nekoPosY < 32) { - avalibleIdleAnimations.push("scratchWallN"); - } - if (nekoPosX > window.innerWidth - 32) { - avalibleIdleAnimations.push("scratchWallE"); - } - if (nekoPosY > window.innerHeight - 32) { - avalibleIdleAnimations.push("scratchWallS"); - } - idleAnimation = - avalibleIdleAnimations[ - Math.floor(Math.random() * avalibleIdleAnimations.length) - ]; - } - - switch (idleAnimation) { - case "sleeping": - if (idleAnimationFrame < 8) { - setSprite("tired", 0); - break; - } - setSprite("sleeping", Math.floor(idleAnimationFrame / 4)); - if (idleAnimationFrame > 192) { - resetIdleAnimation(); - } - break; - case "scratchWallN": - case "scratchWallS": - case "scratchWallE": - case "scratchWallW": - case "scratchSelf": - setSprite(idleAnimation, idleAnimationFrame); - if (idleAnimationFrame > 9) { - resetIdleAnimation(); - } - break; - default: - setSprite("idle", 0); - return; - } - idleAnimationFrame += 1; - } - - function frame() { - frameCount += 1; - const diffX = nekoPosX - mousePosX; - const diffY = nekoPosY - mousePosY; - const distance = Math.sqrt(diffX ** 2 + diffY ** 2); - - if (distance < nekoSpeed || distance < 48) { - idle(); - return; - } - - idleAnimation = null; - idleAnimationFrame = 0; - - if (idleTime > 1) { - setSprite("alert", 0); - // count down after being alerted before moving - idleTime = Math.min(idleTime, 7); - idleTime -= 1; - return; - } - - let direction; - direction = diffY / distance > 0.5 ? "N" : ""; - direction += diffY / distance < -0.5 ? "S" : ""; - direction += diffX / distance > 0.5 ? "W" : ""; - direction += diffX / distance < -0.5 ? "E" : ""; - setSprite(direction, frameCount); - - nekoPosX -= (diffX / distance) * nekoSpeed; - nekoPosY -= (diffY / distance) * nekoSpeed; - - nekoPosX = Math.min(Math.max(16, nekoPosX), window.innerWidth - 16); - nekoPosY = Math.min(Math.max(16, nekoPosY), window.innerHeight - 16); - - nekoEl.style.left = `${nekoPosX - 16}px`; - nekoEl.style.top = `${nekoPosY - 16}px`; - } - - create(); -})(); diff --git a/src/templates/index.nimja b/src/templates/index.nimja deleted file mode 100644 index 29279aa..0000000 --- a/src/templates/index.nimja +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - Blog in a Matrix - - - - - - - -
- - -
-
- -

Blog in a Matrix

- {% if title == "" %} - {% elif title == "404" %} - Page does not exist. - {% else %} - - {% endif %} - -
-
-
- - -- 2.49.0 From 41922dd2cd0ed55527ce9c077117aceda05fef2f Mon Sep 17 00:00:00 2001 From: array-in-a-matrix Date: Sun, 7 Jan 2024 22:16:34 -0500 Subject: [PATCH 4/8] which to SPA --- src/components/content.nim | 12 ++++++++++++ src/components/index.nim | 13 +++++++++++++ src/components/navigation.nim | 16 +++++++++++----- src/index.html | 2 +- src/main.nim | 11 +++++++---- 5 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 src/components/content.nim create mode 100644 src/components/index.nim diff --git a/src/components/content.nim b/src/components/content.nim new file mode 100644 index 0000000..eb89bd7 --- /dev/null +++ b/src/components/content.nim @@ -0,0 +1,12 @@ +# Import HappyX +import happyx + + +# Declare component +component Content: + # Declare HTML template + `template`: + tDiv(class = "p-10"): + "read" + `script`: + echo "Start coding!" diff --git a/src/components/index.nim b/src/components/index.nim new file mode 100644 index 0000000..8628f42 --- /dev/null +++ b/src/components/index.nim @@ -0,0 +1,13 @@ +# Import HappyX +import happyx + + +# Declare component +component Index: + # Declare HTML template + `template`: + tDiv(class = "p-10"): + tH1(): + "Blog in a Matrix" + `script`: + echo "Start coding!" diff --git a/src/components/navigation.nim b/src/components/navigation.nim index d989842..a03ad88 100644 --- a/src/components/navigation.nim +++ b/src/components/navigation.nim @@ -6,8 +6,14 @@ import happyx component Nav: # Declare HTML template `template`: - # tDiv(class = "", id=""): - tNav(class="nav"): - "Hello, world!" - `script`: - echo "Start coding!" + tNav(class="bg-black w-48 text-white text-center"): + tDiv(): + "Title" + tA(): + "button" + tA(): + "button" + tA(): + "button" + tA(): + "button" \ No newline at end of file diff --git a/src/index.html b/src/index.html index 9ebcf9a..f0514ba 100644 --- a/src/index.html +++ b/src/index.html @@ -6,7 +6,7 @@ -
+
\ No newline at end of file diff --git a/src/main.nim b/src/main.nim index e217507..186d5a7 100644 --- a/src/main.nim +++ b/src/main.nim @@ -2,10 +2,13 @@ import happyx, path_params, - components/[navigation] + components/[navigation, index, content] -# Declare application with ID "app" appRoutes("app"): "/": - # Component usage - component Nav \ No newline at end of file + component Nav + component Index + + "/read": + component Nav + component Content -- 2.49.0 From b8beb02fbc8348cedc78ffc653aa452bb8c7d78a Mon Sep 17 00:00:00 2001 From: array-in-a-matrix Date: Mon, 8 Jan 2024 20:02:10 -0500 Subject: [PATCH 5/8] reimplemented UI theme in SPA --- src/components/content.nim | 12 --------- src/components/glass.nim | 8 ++++++ src/components/index.nim | 13 ---------- src/components/nav.nim | 14 +++++++++++ src/components/navButton.nim | 12 +++++++++ src/components/navigation.nim | 19 -------------- src/index.html | 47 ++++++++++++++++++++++++++++++++--- src/main.nim | 15 +++++++---- src/path_params.nim | 4 +-- 9 files changed, 90 insertions(+), 54 deletions(-) delete mode 100644 src/components/content.nim create mode 100644 src/components/glass.nim delete mode 100644 src/components/index.nim create mode 100644 src/components/nav.nim create mode 100644 src/components/navButton.nim delete mode 100644 src/components/navigation.nim diff --git a/src/components/content.nim b/src/components/content.nim deleted file mode 100644 index eb89bd7..0000000 --- a/src/components/content.nim +++ /dev/null @@ -1,12 +0,0 @@ -# Import HappyX -import happyx - - -# Declare component -component Content: - # Declare HTML template - `template`: - tDiv(class = "p-10"): - "read" - `script`: - echo "Start coding!" diff --git a/src/components/glass.nim b/src/components/glass.nim new file mode 100644 index 0000000..297f113 --- /dev/null +++ b/src/components/glass.nim @@ -0,0 +1,8 @@ +import happyx + +component Glass: + arg: string + + `template`: + tArticle(class="flex items-center justify-center flex-1 m-14 max-md:m-7 max-sm:m-0 rounded-3xl max-sm:rounded-none bg-white/20 backdrop-blur-xl drop-shadow-lg noise"): + {self.arg} \ No newline at end of file diff --git a/src/components/index.nim b/src/components/index.nim deleted file mode 100644 index 8628f42..0000000 --- a/src/components/index.nim +++ /dev/null @@ -1,13 +0,0 @@ -# Import HappyX -import happyx - - -# Declare component -component Index: - # Declare HTML template - `template`: - tDiv(class = "p-10"): - tH1(): - "Blog in a Matrix" - `script`: - echo "Start coding!" diff --git a/src/components/nav.nim b/src/components/nav.nim new file mode 100644 index 0000000..065ec30 --- /dev/null +++ b/src/components/nav.nim @@ -0,0 +1,14 @@ +import happyx, navButton + +# https://git.inamatrix.xyz/array-in-a-matrix/bloginamatrix.xyz/src/commit/218b85211755732344f3fd08ab4f4a3e01ab08ac/src/templates/index.nimja#L57 + +component Nav: + `template`: + tNav(class="text-center text-white w-64 max-md:w-32 max-sm:w-full bg-black"): + tP(class="font-asix"): + "Sidebar" + + tUl(class="list-none"): + component NavButton("Home", "/") + component NavButton("Test Article", "/test") + component NavButton("Page does not exist", "/404") \ No newline at end of file diff --git a/src/components/navButton.nim b/src/components/navButton.nim new file mode 100644 index 0000000..adbaf26 --- /dev/null +++ b/src/components/navButton.nim @@ -0,0 +1,12 @@ +import happyx + +component NavButton: + text: string + path: string + + `template`: + tLi(class="list-item cursor-pointer text-white mx-2 my-2 ring-1 ring-white/20 hover:ring-white/50 rounded"): + tButton: + {self.text} + @click: + route({self.path}) \ No newline at end of file diff --git a/src/components/navigation.nim b/src/components/navigation.nim deleted file mode 100644 index a03ad88..0000000 --- a/src/components/navigation.nim +++ /dev/null @@ -1,19 +0,0 @@ -# Import HappyX -import happyx - - -# Declare component -component Nav: - # Declare HTML template - `template`: - tNav(class="bg-black w-48 text-white text-center"): - tDiv(): - "Title" - tA(): - "button" - tA(): - "button" - tA(): - "button" - tA(): - "button" \ No newline at end of file diff --git a/src/index.html b/src/index.html index f0514ba..1855a02 100644 --- a/src/index.html +++ b/src/index.html @@ -3,10 +3,51 @@ Blog in a Matrix - + + + - -
+ +
\ No newline at end of file diff --git a/src/main.nim b/src/main.nim index 186d5a7..29a24bc 100644 --- a/src/main.nim +++ b/src/main.nim @@ -1,14 +1,19 @@ -# Import HappyX import happyx, path_params, - components/[navigation, index, content] + components/[nav, glass] appRoutes("app"): "/": component Nav - component Index + component Glass("Blog in a Matrix") - "/read": + "/": component Nav - component Content + component Glass("HTTP Error: " & $errorCode) + + "/
": + component Nav + component Glass($article) + # TODO: pass article title to component which renders the article + # TODO: modify Glass or a new component is needed \ No newline at end of file diff --git a/src/path_params.nim b/src/path_params.nim index 5e4166c..32735c1 100644 --- a/src/path_params.nim +++ b/src/path_params.nim @@ -1,5 +1,5 @@ import happyx - pathParams: - id int + article string + errorCode int \ No newline at end of file -- 2.49.0 From 7d5840b6fb1d5518fd09a17b1de2c792219581db Mon Sep 17 00:00:00 2001 From: array-in-a-matrix Date: Mon, 8 Jan 2024 20:54:33 -0500 Subject: [PATCH 6/8] fixed button not working --- src/components/navButton.nim | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/navButton.nim b/src/components/navButton.nim index adbaf26..223c472 100644 --- a/src/components/navButton.nim +++ b/src/components/navButton.nim @@ -2,11 +2,10 @@ import happyx component NavButton: text: string - path: string - + path: cstring = "/" `template`: - tLi(class="list-item cursor-pointer text-white mx-2 my-2 ring-1 ring-white/20 hover:ring-white/50 rounded"): - tButton: - {self.text} - @click: - route({self.path}) \ No newline at end of file + tLi(class="list-item cursor-pointer text-white mx-2 my-2 ring-1 ring-white/20 hover:ring-white/50 rounded"): + tButton: + {self.text} + @click: + route self.path \ No newline at end of file -- 2.49.0 From 963b20810cef20abbc91283783a62fc0e8b1b99f Mon Sep 17 00:00:00 2001 From: array-in-a-matrix Date: Mon, 8 Jan 2024 20:55:43 -0500 Subject: [PATCH 7/8] comments and notfound route --- src/main.nim | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main.nim b/src/main.nim index 29a24bc..6f2a215 100644 --- a/src/main.nim +++ b/src/main.nim @@ -8,12 +8,15 @@ appRoutes("app"): component Nav component Glass("Blog in a Matrix") + "/
": + component Nav + component Glass($article) + # TODO: pass article title to component which renders the article; modify Glass or a new component is needed + # TODO: check if article name exists otherwise route to /404 + "/": component Nav component Glass("HTTP Error: " & $errorCode) - "/
": - component Nav - component Glass($article) - # TODO: pass article title to component which renders the article - # TODO: modify Glass or a new component is needed \ No newline at end of file + notfound: + route "/404" \ No newline at end of file -- 2.49.0 From d2677f52206a19d9120cad3a9efeddb218e940d9 Mon Sep 17 00:00:00 2001 From: array-in-a-matrix Date: Mon, 8 Jan 2024 21:03:22 -0500 Subject: [PATCH 8/8] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c93b1f5..98ba7e6 100644 --- a/README.md +++ b/README.md @@ -21,5 +21,5 @@ nimble install happyx Development server: ```sh -npx dev --reload +hpx dev --reload ``` -- 2.49.0