mirror of
https://github.com/jeertmans/manim-slides.git
synced 2025-09-17 11:12:39 +08:00
feat(cli): feally featured RevealJS template (#80)
* feat(cli): feally featured RevealJS template This adds an option for every possible RevealJS option. Error messages are also improved. RevealJS version is bumped to latest (4.4.0). * feat(cli): add primitive support for arbitrary JS functions * fix(cli): some typos / issues in template * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix(lib): pickling issue * fix(lib): ignore typing error due to __reduce_ex__ * feat(cli): add template selection, fixes first slide bug, and rm stuff Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
2
.github/workflows/pages.yml
vendored
2
.github/workflows/pages.yml
vendored
@ -48,7 +48,7 @@ jobs:
|
|||||||
- name: Build animation and convert it into HTML slides
|
- name: Build animation and convert it into HTML slides
|
||||||
run: |
|
run: |
|
||||||
poetry run manim example.py ConvertExample
|
poetry run manim example.py ConvertExample
|
||||||
poetry run manim-slides convert ConvertExample docs/source/_static/slides.html -cembedded=true -ccontrols=true
|
poetry run manim-slides convert ConvertExample docs/source/_static/slides.html -ccontrols=true
|
||||||
- name: Build docs
|
- name: Build docs
|
||||||
run: cd docs && make html
|
run: cd docs && make html
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -23,3 +23,7 @@ docs/build/
|
|||||||
docs/source/_static/slides_assets/
|
docs/source/_static/slides_assets/
|
||||||
|
|
||||||
docs/source/_static/slides.html
|
docs/source/_static/slides.html
|
||||||
|
|
||||||
|
slides_assets/
|
||||||
|
|
||||||
|
slides.html
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import os
|
import os
|
||||||
import webbrowser
|
import webbrowser
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Any, Callable, Dict, Generator, List, Type
|
from typing import Any, Callable, Dict, Generator, List, Optional, Type, Union
|
||||||
|
|
||||||
import click
|
import click
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
from click import Context, Parameter
|
from click import Context, Parameter
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel, PositiveInt, ValidationError
|
||||||
|
|
||||||
from .commons import folder_path_option, verbosity_option
|
from .commons import folder_path_option, verbosity_option
|
||||||
from .config import PresentationConfig
|
from .config import PresentationConfig
|
||||||
@ -34,14 +34,21 @@ def validate_config_option(
|
|||||||
class Converter(BaseModel): # type: ignore
|
class Converter(BaseModel): # type: ignore
|
||||||
presentation_configs: List[PresentationConfig] = []
|
presentation_configs: List[PresentationConfig] = []
|
||||||
assets_dir: str = "{basename}_assets"
|
assets_dir: str = "{basename}_assets"
|
||||||
|
template: Optional[str] = None
|
||||||
|
|
||||||
def convert_to(self, dest: str) -> None:
|
def convert_to(self, dest: str) -> None:
|
||||||
"""Converts self, i.e., a list of presentations, into a given format."""
|
"""Converts self, i.e., a list of presentations, into a given format."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def load_template(self) -> str:
|
||||||
|
"""Returns the template as a string.
|
||||||
|
|
||||||
|
An empty string is returned if no template is used."""
|
||||||
|
return ""
|
||||||
|
|
||||||
def open(self, file: str) -> bool:
|
def open(self, file: str) -> bool:
|
||||||
"""Opens a file, generated with converter, using appropriate application."""
|
"""Opens a file, generated with converter, using appropriate application."""
|
||||||
return webbrowser.open(file)
|
raise NotImplementedError
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_string(cls, s: str) -> Type["Converter"]:
|
def from_string(cls, s: str) -> Type["Converter"]:
|
||||||
@ -51,11 +58,126 @@ class Converter(BaseModel): # type: ignore
|
|||||||
}[s]
|
}[s]
|
||||||
|
|
||||||
|
|
||||||
class JSBool(str, Enum):
|
class Str(str):
|
||||||
|
"""A simple string, but quoted when needed."""
|
||||||
|
|
||||||
|
# This fixes pickling issue on Python 3.8
|
||||||
|
__reduce_ex__ = str.__reduce_ex__
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
"""Ensures that the string is correctly quoted."""
|
||||||
|
if self in ["true", "false", "null"]:
|
||||||
|
return super().__str__()
|
||||||
|
else:
|
||||||
|
return f"'{super().__str__()}'"
|
||||||
|
|
||||||
|
|
||||||
|
Function = str # Basically, anything
|
||||||
|
|
||||||
|
|
||||||
|
class JsTrue(str, Enum):
|
||||||
|
true = "true"
|
||||||
|
|
||||||
|
|
||||||
|
class JsFalse(str, Enum):
|
||||||
|
false = "false"
|
||||||
|
|
||||||
|
|
||||||
|
class JsBool(Str, Enum): # type: ignore
|
||||||
true = "true"
|
true = "true"
|
||||||
false = "false"
|
false = "false"
|
||||||
|
|
||||||
|
|
||||||
|
class JsNull(Str, Enum): # type: ignore
|
||||||
|
null = "null"
|
||||||
|
|
||||||
|
|
||||||
|
class ControlsLayout(Str, Enum): # type: ignore
|
||||||
|
edges = "edges"
|
||||||
|
bottom_right = "bottom-right"
|
||||||
|
|
||||||
|
|
||||||
|
class ControlsBackArrows(Str, Enum): # type: ignore
|
||||||
|
faded = "faded"
|
||||||
|
hidden = "hidden"
|
||||||
|
visibly = "visibly"
|
||||||
|
|
||||||
|
|
||||||
|
class SlideNumber(Str, Enum): # type: ignore
|
||||||
|
true = "true"
|
||||||
|
false = "false"
|
||||||
|
hdotv = "h.v"
|
||||||
|
handv = "h/v"
|
||||||
|
c = "c"
|
||||||
|
candt = "c/t"
|
||||||
|
|
||||||
|
|
||||||
|
class ShowSlideNumber(Str, Enum): # type: ignore
|
||||||
|
all = "all"
|
||||||
|
print = "print"
|
||||||
|
speaker = "speaker"
|
||||||
|
|
||||||
|
|
||||||
|
class KeyboardCondition(Str, Enum): # type: ignore
|
||||||
|
null = "null"
|
||||||
|
focused = "focused"
|
||||||
|
|
||||||
|
|
||||||
|
class NavigationMode(Str, Enum): # type: ignore
|
||||||
|
default = "default"
|
||||||
|
linear = "linear"
|
||||||
|
grid = "grid"
|
||||||
|
|
||||||
|
|
||||||
|
class AutoPlayMedia(Str, Enum): # type: ignore
|
||||||
|
null = "null"
|
||||||
|
true = "true"
|
||||||
|
false = "false"
|
||||||
|
|
||||||
|
|
||||||
|
PreloadIframes = AutoPlayMedia
|
||||||
|
|
||||||
|
|
||||||
|
class AutoAnimateMatcher(Str, Enum): # type: ignore
|
||||||
|
null = "null"
|
||||||
|
|
||||||
|
|
||||||
|
class AutoAnimateEasing(Str, Enum): # type: ignore
|
||||||
|
ease = "ease"
|
||||||
|
|
||||||
|
|
||||||
|
AutoSlide = Union[PositiveInt, JsFalse]
|
||||||
|
|
||||||
|
|
||||||
|
class AutoSlideMethod(Str, Enum): # type: ignore
|
||||||
|
null = "null"
|
||||||
|
|
||||||
|
|
||||||
|
MouseWheel = Union[JsNull, float]
|
||||||
|
|
||||||
|
|
||||||
|
class Transition(Str, Enum): # type: ignore
|
||||||
|
none = "none"
|
||||||
|
fade = "fade"
|
||||||
|
slide = "slide"
|
||||||
|
convex = "convex"
|
||||||
|
concave = "concave"
|
||||||
|
zoom = "zoom"
|
||||||
|
|
||||||
|
|
||||||
|
class TransitionSpeed(Str, Enum): # type: ignore
|
||||||
|
default = "default"
|
||||||
|
fast = "fast"
|
||||||
|
slow = "slow"
|
||||||
|
|
||||||
|
|
||||||
|
BackgroundTransition = Transition
|
||||||
|
|
||||||
|
|
||||||
|
class Display(Str, Enum): # type: ignore
|
||||||
|
block = "block"
|
||||||
|
|
||||||
|
|
||||||
class RevealTheme(str, Enum):
|
class RevealTheme(str, Enum):
|
||||||
black = "black"
|
black = "black"
|
||||||
white = "white"
|
white = "white"
|
||||||
@ -71,21 +193,90 @@ class RevealTheme(str, Enum):
|
|||||||
|
|
||||||
|
|
||||||
class RevealJS(Converter):
|
class RevealJS(Converter):
|
||||||
background_color: str = "black"
|
# Presentation size options from RevealJS
|
||||||
controls: JSBool = JSBool.false
|
width: Union[Str, int] = Str("100%")
|
||||||
embedded: JSBool = JSBool.false
|
height: Union[Str, int] = Str("100%")
|
||||||
fragments: JSBool = JSBool.false
|
margin: float = 0.04
|
||||||
height: str = "100%"
|
min_scale: float = 0.2
|
||||||
loop: JSBool = JSBool.false
|
max_scale: float = 2.0
|
||||||
progress: JSBool = JSBool.false
|
# Configuration options from RevealJS
|
||||||
reveal_version: str = "3.7.0"
|
controls: JsBool = JsBool.false
|
||||||
|
controls_tutorial: JsBool = JsBool.true
|
||||||
|
controls_layout: ControlsLayout = ControlsLayout.bottom_right
|
||||||
|
controls_back_arrows: ControlsBackArrows = ControlsBackArrows.faded
|
||||||
|
progress: JsBool = JsBool.false
|
||||||
|
slide_number: SlideNumber = SlideNumber.false
|
||||||
|
show_slide_number: Union[ShowSlideNumber, Function] = ShowSlideNumber.all
|
||||||
|
hash_one_based_index: JsBool = JsBool.false
|
||||||
|
hash: JsBool = JsBool.false
|
||||||
|
respond_to_hash_changes: JsBool = JsBool.false
|
||||||
|
history: JsBool = JsBool.false
|
||||||
|
keyboard: JsBool = JsBool.true
|
||||||
|
keyboard_condition: Union[KeyboardCondition, Function] = KeyboardCondition.null
|
||||||
|
disable_layout: JsBool = JsBool.false
|
||||||
|
overview: JsBool = JsBool.true
|
||||||
|
center: JsBool = JsBool.true
|
||||||
|
touch: JsBool = JsBool.true
|
||||||
|
loop: JsBool = JsBool.false
|
||||||
|
rtl: JsBool = JsBool.false
|
||||||
|
navigation_mode: NavigationMode = NavigationMode.default
|
||||||
|
shuffle: JsBool = JsBool.false
|
||||||
|
fragments: JsBool = JsBool.true
|
||||||
|
fragment_in_url: JsBool = JsBool.true
|
||||||
|
embedded: JsBool = JsBool.false
|
||||||
|
help: JsBool = JsBool.true
|
||||||
|
pause: JsBool = JsBool.true
|
||||||
|
show_notes: JsBool = JsBool.false
|
||||||
|
auto_play_media: AutoPlayMedia = AutoPlayMedia.null
|
||||||
|
preload_iframes: PreloadIframes = PreloadIframes.null
|
||||||
|
auto_animate: JsBool = JsBool.true
|
||||||
|
auto_animate_matcher: Union[AutoAnimateMatcher, Function] = AutoAnimateMatcher.null
|
||||||
|
auto_animate_easing: AutoAnimateEasing = AutoAnimateEasing.ease
|
||||||
|
auto_animate_duration: float = 1.0
|
||||||
|
auto_animate_unmatched: JsBool = JsBool.true
|
||||||
|
auto_animate_styles: List[str] = [
|
||||||
|
"opacity",
|
||||||
|
"color",
|
||||||
|
"background-color",
|
||||||
|
"padding",
|
||||||
|
"font-size",
|
||||||
|
"line-height",
|
||||||
|
"letter-spacing",
|
||||||
|
"border-width",
|
||||||
|
"border-color",
|
||||||
|
"border-radius",
|
||||||
|
"outline",
|
||||||
|
"outline-offset",
|
||||||
|
]
|
||||||
|
auto_slide: AutoSlide = 0
|
||||||
|
auto_slide_stoppable: JsBool = JsBool.true
|
||||||
|
auto_slide_method: Union[AutoSlideMethod, Function] = AutoSlideMethod.null
|
||||||
|
default_timing: Union[JsNull, int] = JsNull.null
|
||||||
|
mouse_wheel: JsBool = JsBool.false
|
||||||
|
preview_links: JsBool = JsBool.false
|
||||||
|
post_message: JsBool = JsBool.true
|
||||||
|
post_message_events: JsBool = JsBool.false
|
||||||
|
focus_body_on_page_visibility_change: JsBool = JsBool.true
|
||||||
|
transition: Transition = Transition.none
|
||||||
|
transition_speed: TransitionSpeed = TransitionSpeed.default
|
||||||
|
background_transition: BackgroundTransition = BackgroundTransition.none
|
||||||
|
pdf_max_pages_per_slide: Union[int, str] = "Number.POSITIVE_INFINITY"
|
||||||
|
pdf_separate_fragments: JsBool = JsBool.true
|
||||||
|
pdf_page_height_offset: int = -1
|
||||||
|
view_distance: int = 3
|
||||||
|
mobile_view_distance: int = 2
|
||||||
|
display: Display = Display.block
|
||||||
|
hide_inactive_cursor: JsBool = JsBool.true
|
||||||
|
hide_cursor_time: int = 5000
|
||||||
|
# Add. options
|
||||||
|
background_color: str = "black" # TODO: use pydantic.color.Color
|
||||||
|
reveal_version: str = "4.4.0"
|
||||||
reveal_theme: RevealTheme = RevealTheme.black
|
reveal_theme: RevealTheme = RevealTheme.black
|
||||||
shuffle: JSBool = JSBool.false
|
|
||||||
title: str = "Manim Slides"
|
title: str = "Manim Slides"
|
||||||
width: str = "100%"
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
use_enum_values = True
|
use_enum_values = True
|
||||||
|
extra = "forbid"
|
||||||
|
|
||||||
def get_sections_iter(self) -> Generator[str, None, None]:
|
def get_sections_iter(self) -> Generator[str, None, None]:
|
||||||
"""Generates a sequence of sections, one per slide, that will be included into the html template."""
|
"""Generates a sequence of sections, one per slide, that will be included into the html template."""
|
||||||
@ -94,17 +285,27 @@ class RevealJS(Converter):
|
|||||||
file = presentation_config.files[slide_config.start_animation]
|
file = presentation_config.files[slide_config.start_animation]
|
||||||
file = os.path.join(self.assets_dir, os.path.basename(file))
|
file = os.path.join(self.assets_dir, os.path.basename(file))
|
||||||
|
|
||||||
|
# TODO: document this
|
||||||
|
# Videos are muted because, otherwise, the first slide never plays correctly.
|
||||||
|
# This is due to a restriction in playing audio without the user doing anything.
|
||||||
|
# Later, this might be useful to only mute the first video, or to make it optional.
|
||||||
if slide_config.is_loop():
|
if slide_config.is_loop():
|
||||||
yield f'<section data-background-video="{file}" data-background-video-loop></section>'
|
yield f'<section data-background-video="{file}" data-background-video-muted data-background-video-loop></section>'
|
||||||
else:
|
else:
|
||||||
yield f'<section data-background-video="{file}"></section>'
|
yield f'<section data-background-video="{file}" data-background-video-muted></section>'
|
||||||
|
|
||||||
def load_template(self) -> str:
|
def load_template(self) -> str:
|
||||||
"""Returns the RevealJS HTML template as a string."""
|
"""Returns the RevealJS HTML template as a string."""
|
||||||
|
if isinstance(self.template, str):
|
||||||
|
with open(self.template, "r") as f:
|
||||||
|
return f.read()
|
||||||
return pkg_resources.resource_string(
|
return pkg_resources.resource_string(
|
||||||
__name__, "data/revealjs_template.html"
|
__name__, "data/revealjs_template.html"
|
||||||
).decode()
|
).decode()
|
||||||
|
|
||||||
|
def open(self, file: str) -> bool:
|
||||||
|
return webbrowser.open(file)
|
||||||
|
|
||||||
def convert_to(self, dest: str) -> None:
|
def convert_to(self, dest: str) -> None:
|
||||||
"""Converts this configuration into a RevealJS HTML presentation, saved to DEST."""
|
"""Converts this configuration into a RevealJS HTML presentation, saved to DEST."""
|
||||||
dirname = os.path.dirname(dest)
|
dirname = os.path.dirname(dest)
|
||||||
@ -138,19 +339,13 @@ def show_config_options(function: Callable[..., Any]) -> Callable[..., Any]:
|
|||||||
if not value or ctx.resilient_parsing:
|
if not value or ctx.resilient_parsing:
|
||||||
return
|
return
|
||||||
|
|
||||||
to = ctx.params.get("to")
|
to = ctx.params.get("to", "html")
|
||||||
|
|
||||||
if to:
|
converter = Converter.from_string(to)(presentation_configs=[])
|
||||||
converter = Converter.from_string(to)(scenes=[])
|
for key, value in converter.dict().items():
|
||||||
for key, value in converter.dict().items():
|
click.echo(f"{key}: {repr(value)}")
|
||||||
click.echo(f"{key}: {repr(value)}")
|
|
||||||
|
|
||||||
ctx.exit()
|
ctx.exit()
|
||||||
|
|
||||||
else:
|
|
||||||
raise click.UsageError(
|
|
||||||
"Using --show-config option requires to first specify --to option."
|
|
||||||
)
|
|
||||||
|
|
||||||
return click.option(
|
return click.option(
|
||||||
"--show-config",
|
"--show-config",
|
||||||
@ -163,6 +358,35 @@ def show_config_options(function: Callable[..., Any]) -> Callable[..., Any]:
|
|||||||
)(function)
|
)(function)
|
||||||
|
|
||||||
|
|
||||||
|
def show_template_option(function: Callable[..., Any]) -> Callable[..., Any]:
|
||||||
|
"""Wraps a function to add a `--show-template` option."""
|
||||||
|
|
||||||
|
def callback(ctx: Context, param: Parameter, value: bool) -> None:
|
||||||
|
|
||||||
|
if not value or ctx.resilient_parsing:
|
||||||
|
return
|
||||||
|
|
||||||
|
to = ctx.params.get("to", "html")
|
||||||
|
template = ctx.params.get("template", None)
|
||||||
|
|
||||||
|
converter = Converter.from_string(to)(
|
||||||
|
presentation_configs=[], template=template
|
||||||
|
)
|
||||||
|
click.echo(converter.load_template())
|
||||||
|
|
||||||
|
ctx.exit()
|
||||||
|
|
||||||
|
return click.option(
|
||||||
|
"--show-template",
|
||||||
|
is_flag=True,
|
||||||
|
help="Show the template (currently) used for a given conversion format and exit.",
|
||||||
|
default=None,
|
||||||
|
expose_value=False,
|
||||||
|
show_envvar=True,
|
||||||
|
callback=callback,
|
||||||
|
)(function)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.argument("scenes", nargs=-1)
|
@click.argument("scenes", nargs=-1)
|
||||||
@folder_path_option
|
@folder_path_option
|
||||||
@ -187,8 +411,16 @@ def show_config_options(function: Callable[..., Any]) -> Callable[..., Any]:
|
|||||||
"config_options",
|
"config_options",
|
||||||
multiple=True,
|
multiple=True,
|
||||||
callback=validate_config_option,
|
callback=validate_config_option,
|
||||||
help="Configuration options passed to the converter. E.g., pass `-cbackground_color=red` to set the background color to red (if supported).",
|
help="Configuration options passed to the converter. E.g., pass `-cshow_number=true` to display slide numbers.",
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
"--use-template",
|
||||||
|
"template",
|
||||||
|
metavar="FILE",
|
||||||
|
type=click.Path(exists=True, dir_okay=False),
|
||||||
|
help="Use the template given by FILE instead of default one. To echo the default template, use `--show-template`.",
|
||||||
|
)
|
||||||
|
@show_template_option
|
||||||
@show_config_options
|
@show_config_options
|
||||||
@verbosity_option
|
@verbosity_option
|
||||||
def convert(
|
def convert(
|
||||||
@ -199,6 +431,7 @@ def convert(
|
|||||||
open_result: bool,
|
open_result: bool,
|
||||||
force: bool,
|
force: bool,
|
||||||
config_options: Dict[str, str],
|
config_options: Dict[str, str],
|
||||||
|
template: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Convert SCENE(s) into a given format and writes the result in DEST.
|
Convert SCENE(s) into a given format and writes the result in DEST.
|
||||||
@ -206,11 +439,29 @@ def convert(
|
|||||||
|
|
||||||
presentation_configs = get_scenes_presentation_config(scenes, folder)
|
presentation_configs = get_scenes_presentation_config(scenes, folder)
|
||||||
|
|
||||||
converter = Converter.from_string(to)(
|
try:
|
||||||
presentation_configs=presentation_configs, **config_options
|
converter = Converter.from_string(to)(
|
||||||
)
|
presentation_configs=presentation_configs,
|
||||||
|
template=template,
|
||||||
|
**config_options,
|
||||||
|
)
|
||||||
|
|
||||||
converter.convert_to(dest)
|
converter.convert_to(dest)
|
||||||
|
|
||||||
if open_result:
|
if open_result:
|
||||||
converter.open(dest)
|
converter.open(dest)
|
||||||
|
|
||||||
|
except ValidationError as e:
|
||||||
|
|
||||||
|
errors = e.errors()
|
||||||
|
|
||||||
|
msg = [
|
||||||
|
f"{len(errors)} error(s) occured with configuration options for '{to}', see below."
|
||||||
|
]
|
||||||
|
|
||||||
|
for error in errors:
|
||||||
|
option = error["loc"][0]
|
||||||
|
_msg = error["msg"]
|
||||||
|
msg.append(f"Option '{option}': {_msg}")
|
||||||
|
|
||||||
|
raise click.UsageError("\n".join(msg))
|
||||||
|
@ -1,185 +1,291 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
|
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@{reveal_version}/css/reveal.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/{reveal_version}/reveal.min.css">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@{reveal_version}/css/theme/{reveal_theme}.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/{reveal_version}/theme/{reveal_theme}.min.css">
|
||||||
|
|
||||||
<!-- Theme used for syntax highlighting of code -->
|
<!-- Theme used for syntax highlighting of code -->
|
||||||
<!-- <link rel="stylesheet" href="lib/css/zenburn.css"> -->
|
<!-- <link rel="stylesheet" href="lib/css/zenburn.css"> -->
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/zenburn.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/zenburn.min.css">
|
||||||
|
|
||||||
<!-- Printing and PDF exports -->
|
<!-- <link rel="stylesheet" href="index.css"> -->
|
||||||
<script>
|
</head>
|
||||||
var link = document.createElement('link');
|
|
||||||
link.rel = 'stylesheet';
|
|
||||||
link.type = 'text/css';
|
|
||||||
link.href = window.location.search.match(/print-pdf/gi) ? 'https://cdn.jsdelivr.net/npm/reveal.js@{reveal_version}/css/print/pdf.css' : 'https://cdn.jsdelivr.net/npm/reveal.js@{reveal_version}/css/print/paper.css';
|
|
||||||
document.getElementsByTagName('head')[0].appendChild(link);
|
|
||||||
</script>
|
|
||||||
<!-- <link rel="stylesheet" href="index.css"> -->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="reveal">
|
<div class="reveal">
|
||||||
<div class="slides">
|
<div class="slides">
|
||||||
{sections}
|
{sections}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--<script src="lib/js/head.min.js"></script>-->
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/{reveal_version}/reveal.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/headjs@1.0.3/dist/1.0.0/head.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/reveal.js@{reveal_version}/js/reveal.min.js"></script>
|
|
||||||
|
|
||||||
<!-- <script src="index.js"></script> -->
|
<!-- To include plugins, see: https://revealjs.com/plugins/ -->
|
||||||
<script>
|
|
||||||
// More info about config & dependencies:
|
|
||||||
// - https://github.com/hakimel/reveal.js#configuration
|
|
||||||
// - https://github.com/hakimel/reveal.js#dependencies
|
|
||||||
Reveal.initialize({{
|
|
||||||
// Display controls in the bottom right corner
|
|
||||||
controls: {controls},
|
|
||||||
|
|
||||||
width: '{width}',
|
<!-- <script src="index.js"></script> -->
|
||||||
height: '{height}',
|
<script>
|
||||||
|
Reveal.initialize({{
|
||||||
|
|
||||||
// Display a presentation progress bar
|
// The "normal" size of the presentation, aspect ratio will
|
||||||
progress: {progress},
|
// be preserved when the presentation is scaled to fit different
|
||||||
|
// resolutions. Can be specified using percentage units.
|
||||||
|
width: {width},
|
||||||
|
height: {height},
|
||||||
|
|
||||||
// Set default timing of 2 minutes per slide
|
// Factor of the display size that should remain empty around
|
||||||
defaultTiming: 120,
|
// the content
|
||||||
|
margin: {margin},
|
||||||
|
|
||||||
// Display the page number of the current slide
|
// Bounds for smallest/largest possible scale to apply to content
|
||||||
slideNumber: true,
|
minScale: {min_scale},
|
||||||
|
maxScale: {max_scale},
|
||||||
|
|
||||||
// Push each slide change to the browser history
|
// Display presentation control arrows
|
||||||
history: false,
|
controls: {controls},
|
||||||
|
|
||||||
// Enable keyboard shortcuts for navigation
|
// Help the user learn the controls by providing hints, for example by
|
||||||
keyboard: true,
|
// bouncing the down arrow when they first encounter a vertical slide
|
||||||
|
controlsTutorial: {controls_tutorial},
|
||||||
|
|
||||||
// Enable the slide overview mode
|
// Determines where controls appear, "edges" or "bottom-right"
|
||||||
overview: true,
|
controlsLayout: {controls_layout},
|
||||||
|
|
||||||
// Vertical centering of slides
|
// Visibility rule for backwards navigation arrows; "faded", "hidden"
|
||||||
center: true,
|
// or "visible"
|
||||||
|
controlsBackArrows: {controls_back_arrows},
|
||||||
|
|
||||||
// Enables touch navigation on devices with touch input
|
// Display a presentation progress bar
|
||||||
touch: true,
|
progress: {progress},
|
||||||
|
|
||||||
// Loop the presentation
|
// Display the page number of the current slide
|
||||||
loop: {loop},
|
// - true: Show slide number
|
||||||
|
// - false: Hide slide number
|
||||||
|
//
|
||||||
|
// Can optionally be set as a string that specifies the number formatting:
|
||||||
|
// - "h.v": Horizontal . vertical slide number (default)
|
||||||
|
// - "h/v": Horizontal / vertical slide number
|
||||||
|
// - "c": Flattened slide number
|
||||||
|
// - "c/t": Flattened slide number / total slides
|
||||||
|
//
|
||||||
|
// Alternatively, you can provide a function that returns the slide
|
||||||
|
// number for the current slide. The function should take in a slide
|
||||||
|
// object and return an array with one string [slideNumber] or
|
||||||
|
// three strings [n1,delimiter,n2]. See #formatSlideNumber().
|
||||||
|
slideNumber: {slide_number},
|
||||||
|
|
||||||
// Change the presentation direction to be RTL
|
// Can be used to limit the contexts in which the slide number appears
|
||||||
rtl: false,
|
// - "all": Always show the slide number
|
||||||
|
// - "print": Only when printing to PDF
|
||||||
|
// - "speaker": Only in the speaker view
|
||||||
|
showSlideNumber: {show_slide_number},
|
||||||
|
|
||||||
// Randomizes the order of slides each time the presentation loads
|
// Use 1 based indexing for # links to match slide number (default is zero
|
||||||
shuffle: {shuffle},
|
// based)
|
||||||
|
hashOneBasedIndex: {hash_one_based_index},
|
||||||
|
|
||||||
// Turns fragments on and off globally
|
// Add the current slide number to the URL hash so that reloading the
|
||||||
fragments: {fragments},
|
// page/copying the URL will return you to the same slide
|
||||||
|
hash: {hash},
|
||||||
|
|
||||||
// Flags if the presentation is running in an embedded mode,
|
// Flags if we should monitor the hash and change slides accordingly
|
||||||
// i.e. contained within a limited portion of the screen
|
respondToHashChanges: {respond_to_hash_changes},
|
||||||
embedded: {embedded},
|
|
||||||
|
|
||||||
// Flags if we should show a help overlay when the questionmark
|
// Push each slide change to the browser history. Implies `hash: true`
|
||||||
// key is pressed
|
history: {history},
|
||||||
help: true,
|
|
||||||
|
|
||||||
// Flags if speaker notes should be visible to all viewers
|
// Enable keyboard shortcuts for navigation
|
||||||
showNotes: false,
|
keyboard: {keyboard},
|
||||||
|
|
||||||
// Global override for autolaying embedded media (video/audio/iframe)
|
// Optional function that blocks keyboard events when retuning false
|
||||||
// - null: Media will only autoplay if data-autoplay is present
|
//
|
||||||
// - true: All media will autoplay, regardless of individual setting
|
// If you set this to 'focused', we will only capture keyboard events
|
||||||
// - false: No media will autoplay, regardless of individual setting
|
// for embedded decks when they are in focus
|
||||||
autoPlayMedia: null,
|
keyboardCondition: {keyboard_condition},
|
||||||
|
|
||||||
// Number of milliseconds between automatically proceeding to the
|
// Disables the default reveal.js slide layout (scaling and centering)
|
||||||
// next slide, disabled when set to 0, this value can be overwritten
|
// so that you can use custom CSS layout
|
||||||
// by using a data-autoslide attribute on your slides
|
disableLayout: {disable_layout},
|
||||||
autoSlide: 0,
|
|
||||||
|
|
||||||
// Stop auto-sliding after user input
|
// Enable the slide overview mode
|
||||||
autoSlideStoppable: true,
|
overview: {overview},
|
||||||
|
|
||||||
// Use this method for navigation when auto-sliding
|
// Vertical centering of slides
|
||||||
autoSlideMethod: Reveal.navigateNext,
|
center: {center},
|
||||||
|
|
||||||
// Enable slide navigation via mouse wheel
|
// Enables touch navigation on devices with touch input
|
||||||
mouseWheel: false,
|
touch: {touch},
|
||||||
|
|
||||||
// Hides the address bar on mobile devices
|
// Loop the presentation
|
||||||
hideAddressBar: true,
|
loop: {loop},
|
||||||
|
|
||||||
// Opens links in an iframe preview overlay
|
// Change the presentation direction to be RTL
|
||||||
previewLinks: true,
|
rtl: {rtl},
|
||||||
|
|
||||||
// Transition style
|
// Changes the behavior of our navigation directions.
|
||||||
transition: 'none', // none/fade/slide/convex/concave/zoom
|
//
|
||||||
|
// "default"
|
||||||
|
// Left/right arrow keys step between horizontal slides, up/down
|
||||||
|
// arrow keys step between vertical slides. Space key steps through
|
||||||
|
// all slides (both horizontal and vertical).
|
||||||
|
//
|
||||||
|
// "linear"
|
||||||
|
// Removes the up/down arrows. Left/right arrows step through all
|
||||||
|
// slides (both horizontal and vertical).
|
||||||
|
//
|
||||||
|
// "grid"
|
||||||
|
// When this is enabled, stepping left/right from a vertical stack
|
||||||
|
// to an adjacent vertical stack will land you at the same vertical
|
||||||
|
// index.
|
||||||
|
//
|
||||||
|
// Consider a deck with six slides ordered in two vertical stacks:
|
||||||
|
// 1.1 2.1
|
||||||
|
// 1.2 2.2
|
||||||
|
// 1.3 2.3
|
||||||
|
//
|
||||||
|
// If you're on slide 1.3 and navigate right, you will normally move
|
||||||
|
// from 1.3 -> 2.1. If "grid" is used, the same navigation takes you
|
||||||
|
// from 1.3 -> 2.3.
|
||||||
|
navigationMode: {navigation_mode},
|
||||||
|
|
||||||
// Transition speed
|
// Randomizes the order of slides each time the presentation loads
|
||||||
transitionSpeed: 'default', // default/fast/slow
|
shuffle: {shuffle},
|
||||||
|
|
||||||
// Transition style for full page slide backgrounds
|
// Turns fragments on and off globally
|
||||||
backgroundTransition: 'none', // none/fade/slide/convex/concave/zoom
|
fragments: {fragments},
|
||||||
|
|
||||||
// Number of slides away from the current that are visible
|
// Flags whether to include the current fragment in the URL,
|
||||||
viewDistance: 3,
|
// so that reloading brings you to the same fragment position
|
||||||
|
fragmentInURL: {fragment_in_url},
|
||||||
|
|
||||||
// Parallax background image
|
// Flags if the presentation is running in an embedded mode,
|
||||||
parallaxBackgroundImage: '', // e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"
|
// i.e. contained within a limited portion of the screen
|
||||||
|
embedded: {embedded},
|
||||||
|
|
||||||
// Parallax background size
|
// Flags if we should show a help overlay when the question-mark
|
||||||
parallaxBackgroundSize: '', // CSS syntax, e.g. "2100px 900px"
|
// key is pressed
|
||||||
|
help: {help},
|
||||||
|
|
||||||
// Number of pixels to move the parallax background per slide
|
// Flags if it should be possible to pause the presentation (blackout)
|
||||||
// - Calculated automatically unless specified
|
pause: {pause},
|
||||||
// - Set to 0 to disable movement along an axis
|
|
||||||
parallaxBackgroundHorizontal: null,
|
// Flags if speaker notes should be visible to all viewers
|
||||||
parallaxBackgroundVertical: null,
|
showNotes: {show_notes},
|
||||||
|
|
||||||
|
// Global override for autolaying embedded media (video/audio/iframe)
|
||||||
|
// - null: Media will only autoplay if data-autoplay is present
|
||||||
|
// - true: All media will autoplay, regardless of individual setting
|
||||||
|
// - false: No media will autoplay, regardless of individual setting
|
||||||
|
autoPlayMedia: {auto_play_media},
|
||||||
|
|
||||||
|
// Global override for preloading lazy-loaded iframes
|
||||||
|
// - null: Iframes with data-src AND data-preload will be loaded when within
|
||||||
|
// the viewDistance, iframes with only data-src will be loaded when visible
|
||||||
|
// - true: All iframes with data-src will be loaded when within the viewDistance
|
||||||
|
// - false: All iframes with data-src will be loaded only when visible
|
||||||
|
preloadIframes: {preload_iframes},
|
||||||
|
|
||||||
|
// Can be used to globally disable auto-animation
|
||||||
|
autoAnimate: {auto_animate},
|
||||||
|
|
||||||
|
// Optionally provide a custom element matcher that will be
|
||||||
|
// used to dictate which elements we can animate between.
|
||||||
|
autoAnimateMatcher: {auto_animate_matcher},
|
||||||
|
|
||||||
|
// Default settings for our auto-animate transitions, can be
|
||||||
|
// overridden per-slide or per-element via data arguments
|
||||||
|
autoAnimateEasing: {auto_animate_easing},
|
||||||
|
autoAnimateDuration: {auto_animate_duration},
|
||||||
|
autoAnimateUnmatched: {auto_animate_unmatched},
|
||||||
|
|
||||||
|
// CSS properties that can be auto-animated. Position & scale
|
||||||
|
// is matched separately so there's no need to include styles
|
||||||
|
// like top/right/bottom/left, width/height or margin.
|
||||||
|
autoAnimateStyles: {auto_animate_styles},
|
||||||
|
|
||||||
|
// Controls automatic progression to the next slide
|
||||||
|
// - 0: Auto-sliding only happens if the data-autoslide HTML attribute
|
||||||
|
// is present on the current slide or fragment
|
||||||
|
// - 1+: All slides will progress automatically at the given interval
|
||||||
|
// - false: No auto-sliding, even if data-autoslide is present
|
||||||
|
autoSlide: {auto_slide},
|
||||||
|
|
||||||
|
// Stop auto-sliding after user input
|
||||||
|
autoSlideStoppable: {auto_slide_stoppable},
|
||||||
|
|
||||||
|
// Use this method for navigation when auto-sliding (defaults to navigateNext)
|
||||||
|
autoSlideMethod: {auto_slide_method},
|
||||||
|
|
||||||
|
// Specify the average time in seconds that you think you will spend
|
||||||
|
// presenting each slide. This is used to show a pacing timer in the
|
||||||
|
// speaker view
|
||||||
|
defaultTiming: {default_timing},
|
||||||
|
|
||||||
|
// Enable slide navigation via mouse wheel
|
||||||
|
mouseWheel: {mouse_wheel},
|
||||||
|
|
||||||
|
// Opens links in an iframe preview overlay
|
||||||
|
// Add `data-preview-link` and `data-preview-link="false"` to customise each link
|
||||||
|
// individually
|
||||||
|
previewLinks: {preview_links},
|
||||||
|
|
||||||
|
// Exposes the reveal.js API through window.postMessage
|
||||||
|
postMessage: {post_message},
|
||||||
|
|
||||||
|
// Dispatches all reveal.js events to the parent window through postMessage
|
||||||
|
postMessageEvents: {post_message_events},
|
||||||
|
|
||||||
|
// Focuses body when page changes visibility to ensure keyboard shortcuts work
|
||||||
|
focusBodyOnPageVisibilityChange: {focus_body_on_page_visibility_change},
|
||||||
|
|
||||||
|
// Transition style
|
||||||
|
transition: {transition}, // none/fade/slide/convex/concave/zoom
|
||||||
|
|
||||||
|
// Transition speed
|
||||||
|
transitionSpeed: {transition_speed}, // default/fast/slow
|
||||||
|
|
||||||
|
// Transition style for full page slide backgrounds
|
||||||
|
backgroundTransition: {background_transition}, // none/fade/slide/convex/concave/zoom
|
||||||
|
|
||||||
|
// The maximum number of pages a single slide can expand onto when printing
|
||||||
|
// to PDF, unlimited by default
|
||||||
|
pdfMaxPagesPerSlide: {pdf_max_pages_per_slide},
|
||||||
|
|
||||||
|
// Prints each fragment on a separate slide
|
||||||
|
pdfSeparateFragments: {pdf_separate_fragments},
|
||||||
|
|
||||||
|
// Offset used to reduce the height of content within exported PDF pages.
|
||||||
|
// This exists to account for environment differences based on how you
|
||||||
|
// print to PDF. CLI printing options, like phantomjs and wkpdf, can end
|
||||||
|
// on precisely the total height of the document whereas in-browser
|
||||||
|
// printing has to end one pixel before.
|
||||||
|
pdfPageHeightOffset: {pdf_page_height_offset},
|
||||||
|
|
||||||
|
// Number of slides away from the current that are visible
|
||||||
|
viewDistance: {view_distance},
|
||||||
|
|
||||||
|
// Number of slides away from the current that are visible on mobile
|
||||||
|
// devices. It is advisable to set this to a lower number than
|
||||||
|
// viewDistance in order to save resources.
|
||||||
|
mobileViewDistance: {mobile_view_distance},
|
||||||
|
|
||||||
|
// The display mode that will be used to show slides
|
||||||
|
display: {display},
|
||||||
|
|
||||||
|
// Hide cursor if inactive
|
||||||
|
hideInactiveCursor: {hide_inactive_cursor},
|
||||||
|
|
||||||
|
// Time before the cursor is hidden (in ms)
|
||||||
|
hideCursorTime: {hide_cursor_time}
|
||||||
|
|
||||||
|
|
||||||
// The display mode that will be used to show slides
|
}});
|
||||||
display: 'block',
|
</script>
|
||||||
|
</body>
|
||||||
/*
|
|
||||||
multiplex: {{
|
|
||||||
// Example values. To generate your own, see the socket.io server instructions.
|
|
||||||
secret: '13652805320794272084', // Obtained from the socket.io server. Gives this (the master) control of the presentation
|
|
||||||
id: '1ea875674b17ca76', // Obtained from socket.io server
|
|
||||||
url: 'https://reveal-js-multiplex-ccjbegmaii.now.sh' // Location of socket.io server
|
|
||||||
}},
|
|
||||||
*/
|
|
||||||
|
|
||||||
dependencies: [
|
|
||||||
{{ src: 'https://cdn.jsdelivr.net/npm/reveal.js@{reveal_version}/plugin/markdown/marked.js' }},
|
|
||||||
{{ src: 'https://cdn.jsdelivr.net/npm/reveal.js@{reveal_version}/plugin/markdown/markdown.js' }},
|
|
||||||
{{ src: 'https://cdn.jsdelivr.net/npm/reveal.js@{reveal_version}/plugin/notes/notes.js', async: true }},
|
|
||||||
{{ src: 'https://cdn.jsdelivr.net/npm/reveal.js@{reveal_version}/plugin/highlight/highlight.js', async: true, callback: function () {{ hljs.initHighlightingOnLoad(); }} }},
|
|
||||||
//{{ src: '//cdn.socket.io/socket.io-1.3.5.js', async: true }},
|
|
||||||
//{{ src: 'plugin/multiplex/master.js', async: true }},
|
|
||||||
// and if you want speaker notes
|
|
||||||
{{ src: 'https://cdn.jsdelivr.net/npm/reveal.js@{reveal_version}/plugin/notes-server/client.js', async: true }}
|
|
||||||
|
|
||||||
],
|
|
||||||
markdown: {{
|
|
||||||
// renderer: myrenderer,
|
|
||||||
smartypants: true
|
|
||||||
}}
|
|
||||||
}});
|
|
||||||
Reveal.configure({{
|
|
||||||
// PDF Configurations
|
|
||||||
pdfMaxPagesPerSlide: 1
|
|
||||||
|
|
||||||
}});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
Reference in New Issue
Block a user