├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── _extensions └── reveal-header │ ├── _extension.yml │ ├── resources │ ├── css │ │ ├── add_header.css │ │ ├── grid_htext.css │ │ └── grid_no_htext.css │ └── js │ │ ├── add_header.js │ │ └── sc_sb_title.js │ └── reveal-header.lua ├── docs ├── example.html ├── example_all.html ├── example_hide_header_text.html └── example_section_title.html ├── example.qmd ├── example_all.qmd ├── example_hide_header_text.qmd ├── example_section_title.qmd ├── images ├── Rlogo.png ├── quarto.png ├── reveal_logo.svg └── revealjs_minimal_example_ss.png └── testing.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.pdf 3 | *_files/ 4 | *.native 5 | *.rproj 6 | .Rhistory 7 | .Rproj.user/ 8 | !docs/* 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2024 Shafayet Khan Shafee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | rm -rf docs/* 3 | 4 | move: 5 | mv *.html docs/ 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reveal-header Extension For Quarto 2 | 3 | A very simple Quarto filter extension for [`revealjs`](https://quarto.org/docs/presentations/revealjs/) output format that provides 4 | 5 | - Support for adding header text like [`footer`](https://quarto.org/docs/presentations/revealjs/#footer-logo) on slides, level1 (`h1`) and level2 (`h2`) slide titles on slide header, 6 | 7 | - Another YAML option to add a logo on top-left side of each slides. So by using this filter, it is possible to use two logos for each slides (One by using the default [`logo`](https://quarto.org/docs/presentations/revealjs/#footer-logo) option which adds the logo on bottom-right corner and another one by using `header-logo` option provided by this filter.) 8 | 9 | - Provides YAML option `header-logo-link` and `footer-logo-link` to hyperlink the header logo and footer logo respectively. 10 | 11 | View the Demos of using this filter, 12 | 13 | - [`live demo 01`](https://shafayetshafee.github.io/reveal-header/example.html) 14 | - [`live demo 02`](https://shafayetshafee.github.io/reveal-header/example_all.html) 15 | 16 | ## Installing 17 | 18 | :warning: **This extension requires Quarto version to be at least 1.2** 19 | 20 | ```bash 21 | quarto add shafayetShafee/reveal-header 22 | ``` 23 | 24 | This will install the extension under the `_extensions` subdirectory. 25 | If you're using version control, you will want to check in this directory. 26 | 27 | ## Using 28 | 29 | This filter provides the following options, 30 | 31 | | Option | Description | 32 | |---|---| 33 | | `header` | A simple header text to appear in the top part of the each slide. `header` can be overridden by `title-as-header` or `subtitle-as-header` or slide specific header. | 34 | | `header-logo` | A path for logo image which will appear on the top-left corner of each slide. | 35 | | `header-logo-link` | A link in quotes for the header logo. | 36 | | `footer-logo-link` | A link in quotes for the footer logo. | 37 | | `sc-sb-title` | `true` or `false`. Specifies whether level1 (`h1`) and level2 (`h2`) slide titles should appear in the slide header automatically when `slide-level` is 2 or 3. | 38 | | `title-as-header` | `true` or `false`. Specifies whether the Slide title should appear as the slide header automatically. Will override the `header` text. | 39 | | `subtitle-as-header` | `true` or `false`. Specifies whether the Slide subtitle should appear in the slide header automatically. Will override the `title-as-header`. | 40 | | `hide-from-titleSlide` | Use `"text"` to remove the header text from title Slide, `"logo"` to remove the logo from top-left corner of header on the title Slide, `"all"` to remove both text and logo from the header on title Slide. | 41 | 42 | Therefore an example could be, 43 | 44 | ``` 45 | --- 46 | title: "Quarto Presentations" 47 | format: 48 | revealjs: 49 | slide-number: true 50 | logo: images/quarto.png 51 | footer: 52 | header: Quarto Presentations with beautiful slide decks made by RevealJs 53 | header-logo: images/reveal_logo.svg 54 | filters: 55 | - reveal-header 56 | --- 57 | 58 | 59 | ## Slides 60 | 61 | ``` 62 | 63 | Then the text `Quarto Presentations with beautiful slide decks made by RevealJs` will appear on the top margin of each slides (unless you use slide specific custom header) and similarly, the added logo will appear on top-left corner of each slide. 64 | 65 | So the Title slide for the above example looks like, 66 | 67 |
68 | 69 | ![Title Slide](images/revealjs_minimal_example_ss.png) 70 | 71 | You can also include a custom header per-slide by adding a `header` div at the bottom of the the slide, as following, 72 | 73 | ``` 74 | ## Slide 75 | 76 | ::: header 77 | 78 | Custom Header 79 | 80 | ::: 81 | 82 | ``` 83 | 84 | 85 | Another example that uses all of the options, 86 | 87 | ``` 88 | --- 89 | format: 90 | revealjs: 91 | slide-number: true 92 | logo: images/quarto.png 93 | sc-sb-title: true 94 | header: Quarto Presentations with beautiful slide decks made by RevealJs 95 | header-logo: images/reveal_logo.svg 96 | subtitle-as-header: true 97 | footer: 98 | filters: 99 | - reveal-header 100 | slide-level: 3 101 | number-sections: true 102 | --- 103 | ``` 104 | 105 | For a complete example with the live demo of the rendered output, see below. 106 | 107 | 108 | ## Styling 109 | 110 | Now to change the style of header components (i.e. logo, section and subsection title, header text), you can use the following css selectors, 111 | 112 | - `.reveal-header .header-logo`: to change css properties of header image. 113 | - `.reveal-header .header-text`: to change the styles of header text. 114 | - `.reveal-header .sc-title`: to change the styles of section title on left side. 115 | - `.reveal-header .sb-title`: to change the styles of sub-section title on right side. 116 | 117 | Also, to change the header text style for slides with simple [`background`](https://quarto.org/docs/presentations/revealjs/#slide-backgrounds) attributes, use the css selector`.reveal-header .inverse-header`. 118 | 119 | 120 | ## Example 121 | 122 | - The source code for a minimal example: [example.qmd](example.qmd) and the live demo of the rendered revealjs slides, [`example.html`](https://shafayetshafee.github.io/reveal-header/example.html) 123 | 124 | - The source code for another example that uses all the options: [example_all.qmd](example_all.qmd) and the live demo of the rendered revealjs slides, [`example_all.html`](https://shafayetshafee.github.io/reveal-header/example_all.html) 125 | 126 | - The source code for another example that uses only `sc-sb-title`: [example_section-title.qmd](example_section-title.qmd) and the live demo of the rendered revealjs slides, [`example_section_title.html`](https://shafayetshafee.github.io/reveal-header/example_section_title.html) 127 | 128 | - The source code for example where header text is hidden on the title slide: [example_hide_header_text.qmd](example_hide_header_text.qmd) and the [`rendered output`](https://shafayetshafee.github.io/reveal-header/example_hide_header_text.html) 129 | 130 | 131 | ## Similar Extension 132 | 133 | If you find this extension useful, you may also like [`metropolis-beamer`](https://github.com/shafayetShafee/metropolis-beamer/tree/main) extension that provides a custom quarto revealjs format which aims to provide a lookalike [`metropolis beamer theme`](https://www.overleaf.com/latex/templates/metropolis-beamer-theme/qzyvdhrntfmr) for quarto revealjs. -------------------------------------------------------------------------------- /_extensions/reveal-header/_extension.yml: -------------------------------------------------------------------------------- 1 | title: Reveal-header 2 | author: Shafayet Khan Shafee 3 | version: 1.2.8 4 | quarto-required: ">=1.2.0" 5 | contributes: 6 | filters: 7 | - reveal-header.lua 8 | 9 | -------------------------------------------------------------------------------- /_extensions/reveal-header/resources/css/add_header.css: -------------------------------------------------------------------------------- 1 | /*@import url('https://fonts.googleapis.com/css2?family=Source+Serif+4:opsz@8..60&display=swap');*/ 2 | 3 | 4 | :root { 5 | --header-font-size: max(10px, 1.4vw); 6 | --header-font-color: #898E8B; 7 | --header-margin: 0px 0px 0px 0px; 8 | /*--header-font-family: 'Source Serif 4', serif;*/ 9 | } 10 | 11 | .reveal .reveal-header { 12 | top: 0; 13 | margin: 3.2px 0px 2px 0px; 14 | width: 100%; 15 | position: fixed; 16 | z-index: 5; 17 | /*font-family: var(--header-font-family);*/ 18 | } 19 | 20 | .reveal .reveal-header p { 21 | color: var(--header-font-color); 22 | text-align: center; 23 | margin: var(--header-margin); 24 | font-size: var(--header-font-size); 25 | } 26 | 27 | .reveal-header .sc-title p, 28 | .reveal-header .sb-title p { 29 | font-size: max(10px, 1.45vw); 30 | filter: brightness(0.85); 31 | } 32 | 33 | .reveal-header .sc-title p { float: left; margin-left: 0.5vw} 34 | .reveal-header .sb-title p { float: right; margin-right: 0.5vw} 35 | .reveal-header.no-logo .sc-title p {margin-left: 6vw} 36 | 37 | 38 | .reveal .header-logo svg, 39 | .reveal .header-logo img { 40 | margin: var(--header-margin); 41 | padding-left: 1vw; 42 | padding-top: 5px; 43 | height: 100%; 44 | width: auto; 45 | max-width: max(60px, 10vw); 46 | max-height: max(60px, 10vh); 47 | } 48 | 49 | 50 | 51 | 52 | /* .reveal .slides { margin-top: 3vh !important;} */ 53 | .inverse-header { color: #c5d7ce !important;} 54 | 55 | 56 | div.slides section:not(.title-slide):not(#title-slide):not(.stack) { 57 | padding-top: 1em; 58 | } 59 | 60 | /* On screens that are 600px or less*/ 61 | @media screen and (max-width: 600px) { 62 | .reveal .header-logo img { 63 | padding-top: 0px; 64 | margin: 0px 0px 5px 0px; 65 | } 66 | 67 | .reveal-header .sc-title p { margin-left: 1vw; } 68 | .reveal-header.no-logo .sc-title p {margin-left: 2vw; } 69 | div.reveal.has-logo div.slide-number { font-size: 10px; } 70 | } -------------------------------------------------------------------------------- /_extensions/reveal-header/resources/css/grid_htext.css: -------------------------------------------------------------------------------- 1 | div.header-logo { grid-area: logo;} 2 | 3 | .no-logo div.header-logo { grid-area: unset !important; } 4 | 5 | div.sc-title { grid-area: sc;} 6 | div.sb-title { grid-area: sb;} 7 | div.header-text { grid-area: ht;} 8 | div.reveal.has-logo div.slide-number { 9 | grid-area: sn; 10 | top: unset !important; 11 | right: unset !important; 12 | bottom: unset !important; 13 | padding: 5px 5px 5px 5px; 14 | justify-self: center; 15 | /*font-family: var(--header-font-family);*/ 16 | font-size: 18px; 17 | } 18 | 19 | div.reveal-header { 20 | display: grid; 21 | grid-template-columns: 0.4fr 0.4fr 2fr 0.4fr 0.3fr; 22 | grid-template-areas: "logo sc ht sb sn"; 23 | column-gap: 10px; 24 | align-items: center; 25 | } 26 | 27 | div.reveal-header.no-logo { 28 | grid-template-columns: 0.7fr 2fr 0.7fr 0.05fr; 29 | grid-template-areas: "sc ht sb sn"; 30 | margin-top: 1.5vh; 31 | } 32 | 33 | 34 | /* On screens that are 600px or less*/ 35 | @media screen and (max-width: 600px) { 36 | 37 | div.reveal-header { 38 | grid-template-columns: 0.4fr 0.4fr 1fr 0.4fr 0.3fr; 39 | grid-template-areas: "logo sc ht sb sn"; 40 | } 41 | 42 | div.reveal-header.no-logo { 43 | grid-template-columns: 0.7fr 1fr 0.7fr 0.05fr; 44 | grid-template-areas: "sc ht sb sn"; 45 | } 46 | 47 | .reveal-header .sc-title p { margin-left: 1vw; } 48 | .reveal-header.no-logo .sc-title p {margin-left: 2vw; } 49 | div.reveal.has-logo div.slide-number { font-size: 10px; } 50 | } -------------------------------------------------------------------------------- /_extensions/reveal-header/resources/css/grid_no_htext.css: -------------------------------------------------------------------------------- 1 | div.header-logo { grid-area: logo;} 2 | 3 | .no-logo div.header-logo { grid-area: unset !important; } 4 | 5 | div.sc-title { grid-area: sc;} 6 | div.header-text { grid-area: ht;} 7 | div.sb-title { grid-area: sb;} 8 | div.reveal.has-logo div.slide-number { 9 | grid-area: sn; 10 | top: unset !important; 11 | right: unset !important; 12 | bottom: unset !important; 13 | padding: 5px 5px 5px 5px; 14 | justify-self: center; 15 | /*font-family: var(--header-font-family);*/ 16 | font-size: 18px; 17 | } 18 | 19 | div.reveal-header { 20 | display: grid; 21 | grid-template-columns: 0.35fr 1.2fr 0.1fr 1.2fr 0.2fr; 22 | grid-template-areas: "logo sc ht sb sn"; 23 | column-gap: 10px; 24 | align-items: center; 25 | } 26 | 27 | div.reveal-header.no-logo { 28 | grid-template-columns: 1fr 0.1fr 1fr 0.15fr; 29 | grid-template-areas: "sc ht sb sn"; 30 | margin-top: 1.5vh; 31 | } 32 | 33 | 34 | /* On screens that are 600px or less*/ 35 | @media screen and (max-width: 600px) { 36 | 37 | div.reveal-header { 38 | grid-template-columns: 0.2fr 1.2fr 0.1fr 1.2fr 0.4fr; 39 | grid-template-areas: "logo sc ht sb sn"; 40 | } 41 | 42 | div.reveal-header.no-logo { 43 | grid-template-columns: 1fr 0.1fr 1fr 0.25fr; 44 | grid-template-areas: "sc ht sb sn"; 45 | } 46 | 47 | .reveal-header .sc-title p { margin-left: 1vw; } 48 | .reveal-header.no-logo .sc-title p {margin-left: 2vw; } 49 | div.reveal.has-logo div.slide-number { font-size: 10px; } 50 | } -------------------------------------------------------------------------------- /_extensions/reveal-header/resources/js/add_header.js: -------------------------------------------------------------------------------- 1 | /** 2 | * reveal-header 3 | * A filter that adds header text and logo. 4 | * 5 | * MIT License 6 | * Copyright (c) 2023-2024 Shafayet Khan Shafee. 7 | */ 8 | 9 | function header() { 10 | 11 | // add the header structure as the firstChild of div.reveal-header 12 | function add_header() { 13 | let header = document.querySelector("div.reveal-header"); 14 | let reveal = document.querySelector(".reveal"); 15 | reveal.insertBefore(header, reveal.firstChild); 16 | 17 | logo_img = document.querySelector('.header-logo img'); 18 | if (logo_img?.getAttribute('src') == null) { 19 | if (logo_img?.getAttribute('data-src') != null) { 20 | logo_img.src = logo_img?.getAttribute('data-src') || ""; 21 | logo_img?.removeAttribute('data-src'); 22 | }; 23 | }; 24 | }; 25 | 26 | function linkify_logo(logo, href) { 27 | const logo_cloned = logo.cloneNode(true); 28 | const link = document.createElement('a'); 29 | link.href = href; 30 | link.target = '_blank'; 31 | link.appendChild(logo_cloned); 32 | logo.replaceWith(link); 33 | }; 34 | 35 | // add the class inverse-header for slide with has-dark-background class 36 | // otherwise remove it. 37 | function add_class(has_dark, header_paras) { 38 | header_paras.forEach(el => { 39 | el.classList.remove('inverse-header'); 40 | if(has_dark) { 41 | el.classList.add('inverse-header'); 42 | }; 43 | }); 44 | }; 45 | 46 | 47 | // dynamically changing the header 48 | function change_header(dheader, cheader, ctext) { 49 | // dhead => dynamic header 50 | // chead => constant header 51 | // ctext => contstant header_text inner html 52 | if (dheader !== null) { 53 | cheader.innerHTML = dheader.innerHTML; 54 | } else { 55 | cheader.innerHTML = ctext; 56 | }; 57 | }; 58 | 59 | function hide_from_title_slide(element) { 60 | Reveal.on( 'slidechanged' , event => { 61 | if (event.currentSlide.matches('#title-slide')) { 62 | element.style.visibility = 'hidden'; 63 | } else { 64 | element.style.visibility = 'visible'; 65 | } 66 | }); 67 | }; 68 | 69 | function get_clean_attrs(elem, attrName) { 70 | let attrVal = elem.getAttribute(attrName); 71 | if (attrVal != null) { 72 | elem.removeAttribute(attrName); 73 | } 74 | return attrVal; 75 | }; 76 | 77 | 78 | if (Reveal.isReady()) { 79 | 80 | add_header(); 81 | 82 | /*************** linkifying the header and footer logo ********************/ 83 | const header_logo = document.querySelector('div.header-logo'); 84 | if (header_logo != null) { 85 | const header_logo_link = get_clean_attrs(header_logo, 'data-header-logo-link'); 86 | const footer_logo_link = get_clean_attrs(header_logo, 'data-footer-logo-link'); 87 | 88 | if (header_logo_link != null) { 89 | const header_logo_img = document.querySelector('div.header-logo').firstElementChild; 90 | linkify_logo(header_logo_img, header_logo_link); 91 | }; 92 | 93 | if (footer_logo_link != null) { 94 | const footer_logo_img = document.querySelector('.slide-logo'); 95 | footer_logo_img.setAttribute('style', "z-index:99;"); 96 | linkify_logo(footer_logo_img, footer_logo_link); 97 | }; 98 | }; 99 | /****************************** END ***************************************/ 100 | 101 | if (document.querySelector('div.reveal.has-logo') != null) { 102 | var slide_number = document.querySelector('div.slide-number'); 103 | var header = document.querySelector("div.reveal-header"); 104 | header.appendChild(slide_number); 105 | }; 106 | 107 | // Get the default header text element and innner HTML (i.e. literal text) 108 | var header_text = document.querySelector("div.header-text p"); 109 | const header_inner_html = header_text.innerHTML; 110 | 111 | var header_paras = document.querySelectorAll("div.reveal-header p"); 112 | var dark = Reveal.getCurrentSlide().classList.contains('has-dark-background'); 113 | add_class(dark, header_paras); 114 | 115 | Reveal.on( 'slidechanged', event => { 116 | var has_dark = event.currentSlide.classList.contains('has-dark-background'); 117 | add_class(has_dark, header_paras); 118 | }); 119 | 120 | // make the visibility of slide specific header text defined in slide body none 121 | document.querySelectorAll('div.header').forEach(el => { 122 | el.style.display = 'none'; 123 | }); 124 | 125 | 126 | // change the header if currently loaded slide has the header div defined 127 | // which won't be captured by slidechanged event unless we change slides. 128 | let dynamic_header = Reveal.getCurrentSlide().querySelector('div.header p'); 129 | change_header(dynamic_header, header_text, header_inner_html); 130 | 131 | Reveal.on( 'slidechanged', event => { 132 | let dyn_header = event.currentSlide.querySelector('div.header p'); 133 | change_header(dyn_header, header_text, header_inner_html); 134 | }); 135 | 136 | /************** header text in title slide if title or ***********************/ 137 | /************* subtitle is used as header text ***********************/ 138 | 139 | var title_text = document.querySelector('.reveal-header .title-text p'); 140 | if (title_text != null) { 141 | title_text.style.visibility = 'hidden'; 142 | hide_from_title_slide(title_text); 143 | }; 144 | 145 | /*************** hide header text and logo on title slide ********************/ 146 | 147 | var hide_header_text = document.querySelector('.header-text').getAttribute('data-hide-from-titleslide'); 148 | var hide_header_logo = document.querySelector('.header-logo').getAttribute('data-hide-from-titleslide'); 149 | 150 | if (hide_header_text == 'true') { 151 | header_text.style.visibility = 'hidden'; 152 | hide_from_title_slide(header_text); 153 | } 154 | 155 | if (hide_header_logo == 'true') { 156 | logo_img.style.visibility = 'hidden'; 157 | hide_from_title_slide(logo_img); 158 | } 159 | 160 | }; 161 | }; 162 | 163 | 164 | window.addEventListener("load", (event) => { 165 | header(); 166 | }); 167 | -------------------------------------------------------------------------------- /_extensions/reveal-header/resources/js/sc_sb_title.js: -------------------------------------------------------------------------------- 1 | /** 2 | * reveal-header 3 | * A filter that adds header text and logo. 4 | * 5 | * MIT License 6 | * Copyright (c) 2023-2024 Shafayet Khan Shafee. 7 | */ 8 | 9 | function add_sc_sb_title() { 10 | 11 | function get_title() { 12 | var h1_arr = []; 13 | var h2_arr = []; 14 | 15 | Reveal.getSlides().forEach(el => { 16 | if (!el.matches('#title-slide')) { 17 | var h1 = el.querySelector('.title-slide h1')?.innerText; 18 | var h2 = el.querySelector('.title-slide h2')?.innerText; 19 | h1_arr.push(h1); 20 | h2_arr.push(h2); 21 | }; 22 | }); 23 | 24 | return [h1_arr, h2_arr] 25 | }; 26 | 27 | function fill_array(ar) { 28 | let last_val = ar[0] || " "; 29 | for (let i = 1; i < ar.length; i++) { 30 | if (typeof ar[i] === 'undefined') { 31 | ar[i] = last_val; 32 | } else { 33 | last_val = ar[i]; 34 | } 35 | } 36 | return ar 37 | }; 38 | 39 | 40 | if (Reveal.isReady()) { 41 | 42 | if (document.querySelector('div.reveal-header img')?.getAttribute('src')?.length == 0) { 43 | document.querySelector('div.reveal-header').classList.add('no-logo') 44 | } 45 | 46 | var [h1_array, h2_array] = get_title(); 47 | var filled_h1_array = fill_array(h1_array); 48 | var filled_h2_array = fill_array(h2_array); 49 | 50 | Reveal.getSlides().forEach((el, idx) => { 51 | if (!el.matches('#title-slide')) { 52 | el.setAttribute('data-sc-title', filled_h1_array[(idx - 1)]) 53 | el.setAttribute('data-sb-title', filled_h2_array[(idx - 1)]) 54 | } 55 | }); 56 | 57 | Reveal.on( 'slidechanged', event => { 58 | let sp = Reveal.getSlidesElement().querySelector('.stack.present'); 59 | 60 | if (sp != null) { 61 | let header = document.querySelector("div.reveal-header"); 62 | 63 | // handling h1 section title (`.sc-title`) 64 | var section_text = event.currentSlide.getAttribute('data-sc-title') || " "; 65 | if (event.currentSlide.matches('.title-slide.level1')) { 66 | header.querySelector('.sc-title p').innerText = ""; 67 | } else if (event.currentSlide.matches('.title-slide.level2')) { 68 | header.querySelector('.sc-title p').innerText = section_text; 69 | } else { 70 | header.querySelector('.sc-title p').innerText = section_text; 71 | }; 72 | 73 | // handling h2 section title (`.sb-title`) 74 | var sbsection_text = event.currentSlide.getAttribute('data-sb-title') || " "; 75 | if (event.currentSlide.matches('.title-slide.level1')) { 76 | header.querySelector('.sb-title p').innerText = ""; 77 | } else if (event.currentSlide.matches('.title-slide.level2')) { 78 | header.querySelector('.sb-title p').innerText = ""; 79 | } else { 80 | header.querySelector('.sb-title p').innerText = sbsection_text; 81 | }; 82 | }; 83 | }); 84 | }; 85 | }; 86 | 87 | 88 | window.addEventListener("load", (event) => { 89 | add_sc_sb_title(); 90 | }); 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /_extensions/reveal-header/reveal-header.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | MIT License 3 | 4 | Copyright (c) 2023 Shafayet Khan Shafee 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | ]]-- 24 | 25 | 26 | local function ensureHtmlDeps() 27 | quarto.doc.add_html_dependency({ 28 | name = "reveal-header", 29 | version = "1.0.0", 30 | scripts = { 31 | { path = "resources/js/add_header.js", attribs = {defer = "true"}} 32 | }, 33 | stylesheets = {"resources/css/add_header.css"} 34 | }) 35 | end 36 | 37 | local function sc_sb_title() 38 | quarto.doc.add_html_dependency({ 39 | name = "sc-sb-title", 40 | version = "1.0.0", 41 | scripts = { 42 | { path = "resources/js/sc_sb_title.js", attribs = {defer = "true"}} 43 | } 44 | }) 45 | end 46 | 47 | local function grid_htext() 48 | quarto.doc.add_html_dependency({ 49 | name = "grid-htext", 50 | version = "1.0.0", 51 | stylesheets = {"resources/css/grid_htext.css"} 52 | }) 53 | end 54 | 55 | local function grid_no_htext() 56 | quarto.doc.add_html_dependency({ 57 | name = "grid-no-htext", 58 | version = "1.0.0", 59 | stylesheets = {"resources/css/grid_no_htext.css"} 60 | }) 61 | end 62 | 63 | 64 | if quarto.doc.is_format('revealjs') then 65 | -- Ensuring the dependencies got loaded before proceeding 66 | ensureHtmlDeps() 67 | function Pandoc(doc) 68 | local blocks = doc.blocks 69 | local str = pandoc.utils.stringify 70 | local meta = doc.meta 71 | if meta['sc-sb-title'] then 72 | sc_sb_title() 73 | end 74 | if meta['header'] then 75 | grid_htext() 76 | else 77 | grid_no_htext() 78 | end 79 | local header_text = meta['header'] and str(meta['header']) or " " 80 | local header_para_class = {class = "header-text"} 81 | if meta['title-as-header'] then 82 | header_text = meta['title'] 83 | header_para_class = {class = "header-text title-text"} 84 | end 85 | if meta['subtitle-as-header'] then 86 | header_text = meta['subtitle'] 87 | header_para_class = {class = "header-text title-text"} 88 | end 89 | -- make divs structure for holding text and logo. 90 | local header_logo = meta['header-logo'] and str(meta['header-logo']) or "" 91 | local header_logo_link = meta['header-logo-link'] and str(meta['header-logo-link']) or "" 92 | local footer_logo_link = meta['footer-logo-link'] and str(meta['footer-logo-link']) or "" 93 | local header_img = pandoc.Div(pandoc.Image("", header_logo, ""), {class = "header-logo"}) 94 | 95 | if header_logo_link ~= "" then 96 | header_img.attributes['header-logo-link'] = header_logo_link 97 | end 98 | 99 | if footer_logo_link ~= "" then 100 | header_img.attributes['footer-logo-link'] = footer_logo_link 101 | end 102 | 103 | local header_section = pandoc.Div(pandoc.Para(" "), {class = "sc-title"}) 104 | local header_sbsection = pandoc.Div(pandoc.Para(" "), {class = "sb-title"}) 105 | local header_para = pandoc.Div(pandoc.Para(header_text), header_para_class) 106 | if meta['hide-from-titleSlide'] then 107 | local hide = str(meta['hide-from-titleSlide']) 108 | if hide == "text" then 109 | header_para.attributes['hide-from-titleslide'] = "true" 110 | elseif hide == "logo" then 111 | header_img.attributes['hide-from-titleslide'] = "true" 112 | elseif hide == "all" then 113 | header_para.attributes['hide-from-titleslide'] = "true" 114 | header_img.attributes['hide-from-titleslide'] = "true" 115 | end 116 | end 117 | local div = pandoc.Div( 118 | { 119 | header_img, 120 | header_section, 121 | header_para, 122 | header_sbsection 123 | }, 124 | {class = 'reveal-header'}) 125 | table.insert(blocks, div) 126 | return doc 127 | end 128 | end -------------------------------------------------------------------------------- /example.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Quarto Presentations" 3 | subtitle: "Create beautiful interactive slide decks with Reveal.js" 4 | author: Shafayet Khan Shafee 5 | date: last-modified 6 | date-format: "DD MMM, YYYY" 7 | format: 8 | revealjs: 9 | slide-number: true 10 | logo: images/quarto.png 11 | footer: 12 | footer-logo-link: "https://quarto.org" 13 | header: Quarto Presentations with beautiful slide decks made by RevealJs 14 | header-logo: images/reveal_logo.svg 15 | header-logo-link: "https://revealjs.com" 16 | filters: 17 | - reveal-header 18 | execute: 19 | eval: false 20 | echo: true 21 | embed-resources: true 22 | --- 23 | 24 | ## Hello, There 25 | 26 | This presentation shows a few slides made by Quarto and [Reveal.js](https://revealjs.com) along with header logo and header text which are easily embedded by using the Quarto filter `reveal-header` 27 | 28 | 29 | ## Slide Backgrounds {background="#43464B"} 30 | 31 | This slide is created using the `background` attribute (`{background="#43464B"}`) and as you can see that header text color is different (difference is trivial though) than before. 32 | 33 | if you want you can change the color of the header text for slides with `background` attribute using css class `.inverse-header`. For example, 34 | 35 | ~~~ 36 | .inverse-header { 37 | color: #c1c1c1 !important; 38 | } 39 | ~~~ 40 | 41 | Here using `!important` is important :p. 42 | 43 | ::: footer 44 | Learn more: [Slide Backgrounds](https://quarto.org/docs/presentations/revealjs/#color-backgrounds) 45 | ::: 46 | 47 | ## Slide Backgrounds {background="#43464B"} 48 | 49 | ::: header 50 | 51 | Slide with bg color #43464B, used in **.inverse-header** 52 | 53 | ::: 54 | 55 | This slide contains a header div, therefore it has a header. 56 | 57 | ::: footer 58 | Learn more: [Slide Backgrounds](https://quarto.org/docs/presentations/revealjs/#color-backgrounds) 59 | ::: 60 | 61 | 62 | ## Executable Code 63 | 64 | ::: header 65 | 66 | Codes with syntax highlighting and line numbers. 67 | 68 | ::: 69 | 70 | ```{r} 71 | #| echo: true 72 | #| fig-width: 10 73 | #| fig-height: 4.5 74 | 75 | library(ggplot2) 76 | ggplot(mtcars, aes(hp, mpg, color = am)) + 77 | geom_point() + 78 | geom_smooth(formula = y ~ x, method = "loess") 79 | ``` 80 | 81 | ::: footer 82 | Learn more: [Executable Code](https://quarto.org/docs/presentations/revealjs/#executable-code) 83 | ::: 84 | 85 | 86 | ## Line Highlighting 87 | 88 | ::: header 89 | 90 | Codes with specific line highlighted 91 | 92 | ::: 93 | 94 | ``` {.python code-line-numbers="4-5|7|10"} 95 | import numpy as np 96 | import matplotlib.pyplot as plt 97 | 98 | r = np.arange(0, 2, 0.01) 99 | theta = 2 * np.pi * r 100 | fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}) 101 | ax.plot(theta, r) 102 | ax.set_rticks([0.5, 1, 1.5, 2]) 103 | ax.grid(True) 104 | plt.show() 105 | ``` 106 | 107 | ::: footer 108 | Learn more: [Line Highlighting](https://quarto.org/docs/presentations/revealjs/#line-highlighting) 109 | ::: 110 | -------------------------------------------------------------------------------- /example_all.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Quarto Presentations" 3 | subtitle: "Create beautiful interactive slide decks with Reveal.js" 4 | author: Shafayet Khan Shafee 5 | date: last-modified 6 | date-format: "DD MMM, YYYY" 7 | format: 8 | revealjs: 9 | slide-number: true 10 | logo: images/quarto.png 11 | footer-logo-link: "https://quarto.org" 12 | sc-sb-title: true 13 | header: Quarto Presentations with beautiful slide decks made by RevealJs 14 | header-logo: images/reveal_logo.svg 15 | header-logo-link: "https://revealjs.com" 16 | subtitle-as-header: true 17 | footer: 18 | filters: 19 | - reveal-header 20 | slide-level: 3 21 | number-sections: true 22 | engine: knitr 23 | embed-resources: true 24 | --- 25 | 26 | # Section 27 | 28 | ## Subsection 29 | 30 | ### TODO 31 | 32 | - Turn off alarm 33 | - Get out of bed 34 | 35 | 36 | ## Subsection 37 | 38 | ### TODO 39 | 40 | - Eat eggs 41 | - Drink coffee 42 | 43 | ::: header 44 | 45 | Slide specific header. 46 | 47 | ::: 48 | 49 | 50 | # Section {background="#43464B"} 51 | 52 | ## Subsection {background="#43464B"} 53 | 54 | ### TODO {background="#43464B"} 55 | 56 | - Turn off alarm 57 | - Get out of bed 58 | 59 | 60 | 61 | ## Subsection {background="#43464B"} 62 | 63 | ### TODO {background="#43464B"} 64 | 65 | - Eat eggs 66 | - Drink coffee 67 | 68 | 69 | ::: header 70 | 71 | Slide specific header. 72 | 73 | ::: -------------------------------------------------------------------------------- /example_hide_header_text.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Quarto Presentations" 3 | subtitle: "Create beautiful interactive slide decks with Reveal.js" 4 | author: Shafayet Khan Shafee 5 | date: last-modified 6 | date-format: "DD MMM, YYYY" 7 | format: 8 | revealjs: 9 | slide-number: true 10 | logo: images/quarto.png 11 | footer-logo-link: "https://quarto.org" 12 | footer: 13 | header: Quarto Presentations with beautiful slide decks made by RevealJs 14 | header-logo: images/reveal_logo.svg 15 | header-logo-link: "https://revealjs.com" 16 | hide-from-titleSlide: "text" 17 | filters: 18 | - reveal-header 19 | execute: 20 | eval: false 21 | echo: true 22 | embed-resources: true 23 | --- 24 | 25 | ## Hello, There 26 | 27 | This presentation shows a few slides made by Quarto and [Reveal.js](https://revealjs.com) along with header logo and header text which are easily embedded by using the Quarto filter `reveal-header` 28 | 29 | 30 | ## Slide Backgrounds {background="#43464B"} 31 | 32 | This slide is created using the `background` attribute (`{background="#43464B"}`) and as you can see that header text color is different (difference is trivial though) than before. 33 | 34 | if you want you can change the color of the header text for slides with `background` attribute using css class `.inverse-header`. For example, 35 | 36 | ~~~ 37 | .inverse-header { 38 | color: #c1c1c1 !important; 39 | } 40 | ~~~ 41 | 42 | Here using `!important` is important :p. 43 | 44 | ::: footer 45 | Learn more: [Slide Backgrounds](https://quarto.org/docs/presentations/revealjs/#color-backgrounds) 46 | ::: 47 | 48 | ## Slide Backgrounds {background="#43464B"} 49 | 50 | ::: header 51 | 52 | Slide with bg color #43464B, used in **.inverse-header** 53 | 54 | ::: 55 | 56 | This slide contains a header div, therefore it has a header. 57 | 58 | ::: footer 59 | Learn more: [Slide Backgrounds](https://quarto.org/docs/presentations/revealjs/#color-backgrounds) 60 | ::: 61 | 62 | 63 | ## Executable Code 64 | 65 | ::: header 66 | 67 | Codes with syntax highlighting and line numbers. 68 | 69 | ::: 70 | 71 | ```{r} 72 | #| echo: true 73 | #| fig-width: 10 74 | #| fig-height: 4.5 75 | 76 | library(ggplot2) 77 | ggplot(mtcars, aes(hp, mpg, color = am)) + 78 | geom_point() + 79 | geom_smooth(formula = y ~ x, method = "loess") 80 | ``` 81 | 82 | ::: footer 83 | Learn more: [Executable Code](https://quarto.org/docs/presentations/revealjs/#executable-code) 84 | ::: 85 | 86 | 87 | ## Line Highlighting 88 | 89 | ::: header 90 | 91 | Codes with specific line highlighted 92 | 93 | ::: 94 | 95 | ``` {.python code-line-numbers="4-5|7|10"} 96 | import numpy as np 97 | import matplotlib.pyplot as plt 98 | 99 | r = np.arange(0, 2, 0.01) 100 | theta = 2 * np.pi * r 101 | fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}) 102 | ax.plot(theta, r) 103 | ax.set_rticks([0.5, 1, 1.5, 2]) 104 | ax.grid(True) 105 | plt.show() 106 | ``` 107 | 108 | ::: footer 109 | Learn more: [Line Highlighting](https://quarto.org/docs/presentations/revealjs/#line-highlighting) 110 | ::: 111 | -------------------------------------------------------------------------------- /example_section_title.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Quarto Presentations" 3 | subtitle: "Create beautiful interactive slide decks with Reveal.js" 4 | author: Shafayet Khan Shafee 5 | date: last-modified 6 | date-format: "DD MMM, YYYY" 7 | format: 8 | revealjs: 9 | slide-number: true 10 | sc-sb-title: true 11 | logo: images/quarto.png 12 | footer-logo-link: "https://quarto.org" 13 | filters: 14 | - reveal-header 15 | slide-level: 3 16 | number-sections: true 17 | engine: knitr 18 | embed-resources: true 19 | --- 20 | 21 | # Section 22 | 23 | ## Subsection 24 | 25 | ### TODO 26 | 27 | - Turn off alarm 28 | - Get out of bed 29 | 30 | ### TODO 31 | 32 | - Get freshed 33 | - Make the beds 34 | 35 | ## Subsection 36 | 37 | ### TODO 38 | 39 | - Eat eggs 40 | - Drink coffee 41 | 42 | ### TODO 43 | 44 | - Walk a bit 45 | - More ... 46 | 47 | 48 | # Section {background="#43464B"} 49 | 50 | ## Subsection {background="#43464B"} 51 | 52 | ### TODO {background="#43464B"} 53 | 54 | - Turn off alarm 55 | - Get out of bed 56 | 57 | ### TODO {background="#43464B"} 58 | 59 | - Get freshed 60 | - Make the beds 61 | 62 | 63 | ## Subsection {background="#43464B"} 64 | 65 | ### TODO {background="#43464B"} 66 | 67 | - Eat eggs 68 | - Drink coffee 69 | 70 | ### TODO {background="#43464B"} 71 | 72 | - Walk a bit 73 | - More ... -------------------------------------------------------------------------------- /images/Rlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shafayetShafee/reveal-header/8148fb19db2a301202a139168e12390a964aa262/images/Rlogo.png -------------------------------------------------------------------------------- /images/quarto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shafayetShafee/reveal-header/8148fb19db2a301202a139168e12390a964aa262/images/quarto.png -------------------------------------------------------------------------------- /images/reveal_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /images/revealjs_minimal_example_ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shafayetShafee/reveal-header/8148fb19db2a301202a139168e12390a964aa262/images/revealjs_minimal_example_ss.png -------------------------------------------------------------------------------- /testing.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | show_help() { 4 | echo "Usage: ./testing.sh " 5 | echo " clean: Delete HTML files from the docs folder" 6 | echo " render: Render example qmd files to HTML using quarto" 7 | echo " move: Move HTML files to docs folder" 8 | echo " open: Open HTML files from docs folder" 9 | echo " help: Show this help message" 10 | } 11 | 12 | if [ $# -eq 0 ]; then 13 | echo "Error: No argument provided." 14 | show_help 15 | exit 1 16 | fi 17 | 18 | argument="$1" 19 | 20 | case "$argument" in 21 | "clean") 22 | echo "Deleting HTML files from docs folder" 23 | rm -rf docs/* 24 | ;; 25 | "render") 26 | echo "Rendering qmd files using quarto" 27 | quarto render example.qmd && 28 | quarto render example_all.qmd && 29 | quarto render example_section_title.qmd && 30 | quarto render example_hide_header_text.qmd 31 | ;; 32 | "move") 33 | echo "Moving HTML files to docs folder" 34 | mv *.html docs/ 35 | ;; 36 | "open") 37 | echo "Opening HTML files from docs folder" 38 | for html_file in docs/*.html; do 39 | start "$html_file" 40 | done 41 | ;; 42 | "check_all") 43 | echo "Deleting HTML files from docs folder" 44 | rm -rf docs/* 45 | echo "Rendering qmd files using quarto" 46 | quarto render example.qmd && 47 | quarto render example_all.qmd && 48 | quarto render example_section_title.qmd && 49 | quarto render example_hide_header_text.qmd 50 | echo "Moving HTML files to docs folder" 51 | mv *.html docs/ 52 | echo "Opening HTML files from docs folder" 53 | for html_file in docs/*.html; do 54 | open "$html_file" 55 | done 56 | ;; 57 | "help") 58 | show_help 59 | ;; 60 | *) 61 | echo "Invalid argument: $argument" 62 | show_help 63 | exit 1 64 | ;; 65 | esac 66 | 67 | # Exit with success status 68 | exit 0 --------------------------------------------------------------------------------