diff --git a/TutorialMaker/Lib/TutorialExporter.py b/TutorialMaker/Lib/TutorialExporter.py index de585f9..a155a6c 100644 --- a/TutorialMaker/Lib/TutorialExporter.py +++ b/TutorialMaker/Lib/TutorialExporter.py @@ -71,6 +71,7 @@ class Theme(Enum):
{description}
+ {slide_number} """, 'backcover': """ @@ -88,6 +89,7 @@ class Theme(Enum):

{title}

+ {slide_number} """, 'text': """ @@ -96,6 +98,7 @@ class Theme(Enum):

{title}

{body}
+ {slide_number} """, 'blank': """ @@ -127,6 +130,7 @@ class Theme(Enum):
{description}
+ {slide_number} """, 'backcover': """ @@ -148,6 +152,7 @@ class Theme(Enum):

{title}

+ {slide_number} """, 'text': """ @@ -156,6 +161,7 @@ class Theme(Enum):

{title}

{body}
+ {slide_number} """, 'blank': """ @@ -185,6 +191,7 @@ class Theme(Enum):
{description}
+ {slide_number} """, 'backcover': """ @@ -202,6 +209,7 @@ class Theme(Enum):

{title}

+ {slide_number} """, 'text': """ @@ -210,6 +218,7 @@ class Theme(Enum):

{title}

