From 362e7ac62fd2a78b7fc9f3d90ed34a0c57e3e981 Mon Sep 17 00:00:00 2001 From: vitrinekast Date: Mon, 25 Nov 2024 16:01:56 +0100 Subject: [PATCH] now using python --- .gitignore | 4 +- README.md | 76 +++++++++++++--- app.py | 115 ++++++++++++++++++++++++ dist/newsletters/december.md.html | 6 -- get_events.sh | 5 +- include-files.lua | 127 --------------------------- install.sh | 11 --- make_newsletter.sh | 10 --- newsletters/december.md | 9 -- requirements.txt | 10 +++ src/assets/image.png | Bin 0 -> 21666 bytes src/assets/style.css | 92 +++++++++++++++++++ src/content/component-inventory.csv | 4 + src/content/components/capacitors.md | 9 ++ src/content/components/resistors.md | 9 ++ src/content/index.md | 9 ++ src/content/newsletters/december.md | 10 +++ src/content/recipes/two.md | 7 ++ src/content/repair-logs/21112024.md | 9 ++ src/templates/base.jinja | 52 +++++++++++ src/templates/components.jinja | 49 +++++++++++ src/templates/index.jinja | 6 ++ src/templates/post.jinja | 11 +++ templates/event.md | 2 - 24 files changed, 462 insertions(+), 180 deletions(-) create mode 100644 app.py delete mode 100644 dist/newsletters/december.md.html delete mode 100644 include-files.lua delete mode 100644 install.sh delete mode 100644 make_newsletter.sh delete mode 100644 newsletters/december.md create mode 100644 requirements.txt create mode 100644 src/assets/image.png create mode 100644 src/assets/style.css create mode 100644 src/content/component-inventory.csv create mode 100644 src/content/components/capacitors.md create mode 100644 src/content/components/resistors.md create mode 100644 src/content/index.md create mode 100644 src/content/newsletters/december.md create mode 100644 src/content/recipes/two.md create mode 100644 src/content/repair-logs/21112024.md create mode 100644 src/templates/base.jinja create mode 100644 src/templates/components.jinja create mode 100644 src/templates/index.jinja create mode 100644 src/templates/post.jinja delete mode 100644 templates/event.md diff --git a/.gitignore b/.gitignore index 9168178..ce63e47 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -events -mo \ No newline at end of file +venv +dist \ No newline at end of file diff --git a/README.md b/README.md index cbb424f..445b5d3 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,72 @@ -# Klank docs +# README.md -## installation -Run the install.sh to install [Mustache](https://github.com/tests-always-included/mo) +### Installation +Create a virtual python environment using ` python -m venv venv` +Activate the virtual environment using `source venv/bin/activate` +Install the packages using `pip install -r requirements.txt` -Also, pandoc is needed. Additionally researching this thing https://github.com/pandoc-ext/include-files/tree/main +### Running +Compile the content into a static site using +``` +python app.py +``` + +This creates the "dist" directory, with all of the HTML in there. +At the moment, `dist` is part of the `.gitignore`! -More info to come ;) +### Writing Content +Within the `content` directory, you can create/edit markdown files. When compiling the markdown content, `app.py` will look for jinja templates in the `templates` directory. If the markdown file is in the root of `content`, it will try to load a template with the same filename as the markdown file. For instance, `about.md` will look for `about.jinja`. +If the markdown file is in a subdirectory, it will look for a template with the same name as the subdirectory. At the moment, there is no functionality for deep nested folders. So, `recipes/tomato-soup.md` wants `recipes.jinja`. If the template does not exist, the default template is `post.jinja`. -## Scripts & folders +The project uses [Jinja](https://jinja.palletsprojects.com/), which allows for extending templates, using variables, looping trough variables, and other funky features! -- `newsletters` write your new newsletter here -- `templates` contains a markdown template for events, that are being grabbed via -- `get_events.sh` run as `sh get_events.sh` to grab all events from the klankschool calendar and store them as markdwon files -- `install.sh` the installation script for Mustache -- `make_newsletter.sh` run as `sh make_newsletter` to translate all created newsletters in the `newsletters` directory into HTML. Created newsletters are stored in the `dist` directory +Additionally, `component-inventory.csv` is loaded as a dataset. + +### Transclusion +You'll be able to transclude one markdown file into another, by applying the following syntax: + +```MARKDOWN +{! path-to-file.md !} +``` + +The transclusion package also allows for transcluding specific lines: + +```MARKDOWN +{! path-to-file.md!lines=1 3 8-10 2} +``` +In the example above, it would read the file and include the lines 1, 3, 8, 9, 10, 2. + + + + +### Metadata +Metadata can be applied to markdown files using FrontMatters YAML. The metadata is accessable in the jinja tempaltes using `page.{metadata}`. In the example below, this could be, `page.title`. + +```MARKDOWN +--- +excerpt: tl;dr +title: Capacitors +type: Capacitor +valueSymbol: unf +description: This is the description +--- +``` + + +### Assets +At the moment, the `src/assets` directory is copied to the `dist` folder, to apply CSS. + + +### TODO +- [ ] update readme +- [ ] fix issue with YAML data showing up in included files +- [ ] lurk newsletter? +- [ ] minify/gzip the HTML +- [ ] Export to PDF +- [ ] Export to mediawiki +- [ ] Export to PDF with zine layout +- [ ] last edited date +- [ ] Direct link to the markdown file in git? +- [ ] Markdown page breaks \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..aa6f3ad --- /dev/null +++ b/app.py @@ -0,0 +1,115 @@ +import os +from pathlib import Path +import shutil +import csv + +from jinja2 import Environment, PackageLoader, select_autoescape +import frontmatter +import markdown +from markdown_include.include import MarkdownInclude +from slugify import slugify + +markdown_include = MarkdownInclude( + configs={'base_path': 'src/content/'} +) + +env = Environment( + loader=PackageLoader("src"), + autoescape=select_autoescape() +) + +CONTENT_D = os.path.abspath("src/content") +OUTPUT_D = "dist" +documents = {} + +def slugify_filter(value): + return slugify(value) + +env.filters["slugify"] = slugify_filter + + +def render_single_file(template, page, path, dist): + html = template.render(documents=documents, page=page) + name = Path(path).stem + + if not os.path.exists(dist): + os.makedirs(dist) + + with open(f"{dist}/{name}.html", "w", encoding="utf-8") as output_file: + output_file.write(html) + + +def get_page_data(path): + filename = Path(path).stem + page = frontmatter.load(path) + page['slug'] = slugify(filename) + page.body = markdown.markdown(page.content, extensions=['def_list', 'footnotes', markdown_include]) + + return page + + +def render_posts(path): + name = Path(path).stem + print(f"looking for {name}.jinja") + template = env.select_template([f"{name}.jinja", "post.jinja"]) + + for filename in os.listdir(path): + if filename.endswith(".md"): + post_path = os.path.join(path, filename) + page = get_page_data(post_path) + render_single_file(template, page, post_path, f"{OUTPUT_D}/{name}") + + +def preload_documents(): + print("preload any needed data") + + for subdir in os.listdir(CONTENT_D): + path = os.path.join(CONTENT_D, subdir) + + if os.path.isdir(path): + name = Path(path).stem + if name not in documents: + documents[name] = [] + for filename in os.listdir(path): + if filename.endswith(".md"): + post_path = os.path.join(path, filename) + + documents[name].append(get_page_data(post_path)) + + elif Path(path).suffix == '.md': + documents[Path(path).stem] = get_page_data(path) + +def copy_assets(): + if os.path.exists("dist/assets"): + shutil.rmtree("dist/assets") + + shutil.copytree("src/assets", "dist/assets") + +def get_inventory(): + + with open("src/content/component-inventory.csv") as f: + documents['inventory'] = [] + for line in csv.DictReader(f, fieldnames=('ID', 'Name', 'Value', 'Type', 'Date', 'Where')): + documents['inventory'].append(line) + +def main(): + get_inventory() + preload_documents() + + print("render the content") + for subdir in os.listdir(CONTENT_D): + path = os.path.join(CONTENT_D, subdir) + + if os.path.isdir(path): + render_posts(path) + elif Path(path).suffix == '.md': + template = env.select_template( + [f"{Path(path).stem}.jinja", "post.jinja"]) + page = get_page_data(path) + render_single_file(template, page, path, OUTPUT_D) + else: + print("i cannot handle this file yet") + + copy_assets() + +main() diff --git a/dist/newsletters/december.md.html b/dist/newsletters/december.md.html deleted file mode 100644 index 404c568..0000000 --- a/dist/newsletters/december.md.html +++ /dev/null @@ -1,6 +0,0 @@ -

