mirror of
https://github.com/mfontanini/presenterm.git
synced 2025-05-31 23:25:17 +00:00
feat: add event, location, and date frontmatter (#317)
Hello! Closes #312 This PR adds fields for the presentation `event`, `location`, and `date`---these are optional fields but are common frontmatter elements, particularly if the presentation is for a larger conference / event. Example: ~~~markdown --- title: How to Think Like a Designer sub_title: It's easier than you think event: Laracon US 2024 location: Dallas, TX date: 2024-08-28 author: Jack McDade --- ~~~
This commit is contained in:
commit
7dba250b6e
@ -493,6 +493,18 @@ pub(crate) struct PresentationMetadata {
|
||||
#[serde(default)]
|
||||
pub(crate) sub_title: Option<String>,
|
||||
|
||||
/// The presentation event.
|
||||
#[serde(default)]
|
||||
pub(crate) event: Option<String>,
|
||||
|
||||
/// The presentation location.
|
||||
#[serde(default)]
|
||||
pub(crate) location: Option<String>,
|
||||
|
||||
/// The presentation date.
|
||||
#[serde(default)]
|
||||
pub(crate) date: Option<String>,
|
||||
|
||||
/// The presentation author.
|
||||
#[serde(default)]
|
||||
pub(crate) author: Option<String>,
|
||||
@ -510,6 +522,19 @@ pub(crate) struct PresentationMetadata {
|
||||
pub(crate) options: Option<OptionsConfig>,
|
||||
}
|
||||
|
||||
impl PresentationMetadata {
|
||||
/// Check if this presentation has frontmatter.
|
||||
pub(crate) fn has_frontmatter(&self) -> bool {
|
||||
self.title.is_some()
|
||||
|| self.sub_title.is_some()
|
||||
|| self.event.is_some()
|
||||
|| self.location.is_some()
|
||||
|| self.date.is_some()
|
||||
|| self.author.is_some()
|
||||
|| !self.authors.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
/// A presentation's theme metadata.
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
pub(crate) struct PresentationThemeMetadata {
|
||||
|
@ -283,11 +283,7 @@ impl<'a> PresentationBuilder<'a> {
|
||||
}
|
||||
self.footer_context.borrow_mut().author = metadata.author.clone().unwrap_or_default();
|
||||
self.set_theme(&metadata.theme)?;
|
||||
if metadata.title.is_some()
|
||||
|| metadata.sub_title.is_some()
|
||||
|| metadata.author.is_some()
|
||||
|| !metadata.authors.is_empty()
|
||||
{
|
||||
if metadata.has_frontmatter() {
|
||||
self.push_slide_prelude();
|
||||
self.push_intro_slide(metadata);
|
||||
}
|
||||
@ -336,15 +332,14 @@ impl<'a> PresentationBuilder<'a> {
|
||||
}
|
||||
|
||||
fn push_intro_slide(&mut self, metadata: PresentationMetadata) {
|
||||
let styles = &self.theme.intro_slide;
|
||||
let title = Text::new(
|
||||
metadata.title.unwrap_or_default().clone(),
|
||||
TextStyle::default().bold().colors(styles.title.colors.clone()),
|
||||
);
|
||||
let sub_title = metadata
|
||||
.sub_title
|
||||
.as_ref()
|
||||
.map(|text| Text::new(text.clone(), TextStyle::default().colors(styles.subtitle.colors.clone())));
|
||||
let styles = self.theme.intro_slide.clone();
|
||||
let create_text =
|
||||
|text: Option<String>, style: TextStyle| -> Option<Text> { text.map(|text| Text::new(text, style)) };
|
||||
let title = create_text(metadata.title, TextStyle::default().bold().colors(styles.title.colors));
|
||||
let sub_title = create_text(metadata.sub_title, TextStyle::default().colors(styles.subtitle.colors));
|
||||
let event = create_text(metadata.event, TextStyle::default().colors(styles.event.colors));
|
||||
let location = create_text(metadata.location, TextStyle::default().colors(styles.location.colors));
|
||||
let date = create_text(metadata.date, TextStyle::default().colors(styles.date.colors));
|
||||
let authors: Vec<_> = metadata
|
||||
.author
|
||||
.into_iter()
|
||||
@ -355,11 +350,24 @@ impl<'a> PresentationBuilder<'a> {
|
||||
self.slide_state.ignore_footer = true;
|
||||
}
|
||||
self.chunk_operations.push(RenderOperation::JumpToVerticalCenter);
|
||||
self.push_text(TextBlock::from(title), ElementType::PresentationTitle);
|
||||
self.push_line_break();
|
||||
if let Some(text) = sub_title {
|
||||
self.push_text(TextBlock::from(text), ElementType::PresentationSubTitle);
|
||||
if let Some(title) = title {
|
||||
self.push_line(title, ElementType::PresentationTitle);
|
||||
}
|
||||
if let Some(sub_title) = sub_title {
|
||||
self.push_line(sub_title, ElementType::PresentationSubTitle);
|
||||
}
|
||||
if event.is_some() || location.is_some() || date.is_some() {
|
||||
self.push_line_break();
|
||||
self.push_line_break();
|
||||
if let Some(event) = event {
|
||||
self.push_line(event, ElementType::PresentationEvent);
|
||||
}
|
||||
if let Some(location) = location {
|
||||
self.push_line(location, ElementType::PresentationLocation);
|
||||
}
|
||||
if let Some(date) = date {
|
||||
self.push_line(date, ElementType::PresentationDate);
|
||||
}
|
||||
}
|
||||
if !authors.is_empty() {
|
||||
match self.theme.intro_slide.author.positioning {
|
||||
@ -373,8 +381,7 @@ impl<'a> PresentationBuilder<'a> {
|
||||
}
|
||||
};
|
||||
for author in authors {
|
||||
self.push_text(TextBlock::from(author), ElementType::PresentationAuthor);
|
||||
self.push_line_break();
|
||||
self.push_line(author, ElementType::PresentationAuthor);
|
||||
}
|
||||
}
|
||||
self.slide_state.title = Some(TextBlock::from("[Introduction]"));
|
||||
@ -671,6 +678,11 @@ impl<'a> PresentationBuilder<'a> {
|
||||
self.chunk_operations.push(RenderOperation::SetColors(self.theme.default_style.colors.clone()));
|
||||
}
|
||||
|
||||
fn push_line(&mut self, text: Text, element_type: ElementType) {
|
||||
self.push_text(TextBlock::from(text), element_type);
|
||||
self.push_line_break();
|
||||
}
|
||||
|
||||
fn push_text(&mut self, text: TextBlock, element_type: ElementType) {
|
||||
let alignment = self.theme.alignment(&element_type);
|
||||
self.push_aligned_text(text, alignment);
|
||||
@ -1084,6 +1096,15 @@ struct StrictPresentationMetadata {
|
||||
#[serde(default)]
|
||||
sub_title: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
event: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
location: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
date: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
author: Option<String>,
|
||||
|
||||
@ -1099,8 +1120,9 @@ struct StrictPresentationMetadata {
|
||||
|
||||
impl From<StrictPresentationMetadata> for PresentationMetadata {
|
||||
fn from(strict: StrictPresentationMetadata) -> Self {
|
||||
let StrictPresentationMetadata { title, sub_title, author, authors, theme, options } = strict;
|
||||
Self { title, sub_title, author, authors, theme, options }
|
||||
let StrictPresentationMetadata { title, sub_title, event, location, date, author, authors, theme, options } =
|
||||
strict;
|
||||
Self { title, sub_title, event, location, date, author, authors, theme, options }
|
||||
}
|
||||
}
|
||||
|
||||
|
18
src/theme.rs
18
src/theme.rs
@ -206,6 +206,9 @@ impl PresentationTheme {
|
||||
Code => &self.code.alignment,
|
||||
PresentationTitle => &self.intro_slide.title.alignment,
|
||||
PresentationSubTitle => &self.intro_slide.subtitle.alignment,
|
||||
PresentationEvent => &self.intro_slide.event.alignment,
|
||||
PresentationLocation => &self.intro_slide.location.alignment,
|
||||
PresentationDate => &self.intro_slide.date.alignment,
|
||||
PresentationAuthor => &self.intro_slide.author.alignment,
|
||||
Table => &self.table,
|
||||
BlockQuote => &self.block_quote.alignment,
|
||||
@ -336,6 +339,18 @@ pub(crate) struct IntroSlideStyle {
|
||||
#[serde(default)]
|
||||
pub(crate) subtitle: BasicStyle,
|
||||
|
||||
/// The style of the event line.
|
||||
#[serde(default)]
|
||||
pub(crate) event: BasicStyle,
|
||||
|
||||
/// The style of the location line.
|
||||
#[serde(default)]
|
||||
pub(crate) location: BasicStyle,
|
||||
|
||||
/// The style of the date line.
|
||||
#[serde(default)]
|
||||
pub(crate) date: BasicStyle,
|
||||
|
||||
/// The style of the author line.
|
||||
#[serde(default)]
|
||||
pub(crate) author: AuthorStyle,
|
||||
@ -580,6 +595,9 @@ pub(crate) enum ElementType {
|
||||
Code,
|
||||
PresentationTitle,
|
||||
PresentationSubTitle,
|
||||
PresentationEvent,
|
||||
PresentationLocation,
|
||||
PresentationDate,
|
||||
PresentationAuthor,
|
||||
Table,
|
||||
BlockQuote,
|
||||
|
@ -1,3 +1,4 @@
|
||||
---
|
||||
default:
|
||||
margin:
|
||||
percent: 8
|
||||
@ -48,6 +49,18 @@ intro_slide:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "85c1dc"
|
||||
event:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "a6d189"
|
||||
location:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "85c1dc"
|
||||
date:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "e5c890"
|
||||
author:
|
||||
alignment: center
|
||||
colors:
|
||||
|
@ -1,3 +1,4 @@
|
||||
---
|
||||
default:
|
||||
margin:
|
||||
percent: 8
|
||||
@ -48,6 +49,18 @@ intro_slide:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "209fb5"
|
||||
event:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "40a02b"
|
||||
location:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "209fb5"
|
||||
date:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "df8e1d"
|
||||
author:
|
||||
alignment: center
|
||||
colors:
|
||||
|
@ -1,3 +1,4 @@
|
||||
---
|
||||
default:
|
||||
margin:
|
||||
percent: 8
|
||||
@ -48,6 +49,18 @@ intro_slide:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "7dc4e4"
|
||||
event:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "a6da95"
|
||||
location:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "7dc4e4"
|
||||
date:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "eed49f"
|
||||
author:
|
||||
alignment: center
|
||||
colors:
|
||||
|
@ -1,3 +1,4 @@
|
||||
---
|
||||
default:
|
||||
margin:
|
||||
percent: 8
|
||||
@ -48,6 +49,18 @@ intro_slide:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "74c7ec"
|
||||
event:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "a6e3a1"
|
||||
location:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "74c7ec"
|
||||
date:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "f9e2af"
|
||||
author:
|
||||
alignment: center
|
||||
colors:
|
||||
|
@ -1,3 +1,4 @@
|
||||
---
|
||||
default:
|
||||
margin:
|
||||
percent: 8
|
||||
@ -49,6 +50,18 @@ intro_slide:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "a5d7e8"
|
||||
event:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "b4ccff"
|
||||
location:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "a5d7e8"
|
||||
date:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "ee9322"
|
||||
author:
|
||||
alignment: center
|
||||
colors:
|
||||
@ -93,7 +106,7 @@ typst:
|
||||
foreground: "f0f0f0"
|
||||
background: "292e42"
|
||||
|
||||
footer:
|
||||
footer:
|
||||
style: progress_bar
|
||||
colors:
|
||||
foreground: "7aa2f7"
|
||||
|
@ -1,3 +1,4 @@
|
||||
---
|
||||
default:
|
||||
margin:
|
||||
percent: 8
|
||||
@ -49,6 +50,18 @@ intro_slide:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "8e9aaf"
|
||||
event:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "52b788"
|
||||
location:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "f77f00"
|
||||
date:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "f77f00"
|
||||
author:
|
||||
alignment: center
|
||||
colors:
|
||||
@ -93,7 +106,7 @@ typst:
|
||||
foreground: "212529"
|
||||
background: "e9ecef"
|
||||
|
||||
footer:
|
||||
footer:
|
||||
style: progress_bar
|
||||
colors:
|
||||
foreground: "7aa2f7"
|
||||
|
@ -1,9 +1,10 @@
|
||||
---
|
||||
default:
|
||||
margin:
|
||||
percent: 8
|
||||
colors:
|
||||
foreground: null
|
||||
background: null
|
||||
background: null
|
||||
|
||||
slide_title:
|
||||
alignment: center
|
||||
@ -47,6 +48,18 @@ intro_slide:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: blue
|
||||
event:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: green
|
||||
location:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: blue
|
||||
date:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: yellow
|
||||
author:
|
||||
alignment: center
|
||||
colors:
|
||||
@ -91,7 +104,7 @@ typst:
|
||||
foreground: "f0f0f0"
|
||||
background: "292e42"
|
||||
|
||||
footer:
|
||||
footer:
|
||||
style: progress_bar
|
||||
colors:
|
||||
foreground: blue
|
||||
|
@ -1,3 +1,4 @@
|
||||
---
|
||||
default:
|
||||
margin:
|
||||
percent: 8
|
||||
@ -47,6 +48,18 @@ intro_slide:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: dark_blue
|
||||
event:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: dark_green
|
||||
location:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: dark_blue
|
||||
date:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: dark_yellow
|
||||
author:
|
||||
alignment: center
|
||||
colors:
|
||||
@ -91,7 +104,7 @@ typst:
|
||||
foreground: "212529"
|
||||
background: "e9ecef"
|
||||
|
||||
footer:
|
||||
footer:
|
||||
style: progress_bar
|
||||
colors:
|
||||
foreground: dark_blue
|
||||
|
@ -1,3 +1,4 @@
|
||||
---
|
||||
default:
|
||||
margin:
|
||||
percent: 8
|
||||
@ -49,6 +50,18 @@ intro_slide:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "a9b1d6"
|
||||
event:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "7aa2f7"
|
||||
location:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "a9b1d6"
|
||||
date:
|
||||
alignment: center
|
||||
colors:
|
||||
foreground: "e0af68"
|
||||
author:
|
||||
alignment: center
|
||||
colors:
|
||||
@ -93,7 +106,7 @@ typst:
|
||||
foreground: "f0f0f0"
|
||||
background: "545c7e"
|
||||
|
||||
footer:
|
||||
footer:
|
||||
style: progress_bar
|
||||
colors:
|
||||
foreground: "7aa2f7"
|
||||
|
Loading…
x
Reference in New Issue
Block a user