move new versino from volta website
This commit is contained in:
parent
5f22cdf06f
commit
02049b6d33
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,2 +1,2 @@
|
||||
/__pycache__
|
||||
/public
|
||||
/target
|
||||
/html
|
||||
264
Cargo.lock
generated
Normal file
264
Cargo.lock
generated
Normal file
@ -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",
|
||||
]
|
||||
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@ -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"
|
||||
10
Dockerfile
10
Dockerfile
@ -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" ]
|
||||
31
header.py
31
header.py
@ -1,31 +0,0 @@
|
||||
import yaml
|
||||
|
||||
from render import listPages
|
||||
|
||||
firstItem = True
|
||||
|
||||
def headerGen(item, root):
|
||||
global firstItem
|
||||
if(root and not firstItem):
|
||||
separator = '<span class="menuSeparator">|</span>'
|
||||
else:
|
||||
separator = ''
|
||||
firstItem = False
|
||||
|
||||
if(not ('klickable' in item and item['klickable'] is False)):
|
||||
item['lable'] = '<a href="' + item["url"] + '">' + item["lable"] + '</a>'
|
||||
|
||||
if('sub' not in item):
|
||||
return '<li>' + separator + '<span class="menuLable">' + item["lable"] + '</span></li>'
|
||||
|
||||
data = ''
|
||||
subicon = ''
|
||||
if(root):
|
||||
subicon = ' <svg class="menuDropIcon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><path d="M1,3.7L5,8L9,3.7" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" fill="none" stroke="#eee"></path></svg>'
|
||||
data += ' data-hassub="true"'
|
||||
|
||||
html = '<li' + data + '>' + separator + '<span class="menuLable sub">' + item["lable"] + subicon + '</span><ul class="submenu">'
|
||||
html += listPages(item['sub'], item['url'], headerGen)
|
||||
|
||||
return html + '</ul></li>'
|
||||
|
||||
139
index.py
139
index.py
@ -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 += "<span class='menuSeparator'>|</span>"
|
||||
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')
|
||||
181
index.yml
181
index.yml
@ -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
|
||||
211
page.py
211
page.py
@ -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"<span class='menuLable'><a href='{self.url}'>{self.lable}</a></span>"
|
||||
else:
|
||||
html = f"<span class='menuLable'>{self.lable}</span>"
|
||||
else:
|
||||
subicon = " <svg class='menuDropIcon' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><path d='M1,3.7L5,8L9,3.7' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' fill='none' stroke='#eee'></path></svg>"
|
||||
propertys = " data-hassub='true'"
|
||||
propertys += " class=\"sub\""
|
||||
if (self.clickable):
|
||||
html = f"<span class='menuLable'><a href='{self.url}'>{self.lable}</a>{subicon}</span><ul>"
|
||||
else:
|
||||
html = f"<span class='menuLable'>{self.lable}{subicon}</span><ul>"
|
||||
for page in self.subPages:
|
||||
html += page.topMenuHTML()
|
||||
html += "</ul>"
|
||||
|
||||
return f"<li{propertys}>{html}</li>"
|
||||
|
||||
def sidebarHTML(self):
|
||||
if (len(self.subPages) == 0):
|
||||
propertys = ""
|
||||
if (self.clickable):
|
||||
html = f"<span class='menuLable'><a href='{self.url}'>{self.lable}</a></span>"
|
||||
else:
|
||||
html = f"<span class='menuLable'>{self.lable}</span>"
|
||||
else:
|
||||
propertys = " data-hassub='true'"
|
||||
propertys += " class=\"sub\""
|
||||
if (self.clickable):
|
||||
html = f"<span class='menuLable'><a href='{self.url}'>{self.lable}</a></span><ul>"
|
||||
else:
|
||||
html = f"<span class='menuLable'>{self.lable}</span><ul>"
|
||||
for page in self.subPages:
|
||||
html += page.sidebarHTML()
|
||||
html += "</ul>"
|
||||
|
||||
return f"<li{propertys}>{html}</li>"
|
||||
|
||||
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 = '<aside><nav><ul id="sidemenu">'
|
||||
for item in self.getSidebar():
|
||||
sidebar += item.sidebarHTML()
|
||||
sidebar += '</ul></nav></aside>'
|
||||
else:
|
||||
sidebar = ""
|
||||
|
||||
html = template.render(
|
||||
header = header,
|
||||
sidebar = sidebar,
|
||||
body = renderMD(srcDir + srcFile)
|
||||
)
|
||||
|
||||
return html
|
||||
179
render.py
179
render.py
@ -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 = '<span class="menuSeparator">|</span>'
|
||||
else:
|
||||
separator = ''
|
||||
firstItem = False
|
||||
|
||||
lable = item['lable']
|
||||
|
||||
if(not ('klickable' in item and item['klickable'] is False)):
|
||||
lable = '<a href="' + item["url"] + '">' + item["lable"] + '</a>'
|
||||
|
||||
if('sub' not in item):
|
||||
return '<li>' + separator + '<span class="menuLable">' + lable + '</span></li>'
|
||||
|
||||
data = ''
|
||||
subicon = ''
|
||||
if(root):
|
||||
subicon = ' <svg class="menuDropIcon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><path d="M1,3.7L5,8L9,3.7" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" fill="none" stroke="#eee"></path></svg>'
|
||||
data += ' data-hassub="true"'
|
||||
|
||||
html = '<li' + data + '>' + separator + '<span class="menuLable sub">' + lable + subicon + '</span><ul class="submenu">'
|
||||
html += listPages(item['sub'], item['url'], headerGen)
|
||||
|
||||
return html + '</ul></li>'
|
||||
|
||||
def sidebarGen(item, root):
|
||||
if(not ('klickable' in item and item['klickable'] is False)):
|
||||
item['lable'] = '<a href="' + item["url"] + '">' + item["lable"] + '</a>'
|
||||
|
||||
if('sub' not in item):
|
||||
return '<li><span class="menuLable">' + item["lable"] + '</span></li>'
|
||||
|
||||
html = '<li><span class="menuLable sub">' + item["lable"] + '</span><ul class="submenu">'
|
||||
html += listPages(item['sub'], item['url'], sidebarGen)
|
||||
|
||||
return html + '</ul></li>'
|
||||
|
||||
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 = '<aside><nav><ul id="sidemenu">'
|
||||
sidebar += listPages(item['sidebar'], item['url'], sidebarGen)
|
||||
sidebar += '</ul></nav></aside>'
|
||||
|
||||
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 = '<header><nav><ul id="menu">'
|
||||
header += listPages(index, '', headerGen)
|
||||
header += '</ul></nav></header>'
|
||||
|
||||
copyAssets('/')
|
||||
listPages(index, '', renderPage)
|
||||
10
render.sh
10
render.sh
@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd $HOME/webTemplate
|
||||
|
||||
rm -r ../public/*
|
||||
|
||||
python3 render.py
|
||||
|
||||
# cd ../public/ && python3 -m http.server 8000
|
||||
|
||||
43
renderMD.py
43
renderMD.py
@ -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 '<code>{}</code>\n'.format(code.strip())
|
||||
def blockcode(self, code, lang):
|
||||
if(lang == 'latex/equetion'):
|
||||
return '<p data-latex="{}">{}</p>\n'.format(code.strip(), renderLatex(code))
|
||||
return '<pre><code class="{}">{}</code></pre>\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
|
||||
@ -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
|
||||
@ -1,5 +0,0 @@
|
||||
pyyaml
|
||||
jinja2
|
||||
misaka
|
||||
latex2mathml
|
||||
libsass
|
||||
50
sidemenu.py
50
sidemenu.py
@ -1,50 +0,0 @@
|
||||
import yaml
|
||||
|
||||
def parseHTML(item):
|
||||
if(not ('klickable' in item and item['klickable'] is False)):
|
||||
item['lable'] = '<a href="' + item["url"] + '">' + item["lable"] + '</a>'
|
||||
|
||||
if('sub' not in item):
|
||||
return '<li><span class="menuLable">' + item["lable"] + '</span></li>'
|
||||
|
||||
html = '<li><span class="menuLable sub">' + item["lable"] + '</span><ul class="submenu">'
|
||||
html += genHTML(item['sub'], item['url'])
|
||||
|
||||
return html + '</ul></li>'
|
||||
|
||||
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 = '<aside><nav><ul id="sidemenu">'
|
||||
html += genHTML(items, parentUrl)
|
||||
html += '</ul></nav></aside>'
|
||||
return html
|
||||
64
src/main.rs
Normal file
64
src/main.rs
Normal file
@ -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);
|
||||
}
|
||||
118
src/render.rs
Normal file
118
src/render.rs
Normal file
@ -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<Box<indexer::Template>>) -> Environment<'a> {
|
||||
build_jinja_env_dir(templates)
|
||||
}
|
||||
fn build_jinja_env_dir<'a>(templates: Vec<Box<indexer::Template>>) -> 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<Path>
|
||||
}
|
||||
impl Renderer {
|
||||
pub fn index(path: &Path) -> Option<Renderer> {
|
||||
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<Value> = Vec::new();
|
||||
for item in val {
|
||||
list.push(Renderer::convert_yaml(item));
|
||||
}
|
||||
Value::from(list)
|
||||
},
|
||||
Yaml::Hash(val) => {
|
||||
let mut list: BTreeMap<String, Value> = 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<String> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
354
src/render/index.rs
Normal file
354
src/render/index.rs
Normal file
@ -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<String>,
|
||||
pub is_asset: bool,
|
||||
pub path: String,
|
||||
pub title: String,
|
||||
pub friendly: String,
|
||||
pub public: bool,
|
||||
pub template: String,
|
||||
pub sub_pages: Vec<Box<IndexItem>>,
|
||||
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> {
|
||||
IndexItem::scan_entry(path, String::from("/"))
|
||||
}
|
||||
|
||||
fn scan_entry(path: &Path, last_url: String) -> Option<IndexItem> {
|
||||
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<Box<IndexItem>>, bool) {
|
||||
let mut items: Vec<Box<IndexItem>> = 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<String, minijinja::Value> = 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<minijinja::Value> = 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<String>,
|
||||
pub src: Option<String>,
|
||||
pub sub_templates: Vec<Box<Template>>
|
||||
}
|
||||
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<Box<Template>> {
|
||||
match Template::scan_template(path) {
|
||||
Some(templates) => templates.sub_templates,
|
||||
None => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn scan_template(path: &Path) -> Option<Template> {
|
||||
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<Box<Template>> {
|
||||
let mut items: Vec<Box<Template>> = 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>) -> Yaml {
|
||||
let mut out: LinkedHashMap<Yaml, Yaml> = 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,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
223
src/render/parse_md.rs
Normal file
223
src/render/parse_md.rs
Normal file
@ -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<String> {
|
||||
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<Event> = 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"^%(?<tags>[^%]+)%").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<String> {
|
||||
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<String, Value> = BTreeMap::new();
|
||||
let mut list: Vec<Value> = 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::<f64>() {
|
||||
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
|
||||
},
|
||||
}
|
||||
}
|
||||
215
style.scss
215
style.scss
@ -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; }
|
||||
@ -1,24 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<title>Kladjes</title>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav>
|
||||
<ul class="menu">
|
||||
{{ header }}
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
{{ sidebar }}
|
||||
<main>
|
||||
{{ body }}
|
||||
</main>
|
||||
<script src="/scripts/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user