From 6faf695727092c162cc77625ae9165336304b949 Mon Sep 17 00:00:00 2001 From: George Cushen Date: Sun, 16 Sep 2018 16:39:30 +0100 Subject: [PATCH] Add slides feature Example added to `exampleSite/content/slides/example-slides.md` and linked from `exampleSite/content/talk/example-talk.md`. Close #693 --- .gitignore | 1 + archetypes/slides.md | 15 + assets/css/reveal.css | 31 + assets/css/reveal_custom.css | 0 exampleSite/content/slides/example-slides.md | 159 ++++ exampleSite/content/talk/example-talk.md | 14 +- layouts/partials/slides.html | 25 + layouts/partials/talk_links.html | 10 +- layouts/shortcodes/fragment.html | 3 + layouts/shortcodes/slide.html | 6 + layouts/shortcodes/speaker_note.html | 3 + layouts/slides/baseof.html | 66 ++ layouts/slides/list.html | 0 layouts/slides/single.html | 3 + .../vendor/reveal.js/plugin/notes/notes.html | 792 ++++++++++++++++++ .../js/vendor/reveal.js/plugin/notes/notes.js | 147 ++++ 16 files changed, 1268 insertions(+), 7 deletions(-) create mode 100644 archetypes/slides.md create mode 100644 assets/css/reveal.css create mode 100644 assets/css/reveal_custom.css create mode 100644 exampleSite/content/slides/example-slides.md create mode 100644 layouts/partials/slides.html create mode 100644 layouts/shortcodes/fragment.html create mode 100644 layouts/shortcodes/slide.html create mode 100644 layouts/shortcodes/speaker_note.html create mode 100644 layouts/slides/baseof.html create mode 100644 layouts/slides/list.html create mode 100644 layouts/slides/single.html create mode 100644 static/js/vendor/reveal.js/plugin/notes/notes.html create mode 100644 static/js/vendor/reveal.js/plugin/notes/notes.js diff --git a/.gitignore b/.gitignore index a818973a..9dacd5be 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ # IDE specific .idea/ .vscode/ +resources/ diff --git a/archetypes/slides.md b/archetypes/slides.md new file mode 100644 index 00000000..27e4f6dd --- /dev/null +++ b/archetypes/slides.md @@ -0,0 +1,15 @@ ++++ +title = "Slides" + +[slides] +# Choose a theme from https://github.com/hakimel/reveal.js#theming +theme = "black" ++++ + +# Title + +Author Name + +--- + +## Slide 2 diff --git a/assets/css/reveal.css b/assets/css/reveal.css new file mode 100644 index 00000000..ca174e39 --- /dev/null +++ b/assets/css/reveal.css @@ -0,0 +1,31 @@ +/************************************************* + * Reveal JS + **************************************************/ + +/* This is a copy of MathJax's `.mjx-chtml` with font-family added to override `.reveal span`. */ +/* See https://github.com/hakimel/reveal.js/issues/1924 */ +.reveal span.mjx-chtml { + display: inline-block; + line-height: 0; + text-indent: 0; + text-align: left; + text-transform: none; + font-style: normal; + font-weight: normal; + font-size: 100%; + font-size-adjust: none; + letter-spacing: normal; + word-wrap: normal; + word-spacing: normal; + white-space: nowrap; + float: none; + direction: ltr; + max-width: none; + max-height: none; + min-width: 0; + min-height: 0; + border: 0; + margin: 0; + padding: 1px 0; + font-family: MJXc-TeX-math-I,MJXc-TeX-math-Ix,MJXc-TeX-math-Iw; +} diff --git a/assets/css/reveal_custom.css b/assets/css/reveal_custom.css new file mode 100644 index 00000000..e69de29b diff --git a/exampleSite/content/slides/example-slides.md b/exampleSite/content/slides/example-slides.md new file mode 100644 index 00000000..9de1d3f8 --- /dev/null +++ b/exampleSite/content/slides/example-slides.md @@ -0,0 +1,159 @@ ++++ +title = "Slides" + +[slides] +# Choose a theme from https://github.com/hakimel/reveal.js#theming +theme = "black" ++++ + +# Welcome to Slides + +[Academic](https://sourcethemes.com/academic/) + +--- + +## Features + +- Efficiently write slides in Markdown +- 3-in-1: Create, Present, and Publish your slides +- Supports speaker notes +- Mobile friendly slides + +--- + +## Controls + +- Next: `Right Arrow` or `Space` +- Previous: `Left Arrow` +- Start: `Home` +- Finish: `End` +- Overview: `Esc` +- Speaker notes: `S` +- Fullscreen: `F` +- Zoom: `Alt + Click` +- [PDF Export](https://github.com/hakimel/reveal.js#pdf-export): `E` + +--- + +## Code Highlighting + +Inline code: `variable` + +Code block: +```python +porridge = "blueberry" +if porridge == "blueberry": + print("Eating...") +``` + +--- + +## Math + +In-line math: $x + y = z$ + +Block math: + +$$ +f\left( x \right) = \;\frac{{2\left( {x + 4} \right)\left( {x - 4} \right)}}{{\left( {x + 4} \right)\left( {x + 1} \right)}} +$$ + +--- + +## Fragments + +Make content appear incrementally + +``` +{{%/* fragment */%}} One {{%/* /fragment */%}} +{{%/* fragment */%}} **Two** {{%/* /fragment */%}} +{{%/* fragment */%}} Three {{%/* /fragment */%}} +``` + +Press `Space` to play! + +{{% fragment %}} One {{% /fragment %}} +{{% fragment %}} **Two** {{% /fragment %}} +{{% fragment %}} Three {{% /fragment %}} + +--- + +A fragment can accept two optional parameters: + +- `class`: use a custom style (requires definition in custom CSS) +- `weight`: sets the order in which a fragment appears + +--- + +## Speaker Notes + +Add speaker notes to your presentation + +```markdown +{{%/* speaker_note */%}} +- Only the speaker can read these notes +- Press `S` key to view +{{%/* /speaker_note */%}} +``` + +Press the `S` key to view the speaker notes! + +{{< speaker_note >}} +- Only the speaker can read these notes +- Press `S` key to view +{{< /speaker_note >}} + +--- + +## Themes + +- black: Black background, white text, blue links (default) +- white: White background, black text, blue links +- league: Gray background, white text, blue links +- beige: Beige background, dark text, brown links +- sky: Blue background, thin dark text, blue links + +--- + +- night: Black background, thick white text, orange links +- serif: Cappuccino background, gray text, brown links +- simple: White background, black text, blue links +- solarized: Cream-colored background, dark green text, blue links + +--- + +{{< slide background-image="/img/boards.jpg" >}} + +## Custom Slide + +Customize the slide style and background + +```markdown +{{}} +{{}} +{{}} +``` + +--- + +## Custom CSS Example + +Let's make headers navy colored. + +Create `assets/css/reveal_custom.css` with: + +```css +.reveal section h1, +.reveal section h2, +.reveal section h3 { + color: navy; +} +``` + +--- + +# Questions? + +[Ask](https://discourse.gohugo.io) + +[Documentation](https://sourcethemes.com/academic/docs/) diff --git a/exampleSite/content/talk/example-talk.md b/exampleSite/content/talk/example-talk.md index d140a1a7..299c6c7e 100644 --- a/exampleSite/content/talk/example-talk.md +++ b/exampleSite/content/talk/example-talk.md @@ -38,7 +38,7 @@ tags = [] # Links (optional). url_pdf = "" -url_slides = "" +url_slides = "slides/example-slides" url_video = "" url_code = "" @@ -56,4 +56,14 @@ caption = "My caption :smile:" +++ -Embed your slides or video here using [shortcodes](https://sourcethemes.com/academic/post/writing-markdown-latex/). Further details can easily be added using *Markdown* and $\rm \LaTeX$ math code. +{{% alert note %}} +Click on the **Slides** button above to view the built-in slides feature. +{{% /alert %}} + +Slides can be added in a few ways: + +- **Create** slides using Academic's *Slides* feature and link using `url_slides` parameter in the front matter of the talk file +- **Upload** an existing slide deck to `static/` and link using `url_slides` parameter in the front matter of the talk file +- **Embed** your slides (e.g. Google Slides) or presentation video on this page using [shortcodes](https://sourcethemes.com/academic/docs/writing-markdown-latex/). + +Further talk details can easily be added to this page using *Markdown* and $\rm \LaTeX$ math code. diff --git a/layouts/partials/slides.html b/layouts/partials/slides.html new file mode 100644 index 00000000..0cdfd9a3 --- /dev/null +++ b/layouts/partials/slides.html @@ -0,0 +1,25 @@ +
+
+ {{/* Loop over each page. */}} + {{ range . }} + {{ if ne (len .Content) 0 }} + + {{/* Must remove `
` generated by Blackfriday footnotes as conflicts with slide delimiter. */}} + {{ $content := replace .Content "
\n\n
" "
" }} + + {{/* Let `
` delimit slides. */}} + {{ range (split $content "
") }} + + {{/* Each `
` defines a new slide. */}} + {{/* Only begin new slide `
` if not already added by custom `slide` shortcode. */}} + {{ if not (in . "data-noprocess") }} +
+ {{ end }} + {{ . | safeHTML }} +
+ {{ end }} + + {{ end }} + {{ end }} +
+
diff --git a/layouts/partials/talk_links.html b/layouts/partials/talk_links.html index 9894d887..b9fc3336 100644 --- a/layouts/partials/talk_links.html +++ b/layouts/partials/talk_links.html @@ -2,22 +2,22 @@ {{ $ := .content }} {{ with $.Params.url_pdf }} - + {{ i18n "btn_pdf" }} {{ end }} {{ with $.Params.url_slides }} - + {{ i18n "btn_slides" }} {{ end }} {{ with $.Params.url_video }} - + {{ i18n "btn_video" }} {{ end }} {{ with $.Params.url_code }} - + {{ i18n "btn_code" }} {{ end }} @@ -31,7 +31,7 @@ {{ end }} {{ end }} {{ range $.Params.url_custom }} - + {{ .name }} {{ end }} diff --git a/layouts/shortcodes/fragment.html b/layouts/shortcodes/fragment.html new file mode 100644 index 00000000..312208b2 --- /dev/null +++ b/layouts/shortcodes/fragment.html @@ -0,0 +1,3 @@ + + {{ .Inner }} + \ No newline at end of file diff --git a/layouts/shortcodes/slide.html b/layouts/shortcodes/slide.html new file mode 100644 index 00000000..d3bced6a --- /dev/null +++ b/layouts/shortcodes/slide.html @@ -0,0 +1,6 @@ +{{ $non_data_attributes := slice "id" "class" }} +
diff --git a/layouts/shortcodes/speaker_note.html b/layouts/shortcodes/speaker_note.html new file mode 100644 index 00000000..0b32871f --- /dev/null +++ b/layouts/shortcodes/speaker_note.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/layouts/slides/baseof.html b/layouts/slides/baseof.html new file mode 100644 index 00000000..e973a4c0 --- /dev/null +++ b/layouts/slides/baseof.html @@ -0,0 +1,66 @@ + + + + {{ $css := .Site.Data.assets.css }} + {{ $cdn_url_reveal := "https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.7.0" }} + + + + + + + + + + + + + {{ .Title }} | {{ .Site.Title }} + + + {{- $theme := $.Param "slides.theme" | default "black" -}} + + + {{ printf "" (printf $css.highlight.url $css.highlight.version "dracula") | safeHTML }} + + {{ $css := resources.Get "css/reveal.css" }} + {{ $css_custom := resources.Get "css/reveal_custom.css" }} + {{ $style := slice $css $css_custom | resources.Concat "css/reveal_custom.css" | resources.Minify }} + + + + + + + + + {{ block "main" . }}{{ end }} + + + + + + + + diff --git a/layouts/slides/list.html b/layouts/slides/list.html new file mode 100644 index 00000000..e69de29b diff --git a/layouts/slides/single.html b/layouts/slides/single.html new file mode 100644 index 00000000..6bd27b18 --- /dev/null +++ b/layouts/slides/single.html @@ -0,0 +1,3 @@ +{{ define "main" }} +{{ partial "slides" (union (slice .Page) .Pages) }} +{{ end }} diff --git a/static/js/vendor/reveal.js/plugin/notes/notes.html b/static/js/vendor/reveal.js/plugin/notes/notes.html new file mode 100644 index 00000000..f8dc4cfb --- /dev/null +++ b/static/js/vendor/reveal.js/plugin/notes/notes.html @@ -0,0 +1,792 @@ + + + + + + Speaker Notes + + + + + + +
Loading speaker view...
+ +
+
Upcoming
+
+
+

Time Click to Reset

+
+ 0:00 AM +
+
+ 00:00:00 +
+
+ + + +
+ + +
+
+ + +
+ + + + + diff --git a/static/js/vendor/reveal.js/plugin/notes/notes.js b/static/js/vendor/reveal.js/plugin/notes/notes.js new file mode 100644 index 00000000..26294a06 --- /dev/null +++ b/static/js/vendor/reveal.js/plugin/notes/notes.js @@ -0,0 +1,147 @@ +/** + * Handles opening of and synchronization with the reveal.js + * notes window. + * + * Handshake process: + * 1. This window posts 'connect' to notes window + * - Includes URL of presentation to show + * 2. Notes window responds with 'connected' when it is available + * 3. This window proceeds to send the current presentation state + * to the notes window + */ +var RevealNotes = (function() { + + function openNotes( notesFilePath ) { + + if( !notesFilePath ) { + var jsFileLocation = document.querySelector('script[src$="notes.js"]').src; // this js file path + jsFileLocation = jsFileLocation.replace(/notes\.js(\?.*)?$/, ''); // the js folder path + notesFilePath = jsFileLocation + 'notes.html'; + } + + var notesPopup = window.open( notesFilePath, 'reveal.js - Notes', 'width=1100,height=700' ); + + if( !notesPopup ) { + alert( 'Speaker view popup failed to open. Please make sure popups are allowed and reopen the speaker view.' ); + return; + } + + // Allow popup window access to Reveal API + notesPopup.Reveal = window.Reveal; + + /** + * Connect to the notes window through a postmessage handshake. + * Using postmessage enables us to work in situations where the + * origins differ, such as a presentation being opened from the + * file system. + */ + function connect() { + // Keep trying to connect until we get a 'connected' message back + var connectInterval = setInterval( function() { + notesPopup.postMessage( JSON.stringify( { + namespace: 'reveal-notes', + type: 'connect', + url: window.location.protocol + '//' + window.location.host + window.location.pathname + window.location.search, + state: Reveal.getState() + } ), '*' ); + }, 500 ); + + window.addEventListener( 'message', function( event ) { + var data = JSON.parse( event.data ); + if( data && data.namespace === 'reveal-notes' && data.type === 'connected' ) { + clearInterval( connectInterval ); + onConnected(); + } + } ); + } + + /** + * Posts the current slide data to the notes window + */ + function post( event ) { + + var slideElement = Reveal.getCurrentSlide(), + notesElement = slideElement.querySelector( 'aside.notes' ), + fragmentElement = slideElement.querySelector( '.current-fragment' ); + + var messageData = { + namespace: 'reveal-notes', + type: 'state', + notes: '', + markdown: false, + whitespace: 'normal', + state: Reveal.getState() + }; + + // Look for notes defined in a slide attribute + if( slideElement.hasAttribute( 'data-notes' ) ) { + messageData.notes = slideElement.getAttribute( 'data-notes' ); + messageData.whitespace = 'pre-wrap'; + } + + // Look for notes defined in a fragment + if( fragmentElement ) { + var fragmentNotes = fragmentElement.querySelector( 'aside.notes' ); + if( fragmentNotes ) { + notesElement = fragmentNotes; + } + else if( fragmentElement.hasAttribute( 'data-notes' ) ) { + messageData.notes = fragmentElement.getAttribute( 'data-notes' ); + messageData.whitespace = 'pre-wrap'; + + // In case there are slide notes + notesElement = null; + } + } + + // Look for notes defined in an aside element + if( notesElement ) { + messageData.notes = notesElement.innerHTML; + messageData.markdown = typeof notesElement.getAttribute( 'data-markdown' ) === 'string'; + } + + notesPopup.postMessage( JSON.stringify( messageData ), '*' ); + + } + + /** + * Called once we have established a connection to the notes + * window. + */ + function onConnected() { + + // Monitor events that trigger a change in state + Reveal.addEventListener( 'slidechanged', post ); + Reveal.addEventListener( 'fragmentshown', post ); + Reveal.addEventListener( 'fragmenthidden', post ); + Reveal.addEventListener( 'overviewhidden', post ); + Reveal.addEventListener( 'overviewshown', post ); + Reveal.addEventListener( 'paused', post ); + Reveal.addEventListener( 'resumed', post ); + + // Post the initial state + post(); + + } + + connect(); + + } + + if( !/receiver/i.test( window.location.search ) ) { + + // If the there's a 'notes' query set, open directly + if( window.location.search.match( /(\?|\&)notes/gi ) !== null ) { + openNotes(); + } + + // Open the notes when the 's' key is hit + Reveal.addKeyBinding({keyCode: 83, key: 'S', description: 'Speaker notes view'}, function() { + openNotes(); + } ); + + } + + return { open: openNotes }; + +})();