{body}
+ {slide_number} """, 'blank': """ @@ -245,7 +254,7 @@ class Theme(Enum): --- ''', 'slide': ''' -
+
## {title} @@ -261,6 +270,7 @@ class Theme(Enum):
+{slide_number}
--- @@ -285,16 +295,17 @@ class Theme(Enum): --- ''', 'section': ''' -
+
# {title} +{slide_number}
--- ''', 'text': ''' -
+
## {title} @@ -304,6 +315,7 @@ class Theme(Enum):
+{slide_number}
--- @@ -337,7 +349,7 @@ class Theme(Enum): --- ''', 'slide': ''' -
+
## {title} @@ -353,6 +365,7 @@ class Theme(Enum):
+{slide_number}
--- @@ -377,7 +390,7 @@ class Theme(Enum): --- ''', 'section': ''' -
+
@@ -385,12 +398,13 @@ class Theme(Enum):
+{slide_number}
--- ''', 'text': ''' -
+
## {title} @@ -400,6 +414,7 @@ class Theme(Enum):
+{slide_number}
--- @@ -433,7 +448,7 @@ class Theme(Enum): --- ''', 'slide': ''' -
+
## {title} @@ -449,6 +464,7 @@ class Theme(Enum):
+{slide_number}
--- @@ -473,16 +489,17 @@ class Theme(Enum): --- ''', 'section': ''' -
+
# {title} +{slide_number}
--- ''', 'text': ''' -
+
## {title} @@ -492,6 +509,7 @@ class Theme(Enum):
+{slide_number}
--- @@ -537,6 +555,7 @@ class Theme(Enum): height: 600px; display: flex; flex-direction: column; + position: relative; }} /* Stacked content */ @@ -711,6 +730,7 @@ class Theme(Enum): /* Text Slide */ .textSlide {{ background: white; + position: relative; }} .textTitle {{ @@ -729,6 +749,15 @@ class Theme(Enum): text-align: justify; }} + /* Slide Number */ + .slideNumber {{ + position: absolute; + bottom: 15px; + right: 30px; + font-size: 1.3rem; + color: #888; + }} + /* Blank Slide */ .blankSlide {{ background: white; @@ -808,6 +837,7 @@ class Theme(Enum): height: 600px; display: flex; flex-direction: column; + position: relative; }} .slideContent, .textContent, .blankContent {{ @@ -993,6 +1023,15 @@ class Theme(Enum): text-align: justify; }} + /* Slide Number */ + .slideNumber {{ + position: absolute; + bottom: 15px; + right: 30px; + font-size: 1.3rem; + color: #888; + }} + /* Blank Slide */ .blankSlide {{ background: #fefefe; @@ -1071,6 +1110,7 @@ class Theme(Enum): height: 600px; display: flex; flex-direction: column; + position: relative; }} .slideContent, .textContent, .blankContent {{ @@ -1236,6 +1276,15 @@ class Theme(Enum): color: {text}; }} + /* Slide Number */ + .slideNumber {{ + position: absolute; + bottom: 15px; + right: 30px; + font-size: 1.3rem; + color: #888; + }} + /* Blank Slide */ .blankSlide {{ background: white; @@ -1413,7 +1462,7 @@ def _get_image_data_url(self, image_path, base_dir: str = None): print(f"Warning: Could not convert image to base64 ({image_path}): {e}") return image_path - def ToHtml(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False): + def ToHtml(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False, slide_number=None, slide_total=None): template = HTML_TEMPLATES[theme]['slide'] colors = PALETTE_COLORS[palette] base_dir = self.BaseDir @@ -1421,16 +1470,17 @@ def ToHtml(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, e image_src = self._get_image_data_url(self.ImagePath, base_dir=base_dir) else: image_src = self.ImagePath or "" - + slide_number_str = f'
{slide_number} / {slide_total}
' if (slide_number and slide_total) else "" return template.format( title=self.Title, image=image_src, alt=self.Title, description=self.Description, + slide_number=slide_number_str, **colors ) - def ToMarkdown(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False): + def ToMarkdown(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False, slide_number=None, slide_total=None): template = MARKDOWN_TEMPLATES[theme]['slide'] colors = PALETTE_COLORS[palette] base_dir = self.BaseDir @@ -1438,12 +1488,13 @@ def ToMarkdown(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODER image_src = self._get_image_data_url(self.ImagePath, base_dir=base_dir) else: image_src = self.ImagePath or "" - + slide_number_str = f"
{slide_number} / {slide_total}
" if (slide_number and slide_total) else "" return template.format( title=self.Title, image=image_src, alt=self.Title, description=self.Description, + slide_number=slide_number_str, **colors ) @@ -1451,19 +1502,23 @@ class SimpleSection(): def __init__(self, Title: str): self.Title = Title - def ToHtml(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False): + def ToHtml(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False, slide_number=None, slide_total=None): template = HTML_TEMPLATES[theme]['section'] colors = PALETTE_COLORS[palette] + slide_number_str = f'
{slide_number} / {slide_total}
' if (slide_number and slide_total) else "" return template.format( title=self.Title, + slide_number=slide_number_str, **colors ) - def ToMarkdown(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False): + def ToMarkdown(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False, slide_number=None, slide_total=None): template = MARKDOWN_TEMPLATES[theme]['section'] colors = PALETTE_COLORS[palette] + slide_number_str = f"
{slide_number} / {slide_total}
" if (slide_number and slide_total) else "" return template.format( title=self.Title, + slide_number=slide_number_str, **colors ) @@ -1472,21 +1527,25 @@ def __init__(self, Title: str, Body: str): self.Title = Title self.Body = Body - def ToHtml(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False): + def ToHtml(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False, slide_number=None, slide_total=None): template = HTML_TEMPLATES[theme]['text'] colors = PALETTE_COLORS[palette] + slide_number_str = f'
{slide_number} / {slide_total}
' if (slide_number and slide_total) else "" return template.format( title=self.Title, body=self.Body, + slide_number=slide_number_str, **colors ) - def ToMarkdown(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False): + def ToMarkdown(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False, slide_number=None, slide_total=None): template = MARKDOWN_TEMPLATES[theme]['text'] colors = PALETTE_COLORS[palette] + slide_number_str = f"
{slide_number} / {slide_total}
" if (slide_number and slide_total) else "" return template.format( title=self.Title, body=self.Body, + slide_number=slide_number_str, **colors ) @@ -1626,13 +1685,35 @@ def __init__(self, Slides: list[SlidePage], Title: str, html_dir: str = None): self.Markdown = "" def ToHtml(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False): - body = "".join([slide.Model.ToHtml(palette=palette, theme=theme, embed=embed) for slide in self.Slides]) + numberable_indices = [i for i, slide in enumerate(self.Slides) + if hasattr(slide.Model, 'ToHtml') and type(slide.Model).__name__ in ['SimpleSlide', 'SimpleText', 'SimpleSection']] + total = len(numberable_indices) + body = "" + for idx, slide in enumerate(self.Slides): + model = slide.Model + if hasattr(model, 'ToHtml') and type(model).__name__ in ['SimpleSlide', 'SimpleText', 'SimpleSection']: + slide_number = numberable_indices.index(idx) + 1 + body += model.ToHtml(palette=palette, theme=theme, embed=embed, slide_number=slide_number, slide_total=total) + else: + body += model.ToHtml(palette=palette, theme=theme, embed=embed) colors = PALETTE_COLORS[palette] css = CSS_TEMPLATES[theme].format(**colors) return self.Html.format(self.Title, body, css) def ToMarkdown(self, palette: Palette = Palette.BLUE, theme: Theme = Theme.MODERN, embed: bool = False): - md = "".join([slide.Model.ToMarkdown(palette=palette, theme=theme, embed=embed) for slide in self.Slides]) + # Identify which slides are numberable (not cover or backcover) + numberable_indices = [i for i, slide in enumerate(self.Slides) + if hasattr(slide.Model, 'ToMarkdown') and type(slide.Model).__name__ in ['SimpleSlide', 'SimpleText', 'SimpleSection']] + total = len(numberable_indices) + md = "" + for idx, slide in enumerate(self.Slides): + model = slide.Model + if hasattr(model, 'ToMarkdown') and type(model).__name__ in ['SimpleSlide', 'SimpleText', 'SimpleSection']: + # Slide number is 1-based index in numberable slides + slide_number = numberable_indices.index(idx) + 1 + md += model.ToMarkdown(palette=palette, theme=theme, embed=embed, slide_number=slide_number, slide_total=total) + else: + md += model.ToMarkdown(palette=palette, theme=theme, embed=embed) self.Markdown = md return md