nbpresent themes are a simple data structure with a lot of flexibility. They reflect a data-driven view of style, and make some use of references, as for colors. More work needs to be done, especially surrounding reuse!
In this notebook, we look at the themes from revealjs which has provided so many inspirations for nbpresent.
In [407]:
from os.path import join, basename, splitext, abspath
from glob import glob
import re
from pprint import pprint
from collections import defaultdict
from copy import deepcopy
import json
from uuid import uuid4
import colour
import jinja2
import yaml
from IPython.display import Javascript, display, Markdown
In [383]:
var_re = r"^(\$.*)\s*:\s*(.*);"
All sizes in nbpresent are specified in rem
, a device-aware measure that helps avoid surprises. reveal uses a selection of measures, mostly based on em
. I figured these out just by trying it, but there may indeed be a more elegant and robust way to calculate these.
In [384]:
sizes = {
"38px": 6,
"36px": 5,
"30px": 4,
"1.0em": 3,
"1.00em": 3,
"1.3em": 3.5,
"1.55em": 3.75,
"1.6em": 4,
"2.11em": 5,
"2.5em": 5.25,
"3.77em": 7
}
fonts = {
"League Gothic": "Oswald",
"Palatino Linotype": "EB Garamond"
}
In [385]:
def update_headings(rules, directives):
for i in range(1, 8):
rules["h{}".format(i)].update(directives)
In [412]:
def pretty(theme):
display(Markdown("""```yaml\n{}\n```""".format(
yaml.safe_dump(yaml.safe_load(json.dumps(theme))))))
In [413]:
def make_theme(scss, theme_id=None, theme=None):
theme = deepcopy(theme) or {}
theme["id"] = theme_id = theme_id or str(uuid4())
palette = theme["palette"] = theme.get("palette", {})
backgrounds = theme["backgrounds"] = theme.get("backgrounds", {})
rules = theme["rules"] = theme.get("rules", defaultdict(dict))
base = theme["text-base"] = rules["p"] = rules["li"] = theme.get("text-base", {"font-size": 3})
all_vars = dict([
(name, val)
for name, val in
re.findall(var_re, scss, flags=re.M)
])
# handle colors
for name, val in all_vars.items():
if "Color" in name and "selection" not in name and "Hover" not in name:
if val in all_vars:
val = all_vars[val]
cid = name[1:]
palette[cid] = {
"id": cid,
"rgb": [int(256 * c) for c in colour.Color(val).rgb]
}
if "background" in name:
backgrounds[cid] = {
"id": cid,
"background-color": cid
}
elif "heading" in name:
update_headings(rules, {"color": cid})
elif "main" in name:
base["color"] = cid
elif "link" in name:
rules["a"]["color"] = cid
else:
print(theme_id, name, val)
elif re.match(r".*Font$", name):
font = val.split(",")[0].replace("'", "")
if font in fonts:
font = fonts[font]
if "heading" in name:
update_headings(rules, {"font-family": font})
elif "main" in name:
base["font-family"] = font
elif "Size" in name:
size = sizes[val]
if "main" in name:
base["font-size"] = size
elif "heading" in name:
h = "h{}".format(*re.findall(r'\d+', name))
rules[h]["font-size"] = size
return theme
In [414]:
#!git clone https://github.com/hakimel/reveal.js.git ../../revealjs
In [415]:
reveal = abspath(join("..", "..", "revealjs"))
reveal_version = json.load(open(join(reveal, "package.json")))["version"]
reveal_version
Out[415]:
In [416]:
settings = open(join(reveal, "css", "theme", "template", "settings.scss")).read()
base_theme = make_theme(settings)
pretty(base_theme)
In [390]:
scss = dict([
(
"{}-by-revealjs-{}".format(splitext(basename(fname))[0],
reveal_version),
open(fname).read()
)
for fname in glob(join(reveal, "css", "theme", "source", "*.scss"))
])
len(scss)
Out[390]:
In [391]:
themes = dict([
(name, make_theme(s, name, base_theme))
for name, s in scss.items()])
In [423]:
list(map(pretty, themes.values()));
In [424]:
Javascript(jinja2.Template("""
require(["nbextensions/nbpresent/js/nbpresent.min"], function(nbpresent){
nbpresent.initialized().then(function(nbpresent){
nbpresent.mode.tree.set(["themes", "theme"], {{ themes }});
});
});
""").render(themes=json.dumps(themes, indent=2)))
Out[424]:
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
In [433]:
es6_tmpl = jinja2.Template("""/*
THIS IS GENERATED CODE BY /notebooks/Importing revealjs themes.ipynb
DO NOT EDIT DIRECTLY
Source content:
https://github.com/hakimel/reveal.js/tree/master/css/theme
All original themes copyright their respective creators:
beige Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
black Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
blood Author: Walther http://github.com/Walther
league Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
moon Author: Achim Staebler
night Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
serif Copyright (C) 2012-2013 Owen Versteeg, http://owenversteeg.com - it is MIT licensed.
simple Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed.
sky Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
solarized Author: Achim Staebler
white By Hakim El Hattab, http://hakim.se
*/
export const REVEAL_THEMES = {{ themes }};
""")
with open(join("..", "src", "es6", "theme", "theme", "reveal.es6"), "w") as es6:
es6.write(es6_tmpl.render(themes=json.dumps(themes, indent=2)))