yihui / xaringan

Presentation Ninja 幻灯忍者 · 写轮眼
https://slides.yihui.org/xaringan/
Other
1.49k stars 280 forks source link

Suggestion: Add classess to first slide's yaml fields (subtitle, institute, date...) #340

Closed ccamara closed 2 years ago

ccamara commented 2 years ago

Currently, the first slide is generated from yaml fields such as title, subtitle, author, institute, date... Whenever they are present, they are rendered as follows:

I wish a class corresponding to the field could be added, like these ones:

Adding a class to every field would make things easier to theme using CSS. I know I can create a custom initial slide using seal: false, but I do find very convenient not having to retype the same information I will be filling in yaml's frontmatter.


By filing an issue to this repo, I promise that

I understand that my issue may be closed if I don't fulfill my promises.

ccamara commented 2 years ago

@yihui , I thought this would be easy to implement, so I tried to do it myself and propose a pull request. Regretfully, I didn't find how the html file is generated (I expected an html template under inst folder, but I could not find it).

If you A) think this is worth adding, and B) want to spend time guiding me through it (even though it may take more time than if you did it by yourself -considering it make take some further discussion and reviewing my PR), please guide me a little bit on where is (are) the file(s) I need to modify to add those classes based on the field's name and I'd love to contribute in this excellent package.

cderv commented 2 years ago

xaringan work a bit differently than other R Markdown tools using Pandoc. This is because the HTML will contain some Markdown than remark.js will process to convert to HTML in the browser directly.

This means the in the HTML file you'll find this for the title slide. (example with skeleton file)

class: center, middle, inverse, title-slide

# Presentation Ninja
## ⚔<br/>with xaringan
### Yihui Xie
### RStudio, PBC
### 2016/12/12 (updated: 2021-12-23)

This is like what you would write yourself in the Rmd body.

That is why you may not find what you expect.

Adding a class to every field would make things easier to theme using CSS.

As you can see above, the automatic title slide will have a class title-slide added. This is for the purpose of targeting easily its content, at least The HTML tag

div.remark-slide-content.title-slide > h1 {
}

and other CSS selector could be use.

It is not as perfect as what you are suggesting but it is already helpful.

Unfortunately, I am not sure that remark.js support adding a class to a header when writing Markdown.

Pandoc allows

# Presentation Ninja {.class}

but xaringan does not support this Pandoc syntax.

Anyway, I wanted to share some insights. @yihui is the real expert and can have other ideas.

Thank for the suggestion !

gadenbuie commented 2 years ago

One trick that makes seal: false a better option is to use the rmarkdown::metadata object, which contains the information in the yaml frontmatter as a list. This helps avoid the problem of repeating info in both the header and the custom title slide. Here's an example from slides I've created that use the approach: https://github.com/gadenbuie/slides/blob/gh-pages/extra-special-xaringan/index.Rmd

ccamara commented 2 years ago

Thank you for your detailed explanation, @cderv ! I may have phrased my initial issue differently: what I want to do is to be able to style subtitle, authors, institute and date individually, and I am limited to select only by heading levels, which is limited given that authors, institute and date are all h3 and do not have any other selector -I can't use its id, as it will change from slide to slide). Hence, my proposal.

I understand that current solution is quite good, but as far as I understand, currently there is no way to achieve what I want to achieve.

@gadenbuie I didn't know about rmarkdown::metadata. After seeing your example I see I could use that as a workaround if what I was proposing (or any other better option) is not implemented. Thanks for pointing that out.

cderv commented 2 years ago

I may have phrased my initial issue differently: what I want to do is to be able to style subtitle, authors, institute and date individually, and I am limited to select only by heading levels, which is limited given that authors, institute and date are all h3 and do not have any other selector

Ah ok. Yes that would only be possible if we were to write HTML code directly or if remark.js had a way to allow adding classes on headers using Markdown syntax. We may found an idea to allow that though - that would be useful !

Thanks @gadenbuie for the rmarkdown::metadata reminder: Using seal: false is for now the best option.

yihui commented 2 years ago

@cderv has replied pretty much all that I'd say.

what I want to do is to be able to style subtitle, authors, institute and date individually, and I am limited to select only by heading levels, which is limited given that authors, institute and date are all h3 and do not have any other selector

That's not true. CSS selectors are very flexible. For example, you can select the 2nd h3 on the title slide:

.title-slide > h3:nth-of-type(2) {
  color: red;
}

Ref: https://www.w3schools.com/cssref/css_selectors.asp

ccamara commented 2 years ago

CSS selectors are very flexible. For example, you can select the 2nd h3 on the title slide:

@yihui , that's right. But it's not as flexible, as the nth h3 may differ, depending on whether the institute, date or authors are used or not. Therefore, having a class would make things easier to theme in any circumstance.

I thought it was relatively easy to add a class to the output, that's why I asked.

yihui commented 2 years ago

As pointed out at the end of https://github.com/yihui/xaringan/issues/340#issuecomment-1000389049, remark.js does not have a way to add classes to headers like Pandoc.

Personally I would use the nth-of-type() selector that I mentioned above, although I admit classes would be more convenient and robust. For the five elements title (h1), subtitle (h2), author (h3), institute (h3), and date (h3), I feel it's most likely that the h2 subtitle is optional and may or may not be present, but since it is the only h2, it wouldn't be a problem to CSS. For the three h3 elements, how often do you omit one of them? Probably not quite often. If you have to omit one, you could use a white space as a placeholder, so you can assume that the first h3 is author, second is institute, and third is date.

If you don't like the placeholder idea, you can add classes to text using remark.js's syntax, e.g.,

title: ".title[My great title]"
date: ".date[2022-02-22]"

but note that this doesn't add the class to the header element, but to a <span> inside the header.

With the three workarounds (1. nth-of-type() + placeholder, 2. .class[], and 3. seal: false + rmarkdown::metadata), and the fact that remark.js doesn't support adding classes to headers, I'm afraid that we can't do much about this request...

yihui commented 2 years ago

Well, on second thought, I just added the classes anyway (2ad2a6d7c78cbca919d1687765c118a8e8c4e5ea), but the result will be <div class="title"><h1>Title</h1></div>. That is, the class is added to the outer div instead of h1.

This could be a breaking change if any user was styling these elements using the > operator, e.g., .title-slide > h1 (i.e., selecting the direct child of .title-slide), but I guess this might be rare.

ccamara commented 2 years ago

Thanks, @yihui! 👏