16 Commits

9 changed files with 267 additions and 189 deletions

View File

@@ -104,6 +104,12 @@ mjx-container {
p.metadata { margin: 0 } p.metadata { margin: 0 }
.blog_inline_post {
border-left: 1em solid var(--fg-lc);
padding: 0 1em 0 1em;
margin-bottom: 5em;
}
@media (max-width: 80em) { @media (max-width: 80em) {
/* CSS that should be displayed if width is equal to or less than 60em goes here */ /* CSS that should be displayed if width is equal to or less than 60em goes here */
#contentWrapper { flex-direction: column } #contentWrapper { flex-direction: column }

412
gronk.py
View File

@@ -13,7 +13,8 @@ import copy
import time import time
import magic import magic
import regex as re import regex as re
import pprint from datetime import datetime as dt
import json
import frontmatter import frontmatter
import jinja2 import jinja2
@@ -25,12 +26,12 @@ PANDOC_SERVER_URL = os.getenv("PANDOC_SERVER_URL", r"http://localhost:3030/")
PANDOC_TIMEOUT = int(os.getenv("PANDOC_TIMEOUT", "120")) PANDOC_TIMEOUT = int(os.getenv("PANDOC_TIMEOUT", "120"))
GRONK_CSS_DIR = Path(os.getenv("GRONK_CSS_DIR", "/opt/gronk/css")) GRONK_CSS_DIR = Path(os.getenv("GRONK_CSS_DIR", "/opt/gronk/css"))
GRONK_JS_DIR = Path(os.getenv("GRONK_JS_DIR", "/opt/gronk/js")) GRONK_JS_DIR = Path(os.getenv("GRONK_JS_DIR", "/opt/gronk/js"))
GRONK_TEMPLATES_DIR = Path( GRONK_TEMPLATES_DIR = Path(os.getenv("GRONK_TEMPLATES_DIR", "/opt/gronk/templates/"))
os.getenv("GRONK_TEMPLATES_DIR", "/opt/gronk/templates/"))
JINJA_ENV = jinja2.Environment( JINJA_ENV = jinja2.Environment(
loader=jinja2.FileSystemLoader(searchpath=GRONK_TEMPLATES_DIR), loader=jinja2.FileSystemLoader(searchpath=GRONK_TEMPLATES_DIR),
autoescape=jinja2.select_autoescape) autoescape=jinja2.select_autoescape,
)
JINJA_TEMPLATE_TEXTARTICLE = JINJA_ENV.get_template("article-text.html") JINJA_TEMPLATE_TEXTARTICLE = JINJA_ENV.get_template("article-text.html")
JINJA_TEMPLATE_HOME_INDEX = JINJA_ENV.get_template("home.html") JINJA_TEMPLATE_HOME_INDEX = JINJA_ENV.get_template("home.html")
@@ -58,9 +59,8 @@ class FileMap:
self.output_dir = Path(output_dir) self.output_dir = Path(output_dir)
def get_base_url(self): def get_base_url(self):
props = self.get(self.input_dir.joinpath('readme.md')) props = self.get(self.input_dir.joinpath("readme.md"))
print(props) return props["base_url"]
return props['base_url']
@staticmethod @staticmethod
def _path_to_key(path): def _path_to_key(path):
@@ -68,8 +68,9 @@ class FileMap:
@staticmethod @staticmethod
def is_plaintext(filename): def is_plaintext(filename):
return re.match(r'^text/', magic.from_file(str(filename), return (
mime=True)) is not None re.match(r"^text/", magic.from_file(str(filename), mime=True)) is not None
)
def add(self, filepath): def add(self, filepath):
filepath = Path(filepath) filepath = Path(filepath)
@@ -78,8 +79,8 @@ class FileMap:
else: else:
properties = self._get_file_properties(filepath) properties = self._get_file_properties(filepath)
properties['src_path'] = filepath properties["src_path"] = filepath
properties['dst_path'] = self._get_output_filepath(filepath) properties["dst_path"] = self._get_output_filepath(filepath)
self._map[self._path_to_key(filepath)] = properties self._map[self._path_to_key(filepath)] = properties
@@ -93,8 +94,7 @@ class FileMap:
if self._path_to_key(filepath) not in self._map.keys(): if self._path_to_key(filepath) not in self._map.keys():
self.add(filepath) self.add(filepath)
properties = copy.deepcopy( properties = copy.deepcopy(self._map.get(self._path_to_key(filepath), default))
self._map.get(self._path_to_key(filepath), default))
if raw: if raw:
return properties return properties
@@ -102,49 +102,46 @@ class FileMap:
parent = filepath parent = filepath
while True: while True:
parent = parent.parent parent = parent.parent
if parent == Path('.'): if parent == Path("."):
break break
parent_properties = self.get(parent, raw=True) parent_properties = self.get(parent, raw=True)
# TODO inherit any property that isn't defined, append any lists # TODO inherit any property that isn't defined, append any lists
# that exist # that exist
properties['tags'] = properties.get( properties["tags"] = properties.get("tags", []) + parent_properties.get(
'tags', []) + parent_properties.get('tags', []) "tags", []
)
if parent == self.input_dir: if parent == self.input_dir:
break break
return properties return properties
def _get_directory_properties(self, def _get_directory_properties(self, filepath: Path, include_index_entries=True):
filepath: Path,
include_index_entries=True):
post = { post = {
'title': filepath.name, "title": filepath.name,
'blog': False, "blog": False,
'content_after_search': None, "content_after_search": None,
'automatic_index': True, "automatic_index": True,
'search_bar': True, "search_bar": True,
'tags': [], "tags": [],
} }
if 'readme.md' in [f.name for f in filepath.iterdir()]: if "readme.md" in [f.name for f in filepath.iterdir()]:
with open(filepath.joinpath('readme.md'), with open(filepath.joinpath("readme.md"), encoding="utf-8") as file_pointer:
encoding='utf-8') as file_pointer: for key, val in frontmatter.load(file_pointer).to_dict().items():
for key, val in frontmatter.load(
file_pointer).to_dict().items():
post[key] = val post[key] = val
if post['content_after_search'] is None: if post["content_after_search"] is None:
post['content_after_search'] = post['blog'] post["content_after_search"] = post["blog"]
if 'content' in post.keys(): if "content" in post.keys():
post['content'] = render_markdown(post['content']) post["content"] = render_markdown(post["content"])
post['is_dir'] = True post["is_dir"] = True
if include_index_entries: if include_index_entries:
post['index_entries'] = self._get_index_entries(filepath) post["index_entries"] = self._get_index_entries(filepath)
return post return post
@@ -152,69 +149,67 @@ class FileMap:
entries = [] entries = []
for path in filepath.iterdir(): for path in filepath.iterdir():
if '.git' in path.parts: if ".git" in path.parts:
continue continue
if 'readme.md' == path.name: if "readme.md" == path.name:
continue continue
if path.is_dir(): if path.is_dir():
entry = self._get_directory_properties( entry = self._get_directory_properties(
path, include_index_entries=False) path, include_index_entries=False
)
else: else:
entry = self._get_file_properties(path) entry = self._get_file_properties(path)
entry['path'] = self._get_output_filepath(path)['web'] entry["path"] = self._get_output_filepath(path)["web"]
entries.append(entry) entries.append(entry)
entries.sort(key=lambda entry: str(entry.get('title', '')).lower()) entries.sort(key=lambda entry: str(entry.get("title", "")).lower())
entries.sort(key=lambda entry: entry['is_dir'], reverse=True) entries.sort(key=lambda entry: entry["is_dir"], reverse=True)
return entries return entries
def _get_file_properties(self, filepath): def _get_file_properties(self, filepath):
post = {'title': filepath.name, 'pub_date': False} post = {"title": filepath.name, "pub_date": False}
if filepath.suffix == '.md': if filepath.suffix == ".md":
with open(filepath, encoding='utf-8') as file_pointer: with open(filepath, encoding="utf-8") as file_pointer:
post = frontmatter.load(file_pointer).to_dict() post = frontmatter.load(file_pointer).to_dict()
# don't store file contents in memory # don't store file contents in memory
if 'content' in post.keys(): if "content" in post.keys():
del post['content'] del post["content"]
post['is_dir'] = False post["is_dir"] = False
return post return post
def _get_output_filepath(self, input_filepath): def _get_output_filepath(self, input_filepath):
def webpath(filepath): def webpath(filepath):
return Path('/notes').joinpath( return Path("/notes").joinpath(filepath.relative_to(self.output_dir))
filepath.relative_to(self.output_dir))
r = {} r = {}
r['raw'] = self.output_dir.joinpath( r["raw"] = self.output_dir.joinpath(input_filepath.relative_to(self.input_dir))
input_filepath.relative_to(self.input_dir)) r["web"] = webpath(r["raw"])
r['web'] = webpath(r['raw'])
if input_filepath.is_dir(): if input_filepath.is_dir():
return r return r
if input_filepath.suffix == '.md': if input_filepath.suffix == ".md":
r['html'] = self.output_dir.joinpath( r["html"] = self.output_dir.joinpath(
input_filepath.relative_to( input_filepath.relative_to(self.input_dir)
self.input_dir)).with_suffix('.html') ).with_suffix(".html")
r['web'] = webpath(r['html']) r["web"] = webpath(r["html"])
elif self.is_plaintext(input_filepath): elif self.is_plaintext(input_filepath):
r['html'] = self.output_dir.joinpath( r["html"] = self.output_dir.joinpath(
input_filepath.relative_to( input_filepath.relative_to(self.input_dir)
self.input_dir)).with_suffix(input_filepath.suffix + ).with_suffix(input_filepath.suffix + ".html")
'.html') r["raw"] = self.output_dir.joinpath(
r['raw'] = self.output_dir.joinpath( input_filepath.relative_to(self.input_dir)
input_filepath.relative_to(self.input_dir)) )
r['web'] = webpath(r['html']) r["web"] = webpath(r["html"])
r['web_raw'] = webpath(r['raw']) r["web_raw"] = webpath(r["raw"])
return r return r
@@ -227,55 +222,78 @@ class FileMap:
""" """
r = [] r = []
for _, val in self._map.items(): for _, val in self._map.items():
r.append({ if val["src_path"].name == "readme.md":
'title': val.get('title', ''), continue
'tags': val.get('tags', []),
'path': str(val['dst_path']['web']), r.append(
'is_dir': val['is_dir'] {
}) "title": val.get("title", ""),
"tags": val.get("tags", []),
"path": str(val["dst_path"]["web"]),
"is_dir": val["is_dir"],
}
)
return r return r
def get_uuid_map(self): def get_uuid_map(self):
d = {} d = {}
for _, val in self._map.items(): for _, val in self._map.items():
if 'uuid' not in val.keys(): if "uuid" not in val.keys():
continue continue
d[val['uuid']] = str(val['dst_path']['web'])
if val["uuid"] in d.keys():
if not val["is_dir"]:
# only allow directories to overwrite conflicting UUIDs
# ensures that a readme's folder gets the permalink
continue
d[val["uuid"]] = str(val["dst_path"]["web"])
return d return d
def rfc822_date_sorter_key(date):
if date is None:
ret = 0
else:
ret = int(dt.strptime(date, "%a, %d %b %Y %H:%M:%S %z").timestamp())
return ret
def update_required(src_filepath, output_filepath): def update_required(src_filepath, output_filepath):
""" """
check if file requires an update, check if file requires an update,
return boolean return boolean
""" """
return not output_filepath.exists() or src_filepath.stat( return (
).st_mtime > output_filepath.stat().st_mtimeme() not output_filepath.exists()
or src_filepath.stat().st_mtime > output_filepath.stat().st_mtimeme()
)
def get_args(): def get_args():
""" Get command line arguments """ """Get command line arguments"""
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('notes', type=Path) parser.add_argument("notes", type=Path)
parser.add_argument('-o', '--output-dir', type=Path, default='web') parser.add_argument("-o", "--output-dir", type=Path, default="web")
parser.add_argument( parser.add_argument(
'-F', "-F",
'--force', "--force",
action="store_true", action="store_true",
help= help="Generate new output html even if source file was modified before output html",
"Generate new output html even if source file was modified before output html"
) )
return parser.parse_args() return parser.parse_args()
def render_inline_blog_post(input_filepath): def render_inline_blog_post(input_filepath):
""" """
render markdown file as blog post for inlinining into blog index render markdown file as blog post for inlinining into blog index
returns html returns html
""" """
with open(input_filepath, encoding='utf-8') as file_pointer: with open(input_filepath, encoding="utf-8") as file_pointer:
content = frontmatter.load(file_pointer).content content = frontmatter.load(file_pointer).content
properties = FILEMAP.get(input_filepath) properties = FILEMAP.get(input_filepath)
@@ -294,7 +312,7 @@ def render_inline_blog_post(input_filepath):
base_url=FILEMAP.get_base_url(), base_url=FILEMAP.get_base_url(),
) )
properties['dst_path']['html'].write_text(html) properties["dst_path"]["html"].write_text(html)
return html return html
@@ -305,7 +323,7 @@ def render_markdown_file(input_filepath):
write markdown file to args.output_dir in html, write markdown file to args.output_dir in html,
return list of tuple of output filepath, frontmatter post return list of tuple of output filepath, frontmatter post
""" """
with open(input_filepath, encoding='utf-8') as file_pointer: with open(input_filepath, encoding="utf-8") as file_pointer:
content = frontmatter.load(file_pointer).content content = frontmatter.load(file_pointer).content
properties = FILEMAP.get(input_filepath) properties = FILEMAP.get(input_filepath)
@@ -320,10 +338,10 @@ def render_markdown_file(input_filepath):
tags=properties.get("tags"), tags=properties.get("tags"),
author=properties.get("author"), author=properties.get("author"),
title=properties.get("title"), title=properties.get("title"),
published=properties.get("pub_date") published=properties.get("pub_date"),
) )
properties['dst_path']['html'].write_text(html) properties["dst_path"]["html"].write_text(html)
def render_plaintext_file(input_filepath): def render_plaintext_file(input_filepath):
@@ -338,10 +356,11 @@ def render_plaintext_file(input_filepath):
html = JINJA_TEMPLATE_TEXTARTICLE.render( html = JINJA_TEMPLATE_TEXTARTICLE.render(
license=LICENSE, license=LICENSE,
**properties, **properties,
raw_link=properties['dst_path']['web_raw'], raw_link=properties["dst_path"]["web_raw"],
raw_content=raw_content) raw_content=raw_content,
properties['dst_path']['raw'].write_text(raw_content) )
properties['dst_path']['html'].write_text(html) properties["dst_path"]["raw"].write_text(raw_content)
properties["dst_path"]["html"].write_text(html)
def render_generic_file(input_filepath): def render_generic_file(input_filepath):
@@ -351,7 +370,7 @@ def render_generic_file(input_filepath):
return list of tuple of output filepath, empty dict return list of tuple of output filepath, empty dict
""" """
properties = FILEMAP.get(input_filepath) properties = FILEMAP.get(input_filepath)
output_filepath = properties['dst_path']['raw'] output_filepath = properties["dst_path"]["raw"]
shutil.copyfile(input_filepath, output_filepath) shutil.copyfile(input_filepath, output_filepath)
@@ -362,7 +381,7 @@ def render_file(input_filepath):
return list of tuples of output filepath, frontmatter post return list of tuples of output filepath, frontmatter post
""" """
if input_filepath.suffix == '.md': if input_filepath.suffix == ".md":
return render_markdown_file(input_filepath) return render_markdown_file(input_filepath)
if FileMap.is_plaintext(input_filepath): if FileMap.is_plaintext(input_filepath):
@@ -377,30 +396,29 @@ def render_markdown(content):
""" """
post_body = { post_body = {
'text': content, "text": content,
'toc-depth': 6, "toc-depth": 6,
'highlight-style': 'pygments', "highlight-style": "pygments",
'html-math-method': 'mathml', "html-math-method": "mathml",
'to': 'html', "to": "html",
'files': { "files": {
'data/data/abbreviations': '', "data/data/abbreviations": "",
}, },
'standalone': False, "standalone": False,
} }
headers = {'Accept': 'application/json'} headers = {"Accept": "application/json"}
response = requests.post(PANDOC_SERVER_URL, response = requests.post(
headers=headers, PANDOC_SERVER_URL, headers=headers, json=post_body, timeout=PANDOC_TIMEOUT
json=post_body, )
timeout=PANDOC_TIMEOUT)
response = response.json() response = response.json()
# TODO look at response['messages'] and log them maybe? # TODO look at response['messages'] and log them maybe?
# https://github.com/jgm/pandoc/blob/main/doc/pandoc-server.md#response # https://github.com/jgm/pandoc/blob/main/doc/pandoc-server.md#response
return response['output'] return response["output"]
def process_home_index(args, notes_git_head_sha1=None): def process_home_index(args, notes_git_head_sha1=None):
@@ -408,22 +426,23 @@ def process_home_index(args, notes_git_head_sha1=None):
create home index.html in output_dir create home index.html in output_dir
""" """
post = {'title': 'gronk', 'content': ''} post = {"title": "gronk", "content": ""}
custom_content_file = args.notes.joinpath('readme.md') custom_content_file = args.notes.joinpath("readme.md")
if custom_content_file.is_file(): if custom_content_file.is_file():
fmpost = frontmatter.loads(custom_content_file.read_text()).to_dict() fmpost = frontmatter.loads(custom_content_file.read_text()).to_dict()
for key, val in fmpost.items(): for key, val in fmpost.items():
post[key] = val post[key] = val
post['content'] = render_markdown(post['content']) post["content"] = render_markdown(post["content"])
html = JINJA_TEMPLATE_HOME_INDEX.render( html = JINJA_TEMPLATE_HOME_INDEX.render(
gronk_commit=GRONK_COMMIT, gronk_commit=GRONK_COMMIT,
search_data=FILEMAP.to_search_data(), search_data=FILEMAP.to_search_data(),
notes_git_head_sha1=notes_git_head_sha1, notes_git_head_sha1=notes_git_head_sha1,
post=post) post=post,
)
args.output_dir.joinpath('index.html').write_text(html) args.output_dir.joinpath("index.html").write_text(html)
def generate_permalink_page(output_dir): def generate_permalink_page(output_dir):
@@ -431,11 +450,15 @@ def generate_permalink_page(output_dir):
create the directory and index.html for redirecting permalinks create the directory and index.html for redirecting permalinks
""" """
dir = output_dir.joinpath('permalink') dir = output_dir.joinpath("permalink")
dir.mkdir(exist_ok=True) dir.mkdir(exist_ok=True)
dir.joinpath('index.html').write_text( dir.joinpath("index.html").write_text(
JINJA_TEMPLATE_PERMALINK.render(gronk_commit=GRONK_COMMIT, JINJA_TEMPLATE_PERMALINK.render(
data=FILEMAP.get_uuid_map())) title="redirecting... | gronk",
gronk_commit=GRONK_COMMIT,
data=FILEMAP.get_uuid_map(),
)
)
def generate_tag_browser(output_dir): def generate_tag_browser(output_dir):
@@ -445,19 +468,19 @@ def generate_tag_browser(output_dir):
tags = {} tags = {}
for post in FILEMAP.to_list(): for post in FILEMAP.to_list():
post['path'] = post['dst_path']['web'] post["path"] = post["dst_path"]["web"]
if 'tags' not in post.keys(): if "tags" not in post.keys():
continue continue
for tag in post['tags']: for tag in post["tags"]:
if tag not in tags.keys(): if tag not in tags.keys():
tags[tag] = [] tags[tag] = []
tags[tag].append(post) tags[tag].append(post)
for tag, index_entries in tags.items(): for tag, index_entries in tags.items():
output_file = output_dir.joinpath(tag, 'index.html') output_file = output_dir.joinpath(tag, "index.html")
output_file.parent.mkdir(exist_ok=True, parents=True) output_file.parent.mkdir(exist_ok=True, parents=True)
output_file.write_text( output_file.write_text(
JINJA_TEMPLATE_INDEX.render( JINJA_TEMPLATE_INDEX.render(
@@ -465,36 +488,47 @@ def generate_tag_browser(output_dir):
automatic_index=True, automatic_index=True,
search_bar=True, search_bar=True,
title=tag, title=tag,
index_entries=[{ index_entries=[
'title': entry.get('title', ''), {
'is_dir': entry.get('is_dir', False), "title": entry.get("title", ""),
'path': str(entry.get('path', Path(''))), "is_dir": entry.get("is_dir", False),
} for entry in index_entries], "path": str(entry.get("path", Path(""))),
)) }
for entry in index_entries
if entry.get("src_path").name != "readme.md"
],
)
)
output_file = output_dir.joinpath('index.html') output_file = output_dir.joinpath("index.html")
output_file.parent.mkdir(exist_ok=True, parents=True) output_file.parent.mkdir(exist_ok=True, parents=True)
output_file.write_text( output_file.write_text(
JINJA_TEMPLATE_INDEX.render(automatic_index=True, JINJA_TEMPLATE_INDEX.render(
gronk_commit=GRONK_COMMIT, automatic_index=True,
search_bar=True, gronk_commit=GRONK_COMMIT,
title='tags', search_bar=True,
index_entries=[{ title="tags",
'path': tag, index_entries=[
'title': tag, {
'is_dir': False, "path": tag,
} for tag in tags.keys()])) "title": tag,
"is_dir": True,
}
for tag in sorted(tags.keys())
],
)
)
def main(args): def main(args):
""" Entry point for script """ """Entry point for script"""
start_time = time.time() start_time = time.time()
global LICENSE global LICENSE
global FILEMAP global FILEMAP
FILEMAP = FileMap(args.notes, args.output_dir.joinpath('notes')) FILEMAP = FileMap(args.notes, args.output_dir.joinpath("notes"))
# TODO have some sort of 'site rebuild in progress - come back in a minute # TODO have some sort of 'site rebuild in progress - come back in a minute
# or two!' or auto checking/refreshing page for when site is being built # or two!' or auto checking/refreshing page for when site is being built
@@ -513,53 +547,65 @@ def main(args):
for root_str, _, files in os.walk(args.notes): for root_str, _, files in os.walk(args.notes):
root = Path(root_str) root = Path(root_str)
if '.git' in root.parts: if ".git" in root.parts:
continue continue
root_properties = FILEMAP.get(root) root_properties = FILEMAP.get(root)
root_properties['dst_path']['raw'].mkdir(parents=True, exist_ok=True) root_properties["dst_path"]["raw"].mkdir(parents=True, exist_ok=True)
posts = [] posts = []
if root_properties['blog']: if root_properties["blog"]:
for file in files: for file in files:
props = FILEMAP.get(root.joinpath(file)) props = FILEMAP.get(root.joinpath(file))
post = { post = {
'title': props['title'], "title": props["title"],
'link': props['dst_path']['web'], "link": props["dst_path"]["web"],
'pub_date': props.get('pub_date'), "pub_date": props.get("pub_date"),
'description': render_inline_blog_post(root.joinpath(file)), "description": render_inline_blog_post(root.joinpath(file)),
} }
posts.append(post) posts.append(post)
#pprint.pprint(root_properties) posts.sort(
# render index key=lambda p: rfc822_date_sorter_key(p.get("pub_date")), reverse=True
html = (JINJA_TEMPLATE_BLOGINDEX if root_properties['blog'] else JINJA_TEMPLATE_INDEX).render( )
gronk_commit=GRONK_COMMIT,
title=root_properties.get('title', ''),
content=root_properties.get('content', ''),
content_after_search=root_properties['content_after_search'],
automatic_index=root_properties['automatic_index'],
search_bar=root_properties['search_bar'],
posts=posts,
index_entries=[{
'title': entry.get('title', ''),
'is_dir': entry.get('is_dir', False),
'path': str(entry.get('path', Path(''))),
} for entry in root_properties.get('index_entries', '')],
)
root_properties['dst_path']['raw'].joinpath('index.html').write_text(html)
# render rss feed if blog # render rss feed
if root_properties['blog']:
rss = JINJA_TEMPLATE_BLOG_FEED.render( rss = JINJA_TEMPLATE_BLOG_FEED.render(
title=root_properties.get('title', ''), title=root_properties.get("title", ""),
description=root_properties.get('content', ''), description=root_properties.get("content", ""),
base_url=FILEMAP.get_base_url(), base_url=FILEMAP.get_base_url(),
link=f"{FILEMAP.get_base_url()}{root_properties['dst_path']['web']}", link=f"{FILEMAP.get_base_url()}{root_properties['dst_path']['web']}",
language='en-GB', language="en-GB",
posts=posts, posts=posts,
) )
root_properties['dst_path']['raw'].joinpath('feed.xml').write_text(rss) root_properties["dst_path"]["raw"].joinpath("feed.xml").write_text(rss)
root_properties["dst_path"]["raw"].joinpath("rss.xml").write_text(rss)
# pprint.pprint(root_properties)
# render index
html = (
JINJA_TEMPLATE_BLOGINDEX
if root_properties["blog"]
else JINJA_TEMPLATE_INDEX
).render(
gronk_commit=GRONK_COMMIT,
title=root_properties.get("title", ""),
content=root_properties.get("content", ""),
content_after_search=root_properties["content_after_search"],
automatic_index=root_properties["automatic_index"],
search_bar=root_properties["search_bar"],
posts=posts,
uuid=root_properties.get("uuid"),
index_entries=[
{
"title": entry.get("title", ""),
"is_dir": entry.get("is_dir", False),
"path": str(entry.get("path", Path(""))),
}
for entry in root_properties.get("index_entries", "")
],
)
root_properties["dst_path"]["raw"].joinpath("index.html").write_text(html)
# render each file # render each file
for file in files: for file in files:
@@ -568,19 +614,24 @@ def main(args):
process_home_index(args) process_home_index(args)
# copy styling and js scripts necessary for function # copy styling and js scripts necessary for function
shutil.copytree(GRONK_CSS_DIR, shutil.copytree(GRONK_CSS_DIR, args.output_dir.joinpath("css"), dirs_exist_ok=True)
args.output_dir.joinpath('css'), shutil.copytree(GRONK_JS_DIR, args.output_dir.joinpath("js"), dirs_exist_ok=True)
dirs_exist_ok=True)
shutil.copytree(GRONK_JS_DIR,
args.output_dir.joinpath('js'),
dirs_exist_ok=True)
generate_tag_browser(args.output_dir.joinpath('tags')) generate_tag_browser(args.output_dir.joinpath("tags"))
generate_permalink_page(args.output_dir) generate_permalink_page(args.output_dir)
elapsed_time = time.time() - start_time elapsed_time = time.time() - start_time
print(f"generated notes {elapsed_time=}") print(f"generated notes {elapsed_time=}")
with open(args.output_dir.joinpath("fart.json"), "w+") as fp:
json.dump(
{
k: {prop: str(propval) for prop, propval in v.items()}
for k, v in FILEMAP._map.items()
},
fp,
)
return 0 return 0
@@ -590,14 +641,13 @@ def start_pandoc_server():
successful and return version as string successful and return version as string
""" """
start_time = time.time() start_time = time.time()
process = subprocess.Popen(["/usr/bin/pandoc-server"], process = subprocess.Popen(["/usr/bin/pandoc-server"], stdout=subprocess.PIPE)
stdout=subprocess.PIPE)
version = None version = None
while True: while True:
try: try:
resp = requests.get(f"{PANDOC_SERVER_URL}/version") resp = requests.get(f"{PANDOC_SERVER_URL}/version")
version = resp.content.decode('utf-8') version = resp.content.decode("utf-8")
break break
except requests.ConnectionError: except requests.ConnectionError:
time.sleep(0.1) time.sleep(0.1)
@@ -614,7 +664,7 @@ def start_pandoc_server():
# TODO implement useful logging and debug printing # TODO implement useful logging and debug printing
if __name__ == '__main__': if __name__ == "__main__":
pandoc_process = start_pandoc_server() pandoc_process = start_pandoc_server()
try: try:

View File

@@ -6,7 +6,7 @@ const TITLE = "title"
const SEARCH_TIMEOUT_MS = 100 const SEARCH_TIMEOUT_MS = 100
var SEARCH_TIMEOUT_ID = -1 var SEARCH_TIMEOUT_ID = -1
const fuse = new Fuse(data, { const fuse = new Fuse(search_data, {
keys: [ 'title' ], keys: [ 'title' ],
ignoreLocation: true, ignoreLocation: true,
threshhold: 0.4, threshhold: 0.4,
@@ -30,7 +30,7 @@ function updateResults() {
console.log("updating results") console.log("updating results")
resultsDiv.innerHTML = '' resultsDiv.innerHTML = ''
if (searchBar.value) results = fuse.search(searchBar.value, { limit: RESULTS_MAX }).map(r => r.item) if (searchBar.value) results = fuse.search(searchBar.value, { limit: RESULTS_MAX }).map(r => r.item)
else results = data else results = search_data
results.forEach(r => { results.forEach(r => {
wrapper = document.createElement('li') wrapper = document.createElement('li')

View File

@@ -74,7 +74,7 @@ gronk reads the following YAML [frontmatter](https://jekyllrb.com/docs/front-mat
| variable | description | | variable | description |
|------------------|---------------------------------------------------------------------------------------| |------------------|---------------------------------------------------------------------------------------|
| `author` | The person(s) who wrote the article | | `author` | The person(s) who wrote the article |
| `pub_date` | set the publish date of an article/post/note | | `pub_date` | (for blog mode) set the publish date of an article/post/note (MUST be RFC822 format) |
| `tags` | A YAML list of tags which the article relates to - this is used for browsing and also | | `tags` | A YAML list of tags which the article relates to - this is used for browsing and also |
| `title` | The title of the article | | `title` | The title of the article |
| `uuid` | A unique identifier used for permalinks. | | `uuid` | A unique identifier used for permalinks. |
@@ -88,6 +88,16 @@ This can be done by setting the `blog` variable to `true` in the `readme.md` [cu
Notes under this directory will be published to a blog, whose feed is accesible at `https://notes.alv.cx/notes/<directory..>/feed.xml`. Notes under this directory will be published to a blog, whose feed is accesible at `https://notes.alv.cx/notes/<directory..>/feed.xml`.
When blog mode is enabled, it is required that the `base_url` property is set in the top level `readme.md` file.
Note that there should be no trailing slash.
If a `readme.md` file does not exist, then an empty one can be created:
```md
---
base_url: https://notes.alv.cx
---
```
## Permalinks ## Permalinks

View File

@@ -53,7 +53,7 @@ written by: [ {% for auth in author %}{{ auth }}{% if loop.nextitem %}, {% endif
colors colors
</p> </p>
<p class="smallText metadata"> <p class="smallText metadata">
page generated by <a href="https://git.alv.cx/alvierahman90/gronk">gronk</a> page rendered by <a href="https://git.alv.cx/alvierahman90/gronk">gronk</a>
</p> </p>
{% if license %} {% if license %}
<details id="license"> <details id="license">

View File

@@ -13,6 +13,6 @@
<div id="content"> <div id="content">
{% block content %} {% block content %}
{% endblock %} {% endblock %}
<p class="smallText"> page generated by <a href="https://github.com/alvierahman90/gronk">gronk</a> <!--(commit {{ gronk_commit }}) {% if notes_git_head_sha1 %}notes commit {{ notes_git_head_sha1 }}{% endif %}--></p> <p class="smallText"> page rendered by <a href="https://github.com/alvierahman90/gronk">gronk</a> <!--(commit {{ gronk_commit }}) {% if notes_git_head_sha1 %}notes commit {{ notes_git_head_sha1 }}{% endif %}--></p>
</div> </div>
</body> </body>

View File

@@ -18,7 +18,7 @@
colors colors
</p> </p>
<p class="smallText metadata"> <p class="smallText metadata">
page generated by <a href="https://git.alv.cx/alvierahman90/gronk">gronk</a> page rendered by <a href="https://git.alv.cx/alvierahman90/gronk">gronk</a>
</p> </p>
<p class="smallText metadata"> <p class="smallText metadata">
<a href="./feed.xml">rss feed</a> <a href="./feed.xml">rss feed</a>
@@ -31,7 +31,10 @@
<pre>{{ license }}</pre> <pre>{{ license }}</pre>
</details> </details>
{% endif %} {% endif %}
{% if not content %}
<h1>{{ title }}</h1> <h1>{{ title }}</h1>
{% endif %}
{% if not content_after_search %} {% if not content_after_search %}
{{ content|safe }} {{ content|safe }}
@@ -44,7 +47,7 @@
{% if automatic_index %} {% if automatic_index %}
<details> <details>
<summary> <summary>
<h2> List of posts </h2> <h4> List of posts </h4>
</summary> </summary>
{% if search_bar %} {% if search_bar %}
<div id="searchWrapper"> <div id="searchWrapper">
@@ -68,7 +71,9 @@
{{ content|safe }} {{ content|safe }}
{% for post in posts %} {% for post in posts %}
<div class="blog_inline_post">
{{ post['description']|safe }} {{ post['description']|safe }}
</div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}

View File

@@ -1,6 +1,12 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
{% if not content %}
<h1>{{ title }}</h1> <h1>{{ title }}</h1>
{% endif %}
{% if uuid %}
<p class="smallText metadata"> uuid: {{ uuid }} (<a href="/permalink?uuid={{ uuid }}">permalink</a>) </p>
{% endif %}
{% if not content_after_search %} {% if not content_after_search %}
{{ content|safe }} {{ content|safe }}

View File

@@ -1,10 +1,11 @@
{% extends "base.html" %}
{% block content %} {% block content %}
<p> <p>
You should be being redirected... You should be being redirected...
Otherwise, click <a id="manual_redirect">here</a>. Otherwise, click <a id="manual_redirect">here</a>.
</p> </p>
<p class="smallText"> page generated by <a href="https://github.com/alvierahman90/gronk">gronk</a></p> <p class="smallText"><a href="https://github.com/alvierahman90/gronk">gronk</a></p>
<script> const data = {{ data|tojson }} </script> <script> const data = {{ data|tojson }} </script>
<script src="/js/permalink.js"> </script> <script src="/js/permalink.js"> </script>
{% endblock %} {% endblock %}