This commit is contained in:
gauthiier 2025-09-21 06:54:25 +02:00
parent 6851c67498
commit cc1c7ec065
22 changed files with 1587 additions and 1 deletions

View File

@ -1,3 +1,3 @@
# Mathematics-and-Artifice # Mathematics & Artifice
Site logics of "Mathematics & Artifice" Site logics of "Mathematics & Artifice"

9
conf.edit-me.yml Normal file
View File

@ -0,0 +1,9 @@
site: 'Mathematics & Artifice'
template: 'template/'
content: 'content/'
output: 'public/'
footer_img: '<edit-me>'
ics_url: '<edit-me>'
zotero_group_id: '<edit-me>'
zotero_api_key: '<edit-me>'
zotero_lib_type: '<edit-me>'

138
fetch_bib.py Normal file
View File

@ -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")

91
fetch_ics.py Normal file
View File

@ -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")

118
make.py Normal file
View File

@ -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"<i>When:</i> {p['date']}<br><i>Where:</i> {p['location']}<br>{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)

43
new.py Normal file
View File

@ -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)

23
requirements.txt Normal file
View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

107
resources/js/le_script.js Normal file
View File

@ -0,0 +1,107 @@
var cases = document.getElementsByClassName("case");
var cases_el = document.getElementById("cases");
for (let i = cases.length - 1; i >= 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';
}

View File

@ -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;
}
}

View File

@ -0,0 +1,6 @@
---
type: 'event'
title: '<title>'
date: '<event_date>'
location: '<location>'
---

View File

@ -0,0 +1,4 @@
---
type: 'misc'
title: '<event title>'
---

View File

@ -0,0 +1,4 @@
---
type: 'reading'
title: '<title>'
---

View File

