mirror of
https://github.com/jeertmans/manim-slides.git
synced 2025-07-15 00:52:15 +08:00
feat(lib): add support for presenter notes (#322)
* feat(lib): add support for presenter notes * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix(test): typo * Update test_slide.py * Update convert.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@ -144,6 +144,7 @@ class BaseSlideConfig(BaseModel): # type: ignore
|
||||
auto_next: bool = False
|
||||
playback_rate: float = 1.0
|
||||
reversed_playback_rate: float = 1.0
|
||||
notes: str = ""
|
||||
|
||||
@classmethod
|
||||
def wrapper(cls, arg_name: str) -> Callable[..., Any]:
|
||||
|
@ -406,9 +406,16 @@ class RevealJS(Converter):
|
||||
options = self.dict()
|
||||
options["assets_dir"] = assets_dir
|
||||
|
||||
has_notes = any(
|
||||
slide_config.notes != ""
|
||||
for presentation_config in self.presentation_configs
|
||||
for slide_config in presentation_config.slides
|
||||
)
|
||||
|
||||
content = revealjs_template.render(
|
||||
file_to_data_uri=file_to_data_uri,
|
||||
get_duration_ms=get_duration_ms,
|
||||
has_notes=has_notes,
|
||||
**options,
|
||||
)
|
||||
|
||||
|
@ -5,7 +5,7 @@ from PySide6.QtCore import Qt, QUrl, Signal, Slot
|
||||
from PySide6.QtGui import QCloseEvent, QIcon, QKeyEvent, QScreen
|
||||
from PySide6.QtMultimedia import QMediaPlayer
|
||||
from PySide6.QtMultimediaWidgets import QVideoWidget
|
||||
from PySide6.QtWidgets import QDialog, QGridLayout, QLabel, QMainWindow
|
||||
from PySide6.QtWidgets import QDialog, QGridLayout, QLabel, QMainWindow, QVBoxLayout
|
||||
|
||||
from ..config import Config, PresentationConfig, SlideConfig
|
||||
from ..logger import logger
|
||||
@ -18,17 +18,25 @@ class Info(QDialog): # type: ignore[misc]
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
layout = QGridLayout()
|
||||
main_layout = QVBoxLayout()
|
||||
labels_layout = QGridLayout()
|
||||
notes_layout = QVBoxLayout()
|
||||
self.scene_label = QLabel()
|
||||
self.slide_label = QLabel()
|
||||
self.slide_notes = QLabel("")
|
||||
self.slide_notes.setWordWrap(True)
|
||||
|
||||
layout.addWidget(QLabel("Scene:"), 1, 1)
|
||||
layout.addWidget(QLabel("Slide:"), 2, 1)
|
||||
layout.addWidget(self.scene_label, 1, 2)
|
||||
layout.addWidget(self.slide_label, 2, 2)
|
||||
self.setLayout(layout)
|
||||
self.setFixedWidth(150)
|
||||
self.setFixedHeight(80)
|
||||
labels_layout.addWidget(QLabel("Scene:"), 1, 1)
|
||||
labels_layout.addWidget(QLabel("Slide:"), 2, 1)
|
||||
labels_layout.addWidget(self.scene_label, 1, 2)
|
||||
labels_layout.addWidget(self.slide_label, 2, 2)
|
||||
|
||||
notes_layout.addWidget(self.slide_notes)
|
||||
|
||||
main_layout.addLayout(labels_layout)
|
||||
main_layout.addLayout(notes_layout)
|
||||
|
||||
self.setLayout(main_layout)
|
||||
|
||||
if parent := self.parent():
|
||||
self.closeEvent = parent.closeEvent
|
||||
@ -312,6 +320,7 @@ class Player(QMainWindow): # type: ignore[misc]
|
||||
index = self.current_slide_index
|
||||
count = self.current_slides_count
|
||||
self.info.slide_label.setText(f"{index+1:4d}/{count:4<d}")
|
||||
self.info.slide_notes.setText(self.current_slide_config.notes)
|
||||
|
||||
def show(self) -> None:
|
||||
super().show()
|
||||
|
@ -288,6 +288,11 @@ class BaseSlide:
|
||||
Playback rate at which the reversed video is played.
|
||||
|
||||
Note that this is only supported by ``manim-slides present``.
|
||||
:param notes:
|
||||
Presenter notes, in HTML format.
|
||||
|
||||
Note that this is only supported by ``manim-slides present``
|
||||
and ``manim-slides convert --to=html``.
|
||||
:param kwargs:
|
||||
Keyword arguments to be passed to
|
||||
:meth:`Scene.next_section<manim.scene.scene.Scene.next_section>`,
|
||||
@ -372,6 +377,29 @@ class BaseSlide:
|
||||
self.next_slide()
|
||||
|
||||
self.wipe(square)
|
||||
|
||||
The following contains speaker notes. On the webbrowser,
|
||||
the speaker view can be triggered by pressing :kbd:`S`.
|
||||
|
||||
.. manim-slides:: SpeakerNotesExample
|
||||
|
||||
from manim import *
|
||||
from manim_slides import Slide
|
||||
|
||||
class SpeakerNotesExample(Slide):
|
||||
def construct(self):
|
||||
self.next_slide(notes="Some introduction")
|
||||
square = Square(color=GREEN, side_length=2)
|
||||
|
||||
self.play(GrowFromCenter(square))
|
||||
|
||||
self.next_slide(notes="We now rotate the slide")
|
||||
|
||||
self.play(Rotate(square, PI / 2))
|
||||
|
||||
self.next_slide(notes="Bye bye")
|
||||
|
||||
self.zoom(square)
|
||||
"""
|
||||
if self._current_animation > self._start_animation:
|
||||
if self.wait_time_between_slides > 0.0:
|
||||
|
@ -40,6 +40,9 @@
|
||||
{% if slide_config.auto_next -%}
|
||||
data-autoslide="{{ get_duration_ms(slide_config.file) }}"
|
||||
{%- endif -%}>
|
||||
{% if slide_config.notes != "" -%}
|
||||
<aside class="notes">{{ slide_config.notes }}</aside>
|
||||
{%- endif %}
|
||||
</section>
|
||||
{%- endfor -%}
|
||||
{%- endfor -%}
|
||||
@ -50,9 +53,16 @@
|
||||
|
||||
<!-- To include plugins, see: https://revealjs.com/plugins/ -->
|
||||
|
||||
{% if has_notes -%}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/{{ reveal_version }}/plugin/notes/notes.min.js"></script>
|
||||
{%- endif -%}
|
||||
|
||||
<!-- <script src="index.js"></script> -->
|
||||
<script>
|
||||
Reveal.initialize({
|
||||
{% if has_notes -%}
|
||||
plugins: [ RevealNotes ],
|
||||
{%- endif %}
|
||||
// The "normal" size of the presentation, aspect ratio will
|
||||
// be preserved when the presentation is scaled to fit different
|
||||
// resolutions. Can be specified using percentage units.
|
||||
|
Reference in New Issue
Block a user