diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d680206 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.sif +*.tar diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index ce37dd6..0000000 --- a/.gitmodules +++ /dev/null @@ -1,12 +0,0 @@ -[submodule "markdeep"] - path = markdeep-slides/markdeep - url = https://github.com/morgan3d/markdeep.git -[submodule "remark-cicero/cicero"] - path = remark-cicero/cicero - url = https://github.com/mlouhivu/cicero.git -[submodule "reveal.js"] - path = reveal.js - url = https://github.com/hakimel/reveal.js -[submodule "mathjax"] - path = mathjax - url = https://github.com/mathjax/MathJax.git diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..25622ed --- /dev/null +++ b/Dockerfile @@ -0,0 +1,87 @@ +FROM docker.io/alpine:3.17 AS slidefactory-files + +ARG VERSION + +ADD LICENSE /slidefactory/ +ADD fonts/ /slidefactory/fonts/ +ADD theme/ /slidefactory/theme/ +ADD slidefactory.py /slidefactory/ + +# Remove possible temporary files +RUN find /slidefactory -name '*~' -delete +RUN find /slidefactory -name '.*' -delete + +# Fix permissions +RUN chmod 755 /slidefactory && \ + find /slidefactory -type d -exec chmod 755 {} \; && \ + find /slidefactory -type f -exec chmod 644 {} \; && \ + chmod 755 /slidefactory/slidefactory.py + +# Add checksums +RUN cd /slidefactory && \ + find . -type f -print0 | xargs -0 sha256sum > /tmp/sha256sums_$VERSION && \ + mv /tmp/sha256sums_$VERSION /slidefactory/ + + +FROM docker.io/alpine:3.17 + +RUN apk update && \ + apk add --no-cache \ + ca-certificates \ + chromium \ + git \ + pandoc \ + font-freefont \ + python3 \ + py3-pandocfilters \ + py3-yaml \ + tar \ + zip \ + && \ + rm -rf /var/cache/apk/* + +# Reveal.js +RUN wget https://github.com/hakimel/reveal.js/archive/refs/tags/4.4.0.zip -O tmp.zip && \ + unzip tmp.zip 'reveal.js-4.4.0/LICENSE' -d /slidefactory && \ + unzip tmp.zip 'reveal.js-4.4.0/dist/*' -d /slidefactory && \ + unzip tmp.zip 'reveal.js-4.4.0/plugin/*' -d /slidefactory && \ + rm -f tmp.zip + +# MathJax +RUN wget https://github.com/mathjax/MathJax/archive/refs/tags/3.2.2.zip -O tmp.zip && \ + unzip tmp.zip 'MathJax-3.2.2/LICENSE' -d /slidefactory && \ + unzip tmp.zip 'MathJax-3.2.2/es5/tex-chtml-full.js' -d /slidefactory && \ + unzip tmp.zip 'MathJax-3.2.2/es5/input/tex/extensions/*' -d /slidefactory && \ + unzip tmp.zip 'MathJax-3.2.2/es5/output/chtml/fonts/woff-v2/*' -d /slidefactory && \ + unzip tmp.zip 'MathJax-3.2.2/es5/adaptors/*' -d /slidefactory && \ + rm -f tmp.zip + +# Fonts +RUN FONT_DIR=NotoSans && \ + mkdir -p /slidefactory/fonts/$FONT_DIR && \ + wget https://github.com/notofonts/latin-greek-cyrillic/releases/download/NotoSans-v2.013/NotoSans-v2.013.zip -O tmp.zip && \ + unzip -j tmp.zip 'NotoSans/googlefonts/ttf/*' -d /slidefactory/fonts/$FONT_DIR && \ + unzip -j tmp.zip 'OFL.txt' -d /slidefactory/fonts/$FONT_DIR && \ + rm tmp.zip + +RUN FONT_DIR=Inconsolata && \ + mkdir -p /slidefactory/fonts/$FONT_DIR && \ + wget https://github.com/googlefonts/Inconsolata/archive/refs/tags/v3.000.zip -O tmp.zip && \ + unzip -j tmp.zip 'Inconsolata-3.000/fonts/ttf/Inconsolata-*' -x '*Condensed*' '*Expanded*' -d /slidefactory/fonts/$FONT_DIR && \ + unzip -j tmp.zip 'Inconsolata-3.000/OFL.txt' -d /slidefactory/fonts/$FONT_DIR && \ + rm tmp.zip + +COPY --from=slidefactory-files /slidefactory/ /slidefactory/ + +# Create executable +RUN echo -e '#!/bin/sh\n\ +exec python3 /slidefactory/slidefactory.py "$@"\n\ +' > /usr/bin/slidefactory && \ + chmod a+x /usr/bin/slidefactory + +RUN mkdir /work + +WORKDIR /work + +ENTRYPOINT ["slidefactory"] +CMD ["-h"] diff --git a/INSTALL.md b/INSTALL.md deleted file mode 100644 index c0d6995..0000000 --- a/INSTALL.md +++ /dev/null @@ -1,93 +0,0 @@ -## Install - -Slidefactory consists of two parts: 1) a **git repo** containing files -defining the slide layout (aka themes), pandoc filters, and a convenience -script (`convert.py`) to ease the use of pandoc, and 2) a -**singularity container** with a self-contained software environment that is -tested to work with slidefactory. - - -### Download source code - -``` -git clone https://github.com/csc-training/slide-template -cd slide-template -``` - - -### Install full slidefactory - -To build the singularity container and install it together with the git -repository, you can simply say: -``` -make install -``` - -| Note: In order to build the container image, singularity needs to be -| installed (https://sylabs.io/guides/latest/admin-guide/installation.html) -| and you will need sudo rights. - -If you feel that `make` is too old skool (or your system doesn't have it), -there are also python scripts to do the same: -``` -python3 setup/build.py -python3 setup/install.py -``` - - -### Install only git repository (without container) - -If you prefer to use your local software environment, you can also just -install the git repo without the singularity container: -``` -make git -``` - -In order to use slidefactory, you need to also install all the dependencies: - - python3 - - python3-pandocfilters - - pandoc - - fonts-noto - - fonts-inconsolata - - pandoc-types (1.17.5.4) - - pandoc-emphasize-code - - chromium-browser - - -### Set environment variable SLIDEFACTORY - -After installation, you should edit your `.bashrc` or similar, to set the -environment variable `SLIDEFACTORY` to point to the installation location of -the git repository (as prompted by the installer) and to make sure the -directory containing the container image is in your `PATH`. - -For example: -``` -export SLIDEFACTORY=$HOME/lib/slidefactory -export PATH=$PATH:$HOME/bin -``` - - -### Custom installation location - -By default slidefactory will be installed under `bin/` and `lib/` in your -`$HOME` (i.e. `$HOME/bin/slidefactory.sif` and `$HOME/lib/slidefactory`). If -you prefer to install slidefactory in another location, you can use -environment variable `PREFIX` to point to your preferred location. - -For example to install under `/some/path/bin` and `/some/path/lib`, you can -say: -``` -PREFIX=/some/path make install -``` - -or to install just the git repo: -``` -PREFIX=/some/path make git -``` - -The python installation script has a similar option, please see -`setup/install.py --help` for more details. - -When uninstalling from a custom location, one needs to provide the same -`PREFIX` unless the environment variable `SLIDEFACTORY` is set correctly. diff --git a/LICENSE b/LICENSE index 4f1f1a9..d593fe7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017-2022 CSC - IT Center for Science Ltd. +Copyright (c) 2017-2023 CSC - IT Center for Science Ltd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index d0aa87c..0c2c876 100644 --- a/Makefile +++ b/Makefile @@ -1,68 +1,24 @@ -DEF=slidefactory.def -SIF=slidefactory.sif +IMAGE_ROOT?=ghcr.io/csc-training +IMAGE=slidefactory +IMAGE_VERSION?=$(shell grep -m1 -oP '(?<=VERSION = ").+(?=")' slidefactory.py) -ifndef PREFIX - PREFIX=$(HOME) -endif -INSTALL_BIN=$(PREFIX)/bin -INSTALL_GIT=$(PREFIX)/lib/slidefactory -GIT=https://github.com/csc-training/slide-template -.PHONY: build clean install uninstall -.PHONY: check clone git +build: Dockerfile slidefactory.py + docker build \ + --label "org.opencontainers.image.source=https://github.com/csc-training/slidefactory" \ + --label "org.opencontainers.image.description=slidefactory" \ + --build-arg VERSION=${IMAGE_VERSION} \ + -t ${IMAGE_ROOT}/${IMAGE}:${IMAGE_VERSION} \ + . -build: $(SIF) +push: + docker push ${IMAGE_ROOT}/${IMAGE}:${IMAGE_VERSION} -clean: - rm $(SIF) - -check: - @if [ -e $(INSTALL_GIT) ]; then \ - echo "Already installed. Please run 'make uninstall' to remove old installation."; \ - exit 1; \ - fi - -clone: - git clone --recursive . $(INSTALL_GIT) - cd $(INSTALL_GIT) && git remote set-url origin $(GIT) && git fetch origin - -git: - @make -s check - @make -s clone - @echo "" - @echo "Installed:" - @echo " $(INSTALL_GIT)/" - @echo "" - @echo "Please add the following into your .bashrc or similar" - @echo " export SLIDEFACTORY=$(INSTALL_GIT)" +singularity: + rm -f $(IMAGE).sif $(IMAGE).tar + docker save $(IMAGE_ROOT)/$(IMAGE):$(IMAGE_VERSION) -o $(IMAGE).tar + singularity build $(IMAGE).sif docker-archive://$(IMAGE).tar + rm -f $(IMAGE).tar -install: build - @make -s check - @if [ ! -d $(INSTALL_BIN) ]; then \ - mkdir -p $(INSTALL_BIN); \ - fi - cp -i $(SIF) $(INSTALL_BIN)/ - @make -s clone - @echo "" - @echo "Installed:" - @echo " $(INSTALL_BIN)/$(SIF)" - @echo " $(INSTALL_GIT)/" - @echo "" - @echo "Please add the following into your .bashrc or similar" - @echo " export SLIDEFACTORY=$(INSTALL_GIT)" - -uninstall: - @echo "Removing:" - @if [ -e $(INSTALL_BIN)/$(SIF) ]; then \ - echo " $(INSTALL_BIN)/$(SIF)"; \ - fi - @echo " $(INSTALL_GIT)/" - @read -r -p "Proceed [Y/n]? " OK; \ - [ "$$OK" = "y" ] || [ "$$OK" = "Y" ] || [ "$$OK" = "" ] || (exit 1;) - @if [ -e $(INSTALL_BIN)/$(SIF) ]; then \ - rm -f $(INSTALL_BIN)/$(SIF); \ - fi - rm -rf $(INSTALL_GIT) - -%.sif: %.def - sudo singularity build $@ $< +clean: + rm -f $(IMAGE).sif $(IMAGE).tar diff --git a/README.md b/README.md index f7c1e7a..8780bee 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This repository contains the recipe to build a new *slidefactory* container image and the files needed by the tool to generate slides in CSC style. If you are looking for an example of how to write slides using slidefactory, -please have a look at the empty +please have a look at the [slidefactory template](https://github.com/csc-training/slidefactory-template) that can be used as a basis for new courses. Besides some convenience tooling, it also contains a syntax guide and an example slide set. @@ -14,112 +14,105 @@ it also contains a syntax guide and an example slide set. ## Usage -Convert slides from Markdown to HTML: -```bash -slidefactory.sif example.md -``` +The container can be run via singularity / apptainer or docker / podman. -or the same if not using the singularity container: -```bash -python3 $SLIDEFACTORY/convert.py example.md -``` +### Singularity / apptainer -To see more detailed information when running, such as configuration options -and the exact pandoc command, you can add `--verbose` to the commands above. +Fetch the slidefactory container image: -Use `--help` to see descriptions of all the available arguments. + singularity pull docker://ghcr.io/csc-training/slidefactory:VERSION +Convert the markdown slides to a PDF (default): -### option: `--pdf` + ./slidefactory_VERSION.sif slides --format pdf slides.md -To generate also a PDF version of the slides, add `--pdf` to the command -above, e.g.: +Convert slides to a regular HTML (an internet access required to display): -```bash -slidefactory.sif --pdf example.md -``` + ./slidefactory_VERSION.sif slides --format html slides.md +Convert slides to a local HTML ([a local version of resources](#local-slidefactory-installation) used - no internet access required): -### option: `--self-contained` + ./slidefactory_VERSION.sif slides --format html-local slides.md -One can also use the option `--self-contained` to embed images and other -assets into the HTML file with the aim to produce a file that is as -"self-contained" as possible. +Convert slides to an embedded HTML (images and other resources embedded within the file): -```bash -slidefactory.sif --self-contained example.md -``` + ./slidefactory_VERSION.sif slides --format html-embedded slides.md -Beware that **files produces in this way can become very large** and that not -everything will be contained in the HTML file, so e.g. math formulas will -require internet connection to work. +The embedded HTML files are rather large and [buggy](#known-issues) so +the pdf or the local HTML format is recommended for offline use. +The local HTML requires [a local slidefactory installation](#local-slidefactory-installation). +Change the theme with `--theme`: -## Install + ./slidefactory_VERSION.sif slides --theme .../path/to/any/theme slides.md -Slidefactory consists of two parts: 1) a **git repo** containing files -defining the slide layout (aka themes), pandoc filters, and a convenience -script (`convert.py`) to ease the use of pandoc, and 2) a -**singularity container** with a self-contained software environment that is -tested to work with slidefactory. +Use help for all other options: -Get the source code, build the singularity container and install -slidefactory: -``` -git clone https://github.com/csc-training/slide-template -cd slide-template -make -make install -``` + ./slidefactory_VERSION.sif slides --help -As prompted by the installer, please add the environment variable -`SLIDEFACTORY` to your `.bashrc` (or similar) and make sure that the directory -containing the container image is in the `PATH`. -If needed, please see [INSTALL.md](INSTALL.md) for more detailed installation -instructions (and alternative installation options). +#### Build pages for a project +Use pages sub-command to create an index page and convert all slides: -### Uninstall + ./slidefactory_VERSION.sif pages about.yml build -To uninstall slidefactory, you can say `slidefactory.sif --uninstall` (or -without the container `python3 $SLIDEFACTORY/setup/uninstall.py`). If one is -in the directory containing the source code, `make uninstall` will also work. +#### Local slidefactory installation -## Update +Copy slidefactory files from the container to a local directory: -The installed git repo can be updated (to get new themes etc.) with: -``` -slidefactory.sif --update -``` + ./slidefactory_VERSION.sif install my_slidefactory -or without the singularity container: -``` -python3 $SLIDEFACTORY/setup/update.py -``` +and follow the instructions. -or just simply by using git: -``` -cd $SLIDEFACTORY -git pull -cd - -``` -If you want to update the git repo included inside the container (used only if -no local installation is found), then you can add `--container` flag to the -command above. This will unpack the container, update it, and rebuild the -image. +### Docker / podman -If the container image definition has changed, you need to re-install -slidefactory to get a new version of the image. +Fetch the slidefactory container image: + docker pull ghcr.io/csc-training/slidefactory:VERSION -## Example: template for new courses +Convert the markdown slides to a PDF (default): -Examples and more information on how to write slides using slidefactory are -available in the -[slidefactory template](https://github.com/csc-training/slidefactory-template) -repository. The repository contains an empty template for slidefactory slides -that can be used as a basis for new courses. Please read the `README.md` -included in the repository for more details. + docker run -it --rm -v "$PWD:$PWD:Z" -w "$PWD" ghcr.io/csc-training/slidefactory:VERSION slides --format pdf slides.md + +All the options work the same way as for singularity +but using the above docker command instead. + + +## Known issues + +* Embedded HTML: incorrect math font + * Use local HTML or PDF instead +* Embedded and local HTML: Firefox displays incorrect fonts + * Use Chromium or Chrome instead + + +## Building and updating the container image + +The container recipe is encoded in `Dockerfile` and `Makefile`. + +If you don't have docker or podman, install using + + sudo apt install podman-docker + +If using podman, define + + export BUILDAH_FORMAT=docker + +Build the image + + make build + +Login using GitHub Personal Access Token in order to be able to push: + + docker login ghcr.io + +Push the image + + make push + +For testing, you can also convert the local image to singularity: + + make singularity diff --git a/convert.py b/convert.py deleted file mode 100755 index cc1816c..0000000 --- a/convert.py +++ /dev/null @@ -1,383 +0,0 @@ -#!/usr/bin/python -#---------------------------------------------------------------------------# -# Function: Convert a presentation from Markdown (or reStructuredText) to # -# reveal.js powered HTML5 using pandoc. # -# Usage: python convert.py talk.md # -# Help: python convert.py --help # -#---------------------------------------------------------------------------# -import argparse -import inspect -import os -import sys -import subprocess - -# reveal.js configuration -default_config = [ - 'width=1920', - 'height=1080', - 'history=true', - 'center=false', - 'controls=false', - 'transition=none', - 'backgroundTransition=none' - ] - -# online URLS for the javascript libs -url_reveal = 'https://mlouhivu.github.io/static-engine/reveal/3.5.0' -config_mathjax = '?config=TeX-AMS_HTML-full' -url_mathjax = ( - 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js' - + config_mathjax) - -def error(msg, code=1): - """Custom error messages""" - print('') - print(inspect.cleandoc(msg)) - print('') - if code == 1: # setup error (invalid path etc.) - print('Please see README.md for installation instructions.') - sys.exit(code) - -def remove_duplicates(config): - """Remove duplicate entries from a list of config options.""" - tmp = {} - order = [] - for item in config: - try: - key, value = item.split('=', 1) - except ValueError: - error('Malformed config option: %s' % item, code=2) - tmp[key] = value - if key not in order: - order.append(key) - return [key + '=' + tmp[key] for key in order] - -def check_environment(): - """Check environment variables.""" - for env in ['SLIDEFACTORY', 'SLIDEFACTORY_CONTAINER']: - path = os.environ.get(env, False) - if path and not os.path.isdir(path): - error('Invalid path in environment variable {env}: {path}'.format( - env=env, path=os.environ[env])) - -# global flags -no_local_theme = False -no_local_reveal = False -no_local_mathjax = False - -def get_paths(): - """ - Figure out the paths to files - order of preference: current working directory, environment variable, - default installation path, location of this script - """ - global no_local_theme - global no_local_reveal - global no_local_mathjax - in_container = bool(os.environ.get('SLIDEFACTORY_CONTAINER', False)) - not_installed = False - default_path = os.path.join( - os.environ.get('HOME', os.path.expanduser('~')), - 'lib/slidefactory') - cwd = os.getcwd() - # .. base path - for path in [os.environ.get('SLIDEFACTORY', False), - default_path, - os.environ.get('SLIDEFACTORY_CONTAINER', False)]: - if path and os.path.isdir(path): - break - else: - path = os.path.dirname( - os.path.abspath(inspect.getsourcefile(lambda: None))) - not_installed = True - if path == os.environ.get('SLIDEFACTORY_CONTAINER', False): - not_installed = True - # .. path to themes - path_themes = os.path.join(cwd, 'theme') - if not os.path.isdir(path_themes): - path_themes = os.path.join(path, 'theme') - if in_container and not_installed: - no_local_theme = True - if not os.path.isdir(path_themes): - error('Invalid theme path: {0}'.format( - os.path.join('.', os.path.relpath(path_themes, start=cwd)))) - # .. path to filters - for path_filters in [os.path.join(cwd, 'filter'), - os.path.join(path, 'filter')]: - if os.path.isdir(path_filters): - break - else: - error('Invalid filter path: {0}'.format( - os.path.join('.', os.path.relpath(path_filters, start=cwd)))) - # .. path to reveal - for path_reveal in [os.path.join(cwd, 'reveal.js'), - os.path.join(path, 'reveal.js')]: - if os.path.isdir(path_reveal): - break - else: - path_reveal = '' - no_local_reveal = True - # .. path to mathjax - for path_mathjax in [os.path.join(cwd, 'mathjax/MathJax.js'), - os.path.join(path, 'mathjax/MathJax.js')]: - if os.path.isfile(path_mathjax): - break - else: - path_mathjax = '' - no_local_mathjax = True - path_mathjax = path_mathjax + config_mathjax - # .. only files outside of a container are accessible afterwards - if in_container and not_installed: - if path_reveal != os.path.join(cwd, 'reveal.js'): - no_local_reveal = True - if path_mathjax != os.path.join(cwd, 'mathjax/MathJax.js'): - no_local_mathjax = True - return { - 'base': path, - 'themes': path_themes, - 'filters': path_filters, - 'reveal': path_reveal, - 'mathjax': path_mathjax, - } - -def get_filters(path_filters): - """Get paths to pandoc filters.""" - filters = [os.path.join(path_filters, x) for x in [ - 'contain-slide.py', 'background-image.py']] - if os.path.exists('/usr/local/bin/pandoc-emphasize-code'): - filters.append('/usr/local/bin/pandoc-emphasize-code') - return filters - -def get_themes(path_themes): - """Find existing presentation themes.""" - try: - themes = [x for x in os.listdir(path_themes) - if os.path.isdir(os.path.join(path_themes, x))] - except OSError: - error('Invalid theme path: {0}'.format(path_themes)) - return themes - -def get_highlight_styles(): - """Get highlight styles supported by pandoc.""" - output = subprocess.check_output('pandoc --list-highlight-styles', - shell=True) - return output.decode().split() - - -def run(): - global no_local_theme - global no_local_reveal - global no_local_mathjax - - # find out the environment we are running in - check_environment() - path = get_paths() - themes = get_themes(path['themes']) - filters = get_filters(path['filters']) - highlight_styles = get_highlight_styles() - - parser = argparse.ArgumentParser(description="""Convert a presentation - from Markdown (or reStructuredText) to reveal.js powered HTML5 using - pandoc.""") - parser.add_argument('input', metavar='input.md', nargs='+', - help='filename for presentation source (e.g. in Markdown)') - parser.add_argument('--output', metavar='prefix', - help='prefix for output filenames (by default uses the ' - 'basename of the input file, i.e. talk.md -> talk.html)') - parser.add_argument('-t', '--theme', default='csc-2016', - choices=themes, metavar='THEME', - help='presentation theme: ' + ', '.join(themes) \ - + ' (default: csc-2016)') - parser.add_argument('-s', '--style', default='pygments', - choices=highlight_styles, metavar='name', - help='code highlight style: ' + ', '.join(highlight_styles) \ - + ' (default: pygments)') - parser.set_defaults(html=True) - parser.add_argument('-p', '--pdf', action='store_true', default=False, - help='convert HTMLs to PDFs') - parser.add_argument('-c', '--self-contained', - action='store_true', default=False, - help='produce as self-contained HTMLs as possible') - parser.add_argument('-b', '--browser', default='chromium-browser', - help='browser to use for converting PDFs (default: %(default)s)') - parser.add_argument('--config', action='append', default=default_config, - metavar='key=value', - help='reveal.js config option (multiple allowed)') - parser.add_argument('--filter', action='append', default=filters, - metavar='filter.py', - help='pandoc filter script (multiple allowed)') - parser.add_argument('--reveal', help=argparse.SUPPRESS, default=None) - parser.add_argument('--mathjax', help=argparse.SUPPRESS, default=None) - parser.add_argument('--as-container', help=argparse.SUPPRESS, - action='store_true', default=False) - parser.add_argument('--dry-run', '--show-command', - action='store_true', default=False, - help='do nothing, only show the full pandoc command' - + ' (together with config options and filters used)') - parser.add_argument('--verbose', action='store_true', default=False, - help='be loud and noisy') - parser.add_argument('--debug', action='store_true', default=False, - help='show debug options') - args = parser.parse_args() - - # show hidden debug options and exit? - if args.debug: - parser.print_help() - print('\ndebug options:') - print(' --reveal URL of the reveal.js to use') - print(' : ' + args.reveal) - print(' --mathjax URL of the MathJax.js to use') - print(' : ' + args.mathjax) - parser.exit() - - # without a local theme, container can only produce PDFs - if args.as_container and no_local_theme: - args.pdf = True - args.html = False - if args.verbose: - print('Could not find a local installation of slidefactory. ' - + 'Converting to PDFs only.') - print('If you want HTMLs, please set correct path to the ' - + 'environment variable SLIDEFACTORY or install ' - + 'slidefactory with:') - print(' slidefactory.sif --install') - print('') - - # check if given URLs are actually paths - if args.reveal and os.path.isdir(args.reveal): - no_local_reveal = False - path['reveal'] = args.reveal - if args.mathjax and os.path.isfile(args.mathjax): - no_local_mathjax = False - path['mathjax'] = args.mathjax - - # select local or remote reveal and mathjax - if args.self_contained or no_local_reveal: - args.reveal = args.reveal or url_reveal - else: - args.reveal = args.reveal or path['reveal'] - if args.self_contained or no_local_mathjax: - args.mathjax = args.mathjax or url_mathjax - else: - args.mathjax = args.mathjax or path['mathjax'] - - # self contained HTML - if args.self_contained: - if no_local_reveal: - error('Local copy of reveal.js is needed for --self-contained.') - urlencode = os.path.join(path['filters'], 'url-encode.py') - if urlencode not in args.filter: - args.filter.append(urlencode) - contained = '--self-contained' - else: - contained = '' - - # check config options and remove duplicates (if any) - config = remove_duplicates(args.config) - - # meta variables to pandoc - meta = [ - 'theme=' + args.theme, - 'themepath=' + os.path.join(path['themes'], args.theme), - 'revealjs-url=' + args.reveal, - 'revealjs-css-url=' + ( - path['reveal'] if args.self_contained else args.reveal), - ] - - # extra template variables to pandoc - variables = [ - ] - - # prepare command-line arguments - flags = { - 'style': args.style, - 'input': args.input, - 'output': args.output, - 'meta': ' '.join('-M ' + x for x in meta), - 'vars': ' '.join('-V ' + x for x in variables), - 'config': ' '.join('-V ' + x for x in config), - 'filter': ' '.join('--filter ' + x for x in args.filter), - 'mathjax': args.mathjax, - 'template': os.path.join( - path['themes'], args.theme, 'template.html'), - 'contained': contained, - } - - # display extra info? - if args.verbose or args.dry_run: - print('Using theme from: ' + os.path.join(path['themes'], args.theme)) - print('\nReveal.js configuration:') - for x in config: - print(' {0}'.format(x)) - print('\nPandoc filters:') - if filters: - for x in filters: - print(' {0}'.format(x)) - else: - print(' (none)') - print('\nPandoc variables:') - if meta or variables: - for x in meta: - print(' -M {0}'.format(x)) - for x in variables: - print(' -V {0}'.format(x)) - else: - print(' (none)') - print('\nPandoc options:') - print(' --highlight-style={0}'.format(args.style)) - print(' --mathjax={0}'.format(args.mathjax)) - if args.self_contained: - print(' ' + contained) - - # convert files - for filename in args.input: - # figure out the output filename - base, ext = os.path.splitext(filename) - if args.output: - base = args.output + base - html = base + '.html' - # add filenames to the command-line arguments - flags['input'] = filename - flags['output'] = html - - # construct the pandoc command - cmd = ('pandoc {input} -s -f markdown-native_divs -t revealjs --template={template} ' - + '{meta} {vars} {config} {contained} ' - + '--mathjax={mathjax} --highlight-style={style} ' - + '{filter} -o {output}').format(**flags) - - # display pandoc command? - if args.verbose or args.dry_run: - print('\nPandoc command:') - print(' {0}\n'.format(cmd)) - - # execute pandoc - if not args.dry_run: - os.system(cmd) - - # convert to pdfs? - if args.pdf: - pdf = base + '.pdf' - flags = [ - '--headless', - '--virtual-time-budget=10000', - '--run-all-compositor-stages-before-draw', - ] - cmd = ('{browser} {flags} --print-to-pdf={pdf} ' - + 'file://{path}/{html}?print-pdf').format( - browser=args.browser, - flags=' '.join(flags), - pdf=pdf, - path=os.path.abspath(os.getcwd()), - html=html) - if args.verbose or args.dry_run: - print('') - print('Command to convert to PDF:') - print(' {0}'.format(cmd)) - print('') - if not args.dry_run: - subprocess.run(cmd, shell=True, stderr=subprocess.DEVNULL) - return 0 - -if __name__ == '__main__': - sys.exit(run()) diff --git a/filter/background-image.py b/filter/background-image.py deleted file mode 100755 index ffdbbd0..0000000 --- a/filter/background-image.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python3 -from pandocfilters import toJSONFilter, Header, attributes - -def background(key, value, format, meta): - # language - try: - if meta['lang']['t'] == 'MetaInlines': - lang = ' '.join([x['c'] for x in meta['lang']['c']]) - else: - lang = meta['lang']['c'] - except: - lang = 'en' - # setup a template with correct path to the theme - try: - path = meta['themepath']['c'] - except: - path = 'theme' - template = u'{0}/img/%s.png'.format(path) - # set background image for title slide - if 'title_bg' not in meta: - filename = template % 'title-{0}'.format(lang) - meta['title_bg'] = {'t': 'MetaString', 'c': filename} - # markdown: special class name triggers the setting of a data background - # image unless already present - if key == 'Header' and value[0] == 1: - if 'data-background-image' not in [x[0] for x in value[1][2]]: - for key in ['title', 'author', 'section']: - if key in value[1][1]: - if key == 'title': - key = key + '-' + lang - value[1][2].append( - [u'data-background-image', template % key]) - break - return Header(value[0], value[1], value[2]) - # reST: special class name in a container Div triggers the same as above, - # but only the modified Header is returned - elif key == 'Div' and value[1][0]['t'] == 'Header': - header = value[1][0]['c'] - if 'data-background-image' not in [x[0] for x in header[1][2]]: - for key in ['title', 'author', 'section']: - if key in value[0][1]: - header[1][1].append(key) - if key == 'title': - key = key + '-' + lang - header[1][2].append( - [u'data-background-image', template % key]) - break - return Header(header[0], header[1], header[2]) - - -if __name__ == '__main__': - toJSONFilter(background) diff --git a/filter/contain-slide.py b/filter/contain-slide.py deleted file mode 100755 index ba50ab0..0000000 --- a/filter/contain-slide.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 -from pandocfilters import toJSONFilter, Header, attributes - -def contain(key, value, format, meta): -# raise ValueError, 'key=%s, value=%s, format=%s, meta=%s' % \ -# (repr(key), repr(value), repr(format), repr(meta)) - if key == 'Header' and value[0] == 1: - if 'data-background-size' not in [x[0] for x in value[1][2]]: - value[1][2].append([u'data-background-size', u'contain']) - return Header(value[0], value[1], value[2]) - elif key == 'HorizontalRule': - name = "section" - attr = [[u'data-background', u'empty-slide'], - [u'data-background-size', u'contain']] - return Header(1, (name, [], attr), []) - -if __name__ == '__main__': - toJSONFilter(contain) diff --git a/filter/url-encode.py b/filter/url-encode.py deleted file mode 100755 index c3f930b..0000000 --- a/filter/url-encode.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python3 -from pandocfilters import toJSONFilter, Header, attributes -import base64 - -def _encode(filename): - with open(filename, 'rb') as fp: - data = base64.b64encode(fp.read()) - return 'data:image/png;base64,' + data.decode() - -def urlencode(key, value, format, meta): - # urlencode title background - if 'title_bg' in meta and 'title_bg_encoded' not in meta: - meta['title_bg'] = { - 't': 'MetaString', - 'c': _encode(meta['title_bg']['c']) - } - meta['title_bg_encoded'] = {'t': 'MetaString', 'c': 'yes'} - # markdown: urlencode images - if key == 'Header' and value[0] == 1: - for attribute in value[1][2]: - if attribute[0] == 'data-background-image': - attribute[1] = _encode(attribute[1]) - return Header(value[0], value[1], value[2]) - # reST: urlencode images - elif key == 'Div' and value[1][0]['t'] == 'Header': - header = value[1][0]['c'] - for attribute in header[1][2]: - if attribute[0] == 'data-background-image': - attribute[1] = _encode(attribute[1]) - return Header(header[0], header[1], header[2]) - -if __name__ == '__main__': - toJSONFilter(urlencode) diff --git a/fonts/fonts.css b/fonts/fonts.css new file mode 100644 index 0000000..f431b27 --- /dev/null +++ b/fonts/fonts.css @@ -0,0 +1,47 @@ +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(NotoSans/NotoSans-Regular.ttf) format(truetype); +} + +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + src: url(NotoSans/NotoSans-Bold.ttf) format(truetype); +} + +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 400; + font-stretch: 100%; + src: url(NotoSans/NotoSans-Italic.ttf) format(truetype); +} + +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 700; + font-stretch: 100%; + src: url(NotoSans/NotoSans-BoldItalic.ttf) format(truetype); +} + +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + src: url(Inconsolata/Inconsolata-Regular.ttf) format(truetype); +} + +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + src: url(Inconsolata/Inconsolata-Bold.ttf) format(truetype); +} diff --git a/mathjax b/mathjax deleted file mode 160000 index d71cc40..0000000 --- a/mathjax +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d71cc40666d213dceeb9353822a3b530656d9a4b diff --git a/reveal.js b/reveal.js deleted file mode 160000 index 360bc94..0000000 --- a/reveal.js +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 360bc940062711db9b8020ce4e848f6c37014481 diff --git a/setup/build.py b/setup/build.py deleted file mode 100755 index b27860d..0000000 --- a/setup/build.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/python3 -#---------------------------------------------------------------------------# -# Function: Build slidefactory singularity container. # -# Help: ./build.sh --help # -#---------------------------------------------------------------------------# -import argparse -import sys -import os - -def run(): - desc = 'Build slidefactory singularity container' - parser = argparse.ArgumentParser(description=desc) - parser.add_argument('output', nargs='?', - default='slidefactory.sif', metavar='image.sif', - help='filename for the container image to be built ' \ - + '(default: %(default)s)') - parser.add_argument('-v', '--verbose', action='store_true', default=False, - help='display additional information while running') - parser.add_argument('-d', '--definition', - default='slidefactory.def', metavar='image.def', - help='singularity definition file for the container ' \ - + '(default: %(default)s)') - - args = parser.parse_args() - - # be noisy? - if args.verbose: - print('Image file: {0}'.format(args.output)) - print('Definition: {0}'.format(args.definition)) - print('') - - # check files - if not os.path.isfile(args.definition): - print("Definition file '{0}' missing.".format(args.definition)) - return 1 - if os.path.exists(args.output): - # is the existing container image newer than the definition? - try: - time_def = os.path.getmtime(args.definition) - time_out = os.path.getmtime(args.output) - if time_def < time_out: - if args.verbose: - print('Nothing to do.') - return 0 - except Exception: - if args.verbose: - print('Warning: unable to determine file modification time') - # remove existing file? - yn = input("File '{0}' exists. Overwrite [y/N]? ".format(args.output)) - if yn.lower() in ['y', 'yes']: - try: - os.remove(args.output) - except Exception: - print("Unable to remove '{0}'. Maybe it is not a file?".format( - args.output)) - return 1 - else: - print('Abort.') - return 2 - - # build command - cmd = 'sudo singularity build {0} {1}'.format(args.output, args.definition) - - # execute - if args.verbose: - print('Building image...') - print(' ' + cmd) - print('') - os.system(cmd) - - # the end. - return 0 - -if __name__ == '__main__': - sys.exit(run()) diff --git a/setup/install.py b/setup/install.py deleted file mode 100755 index 62406ac..0000000 --- a/setup/install.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/python3 -#---------------------------------------------------------------------------# -# Function: Install slidefactory container and repository # -# Help: ./install.sh --help # -#---------------------------------------------------------------------------# -import argparse -import sys -import os -import shutil -import subprocess - -def get_version(image): - cmd = [image, '--version'] - proc = subprocess.run(cmd, capture_output=True, encoding='utf-8') - if proc.returncode or not proc.stdout: - print("Couldn't determine the version of image {0}".format(image)) - sys.exit(3) - return proc.stdout.strip() - -def run(): - desc = 'Install slidefactory container and repository' - parser = argparse.ArgumentParser(description=desc) - parser.add_argument('-p', '--prefix', - default=os.environ.get('HOME', os.path.expanduser('~')), - help='install files into this path (under bin/ and lib/)' \ - + ' (default: %(default)s)') - parser.add_argument('-i', '--image', metavar='SIF', - default='slidefactory.sif', - help='container image to install (default: %(default)s)') - parser.add_argument('-r', '--repository', metavar='URL', - default='https://github.com/csc-training/slide-template', - help='URL to the git repository to install (default: %(default)s)') - parser.add_argument('-v', '--verbose', action='store_true', default=False, - help='display additional information while running') - - args = parser.parse_args() - - # install paths - install_git = os.path.join(args.prefix, 'lib/slidefactory') - install_bin = os.path.join(args.prefix, 'bin') - install_sif = os.path.join(install_bin, args.image) - - # be noisy? - if args.verbose: - print('Image file: {0}'.format(args.image)) - print('Repository: {0}'.format(args.repository)) - print('Install paths:') - print(' {0}'.format(install_bin)) - print(' {0}'.format(install_git)) - print('') - - # check files - if not os.path.isfile(args.image): - print("Image file '{0}' missing.".format(args.definition)) - return 1 - if os.path.exists(install_sif): - version_sif = get_version(install_sif) - version_image = get_version(os.path.join('.', args.image)) - if version_image < version_sif: - print() - print(("Newer version of the image installed already " - "({0} vs. {1}).").format(version_sif, version_image)) - print() - print(("To update the installed git repository, please run " - "'setup/update.py'")) - return 1 - yn = input("File '{0}' exists already. Remove [y/N]? ".format( - install_sif)) - if yn.lower() in ['y', 'yes']: - try: - os.remove(install_sif) - except Exception: - print("Unable to remove '{0}'. Maybe it is not a file?".format( - install_sif)) - return 1 - else: - print('Abort.') - return 2 - if os.path.exists(install_git): - yn = input("Path '{0}' exists already. Remove [y/N]? ".format( - install_git)) - if yn.lower() in ['y', 'yes']: - try: - shutil.rmtree(install_git) - except Exception: - print("Unable to remove '{0}'.") - return 1 - else: - print('Abort.') - return 2 - - # copy image - cmd = 'cp -i {0} {1}'.format(args.image, install_sif) - if args.verbose: - print('Copying image...') - print(' ' + cmd) - os.system(cmd) - - # clone git repository - cmd = 'git clone --recursive {0} {1}'.format(args.repository, install_git) - if args.verbose: - print('Cloning repository...') - print(' ' + cmd) - print('') - os.system(cmd) - - print('') - print('Installed:') - print(' {0}'.format(install_sif)) - print(' {0}'.format(install_git)) - print('') - print('Please add the following into your .bashrc or similar:') - print(' export SLIDEFACTORY={0}'.format(install_git)) - - # check if bin in PATH - path = os.environ.get('PATH', '').split(':') - if not install_bin in path: - print('') - print("Please make sure that '{0}' is in your PATH:".format(install_bin)) - print(' export PATH=$PATH:{0}'.format(install_bin)) - - # the end. - return 0 - -if __name__ == '__main__': - sys.exit(run()) diff --git a/setup/uninstall.py b/setup/uninstall.py deleted file mode 100755 index 1f9dd7a..0000000 --- a/setup/uninstall.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/python3 -#---------------------------------------------------------------------------# -# Function: Uninstall slidefactory container and repository # -# Help: ./install.sh --help # -#---------------------------------------------------------------------------# -import argparse -import sys -import os -import shutil - -def get_install_path(): - if 'SLIDEFACTORY' in os.environ: - return os.path.abspath( - os.path.join(os.environ['SLIDEFACTORY'], '../..')) - else: - return os.environ.get('HOME', os.path.expanduser('~')) - -def run(): - desc = 'Uninstall slidefactory container and repository' - parser = argparse.ArgumentParser(description=desc) - parser.add_argument('-p', '--prefix', - default=get_install_path(), - help='uninstall files installed at this path (under bin/ and lib/)' - + ' (default: %(default)s)') - parser.add_argument('-i', '--image', metavar='SIF', - default='slidefactory.sif', - help='name of the container image (default: %(default)s)') - parser.add_argument('-v', '--verbose', action='store_true', default=False, - help='display additional information while running') - - args = parser.parse_args() - - # install paths - install_git = os.path.join(args.prefix, 'lib/slidefactory') - install_bin = os.path.join(args.prefix, 'bin') - install_sif = os.path.join(install_bin, args.image) - - # be noisy? - if args.verbose: - print('Image file: {0}'.format(args.image)) - print('Uninstall paths:') - print(' {0}'.format(install_bin)) - print(' {0}'.format(install_git)) - print('') - - # are there files to remove? - if not os.path.exists(install_sif) and not os.path.exists(install_git): - print('Nothing to uninstall.') - - print('Removing:') - print(' {0}'.format(install_sif)) - print(' {0}'.format(install_git)) - yn = input('Proceed [Y/n]? ') - if yn.lower() not in ['y', 'yes', '']: - print('Abort.') - return 2 - try: - pass - os.remove(install_sif) - shutil.rmtree(install_git) - except Exception: - print('Unable to remove all files.') - return 1 - - # the end. - return 0 - -if __name__ == '__main__': - sys.exit(run()) diff --git a/setup/update.py b/setup/update.py deleted file mode 100755 index 4a2b4d4..0000000 --- a/setup/update.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/python3 -#---------------------------------------------------------------------------# -# Function: Update slidefactory repository (and maybe container) # -# Help: ./update.sh --help # -#---------------------------------------------------------------------------# -import argparse -import sys -import os -import tempfile -from contextlib import contextmanager - -def get_install_path(): - if 'SLIDEFACTORY' in os.environ: - return os.path.abspath( - os.path.join(os.environ['SLIDEFACTORY'], '../..')) - else: - path = os.environ.get('HOME', os.path.expanduser('~')) - if os.path.isdir(os.path.join(path, 'lib/slidefactory')): - return path - raise Exception - -@contextmanager -def change_dir(path): - cwd = os.getcwd() - try: - os.chdir(path) - yield - finally: - os.chdir(cwd) - -def run(): - desc = 'Update slidefactory repository (and maybe container)' - parser = argparse.ArgumentParser(description=desc) - parser.set_defaults(image='slidefactory.sif') - parser.add_argument('--as-container', action='store_true', default=False, - help=argparse.SUPPRESS) - parser.add_argument('-c', '--container', action='store_true', default=False, - help='update also container') - parser.add_argument('-v', '--verbose', action='store_true', default=False, - help='display additional information while running') - - args = parser.parse_args() - - # figure out install paths - try: - install_prefix = get_install_path() - except Exception: - print('Could not find files to update. Please set correct path ' - + 'to the environment variable SLIDEFACTORY.') - print("If you haven't yet installed slidefactory, please first run:") - if args.as_container: - print(' slidefactory.sif --install') - else: - print(' python3 setup/install.py') - return 1 - install_git = os.path.join(install_prefix, 'lib/slidefactory') - install_sif = os.path.join(install_prefix, 'bin', args.image) - - # check files - if not os.path.isdir(install_git) or \ - not os.path.isdir(os.path.join(install_git, '.git')): - print("Invalid git repository path: {0}".format(install_git)) - return 1 - if args.container: - if not os.path.isfile(install_sif): - print("Invalid image file: {0}".format(install_sif)) - return 1 - - # be noisy? - if args.verbose: - print('Repository: {0}'.format(install_git)) - if args.container: - print('Container: {0}'.format(install_sif)) - print('') - - # update repository - cmd = 'git pull && git submodule update --init' - if args.verbose: - print('Updating repository...') - print(' ' + cmd) - print('') - try: - with change_dir(install_git): - os.system(cmd) - except Exception: - print("Unable to update repository: {0}".format(install_git)) - - # update container - if args.container: - with tempfile.TemporaryDirectory(prefix='slidefactory-') as tmp: - sandbox = os.path.join(tmp, 'sandbox') - # create sandbox from the existing container - cmd = 'singularity build --sandbox {0} {1}'.format(sandbox, - install_sif) - if args.verbose: - print('Unpacking container...') - print(' ' + cmd) - try: - os.system(cmd) - except Exception: - print('Unable to unpack container: {0}'.format(install_sif)) - # update the git repo - path = os.path.join(sandbox, 'slidefactory') - cmd = 'git pull && git submodule update --init' - if args.verbose: - print('Updating repository (in container)...') - print(' ' + cmd) - try: - with change_dir(path): - os.system(cmd) - except Exception: - print("Unable to update the repository in the container.") - # create a new container from the sandbox - cmd = 'singularity build --force {0} {1}'.format(install_sif, - sandbox) - if args.verbose: - print('Building container...') - print(' ' + cmd) - print('') - try: - os.system(cmd) - except Exception: - print('Unable to build container: {0}'.format(install_sif)) - - print('Updated:') - print(' {0}'.format(install_git)) - if args.container: - print(' {0}'.format(install_sif)) - - # the end. - return 0 - -if __name__ == '__main__': - sys.exit(run()) diff --git a/slidefactory.def b/slidefactory.def deleted file mode 100644 index 8fcc676..0000000 --- a/slidefactory.def +++ /dev/null @@ -1,46 +0,0 @@ -BootStrap: library -From: ubuntu:20.04 - -%environment - export SLIDEFACTORY_CONTAINER=/lib/slidefactory - export SLIDEFACTORY_VERSION=1.x - -%post - apt update && apt install -y software-properties-common && apt update - add-apt-repository universe - add-apt-repository ppa:phd/chromium-browser - apt update - apt install -y python3-pip pandoc python3-pandocfilters - apt install -y fonts-noto fonts-inconsolata - apt install -y git - apt install -y chromium-browser - apt install -y cabal-install nvi - cabal update - mkdir -p /root/.cabal/bin - cabal install pandoc-types-1.17.5.4 - cabal install pandoc-emphasize-code - apt-get remove -y --autoremove cabal-install - url=https://github.com/csc-training/slide-template - git clone --recursive $url $SINGULARITY_ROOTFS/lib/slidefactory - -%runscript - _SLIDEFACTORY_PATH=$SLIDEFACTORY - if test "$_SLIDEFACTORY_PATH" = "" - then - _SLIDEFACTORY_PATH=$SLIDEFACTORY_CONTAINER - fi - if test "$1" = "--version" - then - shift - echo $SLIDEFACTORY_VERSION - elif test "$1" = "--update" - then - shift - exec python3 $_SLIDEFACTORY_PATH/setup/update.py --as-container "$@" - elif test "$1" = "--install" - then - shift - exec python3 $_SLIDEFACTORY_PATH/setup/install.py "$@" - else - exec python3 $_SLIDEFACTORY_PATH/convert.py --as-container "$@" - fi diff --git a/slidefactory.py b/slidefactory.py new file mode 100755 index 0000000..c59b753 --- /dev/null +++ b/slidefactory.py @@ -0,0 +1,637 @@ +#!/usr/bin/python +# ------------------------------------------------------------------------- # +# Function: Convert a presentation from Markdown (or reStructuredText) to # +# reveal.js powered HTML5 using pandoc. # +# Usage: python slidefactory.py talk.md # +# Help: python slidefactory.py --help # +# ------------------------------------------------------------------------- # +import argparse +import copy +import functools +import hashlib +import html.parser +import inspect +import os +import re +import shlex +import shutil +import sys +import subprocess +import tempfile +import yaml +from collections import namedtuple +from contextlib import contextmanager +from urllib.parse import quote as urlquote, urlparse +from pathlib import Path + + +VERSION = "3.1.0-beta.6" +SLIDEFACTORY_ROOT = Path(__file__).absolute().parent +IN_CONTAINER = SLIDEFACTORY_ROOT == Path('/slidefactory') + +# Modify version string if this file has been edited +with open(__file__, 'rb') as f: + CHECKSUM = hashlib.sha256(f.read()).hexdigest() + + +def __read_checksum_reference(): + checksum_fpath = SLIDEFACTORY_ROOT / f'sha256sums_{VERSION}' + if not checksum_fpath.exists(): + return None + with open(checksum_fpath, 'r') as f: + for line in f: + chk, fpath = line.strip().split(' ', 1) + if fpath == f'./{Path(__file__).name}': + return chk + return None + + +REF_CHECKSUM = __read_checksum_reference() +if CHECKSUM != REF_CHECKSUM: + VERSION += '-edited' + + +URL_KEYS = ( + 'defaults_fpath', + 'template_fpath', + 'theme_url', + 'revealjs_url', + 'mathjax_url', + 'fonts_url', + ) + +Theme = namedtuple('Theme', ['name', 'dpath', 'is_custom']) + + +def get_default_url(key: str, format: str, theme: Theme): + assert key in URL_KEYS + use_local_resources = format in ['pdf', 'html-local', 'html-embedded'] + root_url = f'file://{urlquote(str(SLIDEFACTORY_ROOT))}' + if key == 'theme_url': + if theme.is_custom or not IN_CONTAINER or use_local_resources: + return f'file://{urlquote(str(theme.dpath.absolute()))}/csc.css' # noqa: E501 + else: + return f'https://cdn.jsdelivr.net/gh/csc-training/slidefactory@3.1.0-beta.4/theme/{theme.name}/csc.css' # noqa: E501 + + elif key == 'defaults_fpath': + return theme.dpath / "defaults.yaml" + + elif key == 'template_fpath': + return theme.dpath / "template.html" + + elif key == 'revealjs_url': + if use_local_resources: + return f'{root_url}/reveal.js-4.4.0' + else: + return 'https://cdn.jsdelivr.net/npm/reveal.js@4.4.0' # noqa: E501 + + elif key == 'mathjax_url': + if use_local_resources: + return f'{root_url}/MathJax-3.2.2/es5/tex-chtml-full.js' # noqa: E501 + else: + return 'https://cdn.jsdelivr.net/npm/mathjax@3.2.2/es5/tex-chtml-full.js' # noqa: E501 + + elif key == 'fonts_url': + if use_local_resources: + return f'{root_url}/fonts/fonts.css' + else: + return 'https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wdth,wght@0,100,400;0,100,700;1,100,400;1,100,700&family=Inconsolata:wght@400;700' # noqa: E501 + + +@contextmanager +def named_ctx(name): + """Context manager that returns an object + with object.name being the given name.""" + yield namedtuple('Named', ['name'])(name) + + +class HTMLParser(html.parser.HTMLParser): + def __init__(self): + super().__init__() + self.sources = set() + + def handle_starttag(self, tag, attrs): + if tag == 'img': + for key, value in attrs: + if key == 'data-src': + if urlparse(value).scheme == '': + self.sources.add(value) + + +def run_template(run_args, *, dry_run): + run_args = [str(a) for a in run_args] + + if dry_run: + info(shlex.join(run_args)) + return + + verbose_info(shlex.join(run_args)) + p = subprocess.run(run_args, + check=False, shell=False, + capture_output=True) + + verbose_info(p.stdout.decode()) + + if p.returncode != 0: + error(f'error: {repr(run_args[0])} failed ' + f'with exit code {p.returncode}:\n' + f'{p.stderr.decode()}') + + +def info_template(msg, *, quiet): + if not quiet: + print(msg, flush=True) + + +def error(msg, code=1): + """Custom error messages""" + print('') + print(inspect.cleandoc(msg), + file=sys.stderr, flush=True) + print('') + sys.exit(code) + + +def get_available_themes(theme_root): + available_themes = sorted([str(x.name) for x in theme_root.iterdir() + if x.is_dir()]) + return available_themes + + +def find_theme(name): + is_custom = False + if os.sep in str(name): + is_custom = True + p = Path(name) + name = p.name + if not p.is_dir(): + error(f'Nonexistent theme directory {p.absolute()}') + else: + theme_root = SLIDEFACTORY_ROOT / 'theme' + p = theme_root / name + if not p.is_dir(): + available_themes = get_available_themes(theme_root) + error(f'Invalid theme {name}.' + f' Available themes: {", ".join(available_themes)}.') + for fname in ['defaults.yaml', 'template.html', 'csc.css']: + if not (p / fname).is_file(): + error(f'File {fname} missing from the theme directory' + f' {p.absolute()}') + return Theme(name, p, is_custom) + + +def create_html(input_fpath, html_fpath, *, + defaults_fpath, + template_fpath, + pandoc_vars, + filters=[], + pandoc_args=[], + ): + run_args = [ + 'pandoc', + f'--defaults={defaults_fpath}', + f'--template={template_fpath}', + ] + for key, value in pandoc_vars.items(): + run_args += [f'--variable={key}:{value}'] + run_args += pandoc_args + run_args += [f'--filter={f}' for f in filters] + run_args += [ + f'--output={html_fpath}', + input_fpath, + ] + run(run_args) + + +def copy_html_externals(input_fpath, html_fpath): + # Find external file paths + parser = HTMLParser() + with open(html_fpath, 'r') as f: + parser.feed(f.read()) + externals = parser.sources + + # Check that files exist + for fname in externals: + fpath = input_fpath.parent / fname + if not fpath.exists(): + error(f'Linked file missing: {fpath}') + + # Copy files to output path + if input_fpath.parent.resolve() != html_fpath.parent.resolve(): + for fname in externals: + ext_fpath = input_fpath.parent / fname + tgt_fpath = html_fpath.parent / fname + verbose_info(f'cp {ext_fpath} {tgt_fpath}') + tgt_fpath.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(ext_fpath, tgt_fpath) + + +def create_pdf(html_fpath, pdf_fpath): + run_args = [ + 'chromium-browser', + '--no-sandbox', + '--headless', + '--disable-gpu', + '--disable-software-rasterizer', + '--hide-scrollbars', + '--virtual-time-budget=2147483647', + '--run-all-compositor-stages-before-draw', + f'--print-to-pdf={pdf_fpath}', + f'file://{html_fpath.absolute()}?print-pdf' + ] + run(run_args) + + +def create_index_page(fpath, title, info_content, html_content, pdf_content): + info(f'Create {fpath}') + with fpath.open("w") as fd: + csc_ui_version = '2.1.11' + fd.write(f""" + + + + + {title} + + + + + + + {title} + + + + + + About + +
+{info_content} +
+
+
+ +
+ + + Slides (HTML) + +{html_content} + + + +
+ + + Slides (PDF) + +{pdf_content} + + + +
+
+ +""".strip("\n")) # noqa: E501 + fd.write(""" + + + +""".strip("\n")) # noqa: E501 + + +def build_content(fpath, page_theme_fpath, args, *, line_fmt='{}'): + info(f'Process {fpath}') + with fpath.open() as fd: + metadata = yaml.safe_load(fd.read()) + + title = metadata["title"] + content = "" + + if "modules" in metadata: + content += '\n' + for module in metadata["modules"]: + mod_fpath = fpath.parent / module / fpath.name + mod_title, mod_content = \ + build_content(mod_fpath, page_theme_fpath, args, + line_fmt='

{}

') + content += f'\n' # noqa: E501 + content += mod_content + content += '\n' + content += '
\n' + else: + assert "slidesdir" in metadata + slides_dpath = fpath.parent / metadata["slidesdir"] + for md_fpath in sorted(slides_dpath.glob("*.md")): + meta = read_slides_metadata(md_fpath) + html_name = md_fpath.with_suffix(".html").name + html_fpath = 'html' / fpath.parent / html_name + slides_title = re.sub(r'<.*?>', '', meta["title"]) + m = re.search(r'^\d+', html_name) + prefix = '' if m is None else f'{int(m.group())}.' + content += line_fmt.format(f'{prefix} {slides_title}') # noqa: E501 + content += '\n' + + # Convert slides + formats = ['html'] + if args.with_pdf: + formats += ['pdf'] + for fmt in formats: + args_slides = copy.copy(args) + args_slides.input = [md_fpath] + args_slides.output = args.output / fmt / fpath.parent + args_slides.format = fmt + if fmt == 'html': + theme_url = os.path.relpath(page_theme_fpath, + html_fpath.parent) + args_slides.theme_url = theme_url + main_slides(args_slides) + + return title, content + + +def read_slides_metadata(fpath): + with fpath.open() as fd: + line = fd.readline() + if line.strip() != "---": + raise RuntimeError(f"{fpath} missing metadata") + data = "" + for line in fd: + if line.strip() == "---": + break + data += line + return yaml.safe_load(data) + + +def main(): + # Common args + pparser_common = argparse.ArgumentParser(add_help=False) + pparser_common.add_argument( + '-n', '--dry-run', '--show-command', + action='store_true', default=False, + help='do nothing, only show the full commands to be run') + pparser_common.add_argument( + '-v', '--verbose', action='store_true', default=False, + help='be loud and noisy') + pparser_common.add_argument( + '-q', '--quiet', action='store_true', default=False, + help='suppress all output except errors') + + # Common conversion args + pparser_conversion = argparse.ArgumentParser(add_help=False) + pparser_conversion.add_argument( + '-t', '--theme', metavar='THEME', type=find_theme, + default='csc-plain', + help='presentation theme name or path (default: %(default)s)') + pparser_conversion.add_argument( + '--filters', action='append', default=[], + metavar='filter.py', + help='pandoc filter scripts (multiple allowed)') + pparser_conversion.add_argument( + '--no-math', action='store_true', + help='disable math rendering') + pparser_conversion.add_argument( + '--pandoc-args', nargs='?', + default='', const='', + help='additional arguments passed to pandoc') + + # Main argparser + parser = argparse.ArgumentParser( + description="Convert a presentation from Markdown to " + "a reveal.js-powered HTML5 using pandoc." + ) + subparsers = parser.add_subparsers(help='sub-command', required=True) + + # Main argparser - slides sub-command + parser_slides = subparsers.add_parser( + 'slides', + parents=[pparser_common, pparser_conversion], + help='convert slides') + parser_slides.set_defaults(main=main_slides) + parser_slides.add_argument( + 'input', metavar='input.md', nargs='*', type=Path, + help='presentation file(s)') + parser_slides.add_argument( + '-o', '--output', metavar='DIR', type=Path, + help=('output directory (by default uses ' + 'the same directory as the input files)')) + parser_slides.add_argument( + '-f', '--format', metavar='FORMAT', default='pdf', + choices=['pdf', 'html', 'html-local', 'html-embedded'], + help='output format (default: %(default)s; available: %(choices)s)') + group = parser_slides.add_argument_group( + 'advanced options for overriding paths and urls') + for key in URL_KEYS: + group.add_argument(f'--{key}', help=f'override {key}') + + # Main argparser - pages sub-command + parser_pages = subparsers.add_parser( + 'pages', + parents=[pparser_common, pparser_conversion], + help='build pages and convert slides') + parser_pages.set_defaults(main=main_pages) + parser_pages.add_argument( + 'input', metavar='about.yml', type=Path, + help='metadata file') + parser_pages.add_argument( + 'output', metavar='DIR', type=Path, + help='output directory') + parser_pages.add_argument( + '--info_content', + default='This page is generated with slidefactory.', + help='information shown on the page') + parser_pages.add_argument( + '--with-pdf', action='store_true', + help='include pdf') + + # Main argparser - install sub-command + parser_install = subparsers.add_parser( + 'install', + parents=[pparser_common], + help='install local slidefactory') + parser_install.set_defaults(main=main_install) + parser_install.add_argument( + 'path', metavar='path', type=Path, + help='install path') + + args = parser.parse_args() + + global info + info = functools.partial(info_template, quiet=args.quiet) + + global verbose_info + verbose_info = functools.partial(info_template, quiet=not args.verbose) + + global run + run = functools.partial(run_template, dry_run=args.dry_run) + + info(f'Slidefactory {VERSION}') + verbose_info(f' checksum: {CHECKSUM}') + verbose_info(f' reference: {REF_CHECKSUM}') + args.main(args) + + if args.dry_run: + info("This was DRY RUN. No changes made.") + + +def main_slides(args): + if args.format == 'html-local' and IN_CONTAINER: + error('Install and use local slidefactory in order to ' + 'create local offline htmls.\n\n' + 'In short, run slidefactory container with `--install PATH` ' + 'and follow the instructions (see README for details).' + ) + + include_math = not args.no_math + + # Set resource url defaults if not set + for key in URL_KEYS: + if getattr(args, key, None) is None: + default = get_default_url(key, args.format, args.theme) + setattr(args, key, default) + + if args.verbose: + info("Using following resources (override with the given argument):") + for key in URL_KEYS: + val = getattr(args, key) + info(f" --{key:16} {val}") + + pandoc_vars = { + 'theme-url': args.theme_url, + 'revealjs-url': args.revealjs_url, + 'mathjaxurl': args.mathjax_url, + 'css': args.fonts_url, + } + + if args.format in ['html-embedded'] and include_math: + url = args.mathjax_url + pandoc_vars.update({ + 'mathjaxurl': '', + 'header-includes': f'', + }) + + # Suffix + if args.format == 'pdf': + suffix = '.pdf' + elif args.format == 'html-local': + suffix = '.local.html' + elif args.format == 'html-embedded': + suffix = '.embedded.html' + else: + suffix = '.html' + + # Extra pandoc args + pandoc_args = args.pandoc_args.split() + if include_math: + pandoc_args += ['--mathjax'] + if args.format in ['html-embedded']: + pandoc_args += ['--embed-resources'] + + # Convert files + for in_fpath in args.input: + if args.output: + out_fpath = args.output / in_fpath.with_suffix(suffix).name + if not args.dry_run: + out_fpath.parent.mkdir(parents=True, exist_ok=True) + else: + out_fpath = in_fpath.with_suffix(suffix) + + info(f'Convert {in_fpath} to {out_fpath}') + + # Use temporary html output for pdf + with tempfile.NamedTemporaryFile( + dir=in_fpath.parent, + prefix=f'{in_fpath.stem}-', + suffix='.html') \ + if args.format == 'pdf' \ + else named_ctx(out_fpath) \ + as outfile: + + html_fpath = Path(outfile.name) + create_html(in_fpath, html_fpath, + defaults_fpath=args.defaults_fpath, + template_fpath=args.template_fpath, + pandoc_vars=pandoc_vars, + pandoc_args=pandoc_args, + filters=args.filters, + ) + + if not args.dry_run: + copy_html_externals(in_fpath, html_fpath) + + if args.format == 'pdf': + create_pdf(html_fpath, out_fpath) + + +def main_pages(args): + if args.output.exists(): + error(f'Output path {args.output} exists. Exiting.') + + page_theme_fpath = Path('html') / 'theme' / args.theme.name / 'csc.css' + output_theme_dpath = args.output / page_theme_fpath.parent + info(f'Copy theme to {output_theme_dpath}') + shutil.copytree(args.theme.dpath, output_theme_dpath) + + title, html_content = build_content(args.input, page_theme_fpath, args) + + if args.with_pdf: + pdf_content = re.sub(r'href="html/(.*?).html"', + r'href="pdf/\1.pdf"', + html_content) + pdf_content += '\n' + pdf_content += '\n' + + zip_fpath = args.output / 'slides.zip' + info(f'Create {zip_fpath}') + shutil.make_archive(zip_fpath.with_suffix(''), + 'zip', + args.output / 'pdf') + pdf_content += f'Download a zip file containing all slides.\n' # noqa: E501 + else: + pdf_content = "Not generated." + + # Convert links to html + info_content = re.sub(r'\[(.*?)\]\((.*?)\)', + r'\1', + args.info_content) + + index_fpath = args.output / 'index.html' + create_index_page(index_fpath, title, + info_content, html_content, pdf_content) + + +def main_install(args): + path = args.path + if path.exists(): + error(f'Installation path {path} exists. Exiting.') + + path = path.absolute() + + # Copy slidefactory files + info(f'Copy {SLIDEFACTORY_ROOT} to {path}') + if not args.dry_run: + shutil.copytree(SLIDEFACTORY_ROOT, path) + + py_fpath = shlex.quote(str(path / Path(__file__).name)) + + info(f'\nTo use the local installation, run ' + f'{py_fpath} with the container.\n' + f'In singularity:\n' + f' singularity exec slidefactory_VERSION.sif python3 {py_fpath} slides --format html-local slides.md' # noqa: E501 + '\n' + f'In docker:\n' + f' docker run -it --rm -v "$PWD:$PWD:Z" -w "$PWD" --entrypoint python3 ghcr.io/csc-training/slidefactory:VERSION {py_fpath} slides --format html-local slides.md' # noqa: E501 + '\n' + f'Hint: make an alias of this command.\n' + ) + + +if __name__ == '__main__': + main() diff --git a/theme/csc-2016-prace/csc.css b/theme/csc-2016-prace/csc.css deleted file mode 100644 index d5fe61b..0000000 --- a/theme/csc-2016-prace/csc.css +++ /dev/null @@ -1,583 +0,0 @@ -/* CSC colors - * (main) - * magenta: #830051 - * teal: #006778 - * grey: #5e6a71 - * - * (extra) - * green: #7dc242 - * orange: #ff5800 - * purple: #ea1d77 - * turquoise: #00c7b2 - * dark blue: #002f5f - * blue: #0082bb - */ -:root { - --csc-magenta: #830051; - --csc-teal: #006778; - --csc-grey: #5e6a71; - --csc-green: #7dc242; - --csc-orange: #ff5800; - --csc-purple: #ea1d77; - --csc-turquoise: #00c7b2; - --csc-dark-blue: #002f5f; - --csc-blue: #0082bb; - --csc-highlight: #ffc0b0; -} -/* Screen geometry + base size for text */ -:root { - --xsize: 1920px; - --ysize: 1080px; - --xmargin: 74px; - --ymargin: 84px; - --fontsize: 50px; -} -/* Fonts */ -:root { - --csc-font-family: 'Noto Sans'; - --csc-code-font-family: 'Inconsolata'; -} - -/********************************************* - * GLOBAL STYLES - *********************************************/ -body { - background-color: black; -} -.slide-background { - background: url("img/normal.png"); - background-size: contain; -} - -.reveal { - font-family: var(--csc-font-family); - font-size: var(--fontsize); - color: var(--csc-grey); - font-weight: normal; -} -.reveal .slides { - text-align: left; - line-height: 1.4; -} -.reveal .slides > section, -.reveal .slides > section > section { - padding: 0; -} -.reveal h1, -.reveal h2, -.reveal h3, -.reveal p, -.reveal ul, -.reveal ol, -.reveal dl, -.reveal table, -.reveal pre, -.reveal figure, -.reveal video { - margin-left: var(--xmargin); - margin-right: var(--xmargin); - max-width: calc(var(--xsize) - 2 * var(--xmargin)); -} -.reveal p { - margin-top: 1ex; -} -.reveal .slides > section:before { - content: ""; - display: block; - margin-top: var(--ymargin); -} - -/********************************************* - * HEADERS - *********************************************/ -.reveal h1, .reveal h2, .reveal h3 { - font-weight: normal; - line-height: 1.1; - text-align: left; - font-weight: bold; -} -.reveal h1 { - font-size: 1.2em; - color: var(--csc-teal); -} -.reveal h2 { - font-size: 1.1em; - padding-top: 1ex; -} -.reveal h3 { - font-size: 1em; - padding-top: 1ex; -} -.reveal .slides > section h1:first-child { - padding-bottom: 1.7em; -} -.reveal .slides > section h2:first-child, -.reveal .slides > section h3:first-child, -.reveal .slides > section h1:first-child + p, -.reveal .slides > section h1:first-child + h2, -.reveal .slides > section h1:first-child + h3, -.reveal .column h2:first-child, -.reveal .column h3:first-child { - padding-top: 0; - margin-top: 0; -} - -/********************************************* - * OTHER - *********************************************/ - -/* Ensure certain elements are never larger than the slide itself */ -.reveal img, -.reveal video, -.reveal iframe { - max-width: 95%; - max-height: 95%; -} - -/* General formatting */ -.reveal strong, b { - font-weight: bold; -} -.reveal em { - font-style: italic; -} -.reveal sup { - vertical-align: super; -} -.reveal sub { - vertical-align: sub; -} -.reveal small { - font-size: 0.7em; -} - -/********************************************* - * DOUBLE COLUMN LAYOUT - *********************************************/ -.reveal .column { - width: 49%; -} -.reveal .column:first-of-type { - float: left; - margin-right: 1%; -} -.reveal .column:last-of-type { - float: right; - margin-left: 1%; -} -.reveal .column:first-of-type ul, -.reveal .column:first-of-type ol, -.reveal .column:first-of-type dl, -.reveal .column:first-of-type p, -.reveal .column:first-of-type h2, -.reveal .column:first-of-type h3, -.reveal .column:first-of-type pre, -.reveal .column:first-of-type table, -.reveal .column:first-of-type figure, -.reveal .column:first-of-type video { - margin-right: 0; -} -.reveal .column:last-of-type ul, -.reveal .column:last-of-type ol, -.reveal .column:last-of-type dl, -.reveal .column:last-of-type p, -.reveal .column:last-of-type h2, -.reveal .column:last-of-type h3, -.reveal .column:last-of-type pre, -.reveal .column:last-of-type table, -.reveal .column:last-of-type figure, -.reveal .column:last-of-type video { - margin-left: 0; -} - -/********************************************* - * LISTS - *********************************************/ -.reveal ol, -.reveal dl, -.reveal ul { - display: inline-block; -} -.reveal ol { - list-style-type: decimal; -} -.reveal ul { - list-style-type: disc; -} -.reveal ul ul { - list-style-type: circle; -} -.reveal .slides > section > ul > li, -.reveal .slides > section > ol > li { - margin-bottom: 1ex; -} -.reveal .slides > section > dl > dt { - margin-top: 1ex; -} -.reveal .slides > section > dl > dt:first-child { - margin-top: 0; -} -.reveal ul ul, -.reveal ul ol, -.reveal ol ol, -.reveal ol ul, -.reveal ul dl, -.reveal ol dl { - display: block; - margin-left: 0.5em; -} -.reveal li { - margin-left: 1em; - margin-right: 0; - margin-bottom: 0; -} -.reveal li li { - font-size: 0.9em; -} -.reveal li p { - margin-left: 0; -} -/* description list */ -.reveal dt { - font-family: var(--csc-code-font-family); - font-weight: bold; -} -.reveal dd { - margin-left: 1em; -} -.reveal dd dl { - margin-left: 0; - margin-right: 0; -} -.reveal ul dl dd, -.reveal ol dl dd, -.reveal dd dl dd { - font-size: 0.8em; -} -.reveal dl p:first-child { - margin-top: 0; -} -.reveal dd p { - margin-left: 0; -} -.reveal .split-definition dd dl, -.reveal .split-def-2 dd dl { - column-count: 2; - column-width: calc(0.5 * (var(--xsize) - 2 * var(--xmargin)) - 1em); -} -.reveal .split-def-3 dd dl { - column-count: 3; - column-width: calc(0.33 * (var(--xsize) - 2 * var(--xmargin)) - 1em); -} -.reveal .split-def-3 dd dl dt { - font-size: 0.9em; -} -.reveal .split-def-3 dd dl dd { - font-size: 0.7em; -} - - -/********************************************* - * CODE - *********************************************/ -.reveal div.sourceCode { - margin: 0.1em 0; -} -.reveal pre { - display: block; - margin-top: 2px; - margin-bottom: 1ex; - font-size: 0.7em; - line-height: 1.2; - word-wrap: break-word; - border: 2px solid; -} -.reveal pre, -.reveal code { - font-family: var(--csc-code-font-family); -} -.reveal pre code { - display: block; - padding: 5px; - overflow: auto; - max-height: calc(0.735 * var(--ysize)); - word-wrap: normal; - white-space: pre; -} -.reveal code { - white-space: pre-wrap; -} -.reveal p code { - padding-left: 0.1em; - padding-right: 0.1em; -} -.reveal code.input { - color: var(--csc-orange); -} -.reveal code.output { - color: var(--csc-blue); -} -.reveal code.ghost { - color: transparent; -} -.reveal mark { - background-color: var(--csc-highlight); -} - -/********************************************* - * TABLES - *********************************************/ -.reveal table { - margin-bottom: 1ex; - border-collapse: collapse; - border-spacing: 0; -} -.reveal table th { - font-weight: bold; -} -.reveal table th, -.reveal table td { - padding: 0.2em 0.5em 0.2em 0.5em; -} -.reveal table th[align="center"], -.reveal table td[align="center"] { - text-align: center; -} -.reveal table th[align="right"], -.reveal table td[align="right"] { - text-align: right; -} -.reveal table th[align="left"], -.reveal table td[align="left"] { - text-align: left; -} -/* cell highlight */ -.reveal table strong em, -.reveal table b em { - color: var(--csc-orange); - font-style: normal; - font-weight: normal; -} -/* default style w/ only some horisontal lines */ -.reveal table thead { - border-top: 4px solid; - border-bottom: 2px solid; -} -.reveal table tbody { - border-bottom: 4px solid; -} -/* alternative style w/ color accents */ -.reveal .table-colour table th, -.reveal .table-colour table td:first-child { - color: var(--csc-blue); - font-weight: normal; -} -.reveal .table-colour table strong, b { - color: var(--csc-blue); - font-weight: normal; -} -/* alternative style w/ visible cells in colour */ -.reveal .table-grid table { - border-collapse: separate; - border-spacing: 0.1ex; -} -.reveal .table-grid table th, -.reveal .table-grid table td { - padding: 0.1em 0.5em 0.1em 0.5em; - background-color: var(--csc-blue); - color: white; -} -.reveal .table-grid table thead, -.reveal .table-grid table tbody { - border: none; -} -/* alternative style w/out any extra styling */ -.reveal .table-none table thead, -.reveal .table-none table tbody { - border: none; -} -.reveal .table-none table th { - font-weight: normal; -} -.reveal .table-none table strong em, -.reveal .table-none table b em { - color: var(--csc-grey); - font-style: italic; - font-weight: bold; -} - -/********************************************* - * LINKS - *********************************************/ -.reveal a { - color: #2a76dd; - text-decoration: none; - -webkit-transition: color .15s ease; - -moz-transition: color .15s ease; - transition: color .15s ease; } - -.reveal a:hover { - color: #6ca0e8; - text-shadow: none; - border: none; } - -.reveal .roll span:after { - color: #fff; - background: #1a53a1; } - -/********************************************* - * IMAGES - *********************************************/ -.reveal section img { - border: 0; - box-shadow: none; -} -.reveal section img.border { - border: 4px solid #222; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); -} -.reveal section img.center { - margin-left: auto; - margin-right: auto; - display: block; -} - -.reveal a img { - -webkit-transition: all .15s linear; - -moz-transition: all .15s linear; - transition: all .15s linear; -} -.reveal a:hover img { - background: rgba(255, 255, 255, 0.2); - border-color: #2a76dd; - box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); -} - -/********************************************* - * NAVIGATION CONTROLS - *********************************************/ -.reveal .controls .navigate-left, -.reveal .controls .navigate-left.enabled { - border-right-color: #2a76dd; } - -.reveal .controls .navigate-right, -.reveal .controls .navigate-right.enabled { - border-left-color: #2a76dd; } - -.reveal .controls .navigate-up, -.reveal .controls .navigate-up.enabled { - border-bottom-color: #2a76dd; } - -.reveal .controls .navigate-down, -.reveal .controls .navigate-down.enabled { - border-top-color: #2a76dd; } - -.reveal .controls .navigate-left.enabled:hover { - border-right-color: #6ca0e8; } - -.reveal .controls .navigate-right.enabled:hover { - border-left-color: #6ca0e8; } - -.reveal .controls .navigate-up.enabled:hover { - border-bottom-color: #6ca0e8; } - -.reveal .controls .navigate-down.enabled:hover { - border-top-color: #6ca0e8; } - -/********************************************* - * PROGRESS BAR - *********************************************/ -.reveal .progress { - background: rgba(0, 0, 0, 0.2); -} -.reveal .progress span { - background: #2a76dd; - -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); - -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); - transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); -} - -/********************************************* - * CSC SPECIAL SLIDES - *********************************************/ -.reveal .title h1, .reveal .title p { - margin-left: calc(0.291 * var(--xsize)); - text-align: left; - color: #ffffff; -} -.reveal .slides > section.title h1:first-child { - padding-bottom: 1ex; -} -.reveal .title h1 { - margin-top: calc(0.412 * var(--ysize)); - font-size: 1.4em; - font-weight: bold; - line-height: 1.2; -} -.reveal .title p { - font-size: 0.6em; -} - -.reveal .section h1 { - margin-top: calc(0.412 * var(--ysize)); -} -.reveal .slides > section.section h1:first-child { - padding-bottom: 1ex; -} -.reveal .section p { - font-size: 0.8em; -} - -.reveal .author h1, -.reveal .author p, -.reveal .author div { - margin-left: calc(0.24 * var(--xsize)); - text-align: left; -} -.reveal .slides > section.author h1:first-child { - padding-bottom: 1.4em; -} -.reveal .author h1 { - margin-top: calc(0.58 * var(--ysize)); - font-size: 0.6em; - font-weight: bold; -} -.reveal .author p, -.reveal .author div { - padding-bottom: 1.4em; - font-size: 0.5em; -} -.reveal .author img { - position: absolute; - width: calc(0.142 * var(--xsize)); - top: calc(0.578 * var(--ysize)); - left: calc(0.073 * var(--xsize)); - border: 0; -} - -/********************************************* - * PDF printing - *********************************************/ -.reveal .slides .pdf-page > section h1:first-child { - padding-bottom: 1.7em; -} -.reveal .slides .pdf-page > section h2:first-child, -.reveal .slides .pdf-page > section h3:first-child, -.reveal .slides .pdf-page > section h1:first-child + h2, -.reveal .slides .pdf-page > section h1:first-child + h3, -.reveal .column .pdf-page h2:first-child, -.reveal .column .pdf-page h3:first-child { - padding-top: 0; -} -.reveal .slides .pdf-page > section:before { - content: ""; - display: block; - margin-top: var(--ymargin); -} - -.reveal .slides .pdf-page > section.title h1:first-child { - padding-bottom: 1ex; -} -.reveal .slides .pdf-page > section.author h1:first-child { - padding-bottom: 1.4em; -} diff --git a/theme/csc-2016-prace/fonts.css b/theme/csc-2016-prace/fonts.css deleted file mode 100644 index acda1f6..0000000 --- a/theme/csc-2016-prace/fonts.css +++ /dev/null @@ -1 +0,0 @@ -@import url('https://fonts.googleapis.com/css?family=Noto+Sans:400,400i,700,700i|Inconsolata:400,700&subset=greek,latin-ext'); diff --git a/theme/csc-2016-prace/img/author.png b/theme/csc-2016-prace/img/author.png deleted file mode 100644 index 1685efb..0000000 Binary files a/theme/csc-2016-prace/img/author.png and /dev/null differ diff --git a/theme/csc-2016-prace/img/normal.png b/theme/csc-2016-prace/img/normal.png deleted file mode 100644 index badf378..0000000 Binary files a/theme/csc-2016-prace/img/normal.png and /dev/null differ diff --git a/theme/csc-2016-prace/img/section-leaf.png b/theme/csc-2016-prace/img/section-leaf.png deleted file mode 100644 index 15878d2..0000000 Binary files a/theme/csc-2016-prace/img/section-leaf.png and /dev/null differ diff --git a/theme/csc-2016-prace/img/section.png b/theme/csc-2016-prace/img/section.png deleted file mode 120000 index 025d60a..0000000 --- a/theme/csc-2016-prace/img/section.png +++ /dev/null @@ -1 +0,0 @@ -section-leaf.png \ No newline at end of file diff --git a/theme/csc-2016-prace/img/title-en.png b/theme/csc-2016-prace/img/title-en.png deleted file mode 100644 index d003750..0000000 Binary files a/theme/csc-2016-prace/img/title-en.png and /dev/null differ diff --git a/theme/csc-2016-prace/img/title-fi.png b/theme/csc-2016-prace/img/title-fi.png deleted file mode 100644 index 4577cae..0000000 Binary files a/theme/csc-2016-prace/img/title-fi.png and /dev/null differ diff --git a/theme/csc-2016/fonts.css b/theme/csc-2016/fonts.css deleted file mode 100644 index acda1f6..0000000 --- a/theme/csc-2016/fonts.css +++ /dev/null @@ -1 +0,0 @@ -@import url('https://fonts.googleapis.com/css?family=Noto+Sans:400,400i,700,700i|Inconsolata:400,700&subset=greek,latin-ext'); diff --git a/theme/csc-2016/img/author.png b/theme/csc-2016/img/author.png deleted file mode 100644 index 1685efb..0000000 Binary files a/theme/csc-2016/img/author.png and /dev/null differ diff --git a/theme/csc-2016/img/normal.png b/theme/csc-2016/img/normal.png deleted file mode 100644 index ea96afc..0000000 Binary files a/theme/csc-2016/img/normal.png and /dev/null differ diff --git a/theme/csc-2016/img/section-leaf.png b/theme/csc-2016/img/section-leaf.png deleted file mode 100644 index 15878d2..0000000 Binary files a/theme/csc-2016/img/section-leaf.png and /dev/null differ diff --git a/theme/csc-2016/img/section.png b/theme/csc-2016/img/section.png deleted file mode 120000 index 025d60a..0000000 --- a/theme/csc-2016/img/section.png +++ /dev/null @@ -1 +0,0 @@ -section-leaf.png \ No newline at end of file diff --git a/theme/csc-2016/img/title-en.png b/theme/csc-2016/img/title-en.png deleted file mode 100644 index d003750..0000000 Binary files a/theme/csc-2016/img/title-en.png and /dev/null differ diff --git a/theme/csc-2016/img/title-fi.png b/theme/csc-2016/img/title-fi.png deleted file mode 100644 index 4577cae..0000000 Binary files a/theme/csc-2016/img/title-fi.png and /dev/null differ diff --git a/theme/csc-2016/template.html b/theme/csc-2016/template.html deleted file mode 100644 index cd05160..0000000 --- a/theme/csc-2016/template.html +++ /dev/null @@ -1,265 +0,0 @@ - - - - - -$for(author-meta)$ - -$endfor$ -$if(date-meta)$ - -$endif$ -$if(keywords)$ - -$endif$ - $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$ - - - - - -$if(quotes)$ - -$endif$ -$if(highlighting-css)$ - -$endif$ - - -$for(css)$ - -$endfor$ - - - -$if(math)$ - $math$ -$endif$ -$for(header-includes)$ - $header-includes$ -$endfor$ - - -$for(include-before)$ -$include-before$ -$endfor$ -
-
- -$if(title)$ -
-

$title$

-$if(subtitle)$ -

$subtitle$

-$endif$ -$if(event)$ -$if(date)$ -

$event$, $date$

-$else$ -

$event$

-$endif$ -$else$ -$if(date)$ -

$date$

-$endif$ -$endif$ -$if(author)$ -

$author$

-$endif$ -
-$endif$ -$if(toc)$ -
-$toc$ -
-$endif$ - -$body$ -
-
- - - - - - $for(include-after)$ - $include-after$ - $endfor$ - - diff --git a/theme/csc-2018-portrait/README.md b/theme/csc-2018-portrait/README.md deleted file mode 100644 index da62d9a..0000000 --- a/theme/csc-2018-portrait/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# csc-2018-portrait - -Theme for generating A4 handout title pages. - -## Custom page geometry - -One needs to set a custom page geometry to use the theme, e.g.: -`--config width=905 --config height=1280 -t csc-2018-portrait` - -## Example markdown input - -``` ---- -title: CSC Summer School in High-Performance Computing 2022 -date: June 6 - July 5, 2022 -author: CSC - IT Center for Science, Finland -lang: en ---- - -# {.author} - -All material (C) 2011–2022 by CSC – IT Center for Science Ltd. -This work is licensed under a **Creative Commons Attribution-ShareAlike 4.0** -International License, http://creativecommons.org/licenses/by-sa/4.0 - -# Message passing interface {.section} - -# Hybrid programming {.section} -``` diff --git a/theme/csc-2018-portrait/csc.css b/theme/csc-2018-portrait/csc.css deleted file mode 100644 index d346158..0000000 --- a/theme/csc-2018-portrait/csc.css +++ /dev/null @@ -1,621 +0,0 @@ -/* CSC colors - * (main) - * magenta: #830051 - * teal: #006778 - * grey: #5e6a71 - * - * (extra) - * green: #7dc242 - * orange: #ff5800 - * purple: #ea1d77 - * turquoise: #00c7b2 - * dark blue: #002f5f - * blue: #0082bb - */ -:root { - --csc-magenta: #830051; - --csc-teal: #006778; - --csc-grey: #5e6a71; - --csc-green: #7dc242; - --csc-orange: #ff5800; - --csc-purple: #ea1d77; - --csc-turquoise: #00c7b2; - --csc-dark-blue: #002f5f; - --csc-blue: #0082bb; - --csc-highlight: #ffc0b0; -} -/* Screen geometry + base size for text */ -:root { - --xsize: 905px; - --ysize: 1280px; - --xmargin: 74px; - --ymargin: 84px; - --fontsize: 38px; -} -/* Fonts */ -:root { - --csc-font-family: 'Noto Sans'; - --csc-code-font-family: 'Inconsolata'; -} - -/********************************************* - * GLOBAL STYLES - *********************************************/ -body { - background-color: black; -} -.slide-background { - background: url("img/normal.png"); - background-size: contain; -} - -.reveal { - font-family: var(--csc-font-family); - font-size: var(--fontsize); - color: var(--csc-grey); - font-weight: normal; -} -.reveal .slides { - text-align: right; - line-height: 1.4; -} -.reveal .slides > section, -.reveal .slides > section > section { - padding: 0; -} -.reveal h1, -.reveal h2, -.reveal h3, -.reveal p, -.reveal ul, -.reveal ol, -.reveal dl, -.reveal table, -.reveal pre, -.reveal figure, -.reveal video { - margin-left: var(--xmargin); - margin-right: var(--xmargin); - max-width: calc(var(--xsize) - 2 * var(--xmargin)); -} -.reveal p { - margin-top: 1ex; -} -.reveal .slides > section:before { - content: ""; - display: block; - margin-top: 0; -} -.reveal .text-orange { - color: var(--csc-orange); -} -.reveal .text-teal { - color: var(--csc-teal); -} -.reveal .text-magenta { - color: var(--csc-magenta); -} -.reveal .text-green { - color: var(--csc-green); -} -.reveal .text-grey { - color: var(--csc-grey); -} -.reveal .text-purple { - color: var(--csc-purple); -} -.reveal .text-turquoise { - color: var(--csc-turquoise); -} -.reveal .text-blue { - color: var(--csc-blue); -} -.reveal .text-ghost { - color: transparent; -} - -/********************************************* - * HEADERS - *********************************************/ -.reveal h1, .reveal h2, .reveal h3 { - font-weight: normal; - line-height: 1.1; - text-align: right; - font-weight: bold; -} -.reveal h1 { - font-size: 1.4em; - color: var(--csc-blue); -} -.reveal h2 { - font-size: 1.1em; - padding-top: 1ex; - padding-bottom: 1ex; -} -.reveal h3 { - font-size: 1em; - padding-top: 1ex; -} -.reveal .slides > section h1:first-child { - padding-bottom: 1.7em; -} -.reveal .slides > section h2:first-child, -.reveal .slides > section h3:first-child, -.reveal .slides > section h1:first-child + p, -.reveal .slides > section h1:first-child + h2, -.reveal .slides > section h1:first-child + h3, -.reveal .column h2:first-child, -.reveal .column h3:first-child { - padding-top: 0; - margin-top: 0; -} - -/********************************************* - * OTHER - *********************************************/ - -/* Ensure certain elements are never larger than the slide itself */ -.reveal img, -.reveal video, -.reveal iframe { - max-width: 95%; - max-height: 95%; -} - -/* General formatting */ -.reveal strong, b { - font-weight: bold; -} -.reveal em { - font-style: italic; -} -.reveal sup { - vertical-align: super; -} -.reveal sub { - vertical-align: sub; -} -.reveal small { - font-size: 0.7em; -} - -/********************************************* - * DOUBLE COLUMN LAYOUT - *********************************************/ -.reveal .column { - width: 49%; -} -.reveal .column:first-of-type { - float: left; - margin-right: 1%; -} -.reveal .column:last-of-type { - float: right; - margin-left: 1%; -} -.reveal .column:first-of-type ul, -.reveal .column:first-of-type ol, -.reveal .column:first-of-type dl, -.reveal .column:first-of-type p, -.reveal .column:first-of-type h2, -.reveal .column:first-of-type h3, -.reveal .column:first-of-type pre, -.reveal .column:first-of-type table, -.reveal .column:first-of-type figure, -.reveal .column:first-of-type video { - margin-right: 0; -} -.reveal .column:last-of-type ul, -.reveal .column:last-of-type ol, -.reveal .column:last-of-type dl, -.reveal .column:last-of-type p, -.reveal .column:last-of-type h2, -.reveal .column:last-of-type h3, -.reveal .column:last-of-type pre, -.reveal .column:last-of-type table, -.reveal .column:last-of-type figure, -.reveal .column:last-of-type video { - margin-left: 0; -} - -/********************************************* - * LISTS - *********************************************/ -.reveal ol, -.reveal dl, -.reveal ul { - display: inline-block; -} -.reveal ol { - list-style-type: decimal; -} -.reveal ul { - list-style-type: disc; -} -.reveal ul ul { - list-style-type: circle; -} -.reveal .slides > section > ul > li, -.reveal .slides > section > div > ul > li, -.reveal .slides > section > div > ol > li, -.reveal .slides > section > ol > li { - margin-bottom: 1ex; -} -.reveal .slides > section > dl > dt, -.reveal .slides > section > div > dl > dt { - margin-top: 1ex; -} -.reveal .slides > section > dl > dt:first-child, -.reveal .slides > section > div > dl > dt:first-child { - margin-top: 0; -} -.reveal ul ul, -.reveal ul ol, -.reveal ol ol, -.reveal ol ul, -.reveal ul dl, -.reveal ol dl { - display: block; - margin-left: 0.5em; -} -.reveal li { - margin-left: 1em; - margin-right: 0; - margin-bottom: 0; -} -.reveal li li { - font-size: 0.9em; -} -.reveal li p { - margin-left: 0; -} -/* description list */ -.reveal dt { - font-family: var(--csc-code-font-family); - font-weight: bold; -} -.reveal dd { - margin-left: 1em; -} -.reveal dd dl { - margin-left: 0; - margin-right: 0; -} -.reveal ul dl dd, -.reveal ol dl dd, -.reveal dd dl dd { - font-size: 0.8em; -} -.reveal dl p:first-child { - margin-top: 0; -} -.reveal dd p { - margin-left: 0; -} -.reveal .split-definition dd dl, -.reveal .split-def-2 dd dl { - column-count: 2; - column-width: calc(0.5 * (var(--xsize) - 2 * var(--xmargin)) - 1em); -} -.reveal .split-def-3 dd dl { - column-count: 3; - column-width: calc(0.33 * (var(--xsize) - 2 * var(--xmargin)) - 1em); -} -.reveal .split-def-3 dd dl dt { - font-size: 0.9em; -} -.reveal .split-def-3 dd dl dd { - font-size: 0.7em; -} - - -/********************************************* - * CODE - *********************************************/ -.reveal div.sourceCode { - margin: 0.1em 0; -} -.reveal pre { - display: block; - margin-top: 2px; - margin-bottom: 1ex; - font-size: 0.7em; - line-height: 1.2; - word-wrap: break-word; - border: 2px solid; -} -.reveal pre, -.reveal code { - font-family: var(--csc-code-font-family); -} -.reveal pre code { - display: block; - padding: 5px; - overflow: auto; - max-height: calc(0.735 * var(--ysize)); - word-wrap: normal; - white-space: pre; -} -.reveal code { - white-space: pre-wrap; -} -.reveal p code { - padding-left: 0.1em; - padding-right: 0.1em; -} -.reveal code.input { - color: var(--csc-orange); -} -.reveal code.output { - color: var(--csc-blue); -} -.reveal code.ghost { - color: transparent; -} -.reveal mark { - background-color: var(--csc-highlight); -} - -/********************************************* - * TABLES - *********************************************/ -.reveal table { - margin-bottom: 1ex; - border-collapse: collapse; - border-spacing: 0; -} -.reveal table th { - font-weight: bold; -} -.reveal table th, -.reveal table td { - padding: 0.2em 0.5em 0.2em 0.5em; -} -.reveal table th[align="center"], -.reveal table td[align="center"] { - text-align: center; -} -.reveal table th[align="right"], -.reveal table td[align="right"] { - text-align: right; -} -.reveal table th[align="left"], -.reveal table td[align="left"] { - text-align: left; -} -/* cell highlight */ -.reveal table strong em, -.reveal table b em { - color: var(--csc-orange); - font-style: normal; - font-weight: normal; -} -/* default style w/ only some horisontal lines */ -.reveal table thead { - border-top: 4px solid; - border-bottom: 2px solid; -} -.reveal table tbody { - border-bottom: 4px solid; -} -/* alternative style w/ color accents */ -.reveal .table-colour table th, -.reveal .table-colour table td:first-child { - color: var(--csc-blue); - font-weight: normal; -} -.reveal .table-colour table strong, b { - color: var(--csc-blue); - font-weight: normal; -} -/* alternative style w/ visible cells in colour */ -.reveal .table-grid table { - border-collapse: separate; - border-spacing: 0.1ex; -} -.reveal .table-grid table th, -.reveal .table-grid table td { - padding: 0.1em 0.5em 0.1em 0.5em; - background-color: var(--csc-blue); - color: white; -} -.reveal .table-grid table thead, -.reveal .table-grid table tbody { - border: none; -} -/* alternative style w/out any extra styling */ -.reveal .table-none table thead, -.reveal .table-none table tbody { - border: none; -} -.reveal .table-none table th { - font-weight: normal; -} -.reveal .table-none table strong em, -.reveal .table-none table b em { - color: var(--csc-grey); - font-style: italic; - font-weight: bold; -} - -/********************************************* - * LINKS - *********************************************/ -.reveal a { - color: #2a76dd; - text-decoration: none; - -webkit-transition: color .15s ease; - -moz-transition: color .15s ease; - transition: color .15s ease; } - -.reveal a:hover { - color: #6ca0e8; - text-shadow: none; - border: none; } - -.reveal .roll span:after { - color: #fff; - background: #1a53a1; } - -/********************************************* - * IMAGES - *********************************************/ -.reveal section img { - border: 0; - box-shadow: none; -} -.reveal section img.border { - border: 4px solid #222; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); -} -.reveal section img.center { - margin-left: auto; - margin-right: auto; - display: block; -} - -.reveal a img { - -webkit-transition: all .15s linear; - -moz-transition: all .15s linear; - transition: all .15s linear; -} -.reveal a:hover img { - background: rgba(255, 255, 255, 0.2); - border-color: #2a76dd; - box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); -} - -/********************************************* - * NAVIGATION CONTROLS - *********************************************/ -.reveal .controls .navigate-left, -.reveal .controls .navigate-left.enabled { - border-right-color: #2a76dd; } - -.reveal .controls .navigate-right, -.reveal .controls .navigate-right.enabled { - border-left-color: #2a76dd; } - -.reveal .controls .navigate-up, -.reveal .controls .navigate-up.enabled { - border-bottom-color: #2a76dd; } - -.reveal .controls .navigate-down, -.reveal .controls .navigate-down.enabled { - border-top-color: #2a76dd; } - -.reveal .controls .navigate-left.enabled:hover { - border-right-color: #6ca0e8; } - -.reveal .controls .navigate-right.enabled:hover { - border-left-color: #6ca0e8; } - -.reveal .controls .navigate-up.enabled:hover { - border-bottom-color: #6ca0e8; } - -.reveal .controls .navigate-down.enabled:hover { - border-top-color: #6ca0e8; } - -/********************************************* - * PROGRESS BAR - *********************************************/ -.reveal .progress { - background: rgba(0, 0, 0, 0.2); -} -.reveal .progress span { - background: #2a76dd; - -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); - -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); - transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); -} - -/********************************************* - * CSC SPECIAL SLIDES - *********************************************/ -.reveal .title h1, -.reveal .title p { - text-align: left; - color: #ffffff; -} -.reveal .slides > section.title h1:first-child { - padding-bottom: 1ex; -} -.reveal .title h1 { - margin-top: calc(0.48 * var(--ysize)); - font-size: 1.4em; - font-weight: bold; - line-height: 1.2; -} -.reveal .title p { - font-size: 0.6em; -} - -.reveal .section h1 { - margin-top: calc(0.48 * var(--ysize)); -} -.reveal .slides > section.section h1:first-child { - padding-bottom: 1ex; -} -.reveal .section p { - font-size: 0.8em; -} - -.reveal .author h1, -.reveal .author p, -.reveal .author div { - margin-left: calc(0.32 * var(--xsize)); - text-align: left; -} -.reveal .slides > section.author h1:first-child { - padding-bottom: 1.4em; -} -.reveal .slides > section.author h1:first-child + p { - margin-top: calc(0.32 * var(--ymargin)); -} -.reveal .author h1 { - font-size: 0.0em; - font-weight: bold; -} -.reveal .author p, -.reveal .author div { - font-size: 0.41em; -} -.reveal .author img { - position: absolute; - width: calc(0.142 * var(--xsize)); - top: calc(0.578 * var(--ysize)); - left: calc(0.073 * var(--xsize)); - border: 0; -} - -.reveal .notes h1 { - text-align: left; -} - -/********************************************* - * PDF printing - *********************************************/ -.reveal .slides .pdf-page > section h1:first-child { - padding-bottom: 1.7em; -} -.reveal .slides .pdf-page > section h2:first-child, -.reveal .slides .pdf-page > section h3:first-child, -.reveal .slides .pdf-page > section h1:first-child + h2, -.reveal .slides .pdf-page > section h1:first-child + h3, -.reveal .column .pdf-page h2:first-child, -.reveal .column .pdf-page h3:first-child { - padding-top: 0; -} -.reveal .slides .pdf-page > section:before { - content: ""; - display: block; - margin-top: 0; -} - -.reveal .slides .pdf-page > section.title h1:first-child { - padding-bottom: 1ex; -} -.reveal .slides .pdf-page > section.author h1:first-child { - margin-top: calc(0.32 * var(--ymargin)); - padding-bottom: 1.4em; -} diff --git a/theme/csc-2018-portrait/fonts.css b/theme/csc-2018-portrait/fonts.css deleted file mode 100644 index acda1f6..0000000 --- a/theme/csc-2018-portrait/fonts.css +++ /dev/null @@ -1 +0,0 @@ -@import url('https://fonts.googleapis.com/css?family=Noto+Sans:400,400i,700,700i|Inconsolata:400,700&subset=greek,latin-ext'); diff --git a/theme/csc-2018-portrait/img/author.png b/theme/csc-2018-portrait/img/author.png deleted file mode 100644 index 143717e..0000000 Binary files a/theme/csc-2018-portrait/img/author.png and /dev/null differ diff --git a/theme/csc-2018-portrait/img/normal.png b/theme/csc-2018-portrait/img/normal.png deleted file mode 100644 index eac2538..0000000 Binary files a/theme/csc-2018-portrait/img/normal.png and /dev/null differ diff --git a/theme/csc-2018-portrait/img/section-blocks.png b/theme/csc-2018-portrait/img/section-blocks.png deleted file mode 100644 index c7efa14..0000000 Binary files a/theme/csc-2018-portrait/img/section-blocks.png and /dev/null differ diff --git a/theme/csc-2018-portrait/img/section.png b/theme/csc-2018-portrait/img/section.png deleted file mode 120000 index abc3705..0000000 --- a/theme/csc-2018-portrait/img/section.png +++ /dev/null @@ -1 +0,0 @@ -section-blocks.png \ No newline at end of file diff --git a/theme/csc-2018-portrait/img/title-en.png b/theme/csc-2018-portrait/img/title-en.png deleted file mode 100644 index f81af3e..0000000 Binary files a/theme/csc-2018-portrait/img/title-en.png and /dev/null differ diff --git a/theme/csc-2018-portrait/img/title-fi.png b/theme/csc-2018-portrait/img/title-fi.png deleted file mode 120000 index 4bb578c..0000000 --- a/theme/csc-2018-portrait/img/title-fi.png +++ /dev/null @@ -1 +0,0 @@ -title-en.png \ No newline at end of file diff --git a/theme/csc-2018-portrait/template.html b/theme/csc-2018-portrait/template.html deleted file mode 100644 index cd05160..0000000 --- a/theme/csc-2018-portrait/template.html +++ /dev/null @@ -1,265 +0,0 @@ - - - - - -$for(author-meta)$ - -$endfor$ -$if(date-meta)$ - -$endif$ -$if(keywords)$ - -$endif$ - $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$ - - - - - -$if(quotes)$ - -$endif$ -$if(highlighting-css)$ - -$endif$ - - -$for(css)$ - -$endfor$ - - - -$if(math)$ - $math$ -$endif$ -$for(header-includes)$ - $header-includes$ -$endfor$ - - -$for(include-before)$ -$include-before$ -$endfor$ -
-
- -$if(title)$ -
-

$title$

-$if(subtitle)$ -

$subtitle$

-$endif$ -$if(event)$ -$if(date)$ -

$event$, $date$

-$else$ -

$event$

-$endif$ -$else$ -$if(date)$ -

$date$

-$endif$ -$endif$ -$if(author)$ -

$author$

-$endif$ -
-$endif$ -$if(toc)$ -
-$toc$ -
-$endif$ - -$body$ -
-
- - - - - - $for(include-after)$ - $include-after$ - $endfor$ - - diff --git a/theme/csc-2016/csc.css b/theme/csc-plain/csc.css similarity index 79% rename from theme/csc-2016/csc.css rename to theme/csc-plain/csc.css index 5ede7dd..2e588e8 100644 --- a/theme/csc-2016/csc.css +++ b/theme/csc-plain/csc.css @@ -41,12 +41,31 @@ /********************************************* * GLOBAL STYLES *********************************************/ -body { +.reveal-viewport { background-color: black; } + .slide-background { - background: url("img/normal.png"); - background-size: contain; + background-image: url("img/normal.svg"); + background-repeat: no-repeat; + background-position: center; + background-size: contain; +} + +.slide-background.title { + background-image: url("img/title.svg"); +} + +:lang(fi) .slide-background.title { + background-image: url("img/title.svg"); +} + +.slide-background.section { + background-image: url("img/normal.svg"); +} + +.slide-background.author { + background-image: url("img/author.svg"); } .reveal { @@ -59,32 +78,19 @@ body { text-align: left; line-height: 1.4; } -.reveal .slides > section, -.reveal .slides > section > section { - padding: 0; -} -.reveal h1, -.reveal h2, -.reveal h3, -.reveal p, -.reveal ul, -.reveal ol, -.reveal dl, -.reveal table, -.reveal pre, -.reveal figure, -.reveal video { - margin-left: var(--xmargin); - margin-right: var(--xmargin); - max-width: calc(var(--xsize) - 2 * var(--xmargin)); +.reveal .slides section.slide , +.reveal .slides .pdf-page section.slide { + margin-top: var(--ymargin) !important; + margin-left: var(--xmargin) !important; + margin-right: var(--xmargin) !important; + max-width: calc(var(--xsize) - 2 * var(--xmargin)) !important; + padding: 0 !important; } .reveal p { margin-top: 1ex; } -.reveal .slides > section:before { - content: ""; - display: block; - margin-top: var(--ymargin); +.reveal section.slide::before { + content: ""; } .reveal .text-orange { color: var(--csc-orange); @@ -118,7 +124,6 @@ body { * HEADERS *********************************************/ .reveal h1, .reveal h2, .reveal h3 { - font-weight: normal; line-height: 1.1; text-align: left; font-weight: bold; @@ -136,14 +141,14 @@ body { font-size: 1em; padding-top: 1ex; } -.reveal .slides > section h1:first-child { +.reveal section.slide h1:first-child { padding-bottom: 1.7em; } -.reveal .slides > section h2:first-child, -.reveal .slides > section h3:first-child, -.reveal .slides > section h1:first-child + p, -.reveal .slides > section h1:first-child + h2, -.reveal .slides > section h1:first-child + h3, +.reveal section.slide h2:first-child, +.reveal section.slide h3:first-child, +.reveal section.slide h1:first-child + p, +.reveal section.slide h1:first-child + h2, +.reveal section.slide h1:first-child + h3, .reveal .column h2:first-child, .reveal .column h3:first-child { padding-top: 0; @@ -235,20 +240,12 @@ body { .reveal ul ul { list-style-type: circle; } -.reveal .slides > section > ul > li, -.reveal .slides > section > div > ul > li, -.reveal .slides > section > div > ol > li, -.reveal .slides > section > ol > li { +.reveal li { + margin-left: 1em; + margin-right: 0; margin-bottom: 1ex; } -.reveal .slides > section > dl > dt, -.reveal .slides > section > div > dl > dt { - margin-top: 1ex; -} -.reveal .slides > section > dl > dt:first-child, -.reveal .slides > section > div > dl > dt:first-child { - margin-top: 0; -} + .reveal ul ul, .reveal ul ol, .reveal ol ol, @@ -258,22 +255,24 @@ body { display: block; margin-left: 0.5em; } -.reveal li { - margin-left: 1em; - margin-right: 0; - margin-bottom: 0; -} .reveal li li { font-size: 0.9em; + margin-bottom: 0; } .reveal li p { margin-left: 0; } + /* description list */ .reveal dt { + margin-top: 1ex; font-family: var(--csc-code-font-family); font-weight: bold; } +.reveal dt:first-child, +.reveal dl dl dt { + margin-top: 0; +} .reveal dd { margin-left: 1em; } @@ -313,7 +312,8 @@ body { * CODE *********************************************/ .reveal div.sourceCode { - margin: 0.1em 0; + margin-top: 0.1em; + margin-bottom: 0.1em; } .reveal pre { display: block; @@ -325,7 +325,9 @@ body { border: 2px solid; } .reveal pre, -.reveal code { +.reveal code, +.reveal code.sourceCode, +.reveal code.sourceCode > span { font-family: var(--csc-code-font-family); } .reveal pre code { @@ -532,84 +534,70 @@ body { /********************************************* * CSC SPECIAL SLIDES *********************************************/ -.reveal .title h1, .reveal .title p { - margin-left: calc(0.291 * var(--xsize)); + +/* Title slide */ + +.reveal .slides section.slide.title , +.reveal .slides .pdf-page section.slide.title { + margin-top: calc(0.412 * var(--ysize)) !important; + margin-left: calc(0.291 * var(--xsize)) !important; + margin-right: 0 !important; + max-width: calc(var(--xsize) - 0.291 * var(--xsize)) !important; +} +.reveal section.slide.title * { + color: var(--csc-dark-blue); text-align: left; - color: #ffffff; -} -.reveal .slides > section.title h1:first-child { - padding-bottom: 1ex; } -.reveal .title h1 { - margin-top: calc(0.412 * var(--ysize)); +.reveal section.slide.title h1 { font-size: 1.4em; font-weight: bold; line-height: 1.2; } -.reveal .title p { +.reveal section.slide.title h1:first-child { + padding-bottom: 1ex; +} +.reveal section.slide.title p { font-size: 0.6em; } -.reveal .section h1 { - margin-top: calc(0.412 * var(--ysize)); +/* Section slide */ + +.reveal .slides section.slide.section , +.reveal .slides .pdf-page section.slide.section { + margin-top: calc(0.412 * var(--ysize)) !important; } -.reveal .slides > section.section h1:first-child { +.reveal section.slide.section h1:first-child { padding-bottom: 1ex; } -.reveal .section p { +.reveal section.slide.section p { font-size: 0.8em; } -.reveal .author h1, -.reveal .author p, -.reveal .author div { - margin-left: calc(0.24 * var(--xsize)); - text-align: left; +/* Author slide */ + +.reveal .slides section.slide.author, +.reveal .slides .pdf-page section.slide.author { + margin-top: calc(0.58 * var(--ysize)) !important; + margin-left: calc(0.24 * var(--xsize)) !important; +} +.reveal section.slide.author * { + text-align: left; + font-size: 0.5em; } -.reveal .slides > section.author h1:first-child { +.reveal section.slide.author h1, +.reveal section.slide.author div { padding-bottom: 1.4em; } -.reveal .author h1 { - margin-top: calc(0.58 * var(--ysize)); +.reveal section.slide.author h1 { font-size: 0.6em; font-weight: bold; } -.reveal .author p, -.reveal .author div { - padding-bottom: 1.4em; - font-size: 0.5em; -} -.reveal .author img { +.reveal section.slide.author img { position: absolute; + top: 0; + left: calc(-0.167 * var(--xsize)); width: calc(0.142 * var(--xsize)); - top: calc(0.578 * var(--ysize)); - left: calc(0.073 * var(--xsize)); + max-width: unset; + max-height: unset; border: 0; } - -/********************************************* - * PDF printing - *********************************************/ -.reveal .slides .pdf-page > section h1:first-child { - padding-bottom: 1.7em; -} -.reveal .slides .pdf-page > section h2:first-child, -.reveal .slides .pdf-page > section h3:first-child, -.reveal .slides .pdf-page > section h1:first-child + h2, -.reveal .slides .pdf-page > section h1:first-child + h3, -.reveal .column .pdf-page h2:first-child, -.reveal .column .pdf-page h3:first-child { - padding-top: 0; -} -.reveal .slides .pdf-page > section:before { - content: ""; - display: block; - margin-top: var(--ymargin); -} - -.reveal .slides .pdf-page > section.title h1:first-child { - padding-bottom: 1ex; -} -.reveal .slides .pdf-page > section.author h1:first-child { - padding-bottom: 1.4em; -} diff --git a/theme/csc-plain/defaults.yaml b/theme/csc-plain/defaults.yaml new file mode 100644 index 0000000..134a4f5 --- /dev/null +++ b/theme/csc-plain/defaults.yaml @@ -0,0 +1,15 @@ +--- +standalone: true +from: markdown-native_divs +to: revealjs +variables: + width: 1920 + height: 1080 + history: true + center: false + controls: false + transition: none + backgroundTransition: none +highlight-style: pygments +... +--- diff --git a/theme/csc-plain/img/author.svg b/theme/csc-plain/img/author.svg new file mode 100644 index 0000000..e2e71c2 --- /dev/null +++ b/theme/csc-plain/img/author.svg @@ -0,0 +1,1047 @@ + + + + diff --git a/theme/csc-plain/img/normal.svg b/theme/csc-plain/img/normal.svg new file mode 100644 index 0000000..7ac69c7 --- /dev/null +++ b/theme/csc-plain/img/normal.svg @@ -0,0 +1,63 @@ + + + + diff --git a/theme/csc-plain/img/title.svg b/theme/csc-plain/img/title.svg new file mode 100644 index 0000000..45318ea --- /dev/null +++ b/theme/csc-plain/img/title.svg @@ -0,0 +1,94 @@ + + + + diff --git a/theme/csc-2016-prace/template.html b/theme/csc-plain/template.html similarity index 52% rename from theme/csc-2016-prace/template.html rename to theme/csc-plain/template.html index cd05160..e2fe52f 100644 --- a/theme/csc-2016-prace/template.html +++ b/theme/csc-plain/template.html @@ -16,38 +16,35 @@ - - -$if(quotes)$ - -$endif$ -$if(highlighting-css)$ - +$if(theme-url)$ + +$elseif(theme)$ + +$else$ + $endif$ - - $for(css)$ $endfor$ - - - $if(math)$ $math$ $endif$ $for(header-includes)$ $header-includes$ $endfor$ + $for(include-before)$ @@ -57,30 +54,38 @@
$if(title)$ -
-

$title$

+
+

$title$

$if(subtitle)$ -

$subtitle$

+

$subtitle$

$endif$ $if(event)$ $if(date)$ -

$event$, $date$

+

$event$, $date$

$else$ -

$event$

+

$event$

$endif$ $else$ $if(date)$ -

$date$

+

$date$

$endif$ $endif$ -$if(author)$ -

$author$

-$endif$ +$for(author)$ +

$author$

+$endfor$ +$for(institute)$ +

$institute$

+$endfor$
$endif$ $if(toc)$
-$toc$ +
$endif$ @@ -88,147 +93,213 @@

$title$

- - + + + + + + +$if(mathjax)$ + +$endif$ diff --git a/theme/default b/theme/default deleted file mode 120000 index 1f63b0c..0000000 --- a/theme/default +++ /dev/null @@ -1 +0,0 @@ -csc-2016/ \ No newline at end of file