@ -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)</title>
<id>http://www.zotero.org/styles/chicago-author-date</id>
<link href="http://www.zotero.org/styles/chicago-author-date" rel="self"/>
<link href="http://www.chicagomanualofstyle.org/tools_citationguide.html" rel="documentation"/>
<author>
<name>Julian Onions</name>
<email>julian.onions@gmail.com</email>
</author>
<contributor>
<name>Sebastian Karcher</name>
</contributor>
<contributor>
<name>Richard Karnesky</name>
<email>karnesky+zotero@gmail.com</email>
<uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri>
</contributor>
<contributor>
<name>Andrew Dunning</name>
<email>andrew.dunning@utoronto.ca</email>
<uri>https://orcid.org/0000-0003-0464-5036</uri>
</contributor>
<contributor>
<name>Matthew Roth</name>
<email>matthew.g.roth@yale.edu</email>
<uri> https://orcid.org/0000-0001-7902-6331</uri>
</contributor>
<contributor>
<name>Brenton M. Wiernik</name>
</contributor>
<category citation-format="author-date"/>
<category field="generic-base"/>
<summary>The author-date variant of the Chicago style</summary>
<updated>2018-01-24T12:00:00+00:00</updated>
<rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
</info>
<locale xml:lang="en">
<terms>
<term name="editor" form="verb-short">ed.</term>
<term name="container-author" form="verb">by</term>
<term name="translator" form="verb-short">trans.</term>
<term name="editortranslator" form="verb">edited and translated by</term>
<term name="translator" form="short">trans.</term>
</terms>
</locale>
<macro name="secondary-contributors">
<choose>
<if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="none">
<group delimiter=". ">
<names variable="editor translator" delimiter=". ">
<label form="verb" text-case="capitalize-first" suffix=" "/>
<name and="text" delimiter=", "/>
</names>
<names variable="director" delimiter=". ">
<label form="verb" text-case="capitalize-first" suffix=" "/>
<name and="text" delimiter=", "/>
</names>
</group>
</if>
</choose>
</macro>
<macro name="container-contributors">
<choose>
<if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
<group prefix=", " delimiter=", ">
<names variable="container-author" delimiter=", ">
<label form="verb" suffix=" "/>
<name and="text" delimiter=", "/>
</names>
<names variable="editor translator" delimiter=", ">
<label form="verb" suffix=" "/>
<name and="text" delimiter=", "/>
</names>
</group>
</if>
</choose>
</macro>
<macro name="editor">
<names variable="editor">
<name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
<label form="short" prefix=", "/>
</names>
</macro>
<macro name="translator">
<names variable="translator">
<name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
<label form="short" prefix=", "/>
</names>
</macro>
<macro name="recipient">
<choose>
<if type="personal_communication">
<choose>
<if variable="genre">
<text variable="genre" text-case="capitalize-first"/>
</if>
<else>
<text term="letter" text-case="capitalize-first"/>
</else>
</choose>
</if>
</choose>
<names variable="recipient" delimiter=", ">
<label form="verb" prefix=" " text-case="lowercase" suffix=" "/>
<name and="text" delimiter=", "/>
</names>
</macro>
<macro name="substitute-title">
<choose>
<if type="article-magazine article-newspaper review review-book" match="any">
<text macro="container-title"/>
</if>
</choose>
</macro>
<macro name="contributors">
<group delimiter=". ">
<names variable="author">
<name and="text" name-as-sort-order="first" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
<label form="short" prefix=", "/>
<substitute>
<names variable="editor"/>
<names variable="translator"/>
<names variable="director"/>
<text macro="substitute-title"/>
<text macro="title"/>
</substitute>
</names>
<text macro="recipient"/>
</group>
</macro>
<macro name="contributors-short">
<names variable="author">
<name form="short" and="text" delimiter=", " initialize-with=". "/>
<substitute>
<names variable="editor"/>
<names variable="translator"/>
<names variable="director"/>
<text macro="substitute-title"/>
<text macro="title"/>
</substitute>
</names>
</macro>
<macro name="interviewer">
<names variable="interviewer" delimiter=", ">
<label form="verb" prefix=" " text-case="capitalize-first" suffix=" "/>
<name and="text" delimiter=", "/>
</names>
</macro>
<macro name="archive">
<group delimiter=". ">
<text variable="archive_location" text-case="capitalize-first"/>
<text variable="archive"/>
<text variable="archive-place"/>
</group>
</macro>
<macro name="access">
<group delimiter=". ">
<choose>
<if type="graphic report" match="any">
<text macro="archive"/>
</if>
<else-if type="article-journal bill book chapter legal_case legislation motion_picture paper-conference" match="none">
<text macro="archive"/>
</else-if>
</choose>
<choose>
<if type="webpage post-weblog" match="any">
<date variable="issued" form="text"/>
</if>
</choose>
<choose>
<if variable="issued" match="none">
<group delimiter=" ">
<text term="accessed" text-case="capitalize-first"/>
<date variable="accessed" form="text"/>
</group>
</if>
</choose>
<choose>
<if type="legal_case" match="none">
<choose>
<if variable="DOI">
<text variable="DOI" prefix="https://doi.org/"/>
</if>
<else>
<text variable="URL"/>
</else>
</choose>
</if>
</choose>
</group>
</macro>
<macro name="title">
<choose>
<if variable="title" match="none">
<choose>
<if type="personal_communication" match="none">
<text variable="genre" text-case="capitalize-first"/>
</if>
</choose>
</if>
<else-if type="bill book graphic legislation motion_picture song" match="any">
<text variable="title" text-case="title" font-style="italic"/>
<group prefix=" (" suffix=")" delimiter=" ">
<text term="version"/>
<text variable="version"/>
</group>
</else-if>
<else-if variable="reviewed-author">
<choose>
<if variable="reviewed-title">
<group delimiter=". ">
<text variable="title" text-case="title" quotes="true"/>
<group delimiter=", ">
<text variable="reviewed-title" text-case="title" font-style="italic" prefix="Review of "/>
<names variable="reviewed-author">
<label form="verb-short" text-case="lowercase" suffix=" "/>
<name and="text" delimiter=", "/>
</names>
</group>
</group>
</if>
<else>
<group delimiter=", ">
<text variable="title" text-case="title" font-style="italic" prefix="Review of "/>
<names variable="reviewed-author">
<label form="verb-short" text-case="lowercase" suffix=" "/>
<name and="text" delimiter=", "/>
</names>
</group>
</else>
</choose>
</else-if>
<else-if type="legal_case interview patent" match="any">
<text variable="title"/>
</else-if>
<else>
<text variable="title" text-case="title" quotes="true"/>
</else>
</choose>
</macro>
<macro name="edition">
<choose>
<if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<choose>
<if is-numeric="edition">
<group delimiter=" " prefix=". ">
<number variable="edition" form="ordinal"/>
<text term="edition" form="short" strip-periods="true"/>
</group>
</if>
<else>
<text variable="edition" text-case="capitalize-first" prefix=". "/>
</else>
</choose>
</if>
<else-if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
<choose>
<if is-numeric="edition">
<group delimiter=" " prefix=", ">
<number variable="edition" form="ordinal"/>
<text term="edition" form="short"/>
</group>
</if>
<else>
<text variable="edition" prefix=", "/>
</else>
</choose>
</else-if>
</choose>
</macro>
<macro name="locators">
<choose>
<if type="article-journal">
<choose>
<if variable="volume">
<text variable="volume" prefix=" "/>
<group prefix=" (" suffix=")">
<choose>
<if variable="issue">
<text variable="issue"/>
</if>
<else>
<date variable="issued">
<date-part name="month"/>
</date>
</else>
</choose>
</group>
</if>
<else-if variable="issue">
<group delimiter=" " prefix=", ">
<text term="issue" form="short"/>
<text variable="issue"/>
<date variable="issued" prefix="(" suffix=")">
<date-part name="month"/>
</date>
</group>
</else-if>
<else>
<date variable="issued" prefix=", ">
<date-part name="month"/>
</date>
</else>
</choose>
</if>
<else-if type="legal_case">
<text variable="volume" prefix=", "/>
<text variable="container-title" prefix=" "/>
<text variable="page" prefix=" "/>
</else-if>
<else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<group prefix=". " delimiter=". ">
<group>
<text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
<number variable="volume" form="numeric"/>
</group>
<group>
<number variable="number-of-volumes" form="numeric"/>
<text term="volume" form="short" prefix=" " plural="true"/>
</group>
</group>
</else-if>
<else-if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
<choose>
<if variable="page" match="none">
<group prefix=". ">
<text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
<number variable="volume" form="numeric"/>
</group>
</if>
</choose>
</else-if>
</choose>
</macro>
<macro name="locators-chapter">
<choose>
<if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
<choose>
<if variable="page">
<group prefix=", ">
<text variable="volume" suffix=":"/>
<text variable="page"/>
</group>
</if>
</choose>
</if>
</choose>
</macro>
<macro name="locators-article">
<choose>
<if type="article-newspaper">
<group prefix=", " delimiter=", ">
<group delimiter=" ">
<text variable="edition"/>
<text term="edition"/>
</group>
<group>
<text term="section" form="short" suffix=" "/>
<text variable="section"/>
</group>
</group>
</if>
<else-if type="article-journal">
<choose>
<if variable="volume issue" match="any">
<text variable="page" prefix=": "/>
</if>
<else>
<text variable="page" prefix=", "/>
</else>
</choose>
</else-if>
</choose>
</macro>
<macro name="point-locators">
<choose>
<if variable="locator">
<choose>
<if locator="page" match="none">
<choose>
<if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<choose>
<if variable="volume">
<group>
<text term="volume" form="short" suffix=" "/>
<number variable="volume" form="numeric"/>
<label variable="locator" form="short" prefix=", " suffix=" "/>
</group>
</if>
<else>
<label variable="locator" form="short" suffix=" "/>
</else>
</choose>
</if>
<else>
<label variable="locator" form="short" suffix=" "/>
</else>
</choose>
</if>
<else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<number variable="volume" form="numeric" suffix=":"/>
</else-if>
</choose>
<text variable="locator"/>
</if>
</choose>
</macro>
<macro name="container-prefix">
<text term="in" text-case="capitalize-first"/>
</macro>
<macro name="container-title">
<choose>
<if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
<text macro="container-prefix" suffix=" "/>
</if>
</choose>
<choose>
<if type="webpage">
<text variable="container-title" text-case="title"/>
</if>
<else-if type="legal_case" match="none">
<group delimiter=" ">
<text variable="container-title" text-case="title" font-style="italic"/>
<choose>
<if type="post-weblog">
<text value="(blog)"/>
</if>
</choose>
</group>
</else-if>
</choose>
</macro>
<macro name="publisher">
<group delimiter=": ">
<text variable="publisher-place"/>
<text variable="publisher"/>
</group>
</macro>
<macro name="date">
<choose>
<if variable="issued">
<group delimiter=" ">
<date variable="original-date" form="text" date-parts="year" prefix="(" suffix=")"/>
<date variable="issued">
<date-part name="year"/>
</date>
</group>
</if>
<else-if variable="status">
<text variable="status" text-case="capitalize-first"/>
</else-if>
<else>
<text term="no date" form="short"/>
</else>
</choose>
</macro>
<macro name="date-in-text">
<choose>
<if variable="issued">
<group delimiter=" ">
<date variable="original-date" form="text" date-parts="year" prefix="[" suffix="]"/>
<date variable="issued">
<date-part name="year"/>
</date>
</group>
</if>
<else-if variable="status">
<text variable="status"/>
</else-if>
<else>
<text term="no date" form="short"/>
</else>
</choose>
</macro>
<macro name="day-month">
<date variable="issued">
<date-part name="month"/>
<date-part name="day" prefix=" "/>
</date>
</macro>
<macro name="collection-title">
<choose>
<if match="none" type="article-journal">
<choose>
<if match="none" is-numeric="collection-number">
<group delimiter=", ">
<text variable="collection-title" text-case="title"/>
<text variable="collection-number"/>
</group>
</if>
<else>
<group delimiter=" ">
<text variable="collection-title" text-case="title"/>
<text variable="collection-number"/>
</group>
</else>
</choose>
</if>
</choose>
</macro>
<macro name="collection-title-journal">
<choose>
<if type="article-journal">
<group delimiter=" ">
<text variable="collection-title"/>
<text variable="collection-number"/>
</group>
</if>
</choose>
</macro>
<macro name="event">
<group delimiter=" ">
<choose>
<if variable="genre">
<text term="presented at"/>
</if>
<else>
<text term="presented at" text-case="capitalize-first"/>
</else>
</choose>
<text variable="event"/>
</group>
</macro>
<macro name="description">
<choose>
<if type="interview">
<group delimiter=". ">
<text macro="interviewer"/>
<text variable="medium" text-case="capitalize-first"/>
</group>
</if>
<else-if type="patent">
<group delimiter=" " prefix=". ">
<text variable="authority"/>
<text variable="number"/>
</group>
</else-if>
<else>
<text variable="medium" text-case="capitalize-first" prefix=". "/>
</else>
</choose>
<choose>
<if variable="title" match="none"/>
<else-if type="thesis personal_communication speech" match="any"/>
<else>
<group delimiter=" " prefix=". ">
<text variable="genre" text-case="capitalize-first"/>
<choose>
<if type="report">
<text variable="number"/>
</if>
</choose>
</group>
</else>
</choose>
</macro>
<macro name="issue">
<choose>
<if type="legal_case">
<text variable="authority" prefix=". "/>
</if>
<else-if type="speech">
<group prefix=". " delimiter=", ">
<group delimiter=" ">
<text variable="genre" text-case="capitalize-first"/>
<text macro="event"/>
</group>
<text variable="event-place"/>
<text macro="day-month"/>
</group>
</else-if>
<else-if type="article-newspaper article-magazine personal_communication" match="any">
<date variable="issued" form="text" prefix=", "/>
</else-if>
<else-if type="patent">
<group delimiter=", " prefix=", ">
<group delimiter=" ">
<!--Needs Localization-->
<text value="filed"/>
<date variable="submitted" form="text"/>
</group>
<group delimiter=" ">
<choose>
<if variable="issued submitted" match="all">
<text term="and"/>
</if>
</choose>
<!--Needs Localization-->
<text value="issued"/>
<date variable="issued" form="text"/>
</group>
</group>
</else-if>
<else-if type="article-journal" match="any"/>
<else>
<group prefix=". " delimiter=", ">
<choose>
<if type="thesis">
<text variable="genre" text-case="capitalize-first"/>
</if>
</choose>
<text macro="publisher"/>
</group>
</else>
</choose>
</macro>
<citation et-al-min="4" et-al-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" givenname-disambiguation-rule="primary-name" collapse="year" after-collapse-delimiter="; ">
<layout prefix="(" suffix=")" delimiter="; ">
<group delimiter=", ">
<choose>
<if variable="issued accessed" match="any">
<group delimiter=" ">
<text macro="contributors-short"/>
<text macro="date-in-text"/>
</group>
</if>
<!---comma before forthcoming and n.d.-->
<else>
<group delimiter=", ">
<text macro="contributors-short"/>
<text macro="date-in-text"/>
</group>
</else>
</choose>
<text macro="point-locators"/>
</group>
</layout>
</citation>
<bibliography hanging-indent="true" et-al-min="11" et-al-use-first="7" subsequent-author-substitute="&#8212;&#8212;&#8212;" entry-spacing="0">
<sort>
<key macro="contributors"/>
<key variable="issued"/>
<key variable="title"/>
</sort>
<layout suffix=".">
<group delimiter=". ">
<text macro="contributors"/>
<text macro="date"/>
<text macro="title"/>
</group>
<text macro="description"/>
<text macro="secondary-contributors" prefix=". "/>
<text macro="container-title" prefix=". "/>
<text macro="container-contributors"/>
<text macro="edition"/>
<text macro="locators-chapter"/>
<text macro="collection-title-journal" prefix=", " suffix=", "/>
<text macro="locators"/>
<text macro="collection-title" prefix=". "/>
<text macro="issue"/>
<text macro="locators-article"/>
<text macro="access" prefix=". "/>
</layout>
</bibliography>
</style>

