onpoint/slides.py
2025-11-23 12:13:12 +01:00

83 lines
3.0 KiB
Python
Executable File

import os
import pypandoc
import re
root = ""
# Compiles a single slide by splitting it up into single metadata and data
# attributes, loading them into the corresponding template, and returning the
# result.
def compile_slide(slide, root_directory):
global root
root = root_directory
slide = slide.strip()
slide_metadata = get_slide_metadata(slide)
slide_data = get_slide_data(slide)
slide = get_slide_layout(slide_metadata['layout'])
if 'todo' in slide_data.keys():
# TODO: Move the css into a global onpoint.css file
slide = '<aside class="todo" style="position:absolute; z-index:100; display:block; background:rgba(255,0,0,.8); top:0; right:0; max-width:20%; margin:.5em; padding:.5em; border-radius:1em; font-family:sans-serif; font-size: .8em;">@todo</aside>' + slide
for key, value in slide_data.items():
placeholder = '@' + key
filler = convert_slide_content(value)
# very unelegant attempt at inline elements
inline_key = '@' + key + '(inline)'
if inline_key in slide:
filler_without_outer_paragraph = re.sub(r"<p>(.+)</p>", r"\1", filler, flags=re.DOTALL).strip()
slide = slide.replace(
inline_key,
filler_without_outer_paragraph
)
elif '@' + key in slide:
slide = slide.replace(placeholder, filler)
return slide
# Parses the metadata passage of a given slide and returns the metadata as a
# dictionary. For some items, default values are used if the slide does not
# contain them.
def get_slide_metadata(slide):
metadata = { 'layout': 'default' }
metadata_attributes = re.search('^@slide\((.+)\)', slide.splitlines()[0])
if metadata_attributes:
metadata_attributes = metadata_attributes.group(1).split(' ')
for attribute in metadata_attributes:
metadata[attribute.split('=')[0]] = attribute.split('=')[1]
return metadata
# Parses the data part of a given slide and returns dictionary of field names
# and corresponding raw values.
def get_slide_data(slide):
if slide.startswith('@slide'):
slide = slide[slide.find('\n')+1:] # cut off @slide declaration
slide_data = slide.strip().split('\n\n@')
slide_data = { item.split()[0].strip('@') : "\n".join(item.splitlines()[1:]) for item in slide_data }
return slide_data
# Reads the layout file for a given layout name and returns its content as a
# string.
def get_slide_layout(layout_name):
global root
try:
return open(os.path.join(root, 'layouts/' + layout_name + '.html'), 'r', encoding='utf8').read()
except FileNotFoundError:
raise Exception('Layout ' + layout_name + ' not found!')
# Calls the pandoc converter to convert a given Markdown string to HTML.
# Returns an HTML string.
def convert_slide_content(content):
filters = []
pdoc_args = [
'--mathjax' # Preparing formulas
]
return pypandoc.convert_text(
content, 'html',
format='md',
extra_args=pdoc_args,
filters=filters)