diff --git a/.gitignore b/.gitignore
index 70f0913..9e3641e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-/__pycache__
-/public
+/target
+/html
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..6831faf
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,264 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "arraydeque"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
+
+[[package]]
+name = "bitflags"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
+[[package]]
+name = "getopts"
+version = "0.2.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.15.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
+dependencies = [
+ "foldhash",
+]
+
+[[package]]
+name = "hashlink"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
+dependencies = [
+ "hashbrown",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "memchr"
+version = "2.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
+
+[[package]]
+name = "memo-map"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38d1115007560874e373613744c6fba374c17688327a71c1476d1a5954cc857b"
+
+[[package]]
+name = "minijinja"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e60ac08614cc09062820e51d5d94c2fce16b94ea4e5003bb81b99a95f84e876"
+dependencies = [
+ "memo-map",
+ "self_cell",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "pulldown-cmark"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0"
+dependencies = [
+ "bitflags",
+ "getopts",
+ "memchr",
+ "pulldown-cmark-escape",
+ "serde",
+ "unicase",
+]
+
+[[package]]
+name = "pulldown-cmark-escape"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "self_cell"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749"
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.141"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicase"
+version = "2.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "unicode-width"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
+
+[[package]]
+name = "webTemplate"
+version = "0.2.0"
+dependencies = [
+ "hashlink",
+ "minijinja",
+ "pulldown-cmark",
+ "regex",
+ "yaml-rust2",
+]
+
+[[package]]
+name = "yaml-rust2"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ce2a4ff45552406d02501cea6c18d8a7e50228e7736a872951fe2fe75c91be7"
+dependencies = [
+ "arraydeque",
+ "encoding_rs",
+ "hashlink",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..4d2b46f
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "webTemplate"
+version = "0.2.0"
+edition = "2024"
+
+[dependencies]
+hashlink = "0.10.0"
+minijinja = { version = "2.10.2", features = ["loader", "builtins", "json"] }
+pulldown-cmark = { version = "0.13.0", features = ["serde"] }
+regex = "1.11.1"
+yaml-rust2 = "0.10.2"
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 9595555..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,10 +0,0 @@
-FROM python:3
-
-WORKDIR /app
-
-COPY requirements.txt ./
-RUN pip install --no-cache-dir -r requirements.txt
-
-copy . .
-
-CMD [ "python", "./render.py" ]
diff --git a/header.py b/header.py
deleted file mode 100644
index a921a9f..0000000
--- a/header.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import yaml
-
-from render import listPages
-
-firstItem = True
-
-def headerGen(item, root):
- global firstItem
- if(root and not firstItem):
- separator = ''
- else:
- separator = ''
- firstItem = False
-
- if(not ('klickable' in item and item['klickable'] is False)):
- item['lable'] = '' + item["lable"] + ''
-
- if('sub' not in item):
- return '
' + separator + ''
-
- data = ''
- subicon = ''
- if(root):
- subicon = ' '
- data += ' data-hassub="true"'
-
- html = '' + separator + ''
-
diff --git a/index.py b/index.py
deleted file mode 100644
index 1ed05f0..0000000
--- a/index.py
+++ /dev/null
@@ -1,139 +0,0 @@
-import os
-import yaml
-import shutil
-from jinja2 import Template
-import sass
-
-from page import Page
-
-pages = []
-
-# SRC_DIR = "/home/mreenen/Documents/git/kladjes"
-SRC_DIR = os.path.abspath("/home/mreenen/Documents/git/kladjes")
-TARGET_DIR = os.path.abspath("public")
-
-def renderPage(page, template, header):
- html = page.renderPage(template, header, SRC_DIR)
-
- path = TARGET_DIR + page.url
- if (path.split('.')[-1] != "html"):
- path = os.path.abspath(path + '/index.html')
-
- pathDir = os.path.dirname(path)
- fileName = os.path.basename(path)
-
- os.makedirs(pathDir, exist_ok=True)
- with open(path, 'w') as file:
- file.write(html)
- del html
-
- if (page.assets is not None):
- print("assets found")
- for asset in page.assets:
- srcAssets = SRC_DIR + asset
- destAssets = TARGET_DIR + asset
-
- if(not os.path.isdir(destAssets)):
- os.mkdir(destAssets)
-
- print(f"asset: {asset}")
-
- for f in os.listdir(srcAssets):
- print(f"f: {f}")
- if ((f[0] != '.') and os.path.isfile(srcAssets + "/" + f)):
- print("copy: " + asset + "/" + f)
- shutil.copyfile(srcAssets + "/" + f, destAssets + "/" + f)
-
-def findPageInList(list, url):
- i = 0
- while (i < len(list)):
- if (list[i].url == url):
- return i
- i += 1
- return -1
-
-def render(rootPage, template, header):
- done = False
- isSub = False
- lastPage = []
- curPage = 0
- while not done:
- if (curPage == 0):
- page = rootPage
- else:
- pageIndex = curPage - 1
- page = None
- if (pageIndex < len(rootPage.subPages)):
- page = rootPage.subPages[pageIndex]
- else:
- pageIndex -= len(rootPage.subPages)
- if (pageIndex < len(rootPage.sidebar)):
- page = rootPage.sidebar[pageIndex]
-
- if (page is not None):
- if (page.clickable):
- renderPage(page, template, header)
-
- if ((curPage != 0) and
- ((len(page.subPages) > 0) or (len(page.sidebar) > 0))):
- rootPage = page
- lastPage.append(curPage)
- curPage = 1
- else:
- curPage += 1
-
- else:
- if (len(lastPage) > 0):
- curPage = lastPage.pop() + 1
- rootPage = rootPage.parrent
- else:
- done = True
- print(f"done")
-
-
-
-def index(fileName):
- global pages
- with open(SRC_DIR + '/index.yaml', 'r') as file:
- index = yaml.safe_load(file)
-
- if ('sitemap' not in index):
- print("ERROR: /index.yaml is missing a sitemap")
- else:
- pages = []
- for item in index["sitemap"]:
- pages.append(Page(item, None))
-
- for page in pages:
- page.scan(SRC_DIR)
-
- print("START INDEX")
- for p in pages:
- print(p)
- print("END INDEX")
-
- seperator = False
- header = ""
- for p in pages:
- if (seperator):
- header += ""
- header += p.topMenuHTML()
- seperator = True
-
- os.makedirs(TARGET_DIR, exist_ok=True)
- with open(TARGET_DIR + '/header.html', 'w') as file:
- file.write(header);
-
- with open('template.html') as file:
- template = Template(file.read())
- for p in pages:
- render(p, template, header)
-
- with open('style.scss', 'r') as file:
- css = sass.compile(string=file.read())
- with open(TARGET_DIR + '/style.css', 'w') as file:
- file.write(css)
- del css
-
-if __name__ == '__main__':
- index('index.yml')
diff --git a/index.yml b/index.yml
deleted file mode 100644
index 131f057..0000000
--- a/index.yml
+++ /dev/null
@@ -1,181 +0,0 @@
----
- - lable: Home
- url: /
-# - lable: Niet vergeten
-# url: /niet-vergeten.html
- - lable: HR
- sub:
- - lable: ANE10
- url: ANE10
- sidebar:
- - lable: Index
- url: .
- - lable: Dingen
- url: dingen.html
- - lable: lab 3
- url: lab-3.html
- - lable: lab 5
- url: lab-5.html
- - lable: ANE10-2
- url: ANE10-2
- sidebar:
- - lable: Index
- url: .
- - lable: Bi Polar Junction Transistor
- url: bjt.html
- - lable: Field Effect Transistor
- url: fet.html
-
- - lable: DIS10
- sidebar:
- - lable: index
- url: .
- - lable: handigheidjes
- url: handigheidjes.html
- - lable: opgavens
- url: opgaves.html
- - lable: 3.1 theorie
- url: week-3.1.html
- - lable: 3.2 theorie
- url: week-3.2.html
- - lable: 3.3 theorie
- url: week-3.3.html
- - lable: 3.4 lab
- url: week-3.4.html
- - lable: 3.5 theorie
- url: week-3.5.html
- # - lable: 3.7 lab
- # url: week-3.7.html
- - lable: 4.1 lab
- url: week-4.1.html
- - lable: 4.3 lab
- url: week-4.3.html
- - lable: 4.4 theorie
- url: week-4.4.html
- - lable: 4.5 theorie
- url: week-4.5.html
- - lable: 4.7 lab
- url: week-5.5.html
- - lable: EPS20
- sidebar:
- - lable: index
- url: .
- - lable: week 1
- url: week-1.html
- - lable: lab 1
- url: lab-1.html
- - lable: week 2
- url: week-2.html
-
- - lable: Argief (beta)
- url: argief
- sidebar:
- # year 1
-
- - lable: WIS10 #empty
- clickable: False
- - lable: ELE10 #empty
- clickable: False
- - lable: PEE10 #empty
- clickable: False
- - lable: ELE20
- sub:
- - opamp
-
-
- - lable: WIS20
- sidebar:
- - lable: formuleblad
- url: formuleblad.html
- - lable: diffrencieren
- url: diffrencieeren.html
- - lable: supsitutsie
- url: supsitutsie.html
- - lable: breuksplitsen
- url: breuksplitsen.html
- - lable: parsiele int.
- url: parsiel.html
- - lable: fourier transform
- url: fourier-transformatie.html
- - lable: divrenciaal vergeleiking
- url: difrenciaal-vergeleiking.html
- - lable: 2de Orde DV
- url: 2de-orde-dv.html
- - EMS10 #empty
- - PEE20 #empty
- - lable: EPS10
- sub:
- - buckboost
- - electiesh-en-machnetich-veld
- - lab-1
- - lab-2
- - lab-3
- - lab-4
- - lab-5
- - lab-6
-
- # year 2
-
- - lable: REG10
- url: REG10-2
- sidebar:
- - lable: Index
- url: .
- - lable: Laplace
- url: laplace.html
- - lable: Voorbeelden
- url: voorbeelden.html
- - lable: Eigenschappen
- url: eigenschappen.html
- - lable: P-Regelaar
- url: pregelaar.html
- - lable: polen en nulpunten
- url: polen-en-nulpunten.html
- - lable: Formuleblad
- url: formuleblad.html
- - lable: Lab 1
- url: lab1.html
- - lable: Lab 2
- url: lab2.html
- - lable: Lab 3
- url: lab3.html
- - EMS20 #empyt
- - PEE30 #empty
- #- ANE10
-
- #- DIS10
- #- EPS20
- - PEE40 #empty
- - lable: TEL10
- sidebar:
- - lable: index
- url: .
- # - lable: week 4.1
- # url: week-1.html
- - lable: 4.2 theorie
- url: week-2.html
- - lable: 4.3 lab
- url: week-3.html
- - lable: 4.5 theorie
- url: week-5.html
-
- - lable: Fablab making
- url: fablab-making.html
- - lable: Toki Pona
- url: tokipona
-
-# - lable: Projecten
-# klickable: False
-# url: projecten
-# sub:
-# - lable: MR Function Board
-# url: mr-fn-board
-# sidebar:
-# - lable: blog
-# url: blog.html
-# - lable: Button layout
-# url: button-layout.html
-# - lable: PCB
-# url: pcb.html
-# - lable: Puzzel Game
-# url: puzzel-game
diff --git a/page.py b/page.py
deleted file mode 100644
index 9c79a01..0000000
--- a/page.py
+++ /dev/null
@@ -1,211 +0,0 @@
-import os
-import yaml
-
-from renderMD import renderMD
-
-class Page:
- lable = ''
- url = ''
- clickable = True
-
- subPages = []
- sidebar = []
- parrent = None
- assets = None
-
- def __init__(self, item, parrent):
- self.subPages = []
- self.sidebar = []
- self.parrent = parrent
-
- if (parrent is None):
- root = ''
- else:
- root = parrent.url
-
- if (type(item) is str):
- self.lable = item
- self.url = os.path.abspath(root + '/' + item)
- self.clickable = True
-
- elif (type(item) is dict):
- if('url' not in item):
- if(('klickable' in item) and (item['klickable'] is False)):
- self.url = root # still set the url for sub pages
- else:
- self.url = root + '/' + item['lable']
- else:
- self.url = item['url']
-
- if(self.url == ''):
- self.url = '/'
-
- if(self.url[0] != '/'):
- self.url = root + '/' + self.url
-
- self.url = os.path.abspath(self.url)
-
- if('lable' not in item):
- self.lable = item['url'].split('/')[-1]
- else:
- self.lable = item['lable']
- self.lable = self.lable.replace('<', '<')
- self.lable = self.lable.replace('>', '>')
-
- if ('sub' in item):
- for subItem in item['sub']:
- self.subPages.append(Page(subItem, self))
-
- if ('sidebar' in item):
- for subItem in item['sidebar']:
- self.sidebar.append(Page(subItem, self))
- else:
- self.sidebar = []
-
- if ('klickable' in item):
- self.clickable = item["klickable"]
-
- else:
- print('ERROR: Page.__init__(): invalid index itemtype ' + type(item))
-
- def scan(self, srcDir):
- if ((self.parrent is None) or (self.url != self.parrent.url)):
- indexFile = os.path.abspath(srcDir + self.url + '/index.yaml')
- print(f"INFO: Page.scan(): indexFile: {indexFile}")
-
- index = None
- if (os.path.isfile(indexFile)):
- with open(indexFile, 'r') as file:
- index = yaml.safe_load(file)
-
- if (index is not None):
- if ('subPages' in index):
- print(f"INFO: Page.scan(): subpages found for {self.url}")
- for item in index["subPages"]:
- page = Page(item, self)
- self.subPages.append(page)
- page.scan(srcDir)
-
- if ('sidebar' in index):
- print(f"INFO: Page.scan(): sidemenu found for {self.url}")
- for item in index["sidebar"]:
- page = Page(item, self)
- self.sidebar.append(page)
- page.scan(srcDir)
-
- if ('assets' in index):
- print(f"INFO: Page.scan(): assets found for {self.url}")
- self.assets = index["assets"]
- i = 0
- while (i < len(self.assets)):
- if(self.assets[i][0] != '/'):
- self.assets[i] = self.url + '/' + self.assets[i]
- self.assets[i] = os.path.abspath(self.assets[i])
- i += 1
-
-
-
- def getSidebar(self):
- if ((len(self.sidebar) == 0) and (self.parrent is not None)):
- return self.parrent.getSidebar()
- else:
- return self.sidebar
-
- def __str__(self):
- return self.toString(0)
- def toString(self, indents):
- indent = " "*indents
- str = f"{indent} - lable: {self.lable}\n"
- str += f"{indent} url: {self.url}\n"
- if (self.clickable):
- str += f"{indent} clickable: True\n"
- else:
- str += f"{indent} clickable: False\n"
- if (self.assets is not None):
- str += f"{indent} assets: {len(self.assets)}\n"
- for asset in self.assets:
- str += f"{indent} - {asset}\n"
- if (len(self.subPages) > 0):
- str += f"{indent} sub: {len(self.subPages)}\n"
- for page in self.subPages:
- str += page.toString(indents + 1)
- if (len(self.sidebar) > 0):
- str += f"{indent} sidebar:\n"
- for page in self.sidebar:
- str += page.toString(indents + 1)
- return str
-
- def topMenuHTML(self):
- if (len(self.subPages) == 0):
- propertys = ''
- if (self.clickable):
- html = f""
- else:
- html = f""
- else:
- subicon = " "
- propertys = " data-hassub='true'"
- propertys += " class=\"sub\""
- if (self.clickable):
- html = f""
- else:
- html = f""
- for page in self.subPages:
- html += page.topMenuHTML()
- html += "
"
-
- return f"- {html}
"
-
- def sidebarHTML(self):
- if (len(self.subPages) == 0):
- propertys = ""
- if (self.clickable):
- html = f""
- else:
- html = f""
- else:
- propertys = " data-hassub='true'"
- propertys += " class=\"sub\""
- if (self.clickable):
- html = f""
- else:
- html = f""
- for page in self.subPages:
- html += page.sidebarHTML()
- html += "
"
-
- return f"- {html}
"
-
- def renderPage(self, template, header, srcDir):
- html = ""
-
- if (os.path.isdir(srcDir + self.url)):
- if(self.url[-1] == '/'):
- srcFile = self.url + 'index.md'
- else:
- srcFile = self.url + '/index.md'
- elif (len(self.url.split('.')) > 1 and len(self.url.split('.')[-1]) < 5):
- srcFile = '.'.join(self.url.split('.')[0:-1]) + '.md'
- else:
- srcFile = self.url + '.md'
-
- if(not os.path.isfile(srcDir + srcFile)):
- print(f"ERROR: faild to find srouce file for page {self.lable} ({self.url})")
- else:
- print('md: ' + srcFile)
-
- if(len(self.getSidebar()) != 0):
- sidebar = ''
- else:
- sidebar = ""
-
- html = template.render(
- header = header,
- sidebar = sidebar,
- body = renderMD(srcDir + srcFile)
- )
-
- return html
diff --git a/render.py b/render.py
deleted file mode 100644
index a6b55cc..0000000
--- a/render.py
+++ /dev/null
@@ -1,179 +0,0 @@
-import os
-import yaml
-import shutil
-from jinja2 import Template
-
-# from header import headerGen
-from renderMD import renderMD
-from renderSCSS import renderSCSS
-
-with open('template.html', 'r') as file:
- template = Template(file.read())
-
-srcDir = '/source'
-destDir = '/target'
-
-firstItem = True
-
-def headerGen(item, root):
- global firstItem
- if(root and not firstItem):
- separator = ''
- else:
- separator = ''
- firstItem = False
-
- lable = item['lable']
-
- if(not ('klickable' in item and item['klickable'] is False)):
- lable = '' + item["lable"] + ''
-
- if('sub' not in item):
- return '- ' + separator + '
'
-
- data = ''
- subicon = ''
- if(root):
- subicon = ' '
- data += ' data-hassub="true"'
-
- html = '- ' + separator + '
'
-
-def sidebarGen(item, root):
- if(not ('klickable' in item and item['klickable'] is False)):
- item['lable'] = '' + item["lable"] + ''
-
- if('sub' not in item):
- return ''
-
- html = ''
-
-def listPages(items, parentUrl, cb):
- root = False
- if(firstItem):
- root = True
- html = ""
- for item in items:
-
- if(type(item) is dict):
- if('url' not in item):
- if('lable' not in item):
- print('url or lable reqired')
- continue
- if('klickable' in item and item['klickable'] is False):
- item["url"] = parentUrl
- else:
- item["url"] = parentUrl + '/' + item["lable"]
-
- if(item['url'] == ''):
- item['url'] = '/'
-
- if(item["url"][0] != '/'):
- item["url"] = parentUrl + '/' + item["url"]
-
- #WARNING: XSS vanrable!
- if('lable' not in item):
- item["lable"] = item["url"].split('/')[-1]
-
- # if(not ('klickable' in item and item['klickable'] is False)):
- html += cb(item, root)
- continue
-
- if(type(item) is str):
- html += cb({"lable": item, "url": parentUrl + '/' + item}, root)
- continue
-
- return html
-
-sidebar = ''
-def renderPage(item, root):
- global srcDir, destDir, header, template, sidebar
- html = ''
-
- srcFile = item['url']
- if(os.path.isdir(srcDir + item['url'])):
- if(item['url'][-1] == '/'):
- srcFile = item['url'] + 'index.md'
- else:
- srcFile = item['url'] + '/index.md'
- elif(len(item['url'].split('.')) > 1 and len(item['url'].split('.')[-1]) < 5):
- srcFile = '.'.join(item['url'].split('.')[0:-1]) + '.md'
-
- if(not os.path.isfile(srcDir + srcFile)):
- print('faild to find path to page for ' + item['url'])
- else:
- print('md: ' + srcFile)
-
- if(not os.path.isdir(destDir + '/'.join(srcFile.split('/')[0:-1]))):
- os.mkdir(destDir + '/'.join(srcFile.split('/')[0:-1]))
-
- if('sidebar' in item):
- sidebar = ''
-
- target = open(destDir + '.'.join(srcFile.split('.')[0:-1]) + '.html', "w")
- target.write(template.render(
- header = header,
- sidebar = sidebar,
- body = renderMD(srcDir + srcFile)
- ))
- target.close()
-
- if('sidebar' in item):
- listPages(item['sidebar'], item['url'], renderPage)
- sidebar = ''
- if('sub' in item):
- listPages(item['sub'], item['url'], renderPage)
-
- return ''
-
-def copyAssets(d):
- global srcDir, destDir
- for f in os.listdir(srcDir + d):
- if f == '.git':
- continue
-
- if(os.path.isdir(srcDir + d + f)):
- if(not os.path.isdir(destDir + d + f)):
- os.mkdir(destDir + d + f)
- copyAssets(d + f + '/')
- continue
-
- ext = f.split('.')[-1]
- if(ext == 'md'):
- # print('md: ' + d + f)
- # target = open(destDir + d + '.'.join(f.split('.')[0:-1]) + '.html', "w")
- # target.write(template.render(
- # header = header,
- # body = renderMD(srcDir + d + f)
- # ))
- # target.close()
- continue
-
- if(ext == 'scss'):
- print('scss: ' + d + f)
- target = open(destDir + d + '.'.join(f.split('.')[0:-1]) + '.css', "w")
- target.write(renderSCSS(srcDir + d + f))
- target.close()
- continue
-
- print("copy: " + d + f)
- shutil.copyfile(srcDir + d + f, destDir + d + f)
-
-if(__name__ == '__main__'):
- with open('index.yml', 'r') as file:
- index = yaml.safe_load(file)
-
- header = ''
-
- copyAssets('/')
- listPages(index, '', renderPage)
diff --git a/render.sh b/render.sh
deleted file mode 100644
index 432fc0c..0000000
--- a/render.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-
-cd $HOME/webTemplate
-
-rm -r ../public/*
-
-python3 render.py
-
-# cd ../public/ && python3 -m http.server 8000
-
diff --git a/renderMD.py b/renderMD.py
deleted file mode 100644
index b5b3142..0000000
--- a/renderMD.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import html
-from misaka import Markdown, HtmlRenderer
-import latex2mathml.converter
-import re
-
-def renderLatex(code):
- code = code.strip()
- code = code.replace("=>", "\\Rightarrow")
- code = code.replace("->", "\\rightarrow")
- code = code.replace("\\(", "\\left(")
- code = code.replace("\\)", "\\right)")
- code = code.replace("*", "\\cdot")
-
- a = re.search(r"{[^{}]*} */ *{[^{}]*}", code)
- while a is not None:
- newcode = code[:a.span()[0]]
- newcode += "\\frac"
- newcode += re.sub(r'}[ ]*/[ ]*{', '}{', code[a.span()[0] : a.span()[1]])
- newcode += code[a.span()[1]:]
- code = newcode
- a = re.search(r"{[^{}}]*} */ *{[^{}}]*}", code)
-
- return latex2mathml.converter.convert(code)
-
-class HighlighterRenderer(HtmlRenderer):
- def codespan(self, code):
- lang = code.split(' ')[0]
- if(lang == 'tex'):
- return '{}\n'.format(renderLatex(' '.join(code.split(' ')[1:]).strip()))
- return '{}\n'.format(code.strip())
- def blockcode(self, code, lang):
- if(lang == 'latex/equetion'):
- return '{}
\n'.format(code.strip(), renderLatex(code))
- return '
{}
\n'.format(lang.replace('/', '-'), code)
-
-renderer = HighlighterRenderer()
-md = Markdown(renderer, extensions=('fenced-code','tables'))
-
-def renderMD(src):
- srcFile = open(src, 'r')
- html = md(srcFile.read())
- srcFile.close()
- return html
diff --git a/renderSCSS.py b/renderSCSS.py
deleted file mode 100644
index f649194..0000000
--- a/renderSCSS.py
+++ /dev/null
@@ -1,13 +0,0 @@
-code = """li {
- display: block;
-}
-
-"""
-import sass
-
-def renderSCSS(src):
- srcFile = open(src, 'r')
- # print(src)
- css = sass.compile(string=srcFile.read())
- srcFile.close()
- return css
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 9707c97..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-pyyaml
-jinja2
-misaka
-latex2mathml
-libsass
diff --git a/sidemenu.py b/sidemenu.py
deleted file mode 100644
index 1d652c4..0000000
--- a/sidemenu.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import yaml
-
-def parseHTML(item):
- if(not ('klickable' in item and item['klickable'] is False)):
- item['lable'] = '' + item["lable"] + ''
-
- if('sub' not in item):
- return ''
-
- html = ''
-
-def genHTML(items, parentUrl):
- html = ""
- for item in items:
-
- if(type(item) is dict):
- if('url' not in item):
- if('lable' not in item):
- print('url or lable reqired')
- continue
- if('klickable' in item and item['klickable'] is False):
- item["url"] = parentUrl
- else:
- item["url"] = parentUrl + '/' + item["lable"]
-
- if(item["url"][0] != '/'):
- item["url"] = parentUrl + '/' + item["url"]
-
- #WARNING: XSS vanrable!
- if('lable' not in item):
- item["lable"] = item["url"].split('/')[-1]
-
- html += parseHTML(item)
- continue
-
-
- if(type(item) is str):
- html += parseHTML({"lable": item, "url": parentUrl + '/' + item})
- continue
-
- return html
-
-def getSidebar(items, parentUrl):
- html = ''
- return html
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..8bdcf93
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,64 @@
+use std::{path::Path};
+use std::fs;
+use minijinja::Environment;
+
+mod render;
+use render::{Renderer, IndexItem, build_jinja_env, Template};
+
+const SRC_PATH: &'static str = "../src";
+const OUT_PATH: &'static str = "./html/";
+
+fn render_index(out_path: &Path, index: &IndexItem, cur_path: &Path, site_index: &Renderer, jinja_env: Option<&Environment>) {
+ let dest_path: &Path = &cur_path.join(&index.friendly);
+ println!("dest_path: {:?}", dest_path);
+
+ let jinja_env = match jinja_env {
+ Some(env) => env,
+ None => &build_jinja_env(Template::index(&site_index.path.join("templates"))),
+ };
+
+ match &index.src {
+ Some(src) => {
+ let friendly = match index.friendly.len() {
+ 0 => String::from("index"),
+ _ => index.friendly.clone()
+ };
+
+ if !index.is_asset {
+ let dest_path: &Path = &cur_path.join(format!("{}.{}", friendly, index.target_extention));
+ match site_index.render_page(index, &site_index.site, jinja_env) {
+ Some(html) => {
+ let _ = fs::write(dest_path, html);
+ },
+ None => todo!(),
+ };
+ }
+ else {
+ let _ = fs::copy(src, &cur_path.join(friendly));
+ }
+ },
+ None => {
+ let _ = fs::create_dir(dest_path);
+ },
+ };
+
+ for page in &index.sub_pages {
+ render_index(out_path, page, dest_path, &site_index, Some(&jinja_env));
+ }
+}
+
+fn main() {
+
+ let src_path = Path::new(SRC_PATH);
+ let out_path = Path::new(OUT_PATH);
+
+ let index = Renderer::index(src_path).unwrap();
+
+
+ println!("");
+ println!("index:");
+ println!("{:?}", index);
+
+ let _ = fs::create_dir_all(out_path);
+ render_index(out_path, &index.site, out_path, &index, None);
+}
diff --git a/src/render.rs b/src/render.rs
new file mode 100644
index 0000000..3e799a9
--- /dev/null
+++ b/src/render.rs
@@ -0,0 +1,118 @@
+mod index;
+mod parse_md;
+
+use std::{collections::BTreeMap, fs, path::Path};
+use minijinja::{context, Environment, Value};
+use index::indexer;
+use parse_md::parse_md;
+use yaml_rust2::Yaml;
+
+pub use index::indexer::{IndexItem, Template};
+
+pub fn build_jinja_env<'a>(templates: Vec>) -> Environment<'a> {
+ build_jinja_env_dir(templates)
+}
+fn build_jinja_env_dir<'a>(templates: Vec>) -> Environment<'a> {
+ let mut env: Environment = Environment::new();
+ for template in templates {
+ match template.src {
+ Some(src) => {
+ match env.add_template_owned(template.name.clone(), src) {
+ Ok(_) => {},
+ Err(err) => println!("ERROR: failt to add template \"{}\" ({err:?})", template.name),
+ }
+ },
+ None => {
+ for plate in template.sub_templates {
+ if let Some(src) = plate.src {
+ let name = format!("{}/{}", template.name.clone(), plate.name.clone());
+ match env.add_template_owned(name.clone(), src) {
+ Ok(_) => println!("template name: {name}"),
+ Err(err) => println!("ERROR: failt to add template \"{name}\" ({err:?})"),
+ }
+ }
+ }
+ }
+ };
+ }
+
+ env
+}
+
+#[derive(Debug)]
+pub struct Renderer {
+ // jinja_env: Environment<'a>,
+ pub site: IndexItem,
+ pub path: Box
+}
+impl Renderer {
+ pub fn index(path: &Path) -> Option {
+ if let Some(site_index) = IndexItem::index(&path) {
+ Some(Renderer {
+ site: site_index,
+ path: Box::from(path)
+ })
+ }
+ else {
+ None
+ }
+ }
+
+ fn convert_yaml(yaml: Yaml) -> Value {
+ match yaml {
+ Yaml::Real(val) => Value::from(val),
+ Yaml::Integer(val) => Value::from(val),
+ Yaml::String(val) => Value::from(val),
+ Yaml::Boolean(val) => Value::from(val),
+ Yaml::Array(val) => {
+ let mut list: Vec = Vec::new();
+ for item in val {
+ list.push(Renderer::convert_yaml(item));
+ }
+ Value::from(list)
+ },
+ Yaml::Hash(val) => {
+ let mut list: BTreeMap = BTreeMap::new();
+ for (key, val) in val {
+ if let Yaml::String(key) = key {
+ list.insert(key, Renderer::convert_yaml(val));
+ }
+ else {
+ todo!()
+ }
+ }
+ Value::from(list)
+ },
+ Yaml::Alias(val) => Value::from(val),
+ Yaml::Null => Value::UNDEFINED,
+ Yaml::BadValue => Value::UNDEFINED,
+ }
+ }
+
+ pub fn render_page(&self, page: &IndexItem, index: &IndexItem, jinja_env: &Environment) -> Option {
+ if page.src == None {
+ return None;
+ }
+ match fs::read_to_string(page.src.as_ref().unwrap()) {
+ Ok(content) => {
+ let split = indexer::split_params(content);
+ match parse_md(split.md, jinja_env) {
+ Some(md) => {
+ let template = jinja_env.get_template(&page.template).unwrap();
+ let html = template.render(context! {
+ index => index.to_minijinja(),
+ is_error_not_found => false,
+ url => page.get_url(),
+ body => md,
+ params => Renderer::convert_yaml(split.yaml)
+ }).unwrap();
+
+ Some(html)
+ },
+ None => None
+ }
+ },
+ Err(_) => None,
+ }
+ }
+}
diff --git a/src/render/index.rs b/src/render/index.rs
new file mode 100644
index 0000000..c43678c
--- /dev/null
+++ b/src/render/index.rs
@@ -0,0 +1,354 @@
+
+pub mod indexer {
+ use std::{collections::BTreeMap, ffi::OsString, fs, path::Path};
+ use hashlink::LinkedHashMap;
+ use regex::Regex;
+ use yaml_rust2::{Yaml, YamlLoader};
+
+ #[derive(Debug)]
+ pub struct IndexItem {
+ pub src: Option,
+ pub is_asset: bool,
+ pub path: String,
+ pub title: String,
+ pub friendly: String,
+ pub public: bool,
+ pub template: String,
+ pub sub_pages: Vec>,
+ pub target_extention: String,
+ }
+ impl IndexItem {
+ fn new() -> IndexItem {
+ IndexItem {
+ src: None,
+ is_asset: false,
+ path: String::from("/"),
+ title: String::from(""),
+ friendly: String::from(""),
+ public: false,
+ sub_pages: Vec::new(),
+ template: String::from("default"),
+ target_extention: String::from("html"),
+ }
+ }
+
+ pub fn index(path: &Path) -> Option {
+ IndexItem::scan_entry(path, String::from("/"))
+ }
+
+ fn scan_entry(path: &Path, last_url: String) -> Option {
+ let mut item = IndexItem::new();
+ if let Some(file_name) = path.file_name() {
+ if let Some(file_name) = file_name.to_str() {
+ let file_name = String::from(file_name);
+ if path.is_dir() {
+ if file_name != "templates" {
+ item.friendly = file_name.clone();
+ item.path = last_url.clone();
+ let url = if last_url == String::from("/") {
+ format!("/{file_name}")
+ } else {
+ format!("{}/{file_name}", last_url.clone())
+ };
+ let index_path = path.join("index.md");
+ match IndexItem::scan_entry(&index_path, last_url.clone()) {
+ Some(mut item) => {
+ let sub_pages = IndexItem::scan_dir(&path, last_url);
+ item.sub_pages = sub_pages.0;
+ item.public = sub_pages.1;
+ return Some(item);
+ },
+ None => {
+ let sub_pages = IndexItem::scan_dir(&path, url);
+ item.sub_pages = sub_pages.0;
+ item.public = sub_pages.1;
+ return Some(item);
+ }
+ }
+ }
+ }
+ else if path.is_file() {
+ item.src = match path.to_str() {
+ Some(path) => Some(String::from(path)),
+ None => None,
+ };
+ if item.src == None || file_name.len() < 4 {
+ return None;
+ }
+ let extention: String = file_name.clone().drain(file_name.len()-3..).collect();
+ if extention == ".md" {
+ let friendly = file_name.clone().drain(..file_name.len()-3).collect();
+ item.friendly = if friendly == "index" {
+ String::from("")
+ } else {
+ friendly
+ };
+ item.path = last_url;
+ let md = fs::read_to_string(path);
+ match md {
+ Ok(md) => {
+ let params = split_params(md).yaml;
+ IndexItem::parse_params(&mut item, params);
+ return Some(item)
+ },
+ Err(_) => todo!()
+ }
+ }
+ else {
+ item.is_asset = true;
+ item.friendly = file_name.clone();
+ item.path = last_url;
+ return Some(item);
+ }
+ }
+ return None
+ }
+ }
+
+ None
+ }
+
+ fn scan_dir(path: &Path, last_url: String) -> (Vec>, bool) {
+ let mut items: Vec> = Vec::new();
+ let mut has_public: bool = false;
+
+ let list = fs::read_dir(path);
+ match list {
+ Ok(list) => {
+ for entry in list {
+ match entry {
+ Ok(entry) => {
+ if entry.file_name() != OsString::from("index.md") {
+ let item = IndexItem::scan_entry(&entry.path(), last_url.clone());
+ if let Some(i) = item {
+ if i.public {
+ has_public = true;
+ }
+ items.push(Box::from(i));
+ }
+ }
+ },
+ Err(_) => todo!()
+ }
+ }
+ },
+ Err(_) => todo!()
+ };
+
+ items.sort_by(|i, c| i.friendly.cmp(&c.friendly));
+ (items, has_public)
+ }
+
+ fn parse_params(item: &mut IndexItem, params: Yaml) {
+ if let Yaml::Hash(params) = params {
+ if let Some(value) = params.get(&Yaml::from(Yaml::String(String::from("title")))) {
+ if let Yaml::String(title) = value {
+ item.title = title.clone();
+ }
+ };
+ if let Some(value) = params.get(&Yaml::from(Yaml::String(String::from("public")))) {
+ if let Yaml::Boolean(public) = value {
+ item.public = public.clone();
+ }
+ };
+ if let Some(value) = params.get(&Yaml::from(Yaml::String(String::from("template")))) {
+ if let Yaml::String(template) = value {
+ item.template = template.clone();
+ }
+ };
+ if let Some(value) = params.get(&Yaml::from(Yaml::String(String::from("target_extention")))) {
+ if let Yaml::String(target_extention) = value {
+ item.target_extention = target_extention.clone();
+ }
+ };
+ }
+ }
+
+ pub fn get_url(&self) -> String {
+ if self.src != None {
+ if self.path.ends_with("/") {
+ format!("{}{}", self.path, self.friendly)
+ } else {
+ format!("{}/{}", self.path, self.friendly)
+ }
+ }
+ else {
+ String::from("")
+ }
+ }
+
+ pub fn to_minijinja(&self) -> minijinja::Value {
+ let mut list: BTreeMap = BTreeMap::new();
+ list.insert(String::from("path"), minijinja::Value::from(self.path.clone()));
+ list.insert(String::from("title"), minijinja::Value::from(self.title.clone()));
+ list.insert(String::from("friendly"), minijinja::Value::from(self.friendly.clone()));
+ list.insert(String::from("public"), minijinja::Value::from(self.public.clone()));
+ list.insert(String::from("template"), minijinja::Value::from(self.template.clone()));
+
+ list.insert(String::from("url"), minijinja::Value::from(self.get_url()));
+
+ list.insert(String::from("sub_pages"), minijinja::Value::from({
+ let mut list: Vec = Vec::new();
+ for page in self.sub_pages.iter() {
+ list.push(page.to_minijinja());
+ };
+ list
+ }));
+
+ minijinja::Value::from(list)
+ }
+ }
+
+ #[derive(Debug)]
+ pub struct Template {
+ pub name: String,
+ pub extention: String,
+ pub path: Option,
+ pub src: Option,
+ pub sub_templates: Vec>
+ }
+ impl Template {
+ fn new() -> Template {
+ Template {
+ name: String::new(),
+ extention: String::new(),
+ path: None,
+ src: None,
+ sub_templates: Vec::new()
+ }
+ }
+
+ pub fn index(path: &Path) -> Vec> {
+ match Template::scan_template(path) {
+ Some(templates) => templates.sub_templates,
+ None => Vec::new(),
+ }
+ }
+
+ fn scan_template(path: &Path) -> Option {
+ let mut item = Template::new();
+ if let Some(file_name) = path.file_name() {
+ if let Some(file_name) = file_name.to_str() {
+ let file_name = String::from(file_name);
+ if path.is_dir() {
+ item.name = file_name;
+ item.sub_templates = Template::scan_dir(&path);
+ return Some(item);
+ }
+ else if path.is_file() {
+ item.path = match path.to_str() {
+ Some(path) => Some(String::from(path)),
+ None => None,
+ };
+ if item.path == None {
+ return None;
+ }
+
+ let path = item.path.clone().unwrap();
+ item.src = match fs::read_to_string(path) {
+ Ok(src) => Some(src),
+ Err(_) => None,
+ };
+
+ let re= Regex::new(r"\.").unwrap();
+ let mut matches = re.captures_iter(&file_name);
+ if let Some(dot) = matches.next() {
+ let dot = dot.get(0).unwrap();
+ item.extention = file_name.clone().drain(dot.start()..).collect();
+ item.name = file_name.clone().drain(..dot.start()).collect();
+ return Some(item);
+ }
+ else {
+ item.name = file_name;
+ return Some(item);
+ }
+ }
+ return None
+ }
+ }
+
+ None
+ }
+
+ fn scan_dir(path: &Path) -> Vec> {
+ let mut items: Vec> = Vec::new();
+
+ let list = fs::read_dir(path);
+ match list {
+ Ok(list) => {
+ for entry in list {
+ match entry {
+ Ok(entry) => {
+ let item = Template::scan_template(&entry.path());
+ if let Some(i) = item {
+ items.push(Box::from(i));
+ }
+ },
+ Err(_) => todo!()
+ }
+ }
+ },
+ Err(_) => todo!()
+ };
+
+ items.sort_by(|i, c| i.name.cmp(&c.name));
+ items
+ }
+ }
+
+ pub struct SplitMd {
+ pub yaml: Yaml,
+ pub md: String
+ }
+
+ fn join_yaml(yaml: Vec) -> Yaml {
+ let mut out: LinkedHashMap = LinkedHashMap::new();
+ for yaml in yaml {
+ match yaml {
+ yaml_rust2::Yaml::Hash(map) => {
+ for yaml in map.iter() {
+ out.insert(yaml.0.clone(), yaml.1.clone());
+ }
+ },
+ _ => {
+ todo!();
+ },
+ }
+ }
+
+ Yaml::Hash(out)
+ }
+
+ pub fn split_params(md: String) -> SplitMd {
+ let re= Regex::new(r"---").unwrap();
+ let mut matches = re.captures_iter(&md);
+ if let Some(first_dashes) = matches.next() {
+ let first_dashes = first_dashes.get(0).unwrap();
+ if first_dashes.start() == 0 {
+ if let Some(second_dashes) = matches.next() {
+ let second_dashes = second_dashes.get(0).unwrap();
+ let yaml: String = md.clone().drain(first_dashes.end()..second_dashes.start()).collect();
+ let markdown: String = md.clone().drain(second_dashes.end()..).collect();
+
+ if yaml.len() > 0 {
+ match YamlLoader::load_from_str(&yaml) {
+ Ok(yaml) => {
+ return SplitMd {
+ yaml: join_yaml(yaml),
+ md: markdown,
+ };
+ },
+ Err(_) => {}
+ }
+ }
+ }
+ }
+ }
+
+ SplitMd {
+ yaml: Yaml::BadValue,
+ md: md,
+ }
+ }
+
+}
diff --git a/src/render/parse_md.rs b/src/render/parse_md.rs
new file mode 100644
index 0000000..f35d33f
--- /dev/null
+++ b/src/render/parse_md.rs
@@ -0,0 +1,223 @@
+use std::{collections::BTreeMap};
+
+use pulldown_cmark::{Event, Options, Parser, Tag};
+use minijinja::{context, Environment, Value};
+use regex::Regex;
+
+pub fn parse_md(md: String, jinja_env: &Environment) -> Option {
+ let mut options = Options::empty();
+ options.insert(Options::ENABLE_TABLES);
+ options.insert(Options::ENABLE_FOOTNOTES);
+ options.insert(Options::ENABLE_STRIKETHROUGH);
+ options.insert(Options::ENABLE_TASKLISTS);
+ // options.insert(Options::ENABLE_SMART_PUNCTUATION);
+ // options.insert(Options::ENABLE_HEADING_ATTRIBUTES);
+ options.insert(Options::ENABLE_YAML_STYLE_METADATA_BLOCKS);
+ // options.insert(Options::ENABLE_PLUSES_DELIMITED_METADATA_BLOCKS);
+ // options.insert(Options::ENABLE_OLD_FOOTNOTES);
+ options.insert(Options::ENABLE_MATH);
+ options.insert(Options::ENABLE_GFM);
+ options.insert(Options::ENABLE_DEFINITION_LIST);
+ options.insert(Options::ENABLE_SUPERSCRIPT);
+ options.insert(Options::ENABLE_SUBSCRIPT);
+ options.insert(Options::ENABLE_WIKILINKS);
+
+ let md = md_preprocessor(&md, jinja_env);
+
+ // let mut parser = Parser::new_ext("", options);
+ // let mut in_heading_two: Vec = Vec::new();
+ let parser = Parser::new_ext(&md, options).filter_map(|event| {
+ match &event {
+ Event::Start(tag) => {
+ match tag {
+ Tag::Paragraph => Some(event),
+ Tag::Heading { level, id, classes, attrs } => Some(event),
+ Tag::BlockQuote(_block_quote_kind) => Some(event),
+ Tag::CodeBlock(_code_block_kind) => Some(event),
+ Tag::HtmlBlock => Some(event),
+ Tag::List(_) => Some(event),
+ Tag::Item => Some(event),
+ Tag::FootnoteDefinition(_cow_str) => Some(event),
+ Tag::DefinitionList => Some(event),
+ Tag::DefinitionListTitle => Some(event),
+ Tag::DefinitionListDefinition => Some(event),
+ Tag::Table(_alignments) => Some(event),
+ Tag::TableHead => Some(event),
+ Tag::TableRow => Some(event),
+ Tag::TableCell => Some(event),
+ Tag::Emphasis => Some(event),
+ Tag::Strong => Some(event),
+ Tag::Strikethrough => Some(event),
+ Tag::Superscript => Some(event),
+ Tag::Subscript => Some(event),
+ Tag::Link { link_type, dest_url, title, id } => {
+ let re = Regex::new(r"^%(?[^%]+)%").unwrap();
+ // let out = .unwrap();
+ let (url, args) = match re.captures(&dest_url) {
+ Some(args) => {
+ (dest_url.strip_prefix(args.get(0).unwrap().as_str()).unwrap().to_string(), parse_args(args.name("tags").unwrap().as_str()))
+ },
+ None => (dest_url.to_string(), Value::UNDEFINED)
+ };
+ match render_component("link_start", context! {
+ link_type => link_type,
+ dest_url => url,
+ title => title,
+ id => id,
+ args => args
+ }, jinja_env)
+ {
+ Some(html) => Some(Event::Html(html.into())),
+ None => Some(event),
+ }
+ },
+ Tag::Image { link_type, dest_url, title, id } => Some(event),
+ Tag::MetadataBlock(_metadata_block_kind) => Some(event),
+ }
+ },
+ Event::End(_tag_end) => Some(event),
+ Event::Text(_cow_str) => Some(event),
+ Event::Code(_cow_str) => Some(event),
+ Event::InlineMath(_cow_str) => Some(event),
+ Event::DisplayMath(_cow_str) => Some(event),
+ Event::Html(_cow_str) => Some(event),
+ Event::InlineHtml(_cow_str) => Some(event),
+ Event::FootnoteReference(_cow_str) => Some(event),
+ Event::SoftBreak => Some(event),
+ Event::HardBreak => Some(event),
+ Event::Rule => Some(event),
+ Event::TaskListMarker(_) => Some(event),
+ }
+ });
+ let mut html = String::new();
+ pulldown_cmark::html::push_html(&mut html, parser);
+
+ Some(html)
+}
+
+fn md_preprocessor(md: &String, jinja_env: &Environment) -> String {
+ let re = Regex::new(r"\{\% *(.*)\((.*)\).*\%\}").unwrap();
+ let out = re.replace_all(md, |capture: ®ex::Captures<'_>| {
+ let template = &capture[1];
+ let args = &capture[2];
+ match render_component(template, context! { args => parse_args(args)}, jinja_env){
+ Some(html) => html,
+ None => String::from("")
+ }
+ });
+
+ String::from(out)
+}
+
+fn render_component(component: &str, args: Value, jinja_env: &Environment) -> Option {
+ println!(" tag found: {component} <- {args}");
+ match jinja_env.get_template(&format!("components/{component}")) {
+ Ok(ding) => {
+ // match ding.render(context! { args => args }) {
+ match ding.render(args) {
+ Ok(html) => Some(html),
+ Err(err) => {
+ println!("ERROR: faild to render template: {component} ({err:?})");
+ None
+ },
+ }
+ },
+ Err(_) => {
+ println!("ERROR: could not find template: {component}");
+ Some("".to_string())
+ },
+ }
+}
+
+const NUMBER: i8 = 0;
+const STRING: i8 = 1;
+const OBJECT: i8 = 2;
+const BOOLEAN: i8 = 3;
+const UNDEFINED: i8 = 4;
+
+fn parse_args(args: &str) -> Value {
+ let mut arg_type: i8 = UNDEFINED;
+ let mut hash: BTreeMap = BTreeMap::new();
+ let mut list: Vec = Vec::new();
+ for arg in args.split(",") {
+ if (arg.starts_with("\"") && arg.ends_with("\""))
+ || (arg.starts_with("'") && arg.ends_with("'"))
+ {
+ if arg_type == UNDEFINED || arg_type == STRING {
+ let value = arg.strip_prefix(&['\'', '"']).unwrap().strip_suffix(&['\'', '"']).unwrap();
+ list.push(Value::from(value));
+ arg_type = STRING;
+ } else {
+ println!("ERROR: parse_md: syntax error in template include arguments (inconsistant type; {arg_type} != {STRING})");
+ return Value::UNDEFINED;
+ }
+ } else {
+ let mut obj: Vec<&str> = arg.split("=").collect();
+ if obj.len() > 1 {
+ if arg_type == UNDEFINED || arg_type == OBJECT {
+ if obj[0].len() > 0 {
+ arg_type = OBJECT;
+ let key = obj.remove(0);
+ hash.insert(key.to_string(), parse_args(&obj.join("=")));
+ } else {
+ println!("ERROR: parse_md: syntax error in template include arguments (empty key for key-value type)");
+ return Value::UNDEFINED;
+ }
+ } else {
+ println!("ERROR: parse_md: syntax error in template include arguments (inconsistant type; {arg_type} != {OBJECT})");
+ return Value::UNDEFINED;
+ }
+ } else {
+ match String::from(arg).parse::() {
+ Ok(number) => {
+ if arg_type == UNDEFINED || arg_type == NUMBER {
+ list.push(Value::from(number));
+ arg_type = NUMBER;
+ } else {
+ println!("ERROR: parse_md: syntax error in template include arguments (inconsistant type; {arg_type} != {NUMBER})");
+ return Value::UNDEFINED;
+ }
+ },
+ Err(_) => {
+ let arg_lower = arg.to_lowercase();
+ if arg_lower == "true" || arg_lower == "false" {
+ if arg_type == UNDEFINED || arg_type == BOOLEAN {
+ list.push(Value::from(arg_lower == "true"));
+ arg_type = BOOLEAN;
+ } else {
+ println!("ERROR: parse_md: syntax error in template include arguments (inconsistant type; {arg_type} != {BOOLEAN})");
+ return Value::UNDEFINED;
+ }
+ } else {
+ if arg_type == UNDEFINED || arg_type == OBJECT {
+ if obj[0].len() > 0 {
+ hash.insert(obj[0].to_string(), Value::from(true));
+ arg_type = OBJECT;
+ }
+ } else {
+ println!("ERROR: parse_md: syntax error in template include arguments (inconsistant type; {arg_type} != {OBJECT})");
+ return Value::UNDEFINED;
+ }
+ }
+ },
+ };
+ }
+ }
+ }
+
+ match &list[..] {
+ [value] => {
+ match arg_type {
+ NUMBER => value.to_owned(),
+ STRING => value.to_owned(),
+ BOOLEAN => value.to_owned(),
+ _ => Value::UNDEFINED
+ }
+ },
+ [_, _, ..] => Value::from(list),
+ [] => match arg_type {
+ OBJECT => Value::from(hash),
+ _ => Value::UNDEFINED
+ },
+ }
+}
diff --git a/style.scss b/style.scss
deleted file mode 100644
index 9ad5258..0000000
--- a/style.scss
+++ /dev/null
@@ -1,215 +0,0 @@
-@import url('https://fonts.googleapis.com/css2?family=Roboto&family=Ubuntu&display=swap');
-
-$main-color: #222;
-$second-color: #333;
-$oposit-color: #eee;
-$accent-color: #7d7;
-
-body {
- margin: 0;
- padding: 0;
- overflow-x: hidden;
-
- background-color: $main-color;
- color: $oposit-color;
- font-family: 'Roboto', sans-serif;
-}
-
-header {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- text-align: right;
- height: 50px;
-
- background: linear-gradient(180deg, $main-color 0%, $main-color 80%, rgba(0,0,0,0) 100%);
-
- #headerLogo{
- padding-left: 50px;
- height: 50px;
- }
-
- ul {
- list-style: none;
- padding: 0 50px 0 0;
- margin: 0;
- display: inline-block;
- user-select: none;
-
- font-family: 'Ubuntu', sans-serif;
- font-size: 18px;
-
- .menuSeparator,
- .menuLable{
- display: inline-block;
- }
- li.sub .menuLable{
- padding: 15px 5px;
-
- a {
- display: inline-block;
- padding: 0;
- }
- }
-
- li {
- display: inline-block;
- }
-
- li.open {
- .menuLable {
- background-color: $second-color;
- }
- ul {
- display: block;
- ul {
- display: none;
- }
- }
- }
-
- ul{
- display: none;
- position: absolute;
- text-align: center;
- padding: 0;
- // margin-left: 10px;
- background-color: $second-color;
- border-bottom-right-radius: 5px;
- border-bottom-left-radius: 5px;
-
- li {
- display: block;
- }
- }
- }
-
- .menuDropIcon{
- width: 15px;
- }
-
- a {
- padding: 15px 5px;
- color: $accent-color;
- text-decoration: none;
-
- &:hover{
- color: $accent-color;
- text-decoration: underline;
- }
- }
-
- li a{
- display: block;
- }
-}
-
-aside{
- height: 100vh;
- position: fixed;
- top: 0;
- left: 0;
-
- overflow-y: auto;
-
- ul{
- list-style: none;
- padding: 50px 0 0 0;
- margin: 0;
- display: block;
- user-select: none;
-
- font-family: 'Ubuntu', sans-serif;
- font-size: 18px;
-
- .menuLable {
- height: 50px;
- }
-
- ul {
- padding: 0 0 0 25px;
- }
- }
-
- a {
- width: 150px;
- display: block;
- padding: 15px 5px;
- color: $accent-color;
- text-decoration: none;
-
- &:hover{
- color: $accent-color;
- background-color: $second-color;
- text-decoration: underline;
- }
-
- }
-}
-
-main {
- padding: 0 calc(50vw - 250px) 50px;
- max-width: 500px;
-
- a {
- color: $accent-color;
- text-decoration: none;
-
- &:hover{
- text-decoration: underline;
- }
- }
- a.btn {
- padding: 5px;
- border: 1px $accent-color solid;
- border-radius: 5px;
-
- &:hover{
- color: $main-color;
- background-color: $accent-color;
- text-decoration: none;
- }
- }
-
- img, video {
- width: 100%;
- }
-}
-
-#bigPicture {
- display: none;
- position: fixed;
- top: 50vh;
- width: 100vw;
- transform: translateY(-50%);
- &.show{
- display: block;
- }
- &.tall{
- width: auto;
- height: 100vh;
- left: 50vw;
- transform: translateY(-50%) translateX(-50%);
- }
-}
-
-@media only screen and (max-width: 850px){
- main {
- padding-left: 175px;
- }
-}
-
-@media only screen and (max-width: 555px){
- main {
- width: auto;
- padding: 0 28px 50px;
- }
-}
-
-h1, h2, h3, h4, h5, h6{
- font-family: 'Ubuntu', sans-serif;
-}
-h1 { padding-top: 50px; font-size: 40px; }
-h2 { padding-top: 40px; font-size: 30px; }
-h3 { padding-top: 10px; font-size: 20px; }
diff --git a/template.html b/template.html
deleted file mode 100644
index f39e7a1..0000000
--- a/template.html
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
- Kladjes
-
-
-
- {{ sidebar }}
-
- {{ body }}
-
-
-
-