From cc1c7ec0654e37e00c46ef5ca048b3a46473e083 Mon Sep 17 00:00:00 2001 From: gauthiier Date: Sun, 21 Sep 2025 06:54:25 +0200 Subject: [PATCH] haha --- README.md | 2 +- conf.edit-me.yml | 9 + fetch_bib.py | 138 ++++++ fetch_ics.py | 91 ++++ make.py | 118 +++++ new.py | 43 ++ requirements.txt | 23 + resources/img/UU_logo_2021_EN_RGB.png | Bin 0 -> 28237 bytes resources/js/le_script.js | 107 +++++ resources/style/le_style.css | 245 ++++++++++ template/archetypes/event.md | 6 + template/archetypes/misc.md | 4 + template/archetypes/reading.md | 4 + template/csl/chicago-author-date.csl | 658 ++++++++++++++++++++++++++ template/index.html | 18 + template/partials/cases.html | 47 ++ template/partials/description.html | 3 + template/partials/footer.html | 3 + template/partials/head.html | 6 + template/partials/header.html | 3 + template/partials/section.html | 13 + utils.py | 47 ++ 22 files changed, 1587 insertions(+), 1 deletion(-) create mode 100644 conf.edit-me.yml create mode 100644 fetch_bib.py create mode 100644 fetch_ics.py create mode 100644 make.py create mode 100644 new.py create mode 100644 requirements.txt create mode 100755 resources/img/UU_logo_2021_EN_RGB.png create mode 100644 resources/js/le_script.js create mode 100644 resources/style/le_style.css create mode 100644 template/archetypes/event.md create mode 100644 template/archetypes/misc.md create mode 100644 template/archetypes/reading.md create mode 100644 template/csl/chicago-author-date.csl create mode 100644 template/index.html create mode 100644 template/partials/cases.html create mode 100644 template/partials/description.html create mode 100644 template/partials/footer.html create mode 100644 template/partials/head.html create mode 100644 template/partials/header.html create mode 100644 template/partials/section.html create mode 100644 utils.py diff --git a/README.md b/README.md index 5e97b69..5983175 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# Mathematics-and-Artifice +# Mathematics & Artifice Site logics of "Mathematics & Artifice" \ No newline at end of file diff --git a/conf.edit-me.yml b/conf.edit-me.yml new file mode 100644 index 0000000..08bc866 --- /dev/null +++ b/conf.edit-me.yml @@ -0,0 +1,9 @@ +site: 'Mathematics & Artifice' +template: 'template/' +content: 'content/' +output: 'public/' +footer_img: '' +ics_url: '' +zotero_group_id: '' +zotero_api_key: '' +zotero_lib_type: '' \ No newline at end of file diff --git a/fetch_bib.py b/fetch_bib.py new file mode 100644 index 0000000..d017235 --- /dev/null +++ b/fetch_bib.py @@ -0,0 +1,138 @@ +import pathlib, re, frontmatter, markdown, citeproc, json +from pyzotero import zotero +from html.parser import HTMLParser +import utils + +CEND = '\33[0m' +CRED = '\33[31m' +CGREEN = '\33[32m' +CVIOLET = '\33[35m' +CBLUE = '\33[34m' + +re_html = '<.*?>' +re_punc = r'[^\w\s]' +CLEANR = re.compile(f'{re_html}|{re_punc}') + +def format_reading(title:str, desc:str): + c = frontmatter.Post(content=desc) + c['title'] = title + c['type'] = 'reading' + return c + +def compare_readings(path:pathlib.PosixPath, title:str, desc:str): + p = frontmatter.load(path) + pd = p.to_dict() + pd['content'] = pd['content'].strip() + return p, (pd == {'title': title, 'type': 'reading', 'content': desc.strip()}) + +def update_reading(previous:frontmatter.Post, new:frontmatter.Post): + keys = set(previous.keys()).union(set(new.keys())) + for k in keys: + if not str(previous[k]).strip() == str(new[k]).strip(): + print(f"Update '{k}' (y/n)?\n\tprev: {CRED}{previous[k]}{CEND}\n\tnew: {CGREEN}{new[k]}{CEND}") + c = input() + if c == 'y': + previous[k] = new[k] + + if not previous.content.strip() == new.content.strip(): + print(f"Update 'content' (y/n)?\n\tprev: {CRED}{previous.content}{CEND}\n\tnew: {CGREEN}{new.content}{CEND}") + c = input() + if c == 'y': + previous.content = new.content + + return previous + +def valid_bib_entry(csljson): + v = True + v = v and not ("full text" in csljson['title'].lower()) + v = v and not ("Table of Contents PDF".lower() in csljson['title'].lower()) + v = v and not ("Submitted Version".lower() in csljson['title'].lower()) + v = v and not ("Includes Bibliographical References".lower() in csljson['title'].lower()) + + # add more... + return v + +def format_filename_title(data_csl:dict, bib_entry:str): + index = bib_entry.lower().find(data_csl['title'].lower()) + if index == -1: + return None + index += len(data_csl['title']) + 4 if data_csl['type'] == 'book' else len(data_csl['title']) + 1 + + title = bib_entry[:index] + filename = re.sub(CLEANR, '', title).replace(' ', '-') + ".md" + + return filename, title + + +if __name__ == "__main__": + + conf = utils.load_conf() + + z = zotero.Zotero(conf['zotero_group_id'], conf['zotero_lib_type'], conf['zotero_api_key']) + + for d in z.collections(): + collection_name = d['data']['name'] + collection_key = d['key'] + print("---") + + z.add_parameters(content='csljson') + collection = z.collection_items(collection_key) + collection.reverse() + + # compile bib + + style_file = pathlib.Path(conf['template']) / 'csl' / 'chicago-author-date.csl' + + src = citeproc.source.json.CiteProcJSON(json_data=collection) + style = citeproc.CitationStylesStyle(style_file.absolute(), validate=False) + bib = citeproc.CitationStylesBibliography(style=style, source=src, formatter=citeproc.formatter.html) + + # print(collection) + entries = [citeproc.CitationItem(e['id']) for e in collection if valid_bib_entry(e)] + bib.register(citeproc.Citation(entries)) + + # because citeproc-py can't design shit... + kv = dict(zip(bib.keys, [str(e) for e in bib.style.render_bibliography(entries)])) + + # print(kv) + + # process collection and bib + + for e in collection: + + eid = e['id'].lower() + + if eid not in bib.keys: + continue + + bib_entry = kv[eid] + filename, title = format_filename_title(e, bib_entry) + filepath = pathlib.Path(conf['content']) / "bibliography" / collection_name / filename + + if not filepath.exists(): + print(f"new reading: {title}") + new = format_reading(title=title, desc=bib_entry) + utils.save_file(filepath, frontmatter.dumps(new), mkdirs=True) + + else: + prev, eq = compare_readings(filepath, title, bib_entry) + + if eq: + print(f"reading {CVIOLET}{title}{CEND} already exists... continuing") + continue + print(f"updating reading: {CBLUE}{title}{CEND}") + + ## selective update + new = format_reading(title=title, desc=bib_entry) + + updated = update_reading(prev, new) + utils.save_file(filepath, frontmatter.dumps(updated), overwrite=True) + + print(f"reading {e} updated") + + + + + + + diff --git a/fetch_ics.py b/fetch_ics.py new file mode 100644 index 0000000..84b40dd --- /dev/null +++ b/fetch_ics.py @@ -0,0 +1,91 @@ +import pathlib, ics, requests, arrow, frontmatter +import utils + +DFMT = "YYYY-MM-DD" +DHFMT = "YYYY-MM-DD HH:mm" +HFMT = "HH:mm" + +CEND = '\33[0m' +CRED = '\33[31m' +CGREEN = '\33[32m' +CVIOLET = '\33[35m' +CBLUE = '\33[34m' + +def format_event(title:str, date:str, location:str, desc:str): + c = frontmatter.Post(content=desc) + c['title'] = title + c['date'] = date + c['location'] = location + c['type'] = 'event' + return c + +def compare_events(path:pathlib.PosixPath, title:str, date:str, location:str, desc:str): + p = frontmatter.load(path) + pd = p.to_dict() + pd['content'] = pd['content'].strip() + return p, (pd == {'title': title, 'date': date, 'location': location, 'type': 'event', 'content': desc.strip()}) + +def update_event(previous:frontmatter.Post, new:frontmatter.Post): + keys = set(previous.keys()).union(set(new.keys())) + for k in keys: + if not str(previous[k]).strip() == str(new[k]).strip(): + print(f"Update '{k}' (y/n)?\n\tprev: {CRED}{previous[k]}{CEND}\n\tnew: {CGREEN}{new[k]}{CEND}") + c = input() + if c == 'y': + previous[k] = new[k] + + if not previous.content.strip() == new.content.strip(): + print(f"Update 'content' (y/n)?\n\tprev: {CRED}{previous.content}{CEND}\n\tnew: {CGREEN}{new.content}{CEND}") + c = input() + if c == 'y': + previous.content = new.content + + return previous + +def read_date(p:frontmatter.Post): + date = p['date'] + # 2024-10-06 10:00-12:00 + date = "-".join(date.split("-")[:-1]) + return arrow.get(date, DHFMT) + +if __name__ == "__main__": + + conf = utils.load_conf() + + req = requests.get(conf['ics_url']).text + c = ics.Calendar(req) + + for e in c.events: + + # file path + name + name = e.name.replace(' ', '-') + fm_date = e.begin.format(DFMT) + fm_date_interval = f"{e.begin.format(DHFMT)}-{e.end.format(HFMT)}" + filename = f'{fm_date}-{name}.md' + filepath = pathlib.Path(conf['content']) / 'event' / filename + + if not filepath.exists(): + print(f"new event: {e.name}") + new = format_event(title=e.name, date=fm_date_interval, location=e.location, desc=e.description) + utils.save_file(filepath, frontmatter.dumps(new), mkdirs=True) + + else: + prev, eq = compare_events(filepath, e.name, fm_date_interval, e.location, e.description) + + if eq: + print(f"event {CVIOLET}{e.name}{CEND} already exists... continuing") + continue + print(f"updating event: {CBLUE}{e.name}{CEND}") + + ## selective update + new = format_event(title=e.name, date=fm_date_interval, location=e.location, desc=e.description) + + updated = update_event(prev, new) + utils.save_file(filepath, frontmatter.dumps(updated), overwrite=True) + + print(f"event {e.name} updated") + + + + + diff --git a/make.py b/make.py new file mode 100644 index 0000000..4e63f30 --- /dev/null +++ b/make.py @@ -0,0 +1,118 @@ +import yaml, pathlib, shutil, markdown, frontmatter, arrow, jinja2 +from fetch_ics import read_date +import utils + +if __name__ == "__main__": + + with open('conf.yml') as fp: + conf = yaml.safe_load(fp.read()) + + content = pathlib.Path(conf['content']) + template = pathlib.Path(conf['template']) + + ## description + desc = utils.read_file(content / 'description.md') + if not desc: + print("not description.md in content/") + exit(1) + + # template + index = utils.read_file(template / 'index.html') + if not index: + print("not index.md in template/") + exit(1) + + index_template = jinja2.Template(index) + + # partials templates + partials = utils.get_files_in_subdir(template, 'partials', 'html') + + # head + head_template = jinja2.Template(utils.read_file(partials['head'])) + res_js = [p.relative_to('resources') for p in list(utils.get_files_in_subdir('resources/', 'js', 'js').values())] + res_css = [p.relative_to('resources') for p in list(utils.get_files_in_subdir('resources/', 'style', 'css').values())] + head = head_template.render(title=conf['site'], js_items=res_js, css_items=res_css) + + # header + header_template = jinja2.Template(utils.read_file(partials['header'])) + header = header_template.render(title=conf['site']) + + # cases + cases_template = jinja2.Template(utils.read_file(partials['cases'])) + cases = cases_template.render() + + # description + description_template = jinja2.Template(utils.read_file(partials['description'])) + desc = markdown.markdown(frontmatter.loads(desc).content) + description = description_template.render(desc=desc) + + # section {events + readings} + section_template = jinja2.Template(utils.read_file(partials['section'])) + + # events + events = list(utils.get_files_in_subdir(conf['content'], 'event', 'md').values()) + upcoming_events = [] + previous_events = [] + for e in events: + p = frontmatter.load(e) + summary = f"{p['title']} - {p['date']}" + content = markdown.markdown(p.content) + detail = f"When: {p['date']}
Where: {p['location']}
{content}" + el = {'summary': summary, 'detail': detail} + + if read_date(p) > arrow.utcnow(): + upcoming_events.append(el) + else: + previous_events.append(el) + + upcoming = section_template.render(section_id='events', section_title="Upcoming session(s)", section_items=upcoming_events) + previous = section_template.render(section_id='archive', section_title="Previous sessions", section_items=previous_events) + + # reading bibliography + reading = "" + bibliography_dir = pathlib.Path(conf['content']) / "bibliography" + bibliography = utils.ls_dir(bibliography_dir) + + for b in bibliography: + reading_list = utils.get_files_in_subdir(bibliography_dir, b.stem, 'md') + if not reading_list: + continue + reading_list = list(reading_list.values()) + readings = [] + for r in sorted(reading_list): + p = frontmatter.load(r) + summary = p['title'] + detail = markdown.markdown(p.content) + readings.append({'summary': summary, 'detail': detail}) + + reading += section_template.render(section_id='readings', section_title=b.stem, section_items=readings) + "\n" + + # footer + if 'footer' in partials and 'footer_img' in conf: + footer_template = jinja2.Template(utils.read_file(partials['footer'])) + footer = footer_template.render(footer_img=conf['footer_img']) + + + # index_html + index_html = index_template.render(head=head, header=header, cases=cases, description=description, upcoming=upcoming, reading=reading, previous=previous, footer=footer) + + # save + output_path = pathlib.Path(f"{conf['output']}") + index_path = output_path / "index.html" + utils.save_file(index_path, index_html, overwrite=True, mkdirs=True) + shutil.copytree('resources', output_path, dirs_exist_ok=True) + + + + + + + + + + + + + + + diff --git a/new.py b/new.py new file mode 100644 index 0000000..4975062 --- /dev/null +++ b/new.py @@ -0,0 +1,43 @@ +import yaml, argparse, pathlib +from datetime import datetime +import utils + +if __name__ == "__main__": + + p = argparse.ArgumentParser(description='creates new content files') + p.add_argument('filepath', metavar='filepath', type=str, help='path for new file') + + args = p.parse_args() + + file = pathlib.Path(args.filepath) + + type = file.parent.name + + conf = utils.load_conf() + + atypes = utils.get_files_in_subdir(conf['template'], 'archetypes', 'md') + + if atypes is None: + print('no archetypes in template') + exit(1) + + if type not in atypes.keys(): + ## can relax this later + print('directory of the new file must match an archetype') + exit(1) + + with open(atypes[type]) as fp: + archetype = fp.read() + + + #### process str if needed #### + + file.parent.mkdir(parents=True, exist_ok=True) + + with open(file, 'w') as fp: + fp.write(archetype) + + + + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..abb48da --- /dev/null +++ b/requirements.txt @@ -0,0 +1,23 @@ +arrow==1.3.0 +attrs==24.2.0 +bibtexparser==1.4.2 +certifi==2024.8.30 +charset-normalizer==3.3.2 +feedparser==6.0.11 +ics==0.7.2 +idna==3.10 +Jinja2==3.1.4 +Markdown==3.7 +MarkupSafe==2.1.5 +pyparsing==3.1.4 +python-dateutil==2.9.0.post0 +python-frontmatter==1.1.0 +pytz==2024.2 +PyYAML==6.0.2 +pyzotero==1.5.25 +requests==2.32.3 +sgmllib3k==1.0.0 +six==1.16.0 +TatSu==5.12.1 +types-python-dateutil==2.9.0.20241003 +urllib3==2.2.3 diff --git a/resources/img/UU_logo_2021_EN_RGB.png b/resources/img/UU_logo_2021_EN_RGB.png new file mode 100755 index 0000000000000000000000000000000000000000..c5477169483fae1c0b13b6d3f461891bbfa1119d GIT binary patch literal 28237 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 0; i--) { + toggle_case(cases[i]); + draggable(cases[i]); + initial_height_closed(cases[i]); +} + +function draggable(e) { + var x, y, x_offset, y_offset, dragged = false; + + function drag_start(el) { + console.log("start"); + el = el || window.event; + el.preventDefault(); + x = el.clientX || el.targetTouches[0].pageX; + y = el.clientY || el.targetTouches[0].pageY; + x_offset = x - parseInt(e.offsetLeft); + y_offset = y - parseInt(e.offsetTop); + document.onmouseup = drag_stop; + document.ontouchend = drag_stop; + document.onmousemove = drag; + document.ontouchmove = drag; + // el.target.focus(); + } + + function drag(el) { + el = el || window.event; + el.preventDefault(); + + let cx = el.clientX || el.touches[el.touches.length].pageX; + let cy = el.clientY || el.touches[el.touches.length].pageY; + + if ((cx !== x) & (cy !== y)) { + e.style.left = (cx - x_offset) + "px"; + e.style.top = (cy - y_offset) + "px"; + if (!dragged) + fix_cases_el_height(e); + dragged = true; + } + } + + function drag_stop(el) { + el = el || window.event; + el.preventDefault(); + document.onmouseup = null; + document.ontouchend = null; + document.onmousemove = null; + document.ontouchmove = null; + + let cx = el.clientX || el.touches[el.touches.length].pageX; + let cy = el.clientY || el.touches[el.touches.length].pageY; + + // if no move then collapse + if ((cx == x) & (cy == y)) { + toggle_case(e); + } + } + + e.onmousedown = drag_start; + e.touchstart = drag_start; + +} + +function initial_height_closed(c) { + c.initial_height_closed = c.offsetHeight; +} + +function toggle_case(c) { + for (let i = c.children.length - 1; i >= 1; i--) { + c.children[i].classList.toggle('hidden'); + c.opened = !c.children[i].classList.contains('hidden') + } + + + if(c.opened) { + // c.style.removeProperty('height'); + c.classList.remove('close'); + fix_cases_height(); + } else { + c.classList.add('close'); + } +} + +function fix_cases_height(){ + for (let i = cases.length - 1; i >= 0; i--) { + if (!cases[i].opened) { + cases[i].classList.add('close'); + } + } +} + +function fix_cases_el_height(e){ + let h = cases_el.offsetHeight; + // e.style.position = 'absolute'; + for (let i = cases.length - 1; i >= 0; i--) { + cases[i].style.position = 'absolute'; + } + + cases_el.style.height = h + 'px'; +} + + + diff --git a/resources/style/le_style.css b/resources/style/le_style.css new file mode 100644 index 0000000..30c98d1 --- /dev/null +++ b/resources/style/le_style.css @@ -0,0 +1,245 @@ +#frame { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; +} + +#header { + height: 100px; +} + +#content { + max-width: 1200px; + min-width: 500px; +} + +#content > #description { + font-family: baskerville; + font-size: 2rem; +} + +ma { + font-family: baskerville; + font-size: 5rem; +} + +#footer { + display: flex; + align-items: center; + flex-direction: column; + width: 1200px; +/* min-width: 500px; */ + margin-top: 0.5em; + padding: 0.5em; + border-top: 3px double black; +} + +#footer > img { + max-width: 250px; +} + + +/*section*/ + +.section { + padding-bottom: 1em; +} + + +.section_header { + display: flex; + flex-direction: row; + border-bottom: 3px double red; + margin-bottom: 1.5em; +} + +.section_header > h2 { + padding-right: 0.5em; +} + +#events .list > details { + background-color: lightgoldenrodyellow; +} + +.list > details { + font-size: 1.8rem; + border: 1px solid #aaa; + border-radius: 4px; + margin-bottom: 0.5em; +} + +.list > details[open] { + background-color: lightsalmon; + border-bottom: 3px black solid; + border-radius: 4px; + padding: 0 1em 1em 1em; +} + +.list > details > summary { + font-size: 1.8rem; +/* font-weight: bold;*/ +/* margin: 0.5em;*/ + padding: 0.5em; +} + +.list > details[open] > summary { + border-bottom: 2px black solid; + margin-bottom: 1em; +} + +/*cases*/ + +.hidden { + display: none; +} + +#cases { +/* border: green 1px solid;*/ + display: flex; + flex-direction: row; +} + +.case { + margin: 1em; + padding: 1em; + width: 500px; + border: 1px solid black; + background-color: lightgrey; + border-radius: 5px; +} + +.case.close { + height: 2em; +} + +.title { + font-family: helvetica, sans-serif; + padding-bottom: 0.8em; +} + + +.definition, .origin { + font-family: helvetica, sans-serif; +} + +.title entry { + font-size: 1.5em; +} + +.title phone { + color: grey; + font-size: 1.2em; +} + +.qual { + font-size: 1em; +} + +.qual genre { + font-size: 1.2em; +} + +extra { + color: grey; + font-style: italic; +} + +ex { + font-family: Arial, sans-serif; + font-style: italic; + font-weight: lighter; +} + +xe { + font-style: italic; + font-weight: bold; +} + +.def { + margin: 1em; +} + +.example { + margin-top: 1em; + margin-bottom: 1em; +} + +.origin or { + color: grey; + font-size: 0.8em; + text-transform: uppercase; +} + +/* max-width: 1200px */ + +@media screen and (max-width: 1200px) { + + body { +/* background: #aaa;*/ + } + + #header { + margin-bottom: 1em; + } + + + ma { + font-size: 6em; + } + + #content > #description, .section_header > h2 { + font-size: 3rem; + font-weight: 400; + } + + .title { + font-size: 1.7em; + } + + .origin { + font-size: 1.2em; + } + + .title entry { + font-size: 1.7em; + } + + .title phone { + color: grey; + font-size: 1.4em; + } + + .qual { + font-size: 1.7em; + } + + .qual genre { + font-size: 1.4em; + } + + .list > details, .list > details > summary { + font-size: 1.7rem; + } + + #content, #footer, #cases, .case { + width: 95%; + } + + #cases { + display: flex; + flex-direction: column; + } + + .case { + margin-left: 0.5em; + } + + .case.close { + height: 4rem; + } + + +} + + diff --git a/template/archetypes/event.md b/template/archetypes/event.md new file mode 100644 index 0000000..964a0f1 --- /dev/null +++ b/template/archetypes/event.md @@ -0,0 +1,6 @@ +--- +type: 'event' +title: '' +date: '<event_date>' +location: '<location>' +--- \ No newline at end of file diff --git a/template/archetypes/misc.md b/template/archetypes/misc.md new file mode 100644 index 0000000..0a58bc4 --- /dev/null +++ b/template/archetypes/misc.md @@ -0,0 +1,4 @@ +--- +type: 'misc' +title: '<event title>' +--- \ No newline at end of file diff --git a/template/archetypes/reading.md b/template/archetypes/reading.md new file mode 100644 index 0000000..4b2f91b --- /dev/null +++ b/template/archetypes/reading.md @@ -0,0 +1,4 @@ +--- +type: 'reading' +title: '<title>' +--- \ No newline at end of file diff --git a/template/csl/chicago-author-date.csl b/template/csl/chicago-author-date.csl new file mode 100644 index 0000000..9f126b3 --- /dev/null +++ b/template/csl/chicago-author-date.csl @@ -0,0 +1,658 @@ +<?xml version="1.0" encoding="utf-8"?> +<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="display-and-sort" page-range-format="chicago"> + <info> + <title>Chicago Manual of Style 17th edition (author-date) + http://www.zotero.org/styles/chicago-author-date + + + + Julian Onions + julian.onions@gmail.com + + + Sebastian Karcher + + + Richard Karnesky + karnesky+zotero@gmail.com + http://arc.nucapt.northwestern.edu/Richard_Karnesky + + + Andrew Dunning + andrew.dunning@utoronto.ca + https://orcid.org/0000-0003-0464-5036 + + + Matthew Roth + matthew.g.roth@yale.edu + https://orcid.org/0000-0001-7902-6331 + + + Brenton M. Wiernik + + + + The author-date variant of the Chicago style + 2018-01-24T12:00:00+00:00 + This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License + + + + ed. + by + trans. + edited and translated by + trans. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/template/index.html b/template/index.html new file mode 100644 index 0000000..0c49bd2 --- /dev/null +++ b/template/index.html @@ -0,0 +1,18 @@ + + +{{ head }} + +
+ {{ header }} + {{ cases }} +
+ {{ description }} + {{ upcoming }} + {{ previous }} + {{ reading }} + {{ misc }} +
+ {{ footer }} +
+ + \ No newline at end of file diff --git a/template/partials/cases.html b/template/partials/cases.html new file mode 100644 index 0000000..bca280b --- /dev/null +++ b/template/partials/cases.html @@ -0,0 +1,47 @@ +
+
+
+ mathematics + | ˌmaθ(ə)ˈmatɪks | +
+
+
+ plural noun + [usually treated as singular] +
+
+ the abstract science of number, quantity, and space, either as abstract concepts (pure mathematics), or as applied to other disciplines such as physics and engineering (applied mathematics): a taste for mathematics. +
+
  • [often treated as plural] the mathematical aspects of something: James immerses himself in the mathematics of baseball.
  • +
    +
    +
    +
    + origin +
    + mid 16th century: plural of obsolete mathematic ‘mathematics’, from Old French mathematique, from Latin (ars) mathematica ‘mathematical (art)’, from Greek mathēmatikē (epistēmē), from the base of manthanein ‘learn’. +
    +
    +
    +
    +
    + artifice + | ˈɑːtɪfɪs | +
    +
    +
    + noun + [mass noun] +
    +
    + clever or cunning devices or expedients, especially as used to trick or deceive others: an industry dominated by artifice | [count noun] : the style is not free from the artifices of the period. +
    +
    +
    + origin +
    + early 16th century (in the sense ‘workmanship’): from Anglo-Norman French, from Latin artificium, based on ars, art- ‘art’ + facere ‘make’. Late Middle English has the form artificie, directly from Latin. +
    +
    +
    +
    \ No newline at end of file diff --git a/template/partials/description.html b/template/partials/description.html new file mode 100644 index 0000000..b2ac6f7 --- /dev/null +++ b/template/partials/description.html @@ -0,0 +1,3 @@ +
    + {{ desc }} +
    diff --git a/template/partials/footer.html b/template/partials/footer.html new file mode 100644 index 0000000..f65f451 --- /dev/null +++ b/template/partials/footer.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/template/partials/head.html b/template/partials/head.html new file mode 100644 index 0000000..6599b40 --- /dev/null +++ b/template/partials/head.html @@ -0,0 +1,6 @@ + + + {% for item in css_items %}{% endfor %} + {% for item in js_items %}{% endfor %} + {{ title }} + diff --git a/template/partials/header.html b/template/partials/header.html new file mode 100644 index 0000000..cafd9d9 --- /dev/null +++ b/template/partials/header.html @@ -0,0 +1,3 @@ + diff --git a/template/partials/section.html b/template/partials/section.html new file mode 100644 index 0000000..8560c38 --- /dev/null +++ b/template/partials/section.html @@ -0,0 +1,13 @@ +
    +
    +

    {{ section_title }}

    +
    +
    + {% for item in section_items %} +
    + {{ item.summary }} + {{ item.detail }} +
    + {% endfor %} +
    +
    diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..7ce1b75 --- /dev/null +++ b/utils.py @@ -0,0 +1,47 @@ +import yaml, pathlib + +def load_conf(): + p = pathlib.Path('conf.yml') + if not p.exists(): + return None + with open(p) as fp: + return yaml.safe_load(fp.read()) + +def read_file(path:pathlib.PosixPath): + if not path.exists(): + print(f"File {path} does not exist...") + return None + with open(path) as fp: + return fp.read() + +def save_file(path:pathlib.PosixPath, contents:str, overwrite=False, mkdirs=False): + if path.exists() and not overwrite: + print(f"File {path} already exists and overwrite is False...") + return + + if not path.parent.exists() and not mkdirs: + print(f"Directory {path.parent} does not exists and mkdirs is False...") + return + + if mkdirs: + path.parent.mkdir(parents=True, exist_ok=True) + + with open(path, 'w') as fp: + fp.write(contents) + +def ls_dir(path:str): + directory = pathlib.Path(path) + if not directory.exists() and not directory.is_dir(): + return None + return list(directory.iterdir()) + +def get_files_in_subdir(path:str, subdir:str, suffix:str): + template = pathlib.Path(path) + if template.exists() and template.is_dir(): + partials_path = template / subdir; + if partials_path.exists() and partials_path.is_dir(): + files = list(partials_path.glob('**/*.' + suffix)) + partials = [a.stem for a in files] + return dict(zip(partials, files)) + return None +