December

-

What a great month it was

-

Event

-

Let’s (un)repair things -together!

-

This event starts at 1731603600

diff --git a/get_events.sh b/get_events.sh index dc8ea16..4f4f643 100644 --- a/get_events.sh +++ b/get_events.sh @@ -22,8 +22,9 @@ echo $(curl -s "https://calendar.klank.school/api/events") | jq -c '.[]' | while rm -f -- $filename fi - mo templates/event.md >> $filename - echo "Created a new event markdown file for " $filename + # mo templates/event.md >> $filename + # echo "Created a new event markdown file for " $filename + echo "Whoops! This template is not accessible anymore. Please update me :) " done diff --git a/include-files.lua b/include-files.lua deleted file mode 100644 index 69df689..0000000 --- a/include-files.lua +++ /dev/null @@ -1,127 +0,0 @@ ---- include-files.lua – filter to include Markdown files ---- ---- Copyright: © 2019–2021 Albert Krewinkel ---- License: MIT – see LICENSE file for details - --- Module pandoc.path is required and was added in version 2.12 -PANDOC_VERSION:must_be_at_least '2.12' - -local List = require 'pandoc.List' -local path = require 'pandoc.path' -local system = require 'pandoc.system' - ---- Get include auto mode -local include_auto = false -function get_vars (meta) - if meta['include-auto'] then - include_auto = true - end -end - ---- Keep last heading level found -local last_heading_level = 0 -function update_last_level(header) - last_heading_level = header.level -end - ---- Update contents of included file -local function update_contents(blocks, shift_by, include_path) - local update_contents_filter = { - -- Shift headings in block list by given number - Header = function (header) - if shift_by then - header.level = header.level + shift_by - end - return header - end, - -- If link paths are relative then prepend include file path - Link = function (link) - if path.is_relative(link.target) then - link.target = path.normalize(path.join({include_path, link.target})) - end - return link - end, - -- If image paths are relative then prepend include file path - Image = function (image) - if path.is_relative(image.src) then - image.src = path.normalize(path.join({include_path, image.src})) - end - return image - end, - -- Update path for include-code-files.lua filter style CodeBlocks - CodeBlock = function (cb) - if cb.attributes.include and path.is_relative(cb.attributes.include) then - cb.attributes.include = - path.normalize(path.join({include_path, cb.attributes.include})) - end - return cb - end - } - - return pandoc.walk_block(pandoc.Div(blocks), update_contents_filter).content -end - ---- Filter function for code blocks -local transclude -function transclude (cb) - -- ignore code blocks which are not of class "include". - if not cb.classes:includes 'include' then - return - end - - -- Markdown is used if this is nil. - local format = cb.attributes['format'] - - -- Attributes shift headings - local shift_heading_level_by = 0 - local shift_input = cb.attributes['shift-heading-level-by'] - if shift_input then - shift_heading_level_by = tonumber(shift_input) - else - if include_auto then - -- Auto shift headings - shift_heading_level_by = last_heading_level - end - end - - --- keep track of level before recusion - local buffer_last_heading_level = last_heading_level - - local blocks = List:new() - for line in cb.text:gmatch('[^\n]+') do - if line:sub(1,2) ~= '//' then - local fh = io.open(line) - if not fh then - io.stderr:write("Cannot open file " .. line .. " | Skipping includes\n") - else - -- read file as the given format with global reader options - local contents = pandoc.read( - fh:read '*a', - format, - PANDOC_READER_OPTIONS - ).blocks - last_heading_level = 0 - -- recursive transclusion - contents = system.with_working_directory( - path.directory(line), - function () - return pandoc.walk_block( - pandoc.Div(contents), - { Header = update_last_level, CodeBlock = transclude } - ) - end).content - --- reset to level before recursion - last_heading_level = buffer_last_heading_level - blocks:extend(update_contents(contents, shift_heading_level_by, - path.directory(line))) - fh:close() - end - end - end - return blocks -end - -return { - { Meta = get_vars }, - { Header = update_last_level, CodeBlock = transclude } -} diff --git a/install.sh b/install.sh deleted file mode 100644 index 9c10a57..0000000 --- a/install.sh +++ /dev/null @@ -1,11 +0,0 @@ -# Download -curl -sSL https://raw.githubusercontent.com/tests-always-included/mo/master/mo -o mo - -# Make executable -chmod +x mo - -# Move to the right folder -sudo mv mo /usr/local/bin/ - -# Test -echo "works" | mo \ No newline at end of file diff --git a/make_newsletter.sh b/make_newsletter.sh deleted file mode 100644 index c6218c5..0000000 --- a/make_newsletter.sh +++ /dev/null @@ -1,10 +0,0 @@ - -mkdir dist -mkdir dist/newsletters - -cd newsletters - -for file in *.md; do - echo $file - pandoc --lua-filter=../include-files.lua $file --output ../dist/newsletters/$file.html -done \ No newline at end of file diff --git a/newsletters/december.md b/newsletters/december.md deleted file mode 100644 index bf30cf2..0000000 --- a/newsletters/december.md +++ /dev/null @@ -1,9 +0,0 @@ -# December - -What a great month it was - -## Event - -``` {.include} -../events/lets-unrepair-things-together-2.md -``` \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ced814a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +importlib_metadata==8.5.0 +Jinja2==3.1.4 +Markdown==3.7 +markdown-include==0.8.1 +MarkupSafe==3.0.2 +python-frontmatter==1.1.0 +python-slugify==8.0.4 +PyYAML==5.1 +text-unidecode==1.3 +zipp==3.21.0 diff --git a/src/assets/image.png b/src/assets/image.png new file mode 100644 index 0000000000000000000000000000000000000000..8743c04b9cb880f8aded02b528a23ca0dba1100a GIT binary patch literal 21666 zcmeFZcQjn@_diM!1QAKJM2`|gO9-M9o#?$s^fDy6(V~PPT6CgCi#qBk!-y6wIx`qd zM2R*;8Er7XA@A?^`(F3n|L*$z)?IgftaX;N&pA)q&wloP?bmbWL}_U#k&)1n;Njts zsVK|q;NjsTamVmYLfn;^=<9ZPcqGM+a&lTKa&pXC?rwIDF1C1h%26q4L|VG*)V=Ng z6Lh?H*25PH8}Y6YOM0%qVr9dB5%u&Ak_rN zI;o-r@njfeezgn=$|uc5RDZeecxN$3MdR~oqDoxu>u2c$#N=ohqq}$#8C`cduE`X$ zz6CxKxmzk{$Kt}ZOdNhQ=8m_zn(2Vt@%>Ik<=gjIHDUJMSS^lSH=(5>A<@tBT$&>S zw!WIOEu1My=wPWhEWok!Q-q2J?`yp;g_ z^j6RWs0)%)>VI?WPhCwt9B=yQ;iw2*OeFqukGps?6*K7_czDS@c=Zd5s@)kAHKmYn ze0k;=&#%{>h44MOW~Xd_`0c@y5Sl;NJDBOa-}SsB{Uk$sCv4>vl@a-#4E{8Ucc@M^ z6a6*)pPbKc({>oYxod_m@(nOb#u#Gp1kWN=`w#v{xjW%uoOh^nLh6|V`zUK8?k8|B z6A;McYu%zGVt?^M`C4VDund9LT|E+p@Unbl-o&WF8to*p6t2N#O0>us+qr0$o zWUolm@#|g%Kc~02!O=PR)8#qM!mYG#D}U}b;X`jC-$52Fj@cz5u5sRrju=qzY;r9%sf0%ZV2Rj@@$sw3*o%b#~^Z<^kWBpwPk4ae_%uASqc?D;T) zA}MM!ioILxm+dd>U*h+o3gz6{hB%0oHchiFPH8a>~-up?!Dg=+Ji4gQobP}B(WfocyIPz zjwFrpw3M@qZz^n{$Tg3#*rND0=W8l5s+s8iXo6@ZDsf7s6v||m6qXbN&J?a}-HoDr z2f}BaLK2kiAfq33T>tL*zzvOBC?ysVZ7-Lu9J=*)ySlXY#ZV zAwI{C4&%=dpN%-*cGhk%Yq((|UeD*ymd8D2e4qy;Zi|&FtE@tm^NvY=LWttuC-S)&uP#smu73n1T(tRvn=?^-M&9#uzWt9(+)=;zg)o?Os-)dH{g z;Ipe*GFzP6Yd#w4v*W3IS!Yrw<&o+4&M(fd;Dno0GR7zdK#ihC@}hWjdC5(sYIUmj z>IQ0@z(8lf>!Aj|I;gW;%`Vv3dBSG@J8Ux54Kf1mjdP-LXdJ7W+RkbVYnz4+2TjY4 zJRG))?+T1yVGY;rYufnm*3-vq(-*c|m(->kG4ZwpK5RG4H7qnNw}0#R?r(-1_|BK5 z&bOj#l9C| znOqWY54Dd>3pETkEQRa3G3?0inCxgXiRY$B@j~xg1|tE`qZwKkK1inI#_ykvv!J2e zEv8k=4J^+$HW~U+`kO?j1g_)(^o2}px14Sfc5MAbb!fi0C71gCb4GkNlR&%6#lBYg zsD3`mYO?-tZ@ix9Lq^n=+d~pI>Q+ z+VkWvv~vU{Z+6W01om6+dH;zx;X7lwconMlLc3Gzi`uWl?nSo7!e51VLn8C^{ydry z@eAJTP5zlYkQ_Dnb@KFCfQi|xV}9rpg=w&!$9i;8HjA!y&R3s|iQ4Qz#h!~_(Vm=v z+Cbe17M72$svp^;RZa!W1qTJBdE?E3UcWyhS&Ysyeq@|gOIX)d7i=D7(QiJ}qUt|& zsvlTxTuxpU0_z4jnwLX_eNf-Ta=r97qc(M6*c|H&-Q@isxyguCv)DPW=5y(jGrcU1 zB#vQ7`*(O0MK@Wi?Y4dw{aLsAaa$3|7ah5oE+HIzh z3ZmbHUJz~s=qv0g%qW~At~ZKo=1Z*GH% zREp+pw{6k>lSeMI`)~Q(+~88H(3W#r4C!I8DD(4CkI~<+VCpMs{A|6{`k6Ggs97F%xS3eWEeU!5tM7r>HPMQF2f-MStGrx(7bo+{G2FgKOoH%-XoslQ#EIc zY#U>kocH7ZWifL8{>b0oS5l5#hpE*s{p8KrSW9nu?}_Ge4yCkyu*pT_E)%-#ud)@tOJ3VH3K9>cQ7v-aXco zsBA9z!T7F>8t;*<;iwqi0Ef`cy{yoRhcEFuGw{GQiKibAv&YwUXXWwUS+T#ncL2Po zr49+6u8+Xx?*v!Ln4sM@+wm4f2^7g-MV&a{YG7-mVyCW-_ZWA66AwSq5$^`>3?FyU z;to8#>z^XtXHg_{P)G&6WAG zUaQw`UY?RHESC-a_ut=s+WI>FPfM;I{|pN^K>o`+{7?Cw@c(z+xS|r5SH-j(eQjNg zEWwkFMxjyz_NrWrn|}y&%>ueNdN<$kdDxX&!N~i}#=)s{MDR+}zvYK(wY#qppu*@B+W>oUL>! zZ@HoBSJiy_^Y{^k7Y}DF>ibckylSoJRNhbg7dxIu{>4m@Qs@XCCX8jqd0MYpWoCcl z3bDQF1nX&kxOi1Uplg6KZ0J-Y==e9O`!Y9Ee>c*SYt!zfH^wF4kM{U^<58axuTKD` z;eAFN5>{I0LnC^eXlVOGGcFaCB|KZ6ZE1+=_p^ihjT*o97~#mBEjy{B zJR9AMmuUNpLUE|)2?D%+mb{xHd>@Sg)6i%lCASrfQbr8NGF6MPQw2afHnP^c9 z=;@H=<5r2xL=CnwiYQOpetM+BoE4HaoXhR658N-K4w zM18P^@-HXUkDzZWbH(M#gdEt&j>IQX0ZQ75&!&D>+fKRHd@~+f8T;(@#V!U`3s?g3 zj&2;!6ctx?!iUbPCeLgHd2Z718Z!%-f~mM}LmNyQ(!6@e*k^=y_iJZ@=6`URHN^R^jTfvJEY(kac0v~`do1YGv%Y~dfAf=ITK`x>YHs!R# z!JAYkiOL?u-a$%;Z}@oNAQKk<3DyDXHl4e1Amk-!<>rD z8So)-57wl3-4ji-#W}T0FgUT2>x#84MKYLzZ_E@0#=0RL4S6ims{*GVuMaS7NhfJm zTl^|#z^+oM6?r2x1cHytU2C$LDS3_8in&`Pp0?|?mppDi4|Fk+u+)Ucy`&AOb3|sG zji1=hwxxDf730~#R4i{Hsz-0B$=h1@EraaDeMsR zL&jLzxvT;k6d}%CFXE_1WzM*4FXNru8m0lc>2a^yjUnE%^o>F7xx5pmBy=-jU?s;&Xf5_EgQ5Z!6KC!#=^zf)2zH8qEHiiI*9NpJy*cZ%jbFF)k zG2q4l186{GG8qCxDfK`Pr?S8aw|`rrEdFQGW1*E90v5=uARc|8uhahWuQ8yHhg9_` zHXz5q1{CVNj(Z-X{xwgAc3tJ;d92CKGpQnftWznV3tXf90c>x^rtbtxU0ITfMoO$4 z%$8D^^EdAoiEQ}WsnM8jc+HEfpT6&3t;!WtN4|+q^%C2%lKtY;MpzX|Sz$W10%oEc zpMy5{5qOB3s=g!)7!BiB7_L5eml|NU_oJZubg>$mxPkrkEO?rGd?|uxd6WZN^lc3UO7h)SEQu)96`GREArF2CYg7+OBIK-Y)aMXj9R4ytZ}N z6Ss5y+3dj5dWm&-)Nh1{$k5HF@54FJ@rQH>J%JOGoFW}FhDPztd&b8L(n)dYHXdi-9b7bW z82K$UvoqYMmE5*CRz{M)k~g?>byfq_VN=;-DB2xzgaf`~?2= zgQdu1rGGEmj^}RqR_pp>A!kSaH!*Y@A4k}M>g%y-MNadl?BDyB;DgTq9Aw~Nx<@K0 z6+XIo_Urvs3ifq@wdci;v3+-$nx-)1$BCq>?}2BsP<^LKPki3#+_vT!q5k(+Kl81j ze7$kO){WRq2XgOb%+gCU*WmE}LpOU5Sb4Ve7HCY}<#Esmj3f>;2_`+_SI5Ls-hth0MJq zbm~@x$c31?Cj)9szY;!bF8Fbndr&_5bnx(aD>GpBOm|Bf`XOUOBxwG4T@NK5l%R&&mLm9+=n7FzlxPKw1 zqrM|TyzLQ%bbDgHa7g81nQwTGd9%XJxTp#SdG1&qHo6sj$ui^_^T<8u5T1boa$<}1 zOSR>|6~_7-=OF(hMxAsgIi`IS4>w?35L)OK;3yK!`@@rW23DVy!*cyw4Jx$M1xyZ8 zKg}#YTLhREguubE!TXI?pTR&F-2zyhI_Qt$xH)2`+8m;qqJs)XM4-1L*dW@2z)6@4 z?|sA&LzLT#?X4#&S|ocv^nyFkb+695;d{rkWQNGO0PWdt&L@Rp7u^Dd;)F-vE8K=v zk_cTO#wBxH3g@=|0p6Vn!dOa7JilAujc*kpuAikjrha|SwH(_+ButkPFWGb; zK#r7LNMl1)wt1wFoNH2QZ*D2PZ8-T$5$VDABDn4Q1#_r48)Vf+L}1x@mLU%G1qEU8 zY7{@lLBaX9v-LRMEL(56@n70qpQ<(#cR%sK6HMA?)gGrp#?g4! zZZao~TzlW!y4xNg1$Ada5M76)_#Lm3hk}W1S1*iDJ#9u>xri@oKs%<(tg!@UHn+$rN%MbSyQBd!XuU4>RhI zm!+Ib2E9w_1+Re^+6nfn7jE1stQ!$i0v<`R9H$uGxFdrXBB`9G6AB8vKL?H0x#!xy zjh=QMUuwY|G7oQ&d;Lfs6ZjLJRCu&_Fj8nNjyi#JlSABXSs=SzlnKN znw@$OHhDOea5zSf5l%k_B_JIAQf+%ppx4enML6*y)XtYi_!?F!j0J7Ke_VI(B<4sp z`F`uF#xp9;`W-{?!H_zQLi=bZl%uJOzz_nOsU=qhP2xF`<8z|%9mx0&ZSTOkVzHqS z)Pb6DL2agESDS>a{thM(7U3xr3q)}djdyB-kBfTtS6l7_j( zUu@&rAAQzh3sS&Y$(=sdkZb-gv(DqOkGL?yi-1YOAdUsU6#wYR zz>p?(4CAyhzr>gLYPx0UXv@B>h>BIE*x3A*M^_l%&$zY&wxcys3~kR0zw}+=)|OOs zDDR(P-&2dD_xBF}T=Rb}11{ByFWpYOZabC5-&gy4C-%Th^EpS0AJw_R*V90v{#k8o zDnS@1p=`)ht@3*OM?N>;SZuBN_3bmHIgeV-W2&spEZhbLID&D`=%*=m1ndyRFKm6eFL4V0((XZhN9S zGLTnD49!z>GK+<-ue!lO_vdO~f%O0|v0Ag-Cwl6dX2R<9+~Sk@4yW?O0n_{&G?!%Wg4%i+z(t*L4G%KiK)M&&6E`86@O847z9^s5YA>RWa^lG zZXvzoznHNLc{73DfO~+-4LGE=xf<{Vah?SKhPQu6VFw&~OKhrZHjGsR{bcQxpP!|m zxc`36>oSTR5M(^{Py|ElB(MCi#NBD$Tqm10H~;$q zLg%fOlDC3T^(xy|e-3TwsMKNmsK5!iS`}%Q`gH{VK!Z5OJ+?(DCoiNi(Z#g6o6OX0 zGEj1V+IoBNnQxhPv(e1WOOvMynHMd6icQQdYDT5@w8V1p;urn#3X=^}r z6(7yB_EYaNeR#%m@?&XWS_E@xwRfi5ZhQ*r|Gw>Y6JqFSSoQeR#eu62NVTB;vKDqy zz2n5t6f;Ke$jh+(PG*7hO_%_ekPWv+B%M!|f% zY7(o(cqO&c;G{q*k9SwWy7`gJpP>fYe2FW`j~^#t9@`n#W5&O$Hzu2$8a z1x`BB|ABwC5SBCXIz-@3;d_@6|K@TVPTDC?zb=0{kUk;&P`9e7n=7(cl0Q!RcSmm^ z&C2f%gk5#}=-LfrE9mv@JGf#p%RpJfj{^VN{5i0}OWZ-DM% z$FOok&5g;@q@$E?e>J;hd=0{OeA{pNt|<0we?k@hRa;Im?*7Bz2V&1qK%OfN%e?ZT z;G8oiklOfKP-r`tx_7z>N*j2MJU>jL;x7Gj2@X1QDZZM|JJTqF zS`ui!mU8Ffn~d9FHzagi>H3@6pLFd7dYA=hAjAwfW4l|PnyJwMD5c5>xtyYRGPjAt z4XVuO86|=Bx1hfnjT>FFxo0OdCD|(x^@&z)P_9bTMrzW+_wU~e{OP8!9m*7Pj6oKv zQ1~5Y*cZx0-mbOoy=`3mCf^jBYU-M(lJux~J&{#upe%(O*K^+SN>h;x3BTG~j1or0 zBk7B&mfq_{?t5G%P3r&zxIa%eY|isffm#}$dk=pwS0ugr2TH&Kk9GZ-8yORyW$?LI zH3{g-c5g0M$fUF#xneLA8sh50F4N3Qz41N-=Fos<`Y}i&eel`tc&ndBhNM5Z9)K{& z8P9XU7czg$$(hg-L!)+1NLC14c!C}cBOhpbyJYi)(1K1C?Abv;qfAG(u>(EIX%%%z z|LnDz;d+t&)Ov0+B9_kf^k99wNt<=Oc|>Y&&SRwcq$6Hh>Y`~2vIE@?@6ezJ9;_|y zeHL;y_;(*WV))zGC^$5dFV0UDNF6)eaTsFzD666Ow2*K@MP(;4VE)=|o(=)Y;n-%8p}Akt z0nE8oc4MZlWU|uKa7&F3h~8kID%U5awmlcKAEtLKgu9GL9+`>Cf*26$rZbNqj)Mc% zaDNnStvXY{pAOf3LLjf-*V`!wbz`Ef_IAwkBwmLyM8cJ`x--pigQT*t35a&`k<-(9 z1rcoa_&vN0|D6+PKzQpubCzHLpUAYZZ-aBQ($PArhy(f5wXgG0XN!?cgfVKZ)KpX| zXHO1<3@v#}D3K@^?%8?x{_2p2kBljKVE%$^U`Eib{_SsI0Knm_`FAdVjb_l5uajXm zBzVzF?=SDWK3=2}nay1=ir$3#$O=rPIVB76(~X10Ybv)6-?H7iTv@nK5+n1~^eE02 zbNF$7rH_;2?^V&q)oM_Ls1h$H_1_B?IKOC--hboLE#ifw<9w}M2jzcm{YM)(6Z(&B z{AW4*A9M~RbRw?5*jWYsx;wm(4|tN6CfEM@q8uDx%jxL9edVU`L-_%h@DB$hN3Pwl z9QkSU7r5eeqzPX_M&@_#?D0cE_HSx0>7_d|?|!P$UBO_PZ*_PbaKYy@53e4R`BOx8 zg)y0b8o&Fw`QY=`UkA^8JWlxc><^F3AM`B^@4qPEPJrX}zh}PG%*Q}N4)Lo#;5=yk z-`?DiAiWbH8J5KGx6?N)XRmsLckMsjzf{owC$t~ZNyVL7@YhW6t}zmb@?g<)*=jXCqm*rxOA#r4viW=11|9zT;xAC}b#}7|L znr-&0c^lCBo^m744Af--m)Fc;p@Eo|pINxQcFUae5`^WiT9>0-6fg?&+vif9A?B<< zLw6W_<`&)C)gp~}z1GJSs*YFqR}$oICw>{qvi-3(wg>yOxQB*YLRQkufu)}V2Dn^- z2rxjvVU$^f;ml#CwrDO00dOCcC5l2PNS`cIG#^1RHkX8AihZu1BCNugwbG>F-e!?{ zj)XDcrq=qw1Hn*pn}G8k{-B2(*}h*q*G6Tj`OG*$(9^Qk)5i8@l)wtM={C7$mauwG zzy?=i(63$lfqwNnC>Hx7I;a_302On3stD&AZmaS?9eDBBs7?A=g)M31e&(EZJX^DM|OH?gtr*wwP&C65itFae4Z6-n|oYuYeyd3UW%(T53mhE<4^|q_>t=-%DeS#k@Ayj+`a$ z`Cflufg=w>%()Xhr~Udrv5#vbtHqr_?vs&B172`*!!OCYLen$Bn-7`%mJ``ijkRk0 zSe4?EAI3{{&_Q}B^otX^;m!=>wL zzlX==HG_&ZbGJj?A4${ES~fVPY_%ONxbO2eHjTaC9~K{JBP6I1fF5^}R`~?ZtfWB} zysJO{-EYDT=%7FmmQ|nsYkx%A^1`mG`LsRuwwqm2ixdAW&`R)EM1uWrCi^_Z$0vk+ zy0=(8D^#UsUF)FnfC9E(pC_mi>B{@(QL)Ru<{Tda3HUHGuEzl8)2u~hK6B+!qJJAM z9#U=ne7!JfuBzDa53kzEKN)ul$n(a--5aF^aeU95VJ{!4XD&ye2Xzg=SCDF2^cvr> z!PqA=>o&YwxLTcoTT1 zM&6s$T8;L4HXToBN_#P}*JcIt^jK1WAC3=;>CNhbvQ0GWeRdXV6|R?~ziqWF(TMTP zwg(3vJuN&vRiGD^0Ep1)8`M5Tc?^pxF-~r#d(Te~xG|B}ZjR0@xBHHG^t`=4>KkD7N+bdp9Mkm}fC3u3~n$g|Z@bZN$%}L!Ba{Se;!y)V~Ab6bPUzob! z-~|qHo!KLfIH4Hq-njygK?Ecy6PG)_yv~~;GxJ?(>%AW;e2fZn{TuR!e*db1TX>+S zUc=49Yz=UJ`I zMEquUCmPMRs05ryoo}+0+&JEZX6!Y3xs5OU)HNAap#6XwbKgjWvywwXZVP_8M)ExiAnGYS&RNFons~m5d7J?JRLDjyAkn;cmkl1Sbv*_NA$ij!J-W!*A z_*>Q8n_im>PuD-Vr99T}mMVT7(!bC*n6x#!N=?S+?J+s5?Cqg%je3t`%&)1xR!wWq zHhKozn;EiQ*TH%Cc_E|2iCT#RhSK1j;FMLhS&&Rg%|oe$`1lO@?0qK zufTXnDl9JZ-<5J5 zhw1%g*gZa6%~&%#j=HWq&3kqw`M<;K@FD+dbNlXPJIsxj#Iin9GU284iu?}q@iu{MI=*|-rlewAfx;o}%-$-GaZ@>l(xyN4so4Fa`juOvxamI5Kt6NvoFxtro1 zohu_(y^7=2L^wot^iFm4&R_0a4ab(7qGcVga+E_n{Lmdnt$uoz%VEj{q9yUV)FFBh3ww%p6)|8iLL_h+4bpQ(?gu2AEk^Kwg6*;YTz zr3${)ed8mADlvE^e-1pH;UX8A*h{9P=AUlyDu0>&ME3h8wtLb#H?Yv7L?fzh@W5YT zkS5o7B=9IDjzRqU$iQ>+j1&7GAE~a!_E<-zBiGP z+6(&3lZ!$$4i=@EKk}LPGCV6QDoz5JIu)@A4(LGHvLMDQLkQvFN7(2sY5k0h_)8? zNM!BV?jcOgU19mFVdPRq)Em2vW7bcX%0bQFSCY1sgijh>W^`QPrxI&)t~Gm&S&#c};&7?0k-~7U~mrnls|zG^UmCt-hqO_u_-k(Y)-7xKn9JJsyXOAVjDqAxGdM{ zf^ww-&E92*dK7O4#*Q*0F&|h9yB7Ro)O$HLvx`h!H%+Q7E)hc|0$CwxM>_jE+b74r zVFi}dfHiONOk|Ch7`IDN?Lv1mug!dC3NEFhu(Nq=`KaBS*0b_AX4VC2i%6z$( z5pXu9G*;2I_{LLgJ{_zZnk9(F&&}iZ+p2PsTI8tK^;TM#4`Qz)F0_jSz9m}b$0#4VxO!+{OWEu zBwejl@5*h%`1&8`gjzBvbv@Co`#&Qjb|#oz@FnjL-#(;j zH7M0#Pk(uu>F8%`-t|%XB9GadOjKF_Ae_Zm)j*2wUSsmWNJJNJ!-UlybJ1*YwZxQj z?HRzcV`H?ck*FUyo9d?3*b#6EAaT3$u`-MLh8A4H6%sDfPYka?N;hKop$XT?B}U0s zG$!LW=u6~Mu@gB(=KDXAsd-JZOhM#`A^lz4FR0Ej zgK%WPQUr7<9!XMd6yH&m!I&?%BH z?NiIng1vSm^Gof%l9T zqI#wOgi|aRXSsgDy^j);{nChhVmm0VoleyJMBrowy^q_ILaexf4G1wW-Onz<+)IG! zX}EW>BAI}F^9le&@X1P=`#G6N6Yyn&^y=j{_swI9n`qI~KYwue>(i=(<&Y7?8vx%N z^qv--P9y-&0#Q$IM&sa>r-%x{V3;B48{uvUOHTvrt;z8WH)~Ghb zn}C+&s(|$~o;(p}*bfwPdz8-&haJdH5FbL#{W<>XFz#wEWM*C^MclTS?JA7l+=5-} z-(j1rB#-L6>JxJU;xgz~F{xgytAt3LBvGMvoA_^-#}Sat=F-Vm3?wu8<^HizDgD)6 zi;OFd_49xPabD4WGK?g+4f1LoQMRkNK8IrpSG~`*#I7U>N}Oa>CmZg`GpNK7vk?GTU zm*bYIRT1$QHQM4(Be$9W(~&MHLOFZm#Mg$N0;kJrHG)q>$b{6=Xg<|5w|$>T%4Eo^ z-;~b-u*}5R7GzaowY93ZS?Ow8W3o`0>T$s)+u1{9;I5;A zVd0aL+&u1puuK*-I=C#^u^9#N>e4g4d|}5sU&d;@b!3};5uy3Gf%70HpT%;RS4bLe z7v4M1_N7D4J6yqzhw5a*pIGv|rmrkEMR&4_SH5iX!bg@w+6Sr}S$uB;Lv&YCBCXzs zmNBrc50S*?>CbKsLbRCMoJl15aVIgYjAbjB2;cET4K5FIKM^@QZf5EAj@s(j*h+eE z59o2`I(8_)=-u%69uzH~m~=!l<~UQY|6(M7W$!F~x>$Wf`FK4y+7s?==OwWrPCWmI zKatmjBUOMGuHOkipc-qpuEA@2)ev5VE$QnfaPwrRj0(tIwqc%nn*7+S^W#f|tw~Nbq#{VNEU9mu zDC*Yv%NI%1s>huRu9WQ0fDwK5?5;G6SsHiN$6v-{C5c5US>5}!S)?UjF87Son(#?) zJaji^N`zxM^5cu0?;zD|T5`fa;gSXW8{>qQCk~n7&Kf*`V?&_9ydg5+$dyIFIU{@_ zhjZ_@Wo>{ zhA*fC1bN|Y5uoRa@`&KIDjycx$t7I4z-3UBg}ia*X|bAurxf zvhi@j9b?*%^jh-4t@eP#aAebqPV$_G-`09uLsC-X9%0 z9%*C|Dv#bmsJ_5rEIPfr8>}M66M=sOe zmJN<+^M3bX8v%S*b!(P2u9yTCPr6P06Gwy@cXMne&b~GJwv*?!7u8#cHsM0si{O5^ zq-LZ!R~X!=3_|bEBz~H9-bMTS@J?QR6rH+V5Mn!yO<2r!d2&|hF(UROJ zN4%-2ESBrDRR!`2c!Ca{TyAQQoOQ+Lu;v#qPC7ddne%f!vsQ8O@g9FAH$j~aNH;?s z>+m64d27u%c+=SF#xcUwz5s(Yju9o-GEq(c)$|Jo$9u=cc0CD(KTF1ygBVP67eoDd&<6nNbh^jK($d+9V0mZ;{}% zKk0O#LaczV$0Bq9VpFZ!%}Q^8o|452_=TJspXmy$uU-N?LGsd3bCSUD9P*|^`q;F( zol6b)iJ}E7S&8tvC#9qLZp*DtQCNVtk>ZXT@C6<4XQ0Rfu<$rUZkg|dnW-_H35Nj6 zFP(WtSzB&*z6E5aH$o3v+<{_baB2|emu?aEIO*yMfn6L|!e7g3EWH`018=QTnD4W_WNlN37UNKF7Gpy%p}Z4>7pz&=i=Ir%P`vtPZdFhRci+!sh2}IN0nN zm#+aFs!eY6S4HMbs4W+bn2$&Xpx**felH3QnJTP(T5`VjHk$BOlvt+PNY;UZ@6_b` zVR)(*j3^`%OC8RWi|Aops;Q3)F19jP9t5j`kEUCH(gwO{EX#KX!C#q`DbZEf-H21biaQ| z#5+bQ!u|wRvU_f3CC;=aR?#6z7kO?`7tDj*C1kn^OXwEl9pNU2 z`xWsditk`|7;WVOY;A{KHiwKl{RSxw~iKcnera*882K&5BpzSWl#Pe$)o8 zI+!pw>ap9~@xqR(aNsKwqzhcvGE)tX)muYrkI{vFX>%Upe&*jCKJuK?y>d>Y*rj=% z-nLX=gTJ<9SsI{>)DYvzm7Cp+wb*Cn&;Wzy^>APE&@vUFWXOD?+3AD=e&1OeZACvv z6PApoXC%h!5Wvl{D2d8($;~~6G1<=G=M(3=-AEZK9*q;H5ICRVT0))k4vIErI+(Ny zmej~tCF+Er!XT#AH1DH>qDKn~SRg;@=Rzy8e=y7|bVt;qj^q$Z+kT_Mbm~+t!DHu7 za4%b~+`}O*6uE?cZ9H(=y#Mt3=5}pE-tKqbyO8IUflGLJMD~~80vL8=Qm?gfi{92E6C-|;$0L~^AR$0lRpi$(?jyMD&SbckJSWZ+_{HhaF5*yfrD_gAQle2G(IXH3&92&dP(fmn3Bq=jMB06q38~ z9Tj~;FMHQ)@i9gp2^`vVr{^=wS`~XXG}Xu1jvgHRqC4y4H{;A-y2t}?+Brxn`XnXJ zHvlj-N!Lk7Q(d0PD|vL{wr6r64QdQ6-nk7!cFl;W3r@x_-Xhlsk9=vqSGeXRFOS)l@zVpgMz#&2g8!5+}kX+w%3I5FrOhgoTQF06v_8%wz7tJOh>$>(4+=v3Riq~Z4P?Y*PwZ>thLq>oH`5< zSY4~Gch2pPfCI1@sR-h#bMqo6B-bnxxxv@}wVqSS@*GRVJ??$>-S3;S@~htC>JzEJ z{pRA_Hl5d}l$QOl+B^CBzPaw-C4XI3pZKTj*!c%X6tC_x*7e^SyY2JoOUb9o<{zw@ z8fbrT-=)23mTdW7r>~3IcBUz8)qzy=7}d<`i?L}@dGiIYhdlE8`{LMC6T$zi<|oT$ zW>ywVPT7>38#if}_g1aXf({FcSWn5 + + + + + Document + + + + + +
+
+ {% block content %}{% endblock %} +
+ + +
+ + + + \ No newline at end of file diff --git a/src/templates/components.jinja b/src/templates/components.jinja new file mode 100644 index 0000000..90e14be --- /dev/null +++ b/src/templates/components.jinja @@ -0,0 +1,49 @@ +{% extends "base.jinja" %} + +{% block content %} +

template: components.jinja

+ + +
+

{{page['title']}}

+ {{ page['body'] }} + +

Component inventory

+ +{% set ns = namespace(has_inventory=false) %} +{% for item in documents.inventory %} + {% if item.Type.capitalize() == page['type'].capitalize() %} + {% set ns.has_inventory = true %} + hai + {% endif %} +{% endfor %} + +{% if ns.has_inventory %} + + + + + + + + + + {% for item in documents.inventory %} + {% if item.Type.capitalize() == page.type.capitalize() %} + + + + + + {% endif %} + {% endfor %} + + +
NameWhereDate
{{item.Value}}{{page.valueSymbol}}{{item.Where}}{{item.Date}}
+ +{% else %} +No components were identified yet +{% endif %} + +
+{% endblock %} \ No newline at end of file diff --git a/src/templates/index.jinja b/src/templates/index.jinja new file mode 100644 index 0000000..2bea713 --- /dev/null +++ b/src/templates/index.jinja @@ -0,0 +1,6 @@ +{% extends "base.jinja" %} + +{% block content %} +

This is the index

+ +{% endblock %} \ No newline at end of file diff --git a/src/templates/post.jinja b/src/templates/post.jinja new file mode 100644 index 0000000..e2e2009 --- /dev/null +++ b/src/templates/post.jinja @@ -0,0 +1,11 @@ +{% extends "base.jinja" %} + +{% block content %} +

template: post.jinja

+ + +
+

{{page['title']}}

+ {{ page['body'] }} +
+{% endblock %} \ No newline at end of file diff --git a/templates/event.md b/templates/event.md deleted file mode 100644 index caac345..0000000 --- a/templates/event.md +++ /dev/null @@ -1,2 +0,0 @@ -# {{TITLE}} -This event starts at {{START_DATETIME}} \ No newline at end of file