18
template/index.html Normal file
View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
{{ head }}
<body>
<div id="frame">
{{ header }}
{{ cases }}
<div id="content">
{{ description }}
{{ upcoming }}
{{ previous }}
{{ reading }}
{{ misc }}
</div>
{{ footer }}
</div>
</body>
</html>

View File

@ -0,0 +1,47 @@
<div id="cases">
<div class="case">
<div class="title">
<entry>mathematics</entry>
<phone>| ˌmaθ(ə)ˈmatɪks |</phone>
</div>
<div class="definition">
<div class="qual">
<genre>plural noun</genre>
<extra>[usually treated as singular]</extra>
</div>
<div class="def">
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): <ex>a taste for mathematics.</ex>
<div class="example">
<li> <extra>[often treated as plural]</extra> the mathematical aspects of something: <ex>James immerses himself in the mathematics of baseball.</ex></li>
</div>
</div>
</div>
<div class="origin">
<or>origin</or>
<div class="def">
mid 16th century: plural of obsolete <xe>mathematic</xe> mathematics, from Old French <xe>mathematique</xe>, from Latin <xe>(ars) mathematica mathematical (art)</xe>, from Greek <xe>mathēmatikē (epistēmē)</xe>, from the base of <xe>manthanein learn</xe>.
</div>
</div>
</div>
<div class="case">
<div class="title">
<entry>artifice</entry>
<phone>| ˈɑːtɪfɪs |</phone>
</div>
<div class="definition">
<div class="qual">
<genre>noun</genre>
<extra>[mass noun]</extra>
</div>
<div class="def">
clever or cunning devices or expedients, especially as used to trick or deceive others: <ex>an industry dominated by artifice</ex> | <extra>[count noun] : </extra> <ex>the style is not free from the artifices of the period.</ex>
</div>
</div>
<div class="origin">
<or>origin</or>
<div class="def">
early 16th century (in the sense workmanship): from Anglo-Norman French, from Latin <xe>artificium</xe>, based on <xe>ars</xe>, <xe>art- art</xe> + <xe>facere</xe> make. Late Middle English has the form <xe>artificie</xe>, directly from Latin.
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,3 @@
<div id="description">
{{ desc }}
</div>

View File

@ -0,0 +1,3 @@
<div id="footer">
<img src="{{ footer_img }}"/>
</div>

View File

@ -0,0 +1,6 @@
<head>
<meta charset="utf-8">
{% for item in css_items %}<link rel="stylesheet" type="text/css" href="{{ item }}">{% endfor %}
{% for item in js_items %}<script type="module" src="{{ item }}"></script>{% endfor %}
<title>{{ title }}</title>
</head>

View File

@ -0,0 +1,3 @@
<div id="header">
<ma>{{ title }}</ma>
</div>

View File

@ -0,0 +1,13 @@
<div id="{{ section_id }}" class="section">
<div class="section_header">
<h2>{{ section_title }}</h2>
</div>
<div class="list">
{% for item in section_items %}
<details>
<summary>{{ item.summary }}</summary>
{{ item.detail }}
</details>
{% endfor %}
</div>
</div>

47
utils.py Normal file
View File

@ -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