Layouts
In the closing part of the tutorial, we'll create a layout to be used on all pages of the tutorial app. We'll build it as a separate module that is imported by individual pages.
The layout will consist of a top navigation panel and the content block underneath it. The navigation panel will have basic logic preventing the user from going to the page they're already on.
-
In the tutorial app folder, in
src/tutorial
, create a file calledlayout.nim
with the following content:import karax/[karaxdsl, kdom, vdom] import karkas import pages import state proc render*(body: VNode): VNode = buildHtml: tdiv: for node in body: node
-
Now, do two things in
src/tutorial/pages/index.nim
,src/tutorial/pages/forms.nim
, andsrc/tutorial/pages/notfound.nim
:- Add
import ../layout
underimport ../state
. - Replace
buildHtml(tdiv)
withlayout.render buildHtml(tdiv) do
.
For example,
src/tutorial/pages/index.nim
should look like this:import karax/[karaxdsl, kdom, vdom] import kraut/context import karkas import ../pages import ../state import ../layout proc render*(context: Context): VNode = currentPage = Page.index document.title = "index" layout.render buildHtml(tdiv) do: h1: text "index" tdiv(style = hStack()): tdiv(style = box(size = 1) <- {border: "solid"}): p: text "Box one" tdiv(style = box(size = 2) <- {border: "solid"}): p: text "Box two"
- Add
-
Rebuild the app with
sauer make
, open it in your browser, and make sure that nothing changed. Except that now, we have factored out common logic to a shared module, which we can now edit and thus affect all pages at once. -
Open
src/tutorial/layout.nim
in your favorite editor and update the code:import karax/[karaxdsl, kdom, vdom] import karkas import pages import state proc render*(body: VNode): VNode = buildHtml: tdiv(style = vStack()): tdiv(style = topPanel() <- hStack() <- {padding: "10px", boxShadow: "0 0 10px"}) tdiv: for node in body: node
We've set up basic structure for our layout: a vertical stack with a panel at the top and a content block at the bottom.
Note how we describe the top panel. By composing
topPanel()
withhStack()
and custom styles, we define a full-width horizontal stack container with padding and shadow.Rebuild the app with
sauer make
and check the new (now empty) panel:
-
Now let's define a proc that generates a navigation entry and invoke it in the top panel. Based on the current page, it shows either a link to a page or just its name:
import karax/[karaxdsl, kdom, vdom] import karkas import pages import state proc navEntry(page: Page, url, caption: string): VNode = buildHtml: tdiv(style = box() <- {minWidth: "50px"}): if state.currentPage != page: a(href = k url): text k caption else: text k caption proc render*(body: VNode): VNode = buildHtml: tdiv(style = vStack()): tdiv(style = topPanel() <- hStack() <- {padding: "10px", boxShadow: "0 0 10px"}): navEntry(index, "#/", "Index") navEntry(forms, "#/forms", "Forms") tdiv: for node in body: node
Rebuild the app with sauer make
and see the complete app with navigation: