diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 38ff0eb..0000000 --- a/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) 2011-2024 Hakim El Hattab, http://hakim.se, and reveal.js contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/assets/pictures/Uganda/2023-12-13 09.11.35.jpg b/assets/pictures/Uganda/2023-12-13 09.11.35.jpg new file mode 100644 index 0000000..f97c96d Binary files /dev/null and b/assets/pictures/Uganda/2023-12-13 09.11.35.jpg differ diff --git a/assets/pictures/Uganda/2023-12-13 17.20.42.jpg b/assets/pictures/Uganda/2023-12-13 17.20.42.jpg new file mode 100644 index 0000000..b81fe95 Binary files /dev/null and b/assets/pictures/Uganda/2023-12-13 17.20.42.jpg differ diff --git a/assets/pictures/Uganda/2023-12-14 01.48.30.jpg b/assets/pictures/Uganda/2023-12-14 01.48.30.jpg new file mode 100644 index 0000000..a62be6c Binary files /dev/null and b/assets/pictures/Uganda/2023-12-14 01.48.30.jpg differ diff --git a/assets/pictures/Uganda/2023-12-14 02.15.31.jpg b/assets/pictures/Uganda/2023-12-14 02.15.31.jpg new file mode 100644 index 0000000..f3b02fd Binary files /dev/null and b/assets/pictures/Uganda/2023-12-14 02.15.31.jpg differ diff --git a/assets/pictures/Uganda/2023-12-14 05.15.34.jpg b/assets/pictures/Uganda/2023-12-14 05.15.34.jpg new file mode 100644 index 0000000..4f49f02 Binary files /dev/null and b/assets/pictures/Uganda/2023-12-14 05.15.34.jpg differ diff --git a/assets/pictures/Uganda/2023-12-14 12.13.44.jpg b/assets/pictures/Uganda/2023-12-14 12.13.44.jpg new file mode 100644 index 0000000..3a9ea08 Binary files /dev/null and b/assets/pictures/Uganda/2023-12-14 12.13.44.jpg differ diff --git a/assets/pictures/Uganda/2023-12-14 12.33.21.jpg b/assets/pictures/Uganda/2023-12-14 12.33.21.jpg new file mode 100644 index 0000000..7c8c297 Binary files /dev/null and b/assets/pictures/Uganda/2023-12-14 12.33.21.jpg differ diff --git a/assets/pictures/Uganda/2023-12-14 17.44.43.jpg b/assets/pictures/Uganda/2023-12-14 17.44.43.jpg new file mode 100644 index 0000000..d03c5c8 Binary files /dev/null and b/assets/pictures/Uganda/2023-12-14 17.44.43.jpg differ diff --git a/assets/pictures/Uganda/Tausi_Coaches_Bus_Terminal.JPG b/assets/pictures/Uganda/Tausi_Coaches_Bus_Terminal.JPG new file mode 100644 index 0000000..f50982f Binary files /dev/null and b/assets/pictures/Uganda/Tausi_Coaches_Bus_Terminal.JPG differ diff --git a/css/layout.scss b/css/layout.scss deleted file mode 100644 index f499fdd..0000000 --- a/css/layout.scss +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Layout helpers. - */ - -// Stretch an element vertically based on available space -.reveal .stretch, -.reveal .r-stretch { - max-width: none; - max-height: none; -} - -.reveal pre.stretch code, -.reveal pre.r-stretch code { - height: 100%; - max-height: 100%; - box-sizing: border-box; -} - -// Text that auto-fits its container -.reveal .r-fit-text { - display: inline-block; // https://github.com/rikschennink/fitty#performance - white-space: nowrap; -} - -// Stack multiple elements on top of each other -.reveal .r-stack { - display: grid; -} - -.reveal .r-stack > * { - grid-area: 1/1; - margin: auto; -} - -// Horizontal and vertical stacks -.reveal .r-vstack, -.reveal .r-hstack { - display: flex; - - img, video { - min-width: 0; - min-height: 0; - object-fit: contain; - } -} - -.reveal .r-vstack { - flex-direction: column; - align-items: center; - justify-content: center; -} - -.reveal .r-hstack { - flex-direction: row; - align-items: center; - justify-content: center; -} - -// Naming based on tailwindcss -.reveal .items-stretch { align-items: stretch; } -.reveal .items-start { align-items: flex-start; } -.reveal .items-center { align-items: center; } -.reveal .items-end { align-items: flex-end; } - -.reveal .justify-between { justify-content: space-between; } -.reveal .justify-around { justify-content: space-around; } -.reveal .justify-start { justify-content: flex-start; } -.reveal .justify-center { justify-content: center; } -.reveal .justify-end { justify-content: flex-end; } diff --git a/css/print/paper.scss b/css/print/paper.scss deleted file mode 100644 index 32fab8a..0000000 --- a/css/print/paper.scss +++ /dev/null @@ -1,166 +0,0 @@ - -@media print { - html:not(.print-pdf) { - overflow: visible; - width: auto; - height: auto; - - body { - margin: 0; - padding: 0; - overflow: visible; - } - } - - html:not(.print-pdf) .reveal { - background: #fff; - font-size: 20pt; - - .controls, - .state-background, - .progress, - .backgrounds, - .slide-number { - display: none !important; - } - - p, td, li { - font-size: 20pt!important; - color: #000; - } - - h1,h2,h3,h4,h5,h6 { - color: #000!important; - height: auto; - line-height: normal; - text-align: left; - letter-spacing: normal; - } - - h1 { font-size: 28pt !important; } - h2 { font-size: 24pt !important; } - h3 { font-size: 22pt !important; } - h4 { font-size: 22pt !important; font-variant: small-caps; } - h5 { font-size: 21pt !important; } - h6 { font-size: 20pt !important; font-style: italic; } - - a:link, - a:visited { - color: #000 !important; - font-weight: bold; - text-decoration: underline; - } - - ul, ol, div, p { - visibility: visible; - position: static; - width: auto; - height: auto; - display: block; - overflow: visible; - margin: 0; - text-align: left !important; - } - pre, - table { - margin-left: 0; - margin-right: 0; - } - pre code { - padding: 20px; - } - blockquote { - margin: 20px 0; - } - - .slides { - position: static !important; - width: auto !important; - height: auto !important; - - left: 0 !important; - top: 0 !important; - margin-left: 0 !important; - margin-top: 0 !important; - padding: 0 !important; - zoom: 1 !important; - transform: none !important; - - overflow: visible !important; - display: block !important; - - text-align: left !important; - perspective: none; - - perspective-origin: 50% 50%; - } - .slides section { - visibility: visible !important; - position: static !important; - width: auto !important; - height: auto !important; - display: block !important; - overflow: visible !important; - - left: 0 !important; - top: 0 !important; - margin-left: 0 !important; - margin-top: 0 !important; - padding: 60px 20px !important; - z-index: auto !important; - - opacity: 1 !important; - - page-break-after: always !important; - - transform-style: flat !important; - transform: none !important; - transition: none !important; - } - .slides section.stack { - padding: 0 !important; - } - .slides section:last-of-type { - page-break-after: avoid !important; - } - .slides section .fragment { - opacity: 1 !important; - visibility: visible !important; - - transform: none !important; - } - - .r-fit-text { - white-space: normal !important; - } - - section img { - display: block; - margin: 15px 0px; - background: rgba(255,255,255,1); - border: 1px solid #666; - box-shadow: none; - } - - section small { - font-size: 0.8em; - } - - .hljs { - max-height: 100%; - white-space: pre-wrap; - word-wrap: break-word; - word-break: break-word; - font-size: 15pt; - } - - .hljs .hljs-ln-numbers { - white-space: nowrap; - } - - .hljs td { - font-size: inherit !important; - color: inherit !important; - } - } -} diff --git a/css/print/pdf.scss b/css/print/pdf.scss deleted file mode 100644 index 0a1c2bf..0000000 --- a/css/print/pdf.scss +++ /dev/null @@ -1,159 +0,0 @@ -/** - * This stylesheet is used to print reveal.js - * presentations to PDF. - * - * https://revealjs.com/pdf-export/ - */ - -html.reveal-print { - * { - -webkit-print-color-adjust: exact; - } - - & { - width: 100%; - height: 100%; - overflow: visible; - } - - body { - margin: 0 auto !important; - border: 0; - padding: 0; - float: none !important; - overflow: visible; - } - - /* Remove any elements not needed in print. */ - .nestedarrow, - .reveal .controls, - .reveal .progress, - .reveal .playback, - .reveal.overview, - .state-background { - display: none !important; - } - - .reveal pre code { - overflow: hidden !important; - } - - .reveal { - width: auto !important; - height: auto !important; - overflow: hidden !important; - } - .reveal .slides { - position: static; - width: 100% !important; - height: auto !important; - zoom: 1 !important; - pointer-events: initial; - - left: auto; - top: auto; - margin: 0 !important; - padding: 0 !important; - - overflow: visible; - display: block; - - perspective: none; - perspective-origin: 50% 50%; - } - - .reveal .slides .pdf-page { - position: relative; - overflow: hidden; - z-index: 1; - - page-break-after: always; - } - - .reveal .slides .pdf-page:last-of-type { - page-break-after: avoid; - } - - .reveal .slides section { - visibility: visible !important; - display: block !important; - position: absolute !important; - - margin: 0 !important; - padding: 0 !important; - box-sizing: border-box !important; - min-height: 1px; - - opacity: 1 !important; - - transform-style: flat !important; - transform: none !important; - } - - .reveal section.stack { - position: relative !important; - margin: 0 !important; - padding: 0 !important; - page-break-after: avoid !important; - height: auto !important; - min-height: auto !important; - } - - .reveal img { - box-shadow: none; - } - - /* Slide backgrounds are placed inside of their slide when exporting to PDF */ - .reveal .backgrounds { - display: none; - } - .reveal .slide-background { - display: block !important; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: auto !important; - } - - /* Display slide speaker notes when 'showNotes' is enabled */ - .reveal.show-notes { - max-width: none; - max-height: none; - } - .reveal .speaker-notes-pdf { - display: block; - width: 100%; - height: auto; - max-height: none; - top: auto; - right: auto; - bottom: auto; - left: auto; - z-index: 100; - } - - /* Layout option which makes notes appear on a separate page */ - .reveal .speaker-notes-pdf[data-layout="separate-page"] { - position: relative; - color: inherit; - background-color: transparent; - padding: 20px; - page-break-after: always; - border: 0; - } - - /* Display slide numbers when 'slideNumber' is enabled */ - .reveal .slide-number-pdf { - display: block; - position: absolute; - font-size: 14px; - visibility: visible; - } - - /* This accessibility tool is not useful in PDF and breaks it visually */ - .aria-status { - display: none; - } -} diff --git a/css/reveal.scss b/css/reveal.scss deleted file mode 100644 index 0a3ade7..0000000 --- a/css/reveal.scss +++ /dev/null @@ -1,2109 +0,0 @@ -@use "sass:math"; - -/** - * reveal.js - * http://revealjs.com - * MIT licensed - * - * Copyright (C) Hakim El Hattab, https://hakim.se - */ - -@import 'layout'; - -/********************************************* - * GLOBAL STYLES - *********************************************/ - -html.reveal-full-page { - width: 100%; - height: 100%; - height: 100vh; - height: calc( var(--vh, 1vh) * 100 ); - height: 100svh; - overflow: hidden; -} - -.reveal-viewport { - height: 100%; - overflow: hidden; - position: relative; - line-height: 1; - margin: 0; - - background-color: #fff; - color: #000; - - --r-controls-spacing: 12px; -} - -// Force the presentation to cover the full viewport when we -// enter fullscreen mode. Fixes sizing issues in Safari. -.reveal-viewport:fullscreen { - top: 0 !important; - left: 0 !important; - width: 100% !important; - height: 100% !important; - transform: none !important; -} - - -/********************************************* - * VIEW FRAGMENTS - *********************************************/ - -.reveal .fragment { - transition: all .2s ease; - - &:not(.custom) { - opacity: 0; - visibility: hidden; - will-change: opacity; - } - - &.visible { - opacity: 1; - visibility: inherit; - } - - &.disabled { - transition: none; - } -} - -.reveal .fragment.grow { - opacity: 1; - visibility: inherit; - - &.visible { - transform: scale( 1.3 ); - } -} - -.reveal .fragment.shrink { - opacity: 1; - visibility: inherit; - - &.visible { - transform: scale( 0.7 ); - } -} - -.reveal .fragment.zoom-in { - transform: scale( 0.1 ); - - &.visible { - transform: none; - } -} - -.reveal .fragment.fade-out { - opacity: 1; - visibility: inherit; - - &.visible { - opacity: 0; - visibility: hidden; - } -} - -.reveal .fragment.semi-fade-out { - opacity: 1; - visibility: inherit; - - &.visible { - opacity: 0.5; - visibility: inherit; - } -} - -.reveal .fragment.strike { - opacity: 1; - visibility: inherit; - - &.visible { - text-decoration: line-through; - } -} - -.reveal .fragment.fade-up { - transform: translate(0, 40px); - - &.visible { - transform: translate(0, 0); - } -} - -.reveal .fragment.fade-down { - transform: translate(0, -40px); - - &.visible { - transform: translate(0, 0); - } -} - -.reveal .fragment.fade-right { - transform: translate(-40px, 0); - - &.visible { - transform: translate(0, 0); - } -} - -.reveal .fragment.fade-left { - transform: translate(40px, 0); - - &.visible { - transform: translate(0, 0); - } -} - -.reveal .fragment.fade-in-then-out, -.reveal .fragment.current-visible { - opacity: 0; - visibility: hidden; - - &.current-fragment { - opacity: 1; - visibility: inherit; - } -} - -.reveal .fragment.fade-in-then-semi-out { - opacity: 0; - visibility: hidden; - - &.visible { - opacity: 0.5; - visibility: inherit; - } - - &.current-fragment { - opacity: 1; - visibility: inherit; - } -} - -.reveal .fragment.highlight-red, -.reveal .fragment.highlight-current-red, -.reveal .fragment.highlight-green, -.reveal .fragment.highlight-current-green, -.reveal .fragment.highlight-blue, -.reveal .fragment.highlight-current-blue { - opacity: 1; - visibility: inherit; -} - .reveal .fragment.highlight-red.visible { - color: #ff2c2d - } - .reveal .fragment.highlight-green.visible { - color: #17ff2e; - } - .reveal .fragment.highlight-blue.visible { - color: #1b91ff; - } - -.reveal .fragment.highlight-current-red.current-fragment { - color: #ff2c2d -} -.reveal .fragment.highlight-current-green.current-fragment { - color: #17ff2e; -} -.reveal .fragment.highlight-current-blue.current-fragment { - color: #1b91ff; -} - - -/********************************************* - * DEFAULT ELEMENT STYLES - *********************************************/ - -/* Fixes issue in Chrome where italic fonts did not appear when printing to PDF */ -.reveal:after { - content: ''; - font-style: italic; -} - -.reveal iframe { - z-index: 1; -} - -/** Prevents layering issues in certain browser/transition combinations */ -.reveal a { - position: relative; -} - - -/********************************************* - * CONTROLS - *********************************************/ - -@keyframes bounce-right { - 0%, 10%, 25%, 40%, 50% {transform: translateX(0);} - 20% {transform: translateX(10px);} - 30% {transform: translateX(-5px);} -} - -@keyframes bounce-left { - 0%, 10%, 25%, 40%, 50% {transform: translateX(0);} - 20% {transform: translateX(-10px);} - 30% {transform: translateX(5px);} -} - -@keyframes bounce-down { - 0%, 10%, 25%, 40%, 50% {transform: translateY(0);} - 20% {transform: translateY(10px);} - 30% {transform: translateY(-5px);} -} - -$controlArrowSize: 3.6em; -$controlArrowSpacing: 1.4em; -$controlArrowLength: 2.6em; -$controlArrowThickness: 0.5em; -$controlsArrowAngle: 45deg; -$controlsArrowAngleHover: 40deg; -$controlsArrowAngleActive: 36deg; - -@mixin controlsArrowTransform( $angle ) { - &:before { - transform: translateX(($controlArrowSize - $controlArrowLength)*0.5) translateY(($controlArrowSize - $controlArrowThickness)*0.5) rotate( $angle ); - } - - &:after { - transform: translateX(($controlArrowSize - $controlArrowLength)*0.5) translateY(($controlArrowSize - $controlArrowThickness)*0.5) rotate( -$angle ); - } -} - -.reveal .controls { - display: none; - position: absolute; - top: auto; - bottom: var(--r-controls-spacing); - right: var(--r-controls-spacing); - left: auto; - z-index: 11; - color: #000; - pointer-events: none; - font-size: 10px; - - button { - position: absolute; - padding: 0; - background-color: transparent; - border: 0; - outline: 0; - cursor: pointer; - color: currentColor; - transform: scale(.9999); - transition: color 0.2s ease, - opacity 0.2s ease, - transform 0.2s ease; - z-index: 2; // above slides - pointer-events: auto; - font-size: inherit; - - visibility: hidden; - opacity: 0; - - -webkit-appearance: none; - -webkit-tap-highlight-color: rgba( 0, 0, 0, 0 ); - } - - .controls-arrow:before, - .controls-arrow:after { - content: ''; - position: absolute; - top: 0; - left: 0; - width: $controlArrowLength; - height: $controlArrowThickness; - border-radius: $controlArrowThickness*0.5; - background-color: currentColor; - - transition: all 0.15s ease, background-color 0.8s ease; - transform-origin: math.div(floor(($controlArrowThickness*0.5)*10), 10) 50%; - will-change: transform; - } - - .controls-arrow { - position: relative; - width: $controlArrowSize; - height: $controlArrowSize; - - @include controlsArrowTransform( $controlsArrowAngle ); - - &:hover { - @include controlsArrowTransform( $controlsArrowAngleHover ); - } - - &:active { - @include controlsArrowTransform( $controlsArrowAngleActive ); - } - } - - .navigate-left { - right: $controlArrowSize + $controlArrowSpacing*2; - bottom: $controlArrowSpacing + $controlArrowSize*0.5; - transform: translateX( -10px ); - - &.highlight { - animation: bounce-left 2s 50 both ease-out; - } - } - - .navigate-right { - right: 0; - bottom: $controlArrowSpacing + $controlArrowSize*0.5; - transform: translateX( 10px ); - - .controls-arrow { - transform: rotate( 180deg ); - } - - &.highlight { - animation: bounce-right 2s 50 both ease-out; - } - } - - .navigate-up { - right: $controlArrowSpacing + $controlArrowSize*0.5; - bottom: $controlArrowSpacing*2 + $controlArrowSize; - transform: translateY( -10px ); - - .controls-arrow { - transform: rotate( 90deg ); - } - } - - .navigate-down { - right: $controlArrowSpacing + $controlArrowSize*0.5; - bottom: -$controlArrowSpacing; - padding-bottom: $controlArrowSpacing; - transform: translateY( 10px ); - - .controls-arrow { - transform: rotate( -90deg ); - } - - &.highlight { - animation: bounce-down 2s 50 both ease-out; - } - } - - // Back arrow style: "faded": - // Deemphasize backwards navigation arrows in favor of drawing - // attention to forwards navigation - &[data-controls-back-arrows="faded"] .navigate-up.enabled { - opacity: 0.3; - - &:hover { - opacity: 1; - } - } - - // Back arrow style: "hidden": - // Never show arrows for backwards navigation - &[data-controls-back-arrows="hidden"] .navigate-up.enabled { - opacity: 0; - visibility: hidden; - } - - // Any control button that can be clicked is "enabled" - .enabled { - visibility: visible; - opacity: 0.9; - cursor: pointer; - transform: none; - } - - // Any control button that leads to showing or hiding - // a fragment - .enabled.fragmented { - opacity: 0.5; - } - - .enabled:hover, - .enabled.fragmented:hover { - opacity: 1; - } -} - -.reveal:not(.rtl) .controls { - // Back arrow style: "faded": - // Deemphasize left arrow - &[data-controls-back-arrows="faded"] .navigate-left.enabled { - opacity: 0.3; - - &:hover { - opacity: 1; - } - } - - // Back arrow style: "hidden": - // Never show left arrow - &[data-controls-back-arrows="hidden"] .navigate-left.enabled { - opacity: 0; - visibility: hidden; - } -} - -.reveal.rtl .controls { - // Back arrow style: "faded": - // Deemphasize right arrow in RTL mode - &[data-controls-back-arrows="faded"] .navigate-right.enabled { - opacity: 0.3; - - &:hover { - opacity: 1; - } - } - - // Back arrow style: "hidden": - // Never show right arrow in RTL mode - &[data-controls-back-arrows="hidden"] .navigate-right.enabled { - opacity: 0; - visibility: hidden; - } -} - -.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-up, -.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-down { - display: none; -} - -// Adjust the layout when there are no vertical slides -.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-left, -.reveal:not(.has-vertical-slides) .controls .navigate-left { - bottom: $controlArrowSpacing; - right: 0.5em + $controlArrowSpacing + $controlArrowSize; -} - -.reveal[data-navigation-mode="linear"].has-horizontal-slides .navigate-right, -.reveal:not(.has-vertical-slides) .controls .navigate-right { - bottom: $controlArrowSpacing; - right: 0.5em; -} - -// Adjust the layout when there are no horizontal slides -.reveal:not(.has-horizontal-slides) .controls .navigate-up { - right: $controlArrowSpacing; - bottom: $controlArrowSpacing + $controlArrowSize; -} -.reveal:not(.has-horizontal-slides) .controls .navigate-down { - right: $controlArrowSpacing; - bottom: 0.5em; -} - -// Invert arrows based on background color -.reveal.has-dark-background .controls { - color: #fff; -} -.reveal.has-light-background .controls { - color: #000; -} - -// Disable active states on touch devices -.reveal.no-hover .controls .controls-arrow:hover, -.reveal.no-hover .controls .controls-arrow:active { - @include controlsArrowTransform( $controlsArrowAngle ); -} - -// Edge aligned controls layout -@media screen and (min-width: 500px) { - - .reveal-viewport { - --r-controls-spacing: 0.8em; - } - - .reveal .controls[data-controls-layout="edges"] { - & { - top: 0; - right: 0; - bottom: 0; - left: 0; - } - - .navigate-left, - .navigate-right, - .navigate-up, - .navigate-down { - bottom: auto; - right: auto; - } - - .navigate-left { - top: 50%; - left: var(--r-controls-spacing); - margin-top: -$controlArrowSize*0.5; - } - - .navigate-right { - top: 50%; - right: var(--r-controls-spacing); - margin-top: -$controlArrowSize*0.5; - } - - .navigate-up { - top: var(--r-controls-spacing); - left: 50%; - margin-left: -$controlArrowSize*0.5; - } - - .navigate-down { - bottom: calc(var(--r-controls-spacing) - #{$controlArrowSpacing} + 0.3em); - left: 50%; - margin-left: -$controlArrowSize*0.5; - } - } - -} - - -/********************************************* - * PROGRESS BAR - *********************************************/ - -.reveal .progress { - position: absolute; - display: none; - height: 3px; - width: 100%; - bottom: 0; - left: 0; - z-index: 10; - - background-color: rgba( 0, 0, 0, 0.2 ); - color: #fff; -} - .reveal .progress:after { - content: ''; - display: block; - position: absolute; - height: 10px; - width: 100%; - top: -10px; - } - .reveal .progress span { - display: block; - height: 100%; - width: 100%; - - background-color: currentColor; - transition: transform 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - transform-origin: 0 0; - transform: scaleX(0); - } - -/********************************************* - * SLIDE NUMBER - *********************************************/ - -.reveal .slide-number { - position: absolute; - display: block; - right: 8px; - bottom: 8px; - z-index: 31; - font-family: Helvetica, sans-serif; - font-size: 12px; - line-height: 1; - color: #fff; - background-color: rgba( 0, 0, 0, 0.4 ); - padding: 5px; -} - -.reveal .slide-number a { - color: currentColor; -} - -.reveal .slide-number-delimiter { - margin: 0 3px; -} - -/********************************************* - * SLIDES - *********************************************/ - -.reveal { - position: relative; - width: 100%; - height: 100%; - overflow: hidden; - touch-action: pinch-zoom; -} - -// Swiping on an embedded deck should not block page scrolling -.reveal.embedded { - touch-action: pan-y; -} - -.reveal .slides { - position: absolute; - width: 100%; - height: 100%; - top: 0; - right: 0; - bottom: 0; - left: 0; - margin: auto; - pointer-events: none; - - overflow: visible; - z-index: 1; - text-align: center; - perspective: 600px; - perspective-origin: 50% 40%; -} - -.reveal .slides>section { - perspective: 600px; -} - -.reveal .slides>section, -.reveal .slides>section>section { - display: none; - position: absolute; - width: 100%; - pointer-events: auto; - - z-index: 10; - transform-style: flat; - transition: transform-origin 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985), - transform 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985), - visibility 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985), - opacity 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); -} - -/* Global transition speed settings */ -.reveal[data-transition-speed="fast"] .slides section { - transition-duration: 400ms; -} -.reveal[data-transition-speed="slow"] .slides section { - transition-duration: 1200ms; -} - -/* Slide-specific transition speed overrides */ -.reveal .slides section[data-transition-speed="fast"] { - transition-duration: 400ms; -} -.reveal .slides section[data-transition-speed="slow"] { - transition-duration: 1200ms; -} - -.reveal .slides>section.stack { - padding-top: 0; - padding-bottom: 0; - pointer-events: none; - height: 100%; -} - -.reveal .slides>section.present, -.reveal .slides>section>section.present { - display: block; - z-index: 11; - opacity: 1; -} - -.reveal .slides>section:empty, -.reveal .slides>section>section:empty, -.reveal .slides>section[data-background-interactive], -.reveal .slides>section>section[data-background-interactive] { - pointer-events: none; -} - -.reveal.center, -.reveal.center .slides, -.reveal.center .slides section { - min-height: 0 !important; -} - -/* Don't allow interaction with invisible slides */ -.reveal .slides>section:not(.present), -.reveal .slides>section>section:not(.present) { - pointer-events: none; -} - -.reveal.overview .slides>section, -.reveal.overview .slides>section>section { - pointer-events: auto; -} - -.reveal .slides>section.past, -.reveal .slides>section.future, -.reveal .slides>section.past>section, -.reveal .slides>section.future>section, -.reveal .slides>section>section.past, -.reveal .slides>section>section.future { - opacity: 0; -} - - -/********************************************* - * Mixins for readability of transitions - *********************************************/ - -@mixin transition-global($style) { - .reveal .slides section[data-transition=#{$style}], - .reveal.#{$style} .slides section:not([data-transition]) { - @content; - } -} -@mixin transition-stack($style) { - .reveal .slides section[data-transition=#{$style}].stack, - .reveal.#{$style} .slides section.stack { - @content; - } -} -@mixin transition-horizontal-past($style) { - .reveal .slides>section[data-transition=#{$style}].past, - .reveal .slides>section[data-transition~=#{$style}-out].past, - .reveal.#{$style} .slides>section:not([data-transition]).past { - @content; - } -} -@mixin transition-horizontal-future($style) { - .reveal .slides>section[data-transition=#{$style}].future, - .reveal .slides>section[data-transition~=#{$style}-in].future, - .reveal.#{$style} .slides>section:not([data-transition]).future { - @content; - } -} - -@mixin transition-vertical-past($style) { - .reveal .slides>section>section[data-transition=#{$style}].past, - .reveal .slides>section>section[data-transition~=#{$style}-out].past, - .reveal.#{$style} .slides>section>section:not([data-transition]).past { - @content; - } -} -@mixin transition-vertical-future($style) { - .reveal .slides>section>section[data-transition=#{$style}].future, - .reveal .slides>section>section[data-transition~=#{$style}-in].future, - .reveal.#{$style} .slides>section>section:not([data-transition]).future { - @content; - } -} - -/********************************************* - * SLIDE TRANSITION - * Aliased 'linear' for backwards compatibility - *********************************************/ - -@each $stylename in slide, linear { - @include transition-horizontal-past(#{$stylename}) { - transform: translate(-150%, 0); - } - @include transition-horizontal-future(#{$stylename}) { - transform: translate(150%, 0); - } - @include transition-vertical-past(#{$stylename}) { - transform: translate(0, -150%); - } - @include transition-vertical-future(#{$stylename}) { - transform: translate(0, 150%); - } -} - -/********************************************* - * CONVEX TRANSITION - * Aliased 'default' for backwards compatibility - *********************************************/ - -@each $stylename in default, convex { - @include transition-stack(#{$stylename}) { - transform-style: preserve-3d; - } - - @include transition-horizontal-past(#{$stylename}) { - transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0); - } - @include transition-horizontal-future(#{$stylename}) { - transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0); - } - @include transition-vertical-past(#{$stylename}) { - transform: translate3d(0, -300px, 0) rotateX(70deg) translate3d(0, -300px, 0); - } - @include transition-vertical-future(#{$stylename}) { - transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0); - } -} - -/********************************************* - * CONCAVE TRANSITION - *********************************************/ - -@include transition-stack(concave) { - transform-style: preserve-3d; -} - -@include transition-horizontal-past(concave) { - transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0); -} -@include transition-horizontal-future(concave) { - transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0); -} -@include transition-vertical-past(concave) { - transform: translate3d(0, -80%, 0) rotateX(-70deg) translate3d(0, -80%, 0); -} -@include transition-vertical-future(concave) { - transform: translate3d(0, 80%, 0) rotateX(70deg) translate3d(0, 80%, 0); -} - - -/********************************************* - * ZOOM TRANSITION - *********************************************/ - -@include transition-global(zoom) { - transition-timing-function: ease; -} -@include transition-horizontal-past(zoom) { - visibility: hidden; - transform: scale(16); -} -@include transition-horizontal-future(zoom) { - visibility: hidden; - transform: scale(0.2); -} -@include transition-vertical-past(zoom) { - transform: scale(16); -} -@include transition-vertical-future(zoom) { - transform: scale(0.2); -} - - -/********************************************* - * CUBE TRANSITION - * - * WARNING: - * this is deprecated and will be removed in a - * future version. - *********************************************/ - -.reveal.cube .slides { - perspective: 1300px; -} - -.reveal.cube .slides section { - padding: 30px; - min-height: 700px; - backface-visibility: hidden; - box-sizing: border-box; - transform-style: preserve-3d; -} - .reveal.center.cube .slides section { - min-height: 0; - } - .reveal.cube .slides section:not(.stack):before { - content: ''; - position: absolute; - display: block; - width: 100%; - height: 100%; - left: 0; - top: 0; - background: rgba(0,0,0,0.1); - border-radius: 4px; - transform: translateZ( -20px ); - } - .reveal.cube .slides section:not(.stack):after { - content: ''; - position: absolute; - display: block; - width: 90%; - height: 30px; - left: 5%; - bottom: 0; - background: none; - z-index: 1; - - border-radius: 4px; - box-shadow: 0px 95px 25px rgba(0,0,0,0.2); - transform: translateZ(-90px) rotateX( 65deg ); - } - -.reveal.cube .slides>section.stack { - padding: 0; - background: none; -} - -.reveal.cube .slides>section.past { - transform-origin: 100% 0%; - transform: translate3d(-100%, 0, 0) rotateY(-90deg); -} - -.reveal.cube .slides>section.future { - transform-origin: 0% 0%; - transform: translate3d(100%, 0, 0) rotateY(90deg); -} - -.reveal.cube .slides>section>section.past { - transform-origin: 0% 100%; - transform: translate3d(0, -100%, 0) rotateX(90deg); -} - -.reveal.cube .slides>section>section.future { - transform-origin: 0% 0%; - transform: translate3d(0, 100%, 0) rotateX(-90deg); -} - - -/********************************************* - * PAGE TRANSITION - * - * WARNING: - * this is deprecated and will be removed in a - * future version. - *********************************************/ - -.reveal.page .slides { - perspective-origin: 0% 50%; - perspective: 3000px; -} - -.reveal.page .slides section { - padding: 30px; - min-height: 700px; - box-sizing: border-box; - transform-style: preserve-3d; -} - .reveal.page .slides section.past { - z-index: 12; - } - .reveal.page .slides section:not(.stack):before { - content: ''; - position: absolute; - display: block; - width: 100%; - height: 100%; - left: 0; - top: 0; - background: rgba(0,0,0,0.1); - transform: translateZ( -20px ); - } - .reveal.page .slides section:not(.stack):after { - content: ''; - position: absolute; - display: block; - width: 90%; - height: 30px; - left: 5%; - bottom: 0; - background: none; - z-index: 1; - - border-radius: 4px; - box-shadow: 0px 95px 25px rgba(0,0,0,0.2); - - -webkit-transform: translateZ(-90px) rotateX( 65deg ); - } - -.reveal.page .slides>section.stack { - padding: 0; - background: none; -} - -.reveal.page .slides>section.past { - transform-origin: 0% 0%; - transform: translate3d(-40%, 0, 0) rotateY(-80deg); -} - -.reveal.page .slides>section.future { - transform-origin: 100% 0%; - transform: translate3d(0, 0, 0); -} - -.reveal.page .slides>section>section.past { - transform-origin: 0% 0%; - transform: translate3d(0, -40%, 0) rotateX(80deg); -} - -.reveal.page .slides>section>section.future { - transform-origin: 0% 100%; - transform: translate3d(0, 0, 0); -} - - -/********************************************* - * FADE TRANSITION - *********************************************/ - -.reveal .slides section[data-transition=fade], -.reveal.fade .slides section:not([data-transition]), -.reveal.fade .slides>section>section:not([data-transition]) { - transform: none; - transition: opacity 0.5s; -} - - -.reveal.fade.overview .slides section, -.reveal.fade.overview .slides>section>section { - transition: none; -} - - -/********************************************* - * NO TRANSITION - *********************************************/ - -@include transition-global(none) { - transform: none; - transition: none; -} - - -/********************************************* - * PAUSED MODE - *********************************************/ - -.reveal .pause-overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: black; - visibility: hidden; - opacity: 0; - z-index: 100; - transition: all 1s ease; -} - -.reveal .pause-overlay .resume-button { - position: absolute; - bottom: 20px; - right: 20px; - color: #ccc; - border-radius: 2px; - padding: 6px 14px; - border: 2px solid #ccc; - font-size: 16px; - background: transparent; - cursor: pointer; - - &:hover { - color: #fff; - border-color: #fff; - } -} - -.reveal.paused .pause-overlay { - visibility: visible; - opacity: 1; -} - - -/********************************************* - * FALLBACK - *********************************************/ - -.reveal .no-transition, -.reveal .no-transition *, -.reveal .slides.disable-slide-transitions section { - transition: none !important; -} - -.reveal .slides.disable-slide-transitions section { - transform: none !important; -} - - -/********************************************* - * PER-SLIDE BACKGROUNDS - *********************************************/ - -.reveal .backgrounds { - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - perspective: 600px; -} - .reveal .slide-background { - display: none; - position: absolute; - width: 100%; - height: 100%; - opacity: 0; - visibility: hidden; - overflow: hidden; - - background-color: rgba( 0, 0, 0, 0 ); - - transition: all 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - } - - .reveal .slide-background-content { - position: absolute; - width: 100%; - height: 100%; - - background-position: 50% 50%; - background-repeat: no-repeat; - background-size: cover; - } - - .reveal .slide-background.stack { - display: block; - } - - .reveal .slide-background.present { - opacity: 1; - visibility: visible; - z-index: 2; - } - - .print-pdf .reveal .slide-background { - opacity: 1 !important; - visibility: visible !important; - } - -/* Video backgrounds */ -.reveal .slide-background video { - position: absolute; - width: 100%; - height: 100%; - max-width: none; - max-height: none; - top: 0; - left: 0; - object-fit: cover; -} - .reveal .slide-background[data-background-size="contain"] video { - object-fit: contain; - } - -/* Immediate transition style */ -.reveal[data-background-transition=none]>.backgrounds .slide-background:not([data-background-transition]), -.reveal>.backgrounds .slide-background[data-background-transition=none] { - transition: none; -} - -/* Slide */ -.reveal[data-background-transition=slide]>.backgrounds .slide-background:not([data-background-transition]), -.reveal>.backgrounds .slide-background[data-background-transition=slide] { - opacity: 1; -} - .reveal[data-background-transition=slide]>.backgrounds .slide-background.past:not([data-background-transition]), - .reveal>.backgrounds .slide-background.past[data-background-transition=slide] { - transform: translate(-100%, 0); - } - .reveal[data-background-transition=slide]>.backgrounds .slide-background.future:not([data-background-transition]), - .reveal>.backgrounds .slide-background.future[data-background-transition=slide] { - transform: translate(100%, 0); - } - - .reveal[data-background-transition=slide]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]), - .reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=slide] { - transform: translate(0, -100%); - } - .reveal[data-background-transition=slide]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]), - .reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=slide] { - transform: translate(0, 100%); - } - - -/* Convex */ -.reveal[data-background-transition=convex]>.backgrounds .slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background.past[data-background-transition=convex] { - opacity: 0; - transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0); -} -.reveal[data-background-transition=convex]>.backgrounds .slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background.future[data-background-transition=convex] { - opacity: 0; - transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0); -} - -.reveal[data-background-transition=convex]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=convex] { - opacity: 0; - transform: translate3d(0, -100%, 0) rotateX(90deg) translate3d(0, -100%, 0); -} -.reveal[data-background-transition=convex]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=convex] { - opacity: 0; - transform: translate3d(0, 100%, 0) rotateX(-90deg) translate3d(0, 100%, 0); -} - - -/* Concave */ -.reveal[data-background-transition=concave]>.backgrounds .slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background.past[data-background-transition=concave] { - opacity: 0; - transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0); -} -.reveal[data-background-transition=concave]>.backgrounds .slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background.future[data-background-transition=concave] { - opacity: 0; - transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0); -} - -.reveal[data-background-transition=concave]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=concave] { - opacity: 0; - transform: translate3d(0, -100%, 0) rotateX(-90deg) translate3d(0, -100%, 0); -} -.reveal[data-background-transition=concave]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=concave] { - opacity: 0; - transform: translate3d(0, 100%, 0) rotateX(90deg) translate3d(0, 100%, 0); -} - -/* Zoom */ -.reveal[data-background-transition=zoom]>.backgrounds .slide-background:not([data-background-transition]), -.reveal>.backgrounds .slide-background[data-background-transition=zoom] { - transition-timing-function: ease; -} - -.reveal[data-background-transition=zoom]>.backgrounds .slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background.past[data-background-transition=zoom] { - opacity: 0; - visibility: hidden; - transform: scale(16); -} -.reveal[data-background-transition=zoom]>.backgrounds .slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background.future[data-background-transition=zoom] { - opacity: 0; - visibility: hidden; - transform: scale(0.2); -} - -.reveal[data-background-transition=zoom]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=zoom] { - opacity: 0; - visibility: hidden; - transform: scale(16); -} -.reveal[data-background-transition=zoom]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]), -.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=zoom] { - opacity: 0; - visibility: hidden; - transform: scale(0.2); -} - - -/* Global transition speed settings */ -.reveal[data-transition-speed="fast"]>.backgrounds .slide-background { - transition-duration: 400ms; -} -.reveal[data-transition-speed="slow"]>.backgrounds .slide-background { - transition-duration: 1200ms; -} - - -/********************************************* - * AUTO ANIMATE - *********************************************/ - -.reveal [data-auto-animate-target^="unmatched"] { - will-change: opacity; -} - -.reveal section[data-auto-animate]:not(.stack):not([data-auto-animate="running"]) [data-auto-animate-target^="unmatched"] { - opacity: 0; -} - - -/********************************************* - * OVERVIEW - *********************************************/ - -.reveal.overview { - perspective-origin: 50% 50%; - perspective: 700px; - - .slides { - // Fixes overview rendering errors in FF48+, not applied to - // other browsers since it degrades performance - -moz-transform-style: preserve-3d; - } - - .slides section { - height: 100%; - top: 0 !important; - opacity: 1 !important; - overflow: hidden; - visibility: visible !important; - cursor: pointer; - box-sizing: border-box; - } - .slides section:hover, - .slides section.present { - outline: 10px solid rgba(150,150,150,0.4); - outline-offset: 10px; - } - .slides section .fragment { - opacity: 1; - transition: none; - } - .slides section:after, - .slides section:before { - display: none !important; - } - .slides>section.stack { - padding: 0; - top: 0 !important; - background: none; - outline: none; - overflow: visible; - } - - .backgrounds { - perspective: inherit; - - // Fixes overview rendering errors in FF48+, not applied to - // other browsers since it degrades performance - -moz-transform-style: preserve-3d; - } - - .backgrounds .slide-background { - opacity: 1; - visibility: visible; - - // This can't be applied to the slide itself in Safari - outline: 10px solid rgba(150,150,150,0.1); - outline-offset: 10px; - } - - .backgrounds .slide-background.stack { - overflow: visible; - } -} - -// Disable transitions transitions while we're activating -// or deactivating the overview mode. -.reveal.overview .slides section, -.reveal.overview-deactivating .slides section { - transition: none; -} - -.reveal.overview .backgrounds .slide-background, -.reveal.overview-deactivating .backgrounds .slide-background { - transition: none; -} - - -/********************************************* - * RTL SUPPORT - *********************************************/ - -.reveal.rtl .slides, -.reveal.rtl .slides h1, -.reveal.rtl .slides h2, -.reveal.rtl .slides h3, -.reveal.rtl .slides h4, -.reveal.rtl .slides h5, -.reveal.rtl .slides h6 { - direction: rtl; - font-family: sans-serif; -} - -.reveal.rtl pre, -.reveal.rtl code { - direction: ltr; -} - -.reveal.rtl ol, -.reveal.rtl ul { - text-align: right; -} - -.reveal.rtl .progress span { - transform-origin: 100% 0; -} - -/********************************************* - * PARALLAX BACKGROUND - *********************************************/ - -.reveal.has-parallax-background .backgrounds { - transition: all 0.8s ease; -} - -/* Global transition speed settings */ -.reveal.has-parallax-background[data-transition-speed="fast"] .backgrounds { - transition-duration: 400ms; -} -.reveal.has-parallax-background[data-transition-speed="slow"] .backgrounds { - transition-duration: 1200ms; -} - - -/********************************************* - * OVERLAY FOR LINK PREVIEWS AND HELP - *********************************************/ - -$overlayHeaderHeight: 40px; -$overlayHeaderPadding: 5px; - -.reveal > .overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 1000; - background: rgba( 0, 0, 0, 0.95 ); - backdrop-filter: blur( 6px ); - transition: all 0.3s ease; -} - - .reveal > .overlay .spinner { - position: absolute; - display: block; - top: 50%; - left: 50%; - width: 32px; - height: 32px; - margin: -16px 0 0 -16px; - z-index: 10; - background-image: url(data:image/gif;base64,R0lGODlhIAAgAPMAAJmZmf%2F%2F%2F6%2Bvr8nJybW1tcDAwOjo6Nvb26ioqKOjo7Ozs%2FLy8vz8%2FAAAAAAAAAAAACH%2FC05FVFNDQVBFMi4wAwEAAAAh%2FhpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh%2BQQJCgAAACwAAAAAIAAgAAAE5xDISWlhperN52JLhSSdRgwVo1ICQZRUsiwHpTJT4iowNS8vyW2icCF6k8HMMBkCEDskxTBDAZwuAkkqIfxIQyhBQBFvAQSDITM5VDW6XNE4KagNh6Bgwe60smQUB3d4Rz1ZBApnFASDd0hihh12BkE9kjAJVlycXIg7CQIFA6SlnJ87paqbSKiKoqusnbMdmDC2tXQlkUhziYtyWTxIfy6BE8WJt5YJvpJivxNaGmLHT0VnOgSYf0dZXS7APdpB309RnHOG5gDqXGLDaC457D1zZ%2FV%2FnmOM82XiHRLYKhKP1oZmADdEAAAh%2BQQJCgAAACwAAAAAIAAgAAAE6hDISWlZpOrNp1lGNRSdRpDUolIGw5RUYhhHukqFu8DsrEyqnWThGvAmhVlteBvojpTDDBUEIFwMFBRAmBkSgOrBFZogCASwBDEY%2FCZSg7GSE0gSCjQBMVG023xWBhklAnoEdhQEfyNqMIcKjhRsjEdnezB%2BA4k8gTwJhFuiW4dokXiloUepBAp5qaKpp6%2BHo7aWW54wl7obvEe0kRuoplCGepwSx2jJvqHEmGt6whJpGpfJCHmOoNHKaHx61WiSR92E4lbFoq%2BB6QDtuetcaBPnW6%2BO7wDHpIiK9SaVK5GgV543tzjgGcghAgAh%2BQQJCgAAACwAAAAAIAAgAAAE7hDISSkxpOrN5zFHNWRdhSiVoVLHspRUMoyUakyEe8PTPCATW9A14E0UvuAKMNAZKYUZCiBMuBakSQKG8G2FzUWox2AUtAQFcBKlVQoLgQReZhQlCIJesQXI5B0CBnUMOxMCenoCfTCEWBsJColTMANldx15BGs8B5wlCZ9Po6OJkwmRpnqkqnuSrayqfKmqpLajoiW5HJq7FL1Gr2mMMcKUMIiJgIemy7xZtJsTmsM4xHiKv5KMCXqfyUCJEonXPN2rAOIAmsfB3uPoAK%2B%2BG%2Bw48edZPK%2BM6hLJpQg484enXIdQFSS1u6UhksENEQAAIfkECQoAAAAsAAAAACAAIAAABOcQyEmpGKLqzWcZRVUQnZYg1aBSh2GUVEIQ2aQOE%2BG%2BcD4ntpWkZQj1JIiZIogDFFyHI0UxQwFugMSOFIPJftfVAEoZLBbcLEFhlQiqGp1Vd140AUklUN3eCA51C1EWMzMCezCBBmkxVIVHBWd3HHl9JQOIJSdSnJ0TDKChCwUJjoWMPaGqDKannasMo6WnM562R5YluZRwur0wpgqZE7NKUm%2BFNRPIhjBJxKZteWuIBMN4zRMIVIhffcgojwCF117i4nlLnY5ztRLsnOk%2BaV%2BoJY7V7m76PdkS4trKcdg0Zc0tTcKkRAAAIfkECQoAAAAsAAAAACAAIAAABO4QyEkpKqjqzScpRaVkXZWQEximw1BSCUEIlDohrft6cpKCk5xid5MNJTaAIkekKGQkWyKHkvhKsR7ARmitkAYDYRIbUQRQjWBwJRzChi9CRlBcY1UN4g0%2FVNB0AlcvcAYHRyZPdEQFYV8ccwR5HWxEJ02YmRMLnJ1xCYp0Y5idpQuhopmmC2KgojKasUQDk5BNAwwMOh2RtRq5uQuPZKGIJQIGwAwGf6I0JXMpC8C7kXWDBINFMxS4DKMAWVWAGYsAdNqW5uaRxkSKJOZKaU3tPOBZ4DuK2LATgJhkPJMgTwKCdFjyPHEnKxFCDhEAACH5BAkKAAAALAAAAAAgACAAAATzEMhJaVKp6s2nIkolIJ2WkBShpkVRWqqQrhLSEu9MZJKK9y1ZrqYK9WiClmvoUaF8gIQSNeF1Er4MNFn4SRSDARWroAIETg1iVwuHjYB1kYc1mwruwXKC9gmsJXliGxc%2BXiUCby9ydh1sOSdMkpMTBpaXBzsfhoc5l58Gm5yToAaZhaOUqjkDgCWNHAULCwOLaTmzswadEqggQwgHuQsHIoZCHQMMQgQGubVEcxOPFAcMDAYUA85eWARmfSRQCdcMe0zeP1AAygwLlJtPNAAL19DARdPzBOWSm1brJBi45soRAWQAAkrQIykShQ9wVhHCwCQCACH5BAkKAAAALAAAAAAgACAAAATrEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiRMDjI0Fd30%2FiI2UA5GSS5UDj2l6NoqgOgN4gksEBgYFf0FDqKgHnyZ9OX8HrgYHdHpcHQULXAS2qKpENRg7eAMLC7kTBaixUYFkKAzWAAnLC7FLVxLWDBLKCwaKTULgEwbLA4hJtOkSBNqITT3xEgfLpBtzE%2FjiuL04RGEBgwWhShRgQExHBAAh%2BQQJCgAAACwAAAAAIAAgAAAE7xDISWlSqerNpyJKhWRdlSAVoVLCWk6JKlAqAavhO9UkUHsqlE6CwO1cRdCQ8iEIfzFVTzLdRAmZX3I2SfZiCqGk5dTESJeaOAlClzsJsqwiJwiqnFrb2nS9kmIcgEsjQydLiIlHehhpejaIjzh9eomSjZR%2BipslWIRLAgMDOR2DOqKogTB9pCUJBagDBXR6XB0EBkIIsaRsGGMMAxoDBgYHTKJiUYEGDAzHC9EACcUGkIgFzgwZ0QsSBcXHiQvOwgDdEwfFs0sDzt4S6BK4xYjkDOzn0unFeBzOBijIm1Dgmg5YFQwsCMjp1oJ8LyIAACH5BAkKAAAALAAAAAAgACAAAATwEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiUd6GGl6NoiPOH16iZKNlH6KmyWFOggHhEEvAwwMA0N9GBsEC6amhnVcEwavDAazGwIDaH1ipaYLBUTCGgQDA8NdHz0FpqgTBwsLqAbWAAnIA4FWKdMLGdYGEgraigbT0OITBcg5QwPT4xLrROZL6AuQAPUS7bxLpoWidY0JtxLHKhwwMJBTHgPKdEQAACH5BAkKAAAALAAAAAAgACAAAATrEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiUd6GAULDJCRiXo1CpGXDJOUjY%2BYip9DhToJA4RBLwMLCwVDfRgbBAaqqoZ1XBMHswsHtxtFaH1iqaoGNgAIxRpbFAgfPQSqpbgGBqUD1wBXeCYp1AYZ19JJOYgH1KwA4UBvQwXUBxPqVD9L3sbp2BNk2xvvFPJd%2BMFCN6HAAIKgNggY0KtEBAAh%2BQQJCgAAACwAAAAAIAAgAAAE6BDISWlSqerNpyJKhWRdlSAVoVLCWk6JKlAqAavhO9UkUHsqlE6CwO1cRdCQ8iEIfzFVTzLdRAmZX3I2SfYIDMaAFdTESJeaEDAIMxYFqrOUaNW4E4ObYcCXaiBVEgULe0NJaxxtYksjh2NLkZISgDgJhHthkpU4mW6blRiYmZOlh4JWkDqILwUGBnE6TYEbCgevr0N1gH4At7gHiRpFaLNrrq8HNgAJA70AWxQIH1%2BvsYMDAzZQPC9VCNkDWUhGkuE5PxJNwiUK4UfLzOlD4WvzAHaoG9nxPi5d%2BjYUqfAhhykOFwJWiAAAIfkECQoAAAAsAAAAACAAIAAABPAQyElpUqnqzaciSoVkXVUMFaFSwlpOCcMYlErAavhOMnNLNo8KsZsMZItJEIDIFSkLGQoQTNhIsFehRww2CQLKF0tYGKYSg%2BygsZIuNqJksKgbfgIGepNo2cIUB3V1B3IvNiBYNQaDSTtfhhx0CwVPI0UJe0%2Bbm4g5VgcGoqOcnjmjqDSdnhgEoamcsZuXO1aWQy8KAwOAuTYYGwi7w5h%2BKr0SJ8MFihpNbx%2B4Erq7BYBuzsdiH1jCAzoSfl0rVirNbRXlBBlLX%2BBP0XJLAPGzTkAuAOqb0WT5AH7OcdCm5B8TgRwSRKIHQtaLCwg1RAAAOwAAAAAAAAAAAA%3D%3D); - - visibility: visible; - opacity: 0.6; - transition: all 0.3s ease; - } - - .reveal > .overlay header { - position: absolute; - left: 0; - top: 0; - width: 100%; - padding: $overlayHeaderPadding; - z-index: 2; - box-sizing: border-box; - } - .reveal > .overlay header a { - display: inline-block; - width: $overlayHeaderHeight; - height: $overlayHeaderHeight; - line-height: 36px; - padding: 0 10px; - float: right; - opacity: 0.6; - - box-sizing: border-box; - } - .reveal > .overlay header a:hover { - opacity: 1; - } - .reveal > .overlay header a .icon { - display: inline-block; - width: 20px; - height: 20px; - - background-position: 50% 50%; - background-size: 100%; - background-repeat: no-repeat; - } - .reveal > .overlay header a.close .icon { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABkklEQVRYR8WX4VHDMAxG6wnoJrABZQPYBCaBTWAD2g1gE5gg6OOsXuxIlr40d81dfrSJ9V4c2VLK7spHuTJ/5wpM07QXuXc5X0opX2tEJcadjHuV80li/FgxTIEK/5QBCICBD6xEhSMGHgQPgBgLiYVAB1dpSqKDawxTohFw4JSEA3clzgIBPCURwE2JucBR7rhPJJv5OpJwDX+SfDjgx1wACQeJG1aChP9K/IMmdZ8DtESV1WyP3Bt4MwM6sj4NMxMYiqUWHQu4KYA/SYkIjOsm3BXYWMKFDwU2khjCQ4ELJUJ4SmClRArOCmSXGuKma0fYD5CbzHxFpCSGAhfAVSSUGDUk2BWZaff2g6GE15BsBQ9nwmpIGDiyHQddwNTMKkbZaf9fajXQca1EX44puJZUsnY0ObGmITE3GVLCbEhQUjGVt146j6oasWN+49Vph2w1pZ5EansNZqKBm1txbU57iRRcZ86RWMDdWtBJUHBHwoQPi1GV+JCbntmvok7iTX4/Up9mgyTc/FJYDTcndgH/AA5A/CHsyEkVAAAAAElFTkSuQmCC); - } - .reveal > .overlay header a.external .icon { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAcElEQVRYR+2WSQoAIQwEzf8f7XiOMkUQxUPlGkM3hVmiQfQR9GYnH1SsAQlI4DiBqkCMoNb9y2e90IAEJPAcgdznU9+engMaeJ7Azh5Y1U67gAho4DqBqmB1buAf0MB1AlVBek83ZPkmJMGc1wAR+AAqod/B97TRpQAAAABJRU5ErkJggg==); - } - - .reveal > .overlay .viewport { - position: absolute; - display: flex; - top: $overlayHeaderHeight + $overlayHeaderPadding*2; - right: 0; - bottom: 0; - left: 0; - } - - .reveal > .overlay.overlay-preview .viewport iframe { - width: 100%; - height: 100%; - max-width: 100%; - max-height: 100%; - border: 0; - - opacity: 0; - visibility: hidden; - transition: all 0.3s ease; - } - - .reveal > .overlay.overlay-preview.loaded .viewport iframe { - opacity: 1; - visibility: visible; - } - - .reveal > .overlay.overlay-preview.loaded .viewport-inner { - position: absolute; - z-index: -1; - left: 0; - top: 45%; - width: 100%; - text-align: center; - letter-spacing: normal; - } - .reveal > .overlay.overlay-preview .x-frame-error { - opacity: 0; - transition: opacity 0.3s ease 0.3s; - } - .reveal > .overlay.overlay-preview.loaded .x-frame-error { - opacity: 1; - } - - .reveal > .overlay.overlay-preview.loaded .spinner { - opacity: 0; - visibility: hidden; - transform: scale(0.2); - } - - .reveal > .overlay.overlay-help .viewport { - overflow: auto; - color: #fff; - } - - .reveal > .overlay.overlay-help .viewport .viewport-inner { - width: 600px; - margin: auto; - padding: 20px 20px 80px 20px; - text-align: center; - letter-spacing: normal; - } - - .reveal > .overlay.overlay-help .viewport .viewport-inner .title { - font-size: 20px; - } - - .reveal > .overlay.overlay-help .viewport .viewport-inner table { - border: 1px solid #fff; - border-collapse: collapse; - font-size: 16px; - } - - .reveal > .overlay.overlay-help .viewport .viewport-inner table th, - .reveal > .overlay.overlay-help .viewport .viewport-inner table td { - width: 200px; - padding: 14px; - border: 1px solid #fff; - vertical-align: middle; - } - - .reveal > .overlay.overlay-help .viewport .viewport-inner table th { - padding-top: 20px; - padding-bottom: 20px; - } - -/********************************************* - * PLAYBACK COMPONENT - *********************************************/ - -.reveal .playback { - position: absolute; - left: 15px; - bottom: 20px; - z-index: 30; - cursor: pointer; - transition: all 400ms ease; - -webkit-tap-highlight-color: rgba( 0, 0, 0, 0 ); -} - -.reveal.overview .playback { - opacity: 0; - visibility: hidden; -} - - -/********************************************* - * CODE HIGHLGIHTING - *********************************************/ - -.reveal .hljs { - min-height: 100%; -} - -.reveal .hljs table { - margin: initial; -} - -.reveal .hljs-ln-code, -.reveal .hljs-ln-numbers { - padding: 0; - border: 0; -} - -.reveal .hljs-ln-numbers { - opacity: 0.6; - padding-right: 0.75em; - text-align: right; - vertical-align: top; -} - -.reveal .hljs.has-highlights tr:not(.highlight-line) { - opacity: 0.4; -} - -.reveal .hljs.has-highlights.fragment { - transition: all .2s ease; -} - -.reveal .hljs:not(:first-child).fragment { - position: absolute; - top: 0; - left: 0; - width: 100%; - box-sizing: border-box; -} - -.reveal pre[data-auto-animate-target] { - overflow: hidden; -} -.reveal pre[data-auto-animate-target] code { - height: 100%; -} - - -/********************************************* - * ROLLING LINKS - *********************************************/ - -.reveal .roll { - display: inline-block; - line-height: 1.2; - overflow: hidden; - - vertical-align: top; - perspective: 400px; - perspective-origin: 50% 50%; -} - .reveal .roll:hover { - background: none; - text-shadow: none; - } -.reveal .roll span { - display: block; - position: relative; - padding: 0 2px; - - pointer-events: none; - transition: all 400ms ease; - transform-origin: 50% 0%; - transform-style: preserve-3d; - backface-visibility: hidden; -} - .reveal .roll:hover span { - background: rgba(0,0,0,0.5); - transform: translate3d( 0px, 0px, -45px ) rotateX( 90deg ); - } -.reveal .roll span:after { - content: attr(data-title); - - display: block; - position: absolute; - left: 0; - top: 0; - padding: 0 2px; - backface-visibility: hidden; - transform-origin: 50% 0%; - transform: translate3d( 0px, 110%, 0px ) rotateX( -90deg ); -} - - -/********************************************* - * SPEAKER NOTES - *********************************************/ - -$notesWidthPercent: 25%; - -// Hide on-page notes -.reveal aside.notes { - display: none; -} - -// An interface element that can optionally be used to show the -// speaker notes to all viewers, on top of the presentation -.reveal .speaker-notes { - display: none; - position: absolute; - width: math.div($notesWidthPercent, (1 - math.div($notesWidthPercent,100))) * 1%; - height: 100%; - top: 0; - left: 100%; - padding: 14px 18px 14px 18px; - z-index: 1; - font-size: 18px; - line-height: 1.4; - border: 1px solid rgba( 0, 0, 0, 0.05 ); - color: #222; - background-color: #f5f5f5; - overflow: auto; - box-sizing: border-box; - text-align: left; - font-family: Helvetica, sans-serif; - -webkit-overflow-scrolling: touch; - - .notes-placeholder { - color: #ccc; - font-style: italic; - } - - &:focus { - outline: none; - } - - &:before { - content: 'Speaker notes'; - display: block; - margin-bottom: 10px; - opacity: 0.5; - } -} - - -.reveal.show-notes { - max-width: 100% - $notesWidthPercent; - overflow: visible; -} - -.reveal.show-notes .speaker-notes { - display: block; -} - -@media screen and (min-width: 1600px) { - .reveal .speaker-notes { - font-size: 20px; - } -} - -@media screen and (max-width: 1024px) { - .reveal.show-notes { - border-left: 0; - max-width: none; - max-height: 70%; - max-height: 70vh; - overflow: visible; - } - - .reveal.show-notes .speaker-notes { - top: 100%; - left: 0; - width: 100%; - height: 30vh; - border: 0; - } -} - -@media screen and (max-width: 600px) { - .reveal.show-notes { - max-height: 60%; - max-height: 60vh; - } - - .reveal.show-notes .speaker-notes { - top: 100%; - height: 40vh; - } - - .reveal .speaker-notes { - font-size: 14px; - } -} - - -/********************************************* - * JUMP-TO-SLIDE COMPONENT - *********************************************/ - - .reveal .jump-to-slide { - position: absolute; - top: 15px; - left: 15px; - z-index: 30; - font-size: 32px; - -webkit-tap-highlight-color: rgba( 0, 0, 0, 0 ); -} - -.reveal .jump-to-slide-input { - background: transparent; - padding: 8px; - font-size: inherit; - color: currentColor; - border: 0; -} -.reveal .jump-to-slide-input::placeholder { - color: currentColor; - opacity: 0.5; -} - -.reveal.has-dark-background .jump-to-slide-input { - color: #fff; -} -.reveal.has-light-background .jump-to-slide-input { - color: #222; -} - -.reveal .jump-to-slide-input:focus { - outline: none; -} - - -/********************************************* - * ZOOM PLUGIN - *********************************************/ - -.zoomed .reveal *, -.zoomed .reveal *:before, -.zoomed .reveal *:after { - backface-visibility: visible !important; -} - -.zoomed .reveal .progress, -.zoomed .reveal .controls { - opacity: 0; -} - -.zoomed .reveal .roll span { - background: none; -} - -.zoomed .reveal .roll span:after { - visibility: hidden; -} - - -/********************************************* - * SCROLL VIEW - *********************************************/ -.reveal-viewport.loading-scroll-mode { - visibility: hidden; -} - -.reveal-viewport.reveal-scroll { - & { - margin: 0 auto; - overflow: auto; - overflow-x: hidden; - overflow-y: auto; - z-index: 1; - - --r-scrollbar-width: 7px; - --r-scrollbar-trigger-size: 5px; - --r-controls-spacing: 8px; - } - - @media screen and (max-width: 500px) { - --r-scrollbar-width: 3px; - --r-scrollbar-trigger-size: 3px; - } - - .controls, - .progress, - .playback, - .backgrounds, - .slide-number, - .speaker-notes { - display: none !important; - } - - .overlay, - .pause-overlay { - position: fixed; - } - - .reveal { - overflow: visible; - touch-action: manipulation; - } - - .slides { - position: static; - pointer-events: initial; - - left: auto; - top: auto; - width: 100% !important; - margin: 0; - padding: 0; - - overflow: visible; - display: block; - - perspective: none; - perspective-origin: 50% 50%; - } - - .scroll-page { - position: relative; - width: 100%; - height: calc(var(--page-height) + var(--page-scroll-padding)); - z-index: 1; - overflow: visible; - } - - .scroll-page-sticky { - position: sticky; - height: var(--page-height); - top: 0px; - } - - .scroll-page-content { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - overflow: hidden; - } - - .scroll-page section { - visibility: visible !important; - display: block !important; - position: absolute !important; - width: var(--slide-width) !important; - height: var(--slide-height) !important; - top: 50% !important; - left: 50% !important; - opacity: 1 !important; - transform: scale(var(--slide-scale)) translate(-50%, -50%) !important; - transform-style: flat !important; - transform-origin: 0 0 !important; - } - - .slide-background { - display: block !important; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: auto !important; - visibility: visible; - opacity: 1; - touch-action: manipulation; - } -} - -// Chromium -.reveal-viewport.reveal-scroll[data-scrollbar="true"]::-webkit-scrollbar, -.reveal-viewport.reveal-scroll[data-scrollbar="auto"]::-webkit-scrollbar { - display: none; -} - -// Firefox -.reveal-viewport.reveal-scroll[data-scrollbar="true"], -.reveal-viewport.reveal-scroll[data-scrollbar="auto"] { - scrollbar-width: none; -} - -.reveal.has-dark-background, -.reveal-viewport.has-dark-background { - --r-overlay-element-bg-color: 240, 240, 240; - --r-overlay-element-fg-color: 0, 0, 0; -} -.reveal.has-light-background, -.reveal-viewport.has-light-background { - --r-overlay-element-bg-color: 0, 0, 0; - --r-overlay-element-fg-color: 240, 240, 240; -} - -.reveal-viewport.reveal-scroll .scrollbar { - position: sticky; - top: 50%; - z-index: 20; - opacity: 0; - transition: all 0.3s ease; - - &.visible, - &:hover { - opacity: 1; - } - - .scrollbar-inner { - position: absolute; - width: var(--r-scrollbar-width); - height: calc(var(--viewport-height) - var(--r-controls-spacing) * 2); - right: var(--r-controls-spacing); - top: 0; - transform: translateY(-50%); - border-radius: var(--r-scrollbar-width); - z-index: 10; - } - - .scrollbar-playhead { - position: absolute; - width: var(--r-scrollbar-width); - height: var(--r-scrollbar-width); - top: 0; - left: 0; - border-radius: var(--r-scrollbar-width); - background-color: rgba(var(--r-overlay-element-bg-color), 1); - z-index: 11; - transition: background-color 0.2s ease; - } - - .scrollbar-slide { - position: absolute; - width: 100%; - background-color: rgba(var(--r-overlay-element-bg-color), 0.2); - box-shadow: 0 0 0px 1px rgba(var(--r-overlay-element-fg-color), 0.1); - border-radius: var(--r-scrollbar-width); - transition: background-color 0.2s ease; - } - - // Hit area - .scrollbar-slide:after { - content: ''; - position: absolute; - width: 200%; - height: 100%; - top: 0; - left: -50%; - background: rgba( 0, 0, 0, 0 ); - z-index: -1; - } - - .scrollbar-slide:hover, - .scrollbar-slide.active { - background-color: rgba(var(--r-overlay-element-bg-color), 0.4); - } - - .scrollbar-trigger { - position: absolute; - width: 100%; - transition: background-color 0.2s ease; - } - - .scrollbar-slide.active.has-triggers { - background-color: rgba(var(--r-overlay-element-bg-color), 0.4); - z-index: 10; - } - - .scrollbar-slide.active .scrollbar-trigger:after { - content: ''; - position: absolute; - width: var(--r-scrollbar-trigger-size); - height: var(--r-scrollbar-trigger-size); - border-radius: 20px; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: rgba(var(--r-overlay-element-bg-color), 1); - transition: transform 0.2s ease, opacity 0.2s ease; - opacity: 0.4; - } - - .scrollbar-slide.active .scrollbar-trigger.active:after, - .scrollbar-slide.active .scrollbar-trigger.active ~ .scrollbar-trigger:after { - opacity: 1; - } - - .scrollbar-slide.active .scrollbar-trigger ~ .scrollbar-trigger.active:after { - transform: translate(calc( var(--r-scrollbar-width) * -2), 0); - background-color: rgba(var(--r-overlay-element-bg-color), 1); - } -} - - -/********************************************* - * PRINT STYLES - *********************************************/ - -@import 'print/pdf.scss'; -@import 'print/paper.scss'; - diff --git a/css/theme/README.md b/css/theme/README.md deleted file mode 100644 index 30916c4..0000000 --- a/css/theme/README.md +++ /dev/null @@ -1,21 +0,0 @@ -## Dependencies - -Themes are written using Sass to keep things modular and reduce the need for repeated selectors across files. Make sure that you have the reveal.js development environment installed before proceeding: https://revealjs.com/installation/#full-setup - -## Creating a Theme - -To create your own theme, start by duplicating a ```.scss``` file in [/css/theme/source](https://github.com/hakimel/reveal.js/blob/master/css/theme/source). It will be automatically compiled from Sass to CSS (see the [gulpfile](https://github.com/hakimel/reveal.js/blob/master/gulpfile.js)) when you run `npm run build -- css-themes`. - -Each theme file does four things in the following order: - -1. **Include [/css/theme/template/mixins.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/mixins.scss)** -Shared utility functions. - -2. **Include [/css/theme/template/settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss)** -Declares a set of custom variables that the template file (step 4) expects. Can be overridden in step 3. - -3. **Override** -This is where you override the default theme. Either by specifying variables (see [settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss) for reference) or by adding any selectors and styles you please. - -4. **Include [/css/theme/template/theme.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/theme.scss)** -The template theme file which will generate final CSS output based on the currently defined variables. diff --git a/css/theme/source/beige.scss b/css/theme/source/beige.scss deleted file mode 100644 index 7598b94..0000000 --- a/css/theme/source/beige.scss +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Beige theme for reveal.js. - * - * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(./fonts/league-gothic/league-gothic.css); -@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); - - -// Override theme settings (see ../template/settings.scss) -$mainColor: #333; -$headingColor: #333; -$headingTextShadow: none; -$backgroundColor: #f7f3de; -$linkColor: #8b743d; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: rgba(79, 64, 28, 0.99); -$heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Background generator -@mixin bodyBackground() { - @include radial-gradient( rgba(247,242,211,1), rgba(255,255,255,1) ); -} - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/black-contrast.scss b/css/theme/source/black-contrast.scss deleted file mode 100644 index 9e1a2ca..0000000 --- a/css/theme/source/black-contrast.scss +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Black compact & high contrast reveal.js theme, with headers not in capitals. - * - * By Peter Kehl. Based on black.(s)css by Hakim El Hattab, http://hakim.se - * - * - Keep the source similar to black.css - for easy comparison. - * - $mainFontSize controls code blocks, too (although under some ratio). - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - -// Include theme-specific fonts -@import url(./fonts/source-sans-pro/source-sans-pro.css); - - -// Override theme settings (see ../template/settings.scss) -$backgroundColor: #000000; - -$mainColor: #fff; -$headingColor: #fff; - -$mainFontSize: 42px; -$mainFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingTextShadow: none; -$headingLetterSpacing: normal; -$headingTextTransform: uppercase; -$headingFontWeight: 600; -$linkColor: #42affa; -$linkColorHover: lighten( $linkColor, 15% ); -$selectionBackgroundColor: lighten( $linkColor, 25% ); - -$heading1Size: 2.5em; -$heading2Size: 1.6em; -$heading3Size: 1.3em; -$heading4Size: 1.0em; - -// Change text colors against light slide backgrounds -@include light-bg-text-color(#000); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/black.scss b/css/theme/source/black.scss deleted file mode 100644 index 7c655c4..0000000 --- a/css/theme/source/black.scss +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Black theme for reveal.js. This is the opposite of the 'white' theme. - * - * By Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - -// Include theme-specific fonts -@import url(./fonts/source-sans-pro/source-sans-pro.css); - - -// Override theme settings (see ../template/settings.scss) -$backgroundColor: #191919; - -$mainColor: #fff; -$headingColor: #fff; - -$mainFontSize: 42px; -$mainFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingTextShadow: none; -$headingLetterSpacing: normal; -$headingTextTransform: uppercase; -$headingFontWeight: 600; -$linkColor: #42affa; -$linkColorHover: lighten( $linkColor, 15% ); -$selectionBackgroundColor: rgba( $linkColor, 0.75 ); - -$heading1Size: 2.5em; -$heading2Size: 1.6em; -$heading3Size: 1.3em; -$heading4Size: 1.0em; - -// Change text colors against light slide backgrounds -@include light-bg-text-color(#222); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/blood.scss b/css/theme/source/blood.scss deleted file mode 100644 index b5a8679..0000000 --- a/css/theme/source/blood.scss +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Blood theme for reveal.js - * Author: Walther http://github.com/Walther - * - * Designed to be used with highlight.js theme - * "monokai_sublime.css" available from - * https://github.com/isagalaev/highlight.js/ - * - * For other themes, change $codeBackground accordingly. - * - */ - - // Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - -// Include theme-specific fonts - -@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,700,300italic,700italic); - -// Colors used in the theme -$blood: #a23; -$coal: #222; -$codeBackground: #23241f; - -$backgroundColor: $coal; - -// Main text -$mainFont: Ubuntu, 'sans-serif'; -$mainColor: #eee; - -// Headings -$headingFont: Ubuntu, 'sans-serif'; -$headingTextShadow: 2px 2px 2px $coal; - -// h1 shadow, borrowed humbly from -// (c) Default theme by Hakim El Hattab -$heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); - -// Links -$linkColor: $blood; -$linkColorHover: lighten( $linkColor, 20% ); - -// Text selection -$selectionBackgroundColor: $blood; -$selectionColor: #fff; - -// Change text colors against dark slide backgrounds -@include light-bg-text-color(#222); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- - -// some overrides after theme template import - -.reveal p { - font-weight: 300; - text-shadow: 1px 1px $coal; -} - -section.has-light-background { - p, h1, h2, h3, h4 { - text-shadow: none; - } -} - -.reveal h1, -.reveal h2, -.reveal h3, -.reveal h4, -.reveal h5, -.reveal h6 { - font-weight: 700; -} - -.reveal p code { - background-color: $codeBackground; - display: inline-block; - border-radius: 7px; -} - -.reveal small code { - vertical-align: baseline; -} \ No newline at end of file diff --git a/css/theme/source/dracula.scss b/css/theme/source/dracula.scss deleted file mode 100644 index ae968b8..0000000 --- a/css/theme/source/dracula.scss +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Dracula Dark theme for reveal.js. - * Based on https://draculatheme.com - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -$systemFontsSansSerif: -apple-system, - BlinkMacSystemFont, - avenir next, - avenir, - segoe ui, - helvetica neue, - helvetica, - Cantarell, - Ubuntu, - roboto, - noto, - arial, - sans-serif; -$systemFontsMono: Menlo, - Consolas, - Monaco, - Liberation Mono, - Lucida Console, - monospace; - -/** - * Dracula colors by Zeno Rocha - * https://draculatheme.com/contribute - */ -html * { - color-profile: sRGB; - rendering-intent: auto; -} - -$background: #282A36; -$foreground: #F8F8F2; -$selection: #44475A; -$comment: #6272A4; -$red: #FF5555; -$orange: #FFB86C; -$yellow: #F1FA8C; -$green: #50FA7B; -$purple: #BD93F9; -$cyan: #8BE9FD; -$pink: #FF79C6; - - - -// Override theme settings (see ../template/settings.scss) -$mainColor: $foreground; -$headingColor: $purple; -$headingTextShadow: none; -$headingTextTransform: none; -$backgroundColor: $background; -$linkColor: $pink; -$linkColorHover: $cyan; -$selectionBackgroundColor: $selection; -$inlineCodeColor: $green; -$listBulletColor: $cyan; - -$mainFont: $systemFontsSansSerif; -$codeFont: "Fira Code", $systemFontsMono; - -// Change text colors against light slide backgrounds -@include light-bg-text-color($background); - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- - -// Define additional color effects based on Dracula spec -// https://spec.draculatheme.com/ -:root { - --r-bold-color: #{$orange}; - --r-italic-color: #{$yellow}; - --r-inline-code-color: #{$inlineCodeColor}; - --r-list-bullet-color: #{$listBulletColor}; -} - -.reveal { - strong, b { - color: var(--r-bold-color); - } - em, i, blockquote { - color: var(--r-italic-color); - } - code { - color: var(--r-inline-code-color); - } - // Dracula colored list bullets and numbers - ul, ol { - li::marker { - color: var(--r-list-bullet-color); - } - } -} - diff --git a/css/theme/source/league.scss b/css/theme/source/league.scss deleted file mode 100644 index ee01258..0000000 --- a/css/theme/source/league.scss +++ /dev/null @@ -1,36 +0,0 @@ -/** - * League theme for reveal.js. - * - * This was the default theme pre-3.0.0. - * - * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(./fonts/league-gothic/league-gothic.css); -@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); - -// Override theme settings (see ../template/settings.scss) -$headingTextShadow: 0px 0px 6px rgba(0,0,0,0.2); -$heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15); - -// Background generator -@mixin bodyBackground() { - @include radial-gradient( rgba(28,30,32,1), rgba(85,90,95,1) ); -} - -// Change text colors against light slide backgrounds -@include light-bg-text-color(#222); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/moon.scss b/css/theme/source/moon.scss deleted file mode 100644 index 59ef0a9..0000000 --- a/css/theme/source/moon.scss +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Solarized Dark theme for reveal.js. - * Author: Achim Staebler - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(./fonts/league-gothic/league-gothic.css); -@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); - -/** - * Solarized colors by Ethan Schoonover - */ - -// Solarized colors -$base03: #002b36; -$base02: #073642; -$base01: #586e75; -$base00: #657b83; -$base0: #839496; -$base1: #93a1a1; -$base2: #eee8d5; -$base3: #fdf6e3; -$yellow: #b58900; -$orange: #cb4b16; -$red: #dc322f; -$magenta: #d33682; -$violet: #6c71c4; -$blue: #268bd2; -$cyan: #2aa198; -$green: #859900; - -// Override theme settings (see ../template/settings.scss) -$mainColor: $base1; -$headingColor: $base2; -$headingTextShadow: none; -$backgroundColor: $base03; -$linkColor: $blue; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: $magenta; - -// Change text colors against light slide backgrounds -@include light-bg-text-color(#222); - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/night.scss b/css/theme/source/night.scss deleted file mode 100644 index 98a2062..0000000 --- a/css/theme/source/night.scss +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Black theme for reveal.js. - * - * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - -// Include theme-specific fonts -@import url(https://fonts.googleapis.com/css?family=Montserrat:700); -@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic,700italic); - - -// Override theme settings (see ../template/settings.scss) -$backgroundColor: #111; - -$mainFont: 'Open Sans', sans-serif; -$linkColor: #e7ad52; -$linkColorHover: lighten( $linkColor, 20% ); -$headingFont: 'Montserrat', Impact, sans-serif; -$headingTextShadow: none; -$headingLetterSpacing: -0.03em; -$headingTextTransform: none; -$selectionBackgroundColor: #e7ad52; - -// Change text colors against light slide backgrounds -@include light-bg-text-color(#222); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- \ No newline at end of file diff --git a/css/theme/source/serif.scss b/css/theme/source/serif.scss deleted file mode 100644 index babec4d..0000000 --- a/css/theme/source/serif.scss +++ /dev/null @@ -1,41 +0,0 @@ -/** - * A simple theme for reveal.js presentations, similar - * to the default theme. The accent color is brown. - * - * This theme is Copyright (C) 2012-2013 Owen Versteeg, http://owenversteeg.com - it is MIT licensed. - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Override theme settings (see ../template/settings.scss) -$mainFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; -$mainColor: #000; -$headingFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; -$headingColor: #383D3D; -$headingTextShadow: none; -$headingTextTransform: none; -$backgroundColor: #F0F1EB; -$linkColor: #51483D; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: #26351C; - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -.reveal a { - line-height: 1.3em; -} - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/simple.scss b/css/theme/source/simple.scss deleted file mode 100644 index 51a21af..0000000 --- a/css/theme/source/simple.scss +++ /dev/null @@ -1,43 +0,0 @@ -/** - * A simple theme for reveal.js presentations, similar - * to the default theme. The accent color is darkblue. - * - * This theme is Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed. - * reveal.js is Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700); -@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); - - -// Override theme settings (see ../template/settings.scss) -$mainFont: 'Lato', sans-serif; -$mainColor: #000; -$headingFont: 'News Cycle', Impact, sans-serif; -$headingColor: #000; -$headingTextShadow: none; -$headingTextTransform: none; -$backgroundColor: #fff; -$linkColor: #00008B; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: rgba(0, 0, 0, 0.99); - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- \ No newline at end of file diff --git a/css/theme/source/sky.scss b/css/theme/source/sky.scss deleted file mode 100644 index 457e9e5..0000000 --- a/css/theme/source/sky.scss +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Sky theme for reveal.js. - * - * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(https://fonts.googleapis.com/css?family=Quicksand:400,700,400italic,700italic); -@import url(https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700); - - -// Override theme settings (see ../template/settings.scss) -$mainFont: 'Open Sans', sans-serif; -$mainColor: #333; -$headingFont: 'Quicksand', sans-serif; -$headingColor: #333; -$headingLetterSpacing: -0.08em; -$headingTextShadow: none; -$backgroundColor: #f7fbfc; -$linkColor: #3b759e; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: #134674; - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Fix links so they are not cut off -.reveal a { - line-height: 1.3em; -} - -// Background generator -@mixin bodyBackground() { - @include radial-gradient( #add9e4, #f7fbfc ); -} - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/solarized.scss b/css/theme/source/solarized.scss deleted file mode 100644 index f325345..0000000 --- a/css/theme/source/solarized.scss +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Solarized Light theme for reveal.js. - * Author: Achim Staebler - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - - -// Include theme-specific fonts -@import url(./fonts/league-gothic/league-gothic.css); -@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic); - - -/** - * Solarized colors by Ethan Schoonover - */ -html * { - color-profile: sRGB; - rendering-intent: auto; -} - -// Solarized colors -$base03: #002b36; -$base02: #073642; -$base01: #586e75; -$base00: #657b83; -$base0: #839496; -$base1: #93a1a1; -$base2: #eee8d5; -$base3: #fdf6e3; -$yellow: #b58900; -$orange: #cb4b16; -$red: #dc322f; -$magenta: #d33682; -$violet: #6c71c4; -$blue: #268bd2; -$cyan: #2aa198; -$green: #859900; - -// Override theme settings (see ../template/settings.scss) -$mainColor: $base00; -$headingColor: $base01; -$headingTextShadow: none; -$backgroundColor: $base3; -$linkColor: $blue; -$linkColorHover: lighten( $linkColor, 20% ); -$selectionBackgroundColor: $magenta; - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Background generator -// @mixin bodyBackground() { -// @include radial-gradient( rgba($base3,1), rgba(lighten($base3, 20%),1) ); -// } - - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/white-contrast.scss b/css/theme/source/white-contrast.scss deleted file mode 100644 index e22007e..0000000 --- a/css/theme/source/white-contrast.scss +++ /dev/null @@ -1,52 +0,0 @@ -/** - * White compact & high contrast reveal.js theme, with headers not in capitals. - * - * By Peter Kehl. Based on white.(s)css by Hakim El Hattab, http://hakim.se - * - * - Keep the source similar to black.css - for easy comparison. - * - $mainFontSize controls code blocks, too (although under some ratio). - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - -// Include theme-specific fonts -@import url(./fonts/source-sans-pro/source-sans-pro.css); - - -// Override theme settings (see ../template/settings.scss) -$backgroundColor: #fff; - -$mainColor: #000; -$headingColor: #000; - -$mainFontSize: 42px; -$mainFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingTextShadow: none; -$headingLetterSpacing: normal; -$headingTextTransform: uppercase; -$headingFontWeight: 600; -$linkColor: #2a76dd; -$linkColorHover: lighten( $linkColor, 15% ); -$selectionBackgroundColor: lighten( $linkColor, 25% ); - -$heading1Size: 2.5em; -$heading2Size: 1.6em; -$heading3Size: 1.3em; -$heading4Size: 1.0em; - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/source/white.scss b/css/theme/source/white.scss deleted file mode 100644 index a2b1292..0000000 --- a/css/theme/source/white.scss +++ /dev/null @@ -1,49 +0,0 @@ -/** - * White theme for reveal.js. This is the opposite of the 'black' theme. - * - * By Hakim El Hattab, http://hakim.se - */ - - -// Default mixins and settings ----------------- -@import "../template/mixins"; -@import "../template/settings"; -// --------------------------------------------- - - -// Include theme-specific fonts -@import url(./fonts/source-sans-pro/source-sans-pro.css); - - -// Override theme settings (see ../template/settings.scss) -$backgroundColor: #fff; - -$mainColor: #222; -$headingColor: #222; - -$mainFontSize: 42px; -$mainFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingFont: 'Source Sans Pro', Helvetica, sans-serif; -$headingTextShadow: none; -$headingLetterSpacing: normal; -$headingTextTransform: uppercase; -$headingFontWeight: 600; -$linkColor: #2a76dd; -$linkColorHover: lighten( $linkColor, 15% ); -$selectionBackgroundColor: lighten( $linkColor, 25% ); - -$heading1Size: 2.5em; -$heading2Size: 1.6em; -$heading3Size: 1.3em; -$heading4Size: 1.0em; - -$overlayElementBgColor: 0, 0, 0; -$overlayElementFgColor: 240, 240, 240; - -// Change text colors against dark slide backgrounds -@include dark-bg-text-color(#fff); - - -// Theme template ------------------------------ -@import "../template/theme"; -// --------------------------------------------- diff --git a/css/theme/template/exposer.scss b/css/theme/template/exposer.scss deleted file mode 100644 index 2e9288d..0000000 --- a/css/theme/template/exposer.scss +++ /dev/null @@ -1,30 +0,0 @@ -// Exposes theme's variables for easy re-use in CSS for plugin authors - -:root { - --r-background-color: #{$backgroundColor}; - --r-main-font: #{$mainFont}; - --r-main-font-size: #{$mainFontSize}; - --r-main-color: #{$mainColor}; - --r-block-margin: #{$blockMargin}; - --r-heading-margin: #{$headingMargin}; - --r-heading-font: #{$headingFont}; - --r-heading-color: #{$headingColor}; - --r-heading-line-height: #{$headingLineHeight}; - --r-heading-letter-spacing: #{$headingLetterSpacing}; - --r-heading-text-transform: #{$headingTextTransform}; - --r-heading-text-shadow: #{$headingTextShadow}; - --r-heading-font-weight: #{$headingFontWeight}; - --r-heading1-text-shadow: #{$heading1TextShadow}; - --r-heading1-size: #{$heading1Size}; - --r-heading2-size: #{$heading2Size}; - --r-heading3-size: #{$heading3Size}; - --r-heading4-size: #{$heading4Size}; - --r-code-font: #{$codeFont}; - --r-link-color: #{$linkColor}; - --r-link-color-dark: #{darken($linkColor , 15% )}; - --r-link-color-hover: #{$linkColorHover}; - --r-selection-background-color: #{$selectionBackgroundColor}; - --r-selection-color: #{$selectionColor}; - --r-overlay-element-bg-color: #{$overlayElementBgColor}; - --r-overlay-element-fg-color: #{$overlayElementFgColor}; -} diff --git a/css/theme/template/mixins.scss b/css/theme/template/mixins.scss deleted file mode 100644 index 17a3db5..0000000 --- a/css/theme/template/mixins.scss +++ /dev/null @@ -1,45 +0,0 @@ -@mixin vertical-gradient( $top, $bottom ) { - background: $top; - background: -moz-linear-gradient( top, $top 0%, $bottom 100% ); - background: -webkit-gradient( linear, left top, left bottom, color-stop(0%,$top), color-stop(100%,$bottom) ); - background: -webkit-linear-gradient( top, $top 0%, $bottom 100% ); - background: -o-linear-gradient( top, $top 0%, $bottom 100% ); - background: -ms-linear-gradient( top, $top 0%, $bottom 100% ); - background: linear-gradient( top, $top 0%, $bottom 100% ); -} - -@mixin horizontal-gradient( $top, $bottom ) { - background: $top; - background: -moz-linear-gradient( left, $top 0%, $bottom 100% ); - background: -webkit-gradient( linear, left top, right top, color-stop(0%,$top), color-stop(100%,$bottom) ); - background: -webkit-linear-gradient( left, $top 0%, $bottom 100% ); - background: -o-linear-gradient( left, $top 0%, $bottom 100% ); - background: -ms-linear-gradient( left, $top 0%, $bottom 100% ); - background: linear-gradient( left, $top 0%, $bottom 100% ); -} - -@mixin radial-gradient( $outer, $inner, $type: circle ) { - background: $outer; - background: -moz-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); - background: -webkit-gradient( radial, center center, 0px, center center, 100%, color-stop(0%,$inner), color-stop(100%,$outer) ); - background: -webkit-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); - background: -o-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); - background: -ms-radial-gradient( center, $type cover, $inner 0%, $outer 100% ); - background: radial-gradient( center, $type cover, $inner 0%, $outer 100% ); -} - -@mixin light-bg-text-color( $color ) { - section.has-light-background { - &, h1, h2, h3, h4, h5, h6 { - color: $color; - } - } -} - -@mixin dark-bg-text-color( $color ) { - section.has-dark-background { - &, h1, h2, h3, h4, h5, h6 { - color: $color; - } - } -} \ No newline at end of file diff --git a/css/theme/template/settings.scss b/css/theme/template/settings.scss deleted file mode 100644 index 3d54ac8..0000000 --- a/css/theme/template/settings.scss +++ /dev/null @@ -1,50 +0,0 @@ -// Base settings for all themes that can optionally be -// overridden by the super-theme - -// Background of the presentation -$backgroundColor: #2b2b2b; - -// Primary/body text -$mainFont: 'Lato', sans-serif; -$mainFontSize: 40px; -$mainColor: #eee; - -// Vertical spacing between blocks of text -$blockMargin: 20px; - -// Headings -$headingMargin: 0 0 $blockMargin 0; -$headingFont: 'League Gothic', Impact, sans-serif; -$headingColor: #eee; -$headingLineHeight: 1.2; -$headingLetterSpacing: normal; -$headingTextTransform: uppercase; -$headingTextShadow: none; -$headingFontWeight: normal; -$heading1TextShadow: $headingTextShadow; - -$heading1Size: 3.77em; -$heading2Size: 2.11em; -$heading3Size: 1.55em; -$heading4Size: 1.00em; - -$codeFont: monospace; - -// Links and actions -$linkColor: #13DAEC; -$linkColorHover: lighten( $linkColor, 20% ); - -// Text selection -$selectionBackgroundColor: #FF5E99; -$selectionColor: #fff; - -// Colors used for UI elements that are overlaid on top of -// the presentation -$overlayElementBgColor: 240, 240, 240; -$overlayElementFgColor: 0, 0, 0; - -// Generates the presentation background, can be overridden -// to return a background image or gradient -@mixin bodyBackground() { - background: $backgroundColor; -} diff --git a/css/theme/template/theme.scss b/css/theme/template/theme.scss deleted file mode 100644 index bc377d3..0000000 --- a/css/theme/template/theme.scss +++ /dev/null @@ -1,331 +0,0 @@ -// Base theme template for reveal.js - -/********************************************* - * GLOBAL STYLES - *********************************************/ - -@import "./exposer"; - -.reveal-viewport { - @include bodyBackground(); - background-color: var(--r-background-color); -} - -.reveal { - font-family: var(--r-main-font); - font-size: var(--r-main-font-size); - font-weight: normal; - color: var(--r-main-color); -} - -.reveal ::selection { - color: var(--r-selection-color); - background: var(--r-selection-background-color); - text-shadow: none; -} - -.reveal ::-moz-selection { - color: var(--r-selection-color); - background: var(--r-selection-background-color); - text-shadow: none; -} - -.reveal .slides section, -.reveal .slides section>section { - line-height: 1.3; - font-weight: inherit; -} - -/********************************************* - * HEADERS - *********************************************/ - -.reveal h1, -.reveal h2, -.reveal h3, -.reveal h4, -.reveal h5, -.reveal h6 { - margin: var(--r-heading-margin); - color: var(--r-heading-color); - - font-family: var(--r-heading-font); - font-weight: var(--r-heading-font-weight); - line-height: var(--r-heading-line-height); - letter-spacing: var(--r-heading-letter-spacing); - - text-transform: var(--r-heading-text-transform); - text-shadow: var(--r-heading-text-shadow); - - word-wrap: break-word; -} - -.reveal h1 {font-size: var(--r-heading1-size); } -.reveal h2 {font-size: var(--r-heading2-size); } -.reveal h3 {font-size: var(--r-heading3-size); } -.reveal h4 {font-size: var(--r-heading4-size); } - -.reveal h1 { - text-shadow: var(--r-heading1-text-shadow); -} - - -/********************************************* - * OTHER - *********************************************/ - -.reveal p { - margin: var(--r-block-margin) 0; - line-height: 1.3; -} - -/* Remove trailing margins after titles */ -.reveal h1:last-child, -.reveal h2:last-child, -.reveal h3:last-child, -.reveal h4:last-child, -.reveal h5:last-child, -.reveal h6:last-child { - margin-bottom: 0; -} - -/* Ensure certain elements are never larger than the slide itself */ -.reveal img, -.reveal video, -.reveal iframe { - max-width: 95%; - max-height: 95%; -} -.reveal strong, -.reveal b { - font-weight: bold; -} - -.reveal em { - font-style: italic; -} - -.reveal ol, -.reveal dl, -.reveal ul { - display: inline-block; - - text-align: left; - margin: 0 0 0 1em; -} - -.reveal ol { - list-style-type: decimal; -} - -.reveal ul { - list-style-type: disc; -} - -.reveal ul ul { - list-style-type: square; -} - -.reveal ul ul ul { - list-style-type: circle; -} - -.reveal ul ul, -.reveal ul ol, -.reveal ol ol, -.reveal ol ul { - display: block; - margin-left: 40px; -} - -.reveal dt { - font-weight: bold; -} - -.reveal dd { - margin-left: 40px; -} - -.reveal blockquote { - display: block; - position: relative; - width: 70%; - margin: var(--r-block-margin) auto; - padding: 5px; - - font-style: italic; - background: rgba(255, 255, 255, 0.05); - box-shadow: 0px 0px 2px rgba(0,0,0,0.2); -} - .reveal blockquote p:first-child, - .reveal blockquote p:last-child { - display: inline-block; - } - -.reveal q { - font-style: italic; -} - -.reveal pre { - display: block; - position: relative; - width: 90%; - margin: var(--r-block-margin) auto; - - text-align: left; - font-size: 0.55em; - font-family: var(--r-code-font); - line-height: 1.2em; - - word-wrap: break-word; - - box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15); -} - -.reveal code { - font-family: var(--r-code-font); - text-transform: none; - tab-size: 2; -} - -.reveal pre code { - display: block; - padding: 5px; - overflow: auto; - max-height: 400px; - word-wrap: normal; -} - -.reveal .code-wrapper { - white-space: normal; -} - -.reveal .code-wrapper code { - white-space: pre; -} - -.reveal table { - margin: auto; - border-collapse: collapse; - border-spacing: 0; -} - -.reveal table th { - font-weight: bold; -} - -.reveal table th, -.reveal table td { - text-align: left; - padding: 0.2em 0.5em 0.2em 0.5em; - border-bottom: 1px solid; -} - -.reveal table th[align="center"], -.reveal table td[align="center"] { - text-align: center; -} - -.reveal table th[align="right"], -.reveal table td[align="right"] { - text-align: right; -} - -.reveal table tbody tr:last-child th, -.reveal table tbody tr:last-child td { - border-bottom: none; -} - -.reveal sup { - vertical-align: super; - font-size: smaller; -} -.reveal sub { - vertical-align: sub; - font-size: smaller; -} - -.reveal small { - display: inline-block; - font-size: 0.6em; - line-height: 1.2em; - vertical-align: top; -} - -.reveal small * { - vertical-align: top; -} - -.reveal img { - margin: var(--r-block-margin) 0; -} - - -/********************************************* - * LINKS - *********************************************/ - -.reveal a { - color: var(--r-link-color); - text-decoration: none; - transition: color .15s ease; -} - .reveal a:hover { - color: var(--r-link-color-hover); - text-shadow: none; - border: none; - } - -.reveal .roll span:after { - color: #fff; - // background: darken( var(--r-link-color), 15% ); - background: var(--r-link-color-dark); - -} - - -/********************************************* - * Frame helper - *********************************************/ - -.reveal .r-frame { - border: 4px solid var(--r-main-color); - box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); -} - -.reveal a .r-frame { - transition: all .15s linear; -} - -.reveal a:hover .r-frame { - border-color: var(--r-link-color); - box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); -} - - -/********************************************* - * NAVIGATION CONTROLS - *********************************************/ - -.reveal .controls { - color: var(--r-link-color); -} - - -/********************************************* - * PROGRESS BAR - *********************************************/ - -.reveal .progress { - background: rgba(0,0,0,0.2); - color: var(--r-link-color); -} - -/********************************************* - * PRINT BACKGROUND - *********************************************/ - @media print { - .backgrounds { - background-color: var(--r-background-color); - } -} diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 003616e..0000000 --- a/gulpfile.js +++ /dev/null @@ -1,321 +0,0 @@ -const pkg = require('./package.json') -const glob = require('glob') -const yargs = require('yargs') -const through = require('through2'); -const qunit = require('node-qunit-puppeteer') - -const {rollup} = require('rollup') -const terser = require('@rollup/plugin-terser') -const babel = require('@rollup/plugin-babel').default -const commonjs = require('@rollup/plugin-commonjs') -const resolve = require('@rollup/plugin-node-resolve').default -const sass = require('sass') - -const gulp = require('gulp') -const tap = require('gulp-tap') -const zip = require('gulp-zip') -const header = require('gulp-header') -const eslint = require('gulp-eslint') -const minify = require('gulp-clean-css') -const connect = require('gulp-connect') -const autoprefixer = require('gulp-autoprefixer') - -const root = yargs.argv.root || '.' -const port = yargs.argv.port || 8000 -const host = yargs.argv.host || 'localhost' - -const banner = `/*! -* reveal.js ${pkg.version} -* ${pkg.homepage} -* MIT licensed -* -* Copyright (C) 2011-2024 Hakim El Hattab, https://hakim.se -*/\n` - -// Prevents warnings from opening too many test pages -process.setMaxListeners(20); - -const babelConfig = { - babelHelpers: 'bundled', - ignore: ['node_modules'], - compact: false, - extensions: ['.js', '.html'], - plugins: [ - 'transform-html-import-to-string' - ], - presets: [[ - '@babel/preset-env', - { - corejs: 3, - useBuiltIns: 'usage', - modules: false - } - ]] -}; - -// Our ES module bundle only targets newer browsers with -// module support. Browsers are targeted explicitly instead -// of using the "esmodule: true" target since that leads to -// polyfilling older browsers and a larger bundle. -const babelConfigESM = JSON.parse( JSON.stringify( babelConfig ) ); -babelConfigESM.presets[0][1].targets = { browsers: [ - 'last 2 Chrome versions', - 'last 2 Safari versions', - 'last 2 iOS versions', - 'last 2 Firefox versions', - 'last 2 Edge versions', -] }; - -let cache = {}; - -// Creates a bundle with broad browser support, exposed -// as UMD -gulp.task('js-es5', () => { - return rollup({ - cache: cache.umd, - input: 'js/index.js', - plugins: [ - resolve(), - commonjs(), - babel( babelConfig ), - terser() - ] - }).then( bundle => { - cache.umd = bundle.cache; - return bundle.write({ - name: 'Reveal', - file: './dist/reveal.js', - format: 'umd', - banner: banner, - sourcemap: true - }); - }); -}) - -// Creates an ES module bundle -gulp.task('js-es6', () => { - return rollup({ - cache: cache.esm, - input: 'js/index.js', - plugins: [ - resolve(), - commonjs(), - babel( babelConfigESM ), - terser() - ] - }).then( bundle => { - cache.esm = bundle.cache; - return bundle.write({ - file: './dist/reveal.esm.js', - format: 'es', - banner: banner, - sourcemap: true - }); - }); -}) -gulp.task('js', gulp.parallel('js-es5', 'js-es6')); - -// Creates a UMD and ES module bundle for each of our -// built-in plugins -gulp.task('plugins', () => { - return Promise.all([ - { name: 'RevealHighlight', input: './plugin/highlight/plugin.js', output: './plugin/highlight/highlight' }, - { name: 'RevealMarkdown', input: './plugin/markdown/plugin.js', output: './plugin/markdown/markdown' }, - { name: 'RevealSearch', input: './plugin/search/plugin.js', output: './plugin/search/search' }, - { name: 'RevealNotes', input: './plugin/notes/plugin.js', output: './plugin/notes/notes' }, - { name: 'RevealZoom', input: './plugin/zoom/plugin.js', output: './plugin/zoom/zoom' }, - { name: 'RevealMath', input: './plugin/math/plugin.js', output: './plugin/math/math' }, - ].map( plugin => { - return rollup({ - cache: cache[plugin.input], - input: plugin.input, - plugins: [ - resolve(), - commonjs(), - babel({ - ...babelConfig, - ignore: [/node_modules\/(?!(highlight\.js|marked)\/).*/], - }), - terser() - ] - }).then( bundle => { - cache[plugin.input] = bundle.cache; - bundle.write({ - file: plugin.output + '.esm.js', - name: plugin.name, - format: 'es' - }) - - bundle.write({ - file: plugin.output + '.js', - name: plugin.name, - format: 'umd' - }) - }); - } )); -}) - -// a custom pipeable step to transform Sass to CSS -function compileSass() { - return through.obj( ( vinylFile, encoding, callback ) => { - const transformedFile = vinylFile.clone(); - - sass.render({ - data: transformedFile.contents.toString(), - file: transformedFile.path, - }, ( err, result ) => { - if( err ) { - callback(err); - } - else { - transformedFile.extname = '.css'; - transformedFile.contents = result.css; - callback( null, transformedFile ); - } - }); - }); -} - -gulp.task('css-themes', () => gulp.src(['./css/theme/source/*.{sass,scss}']) - .pipe(compileSass()) - .pipe(gulp.dest('./dist/theme'))) - -gulp.task('css-core', () => gulp.src(['css/reveal.scss']) - .pipe(compileSass()) - .pipe(autoprefixer()) - .pipe(minify({compatibility: 'ie9'})) - .pipe(header(banner)) - .pipe(gulp.dest('./dist'))) - -gulp.task('css', gulp.parallel('css-themes', 'css-core')) - -gulp.task('qunit', () => { - - let serverConfig = { - root, - port: 8009, - host: 'localhost', - name: 'test-server' - } - - let server = connect.server( serverConfig ) - - let testFiles = glob.sync('test/*.html' ) - - let totalTests = 0; - let failingTests = 0; - - let tests = Promise.all( testFiles.map( filename => { - return new Promise( ( resolve, reject ) => { - qunit.runQunitPuppeteer({ - targetUrl: `http://${serverConfig.host}:${serverConfig.port}/${filename}`, - timeout: 20000, - redirectConsole: false, - puppeteerArgs: ['--allow-file-access-from-files'] - }) - .then(result => { - if( result.stats.failed > 0 ) { - console.log(`${'!'} ${filename} [${result.stats.passed}/${result.stats.total}] in ${result.stats.runtime}ms`.red); - // qunit.printResultSummary(result, console); - qunit.printFailedTests(result, console); - } - else { - console.log(`${'โœ”'} ${filename} [${result.stats.passed}/${result.stats.total}] in ${result.stats.runtime}ms`.green); - } - - totalTests += result.stats.total; - failingTests += result.stats.failed; - - resolve(); - }) - .catch(error => { - console.error(error); - reject(); - }); - } ) - } ) ); - - return new Promise( ( resolve, reject ) => { - - tests.then( () => { - if( failingTests > 0 ) { - reject( new Error(`${failingTests}/${totalTests} tests failed`.red) ); - } - else { - console.log(`${'โœ”'} Passed ${totalTests} tests`.green.bold); - resolve(); - } - } ) - .catch( () => { - reject(); - } ) - .finally( () => { - server.close(); - } ); - - } ); -} ) - -gulp.task('eslint', () => gulp.src(['./js/**', 'gulpfile.js']) - .pipe(eslint()) - .pipe(eslint.format())) - -gulp.task('test', gulp.series( 'eslint', 'qunit' )) - -gulp.task('default', gulp.series(gulp.parallel('js', 'css', 'plugins'), 'test')) - -gulp.task('build', gulp.parallel('js', 'css', 'plugins')) - -gulp.task('package', gulp.series(() => - - gulp.src( - [ - './index.html', - './dist/**', - './lib/**', - './images/**', - './plugin/**', - './**/*.md' - ], - { base: './' } - ) - .pipe(zip('reveal-js-presentation.zip')).pipe(gulp.dest('./')) - -)) - -gulp.task('reload', () => gulp.src(['index.html']) - .pipe(connect.reload())); - -gulp.task('serve', () => { - - connect.server({ - root: root, - port: port, - host: host, - livereload: true - }) - - const slidesRoot = root.endsWith('/') ? root : root + '/' - gulp.watch([ - slidesRoot + '**/*.html', - slidesRoot + '**/*.md', - `!${slidesRoot}**/node_modules/**`, // ignore node_modules - ], gulp.series('reload')) - - gulp.watch(['js/**'], gulp.series('js', 'reload', 'eslint')) - - gulp.watch(['plugin/**/plugin.js', 'plugin/**/*.html'], gulp.series('plugins', 'reload')) - - gulp.watch([ - 'css/theme/source/**/*.{sass,scss}', - 'css/theme/template/*.{sass,scss}', - ], gulp.series('css-themes', 'reload')) - - gulp.watch([ - 'css/*.scss', - 'css/print/*.{sass,scss,css}' - ], gulp.series('css-core', 'reload')) - - gulp.watch(['test/*.html'], gulp.series('test')) - -}) diff --git a/index.html b/index.html deleted file mode 100644 index 9ae3eaa..0000000 --- a/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - reveal.js - - - - - - - - - -
-
-
Slide 1
-
Slide 2
-
Uganda Rundreise - -
-
-
- - - - - - - - diff --git a/js/components/playback.js b/js/components/playback.js deleted file mode 100644 index 06fa7ba..0000000 --- a/js/components/playback.js +++ /dev/null @@ -1,165 +0,0 @@ -/** - * UI component that lets the use control auto-slide - * playback via play/pause. - */ -export default class Playback { - - /** - * @param {HTMLElement} container The component will append - * itself to this - * @param {function} progressCheck A method which will be - * called frequently to get the current playback progress on - * a range of 0-1 - */ - constructor( container, progressCheck ) { - - // Cosmetics - this.diameter = 100; - this.diameter2 = this.diameter/2; - this.thickness = 6; - - // Flags if we are currently playing - this.playing = false; - - // Current progress on a 0-1 range - this.progress = 0; - - // Used to loop the animation smoothly - this.progressOffset = 1; - - this.container = container; - this.progressCheck = progressCheck; - - this.canvas = document.createElement( 'canvas' ); - this.canvas.className = 'playback'; - this.canvas.width = this.diameter; - this.canvas.height = this.diameter; - this.canvas.style.width = this.diameter2 + 'px'; - this.canvas.style.height = this.diameter2 + 'px'; - this.context = this.canvas.getContext( '2d' ); - - this.container.appendChild( this.canvas ); - - this.render(); - - } - - setPlaying( value ) { - - const wasPlaying = this.playing; - - this.playing = value; - - // Start repainting if we weren't already - if( !wasPlaying && this.playing ) { - this.animate(); - } - else { - this.render(); - } - - } - - animate() { - - const progressBefore = this.progress; - - this.progress = this.progressCheck(); - - // When we loop, offset the progress so that it eases - // smoothly rather than immediately resetting - if( progressBefore > 0.8 && this.progress < 0.2 ) { - this.progressOffset = this.progress; - } - - this.render(); - - if( this.playing ) { - requestAnimationFrame( this.animate.bind( this ) ); - } - - } - - /** - * Renders the current progress and playback state. - */ - render() { - - let progress = this.playing ? this.progress : 0, - radius = ( this.diameter2 ) - this.thickness, - x = this.diameter2, - y = this.diameter2, - iconSize = 28; - - // Ease towards 1 - this.progressOffset += ( 1 - this.progressOffset ) * 0.1; - - const endAngle = ( - Math.PI / 2 ) + ( progress * ( Math.PI * 2 ) ); - const startAngle = ( - Math.PI / 2 ) + ( this.progressOffset * ( Math.PI * 2 ) ); - - this.context.save(); - this.context.clearRect( 0, 0, this.diameter, this.diameter ); - - // Solid background color - this.context.beginPath(); - this.context.arc( x, y, radius + 4, 0, Math.PI * 2, false ); - this.context.fillStyle = 'rgba( 0, 0, 0, 0.4 )'; - this.context.fill(); - - // Draw progress track - this.context.beginPath(); - this.context.arc( x, y, radius, 0, Math.PI * 2, false ); - this.context.lineWidth = this.thickness; - this.context.strokeStyle = 'rgba( 255, 255, 255, 0.2 )'; - this.context.stroke(); - - if( this.playing ) { - // Draw progress on top of track - this.context.beginPath(); - this.context.arc( x, y, radius, startAngle, endAngle, false ); - this.context.lineWidth = this.thickness; - this.context.strokeStyle = '#fff'; - this.context.stroke(); - } - - this.context.translate( x - ( iconSize / 2 ), y - ( iconSize / 2 ) ); - - // Draw play/pause icons - if( this.playing ) { - this.context.fillStyle = '#fff'; - this.context.fillRect( 0, 0, iconSize / 2 - 4, iconSize ); - this.context.fillRect( iconSize / 2 + 4, 0, iconSize / 2 - 4, iconSize ); - } - else { - this.context.beginPath(); - this.context.translate( 4, 0 ); - this.context.moveTo( 0, 0 ); - this.context.lineTo( iconSize - 4, iconSize / 2 ); - this.context.lineTo( 0, iconSize ); - this.context.fillStyle = '#fff'; - this.context.fill(); - } - - this.context.restore(); - - } - - on( type, listener ) { - this.canvas.addEventListener( type, listener, false ); - } - - off( type, listener ) { - this.canvas.removeEventListener( type, listener, false ); - } - - destroy() { - - this.playing = false; - - if( this.canvas.parentNode ) { - this.container.removeChild( this.canvas ); - } - - } - -} \ No newline at end of file diff --git a/js/config.js b/js/config.js deleted file mode 100644 index de44bd6..0000000 --- a/js/config.js +++ /dev/null @@ -1,330 +0,0 @@ -/** - * The default reveal.js config object. - */ -export default { - - // The "normal" size of the presentation, aspect ratio will be preserved - // when the presentation is scaled to fit different resolutions - width: 960, - height: 700, - - // Factor of the display size that should remain empty around the content - margin: 0.04, - - // Bounds for smallest/largest possible scale to apply to content - minScale: 0.2, - maxScale: 2.0, - - // Display presentation control arrows - controls: true, - - // Help the user learn the controls by providing hints, for example by - // bouncing the down arrow when they first encounter a vertical slide - controlsTutorial: true, - - // Determines where controls appear, "edges" or "bottom-right" - controlsLayout: 'bottom-right', - - // Visibility rule for backwards navigation arrows; "faded", "hidden" - // or "visible" - controlsBackArrows: 'faded', - - // Display a presentation progress bar - progress: true, - - // Display the page number of the current slide - // - true: Show slide number - // - false: Hide slide number - // - // Can optionally be set as a string that specifies the number formatting: - // - "h.v": Horizontal . vertical slide number (default) - // - "h/v": Horizontal / vertical slide number - // - "c": Flattened slide number - // - "c/t": Flattened slide number / total slides - // - // Alternatively, you can provide a function that returns the slide - // number for the current slide. The function should take in a slide - // object and return an array with one string [slideNumber] or - // three strings [n1,delimiter,n2]. See #formatSlideNumber(). - slideNumber: false, - - // Can be used to limit the contexts in which the slide number appears - // - "all": Always show the slide number - // - "print": Only when printing to PDF - // - "speaker": Only in the speaker view - showSlideNumber: 'all', - - // Use 1 based indexing for # links to match slide number (default is zero - // based) - hashOneBasedIndex: false, - - // Add the current slide number to the URL hash so that reloading the - // page/copying the URL will return you to the same slide - hash: false, - - // Flags if we should monitor the hash and change slides accordingly - respondToHashChanges: true, - - // Enable support for jump-to-slide navigation shortcuts - jumpToSlide: true, - - // Push each slide change to the browser history. Implies `hash: true` - history: false, - - // Enable keyboard shortcuts for navigation - keyboard: true, - - // Optional function that blocks keyboard events when retuning false - // - // If you set this to 'focused', we will only capture keyboard events - // for embedded decks when they are in focus - keyboardCondition: null, - - // Disables the default reveal.js slide layout (scaling and centering) - // so that you can use custom CSS layout - disableLayout: false, - - // Enable the slide overview mode - overview: true, - - // Vertical centering of slides - center: true, - - // Enables touch navigation on devices with touch input - touch: true, - - // Loop the presentation - loop: false, - - // Change the presentation direction to be RTL - rtl: false, - - // Changes the behavior of our navigation directions. - // - // "default" - // Left/right arrow keys step between horizontal slides, up/down - // arrow keys step between vertical slides. Space key steps through - // all slides (both horizontal and vertical). - // - // "linear" - // Removes the up/down arrows. Left/right arrows step through all - // slides (both horizontal and vertical). - // - // "grid" - // When this is enabled, stepping left/right from a vertical stack - // to an adjacent vertical stack will land you at the same vertical - // index. - // - // Consider a deck with six slides ordered in two vertical stacks: - // 1.1 2.1 - // 1.2 2.2 - // 1.3 2.3 - // - // If you're on slide 1.3 and navigate right, you will normally move - // from 1.3 -> 2.1. If "grid" is used, the same navigation takes you - // from 1.3 -> 2.3. - navigationMode: 'default', - - // Randomizes the order of slides each time the presentation loads - shuffle: false, - - // Turns fragments on and off globally - fragments: true, - - // Flags whether to include the current fragment in the URL, - // so that reloading brings you to the same fragment position - fragmentInURL: true, - - // Flags if the presentation is running in an embedded mode, - // i.e. contained within a limited portion of the screen - embedded: false, - - // Flags if we should show a help overlay when the question-mark - // key is pressed - help: true, - - // Flags if it should be possible to pause the presentation (blackout) - pause: true, - - // Flags if speaker notes should be visible to all viewers - showNotes: false, - - // Flags if slides with data-visibility="hidden" should be kep visible - showHiddenSlides: false, - - // Global override for autoplaying embedded media (video/audio/iframe) - // - null: Media will only autoplay if data-autoplay is present - // - true: All media will autoplay, regardless of individual setting - // - false: No media will autoplay, regardless of individual setting - autoPlayMedia: null, - - // Global override for preloading lazy-loaded iframes - // - null: Iframes with data-src AND data-preload will be loaded when within - // the viewDistance, iframes with only data-src will be loaded when visible - // - true: All iframes with data-src will be loaded when within the viewDistance - // - false: All iframes with data-src will be loaded only when visible - preloadIframes: null, - - // Can be used to globally disable auto-animation - autoAnimate: true, - - // Optionally provide a custom element matcher that will be - // used to dictate which elements we can animate between. - autoAnimateMatcher: null, - - // Default settings for our auto-animate transitions, can be - // overridden per-slide or per-element via data arguments - autoAnimateEasing: 'ease', - autoAnimateDuration: 1.0, - autoAnimateUnmatched: true, - - // CSS properties that can be auto-animated. Position & scale - // is matched separately so there's no need to include styles - // like top/right/bottom/left, width/height or margin. - autoAnimateStyles: [ - 'opacity', - 'color', - 'background-color', - 'padding', - 'font-size', - 'line-height', - 'letter-spacing', - 'border-width', - 'border-color', - 'border-radius', - 'outline', - 'outline-offset' - ], - - // Controls automatic progression to the next slide - // - 0: Auto-sliding only happens if the data-autoslide HTML attribute - // is present on the current slide or fragment - // - 1+: All slides will progress automatically at the given interval - // - false: No auto-sliding, even if data-autoslide is present - autoSlide: 0, - - // Stop auto-sliding after user input - autoSlideStoppable: true, - - // Use this method for navigation when auto-sliding (defaults to navigateNext) - autoSlideMethod: null, - - // Specify the average time in seconds that you think you will spend - // presenting each slide. This is used to show a pacing timer in the - // speaker view - defaultTiming: null, - - // Enable slide navigation via mouse wheel - mouseWheel: false, - - // Opens links in an iframe preview overlay - // Add `data-preview-link` and `data-preview-link="false"` to customise each link - // individually - previewLinks: false, - - // Exposes the reveal.js API through window.postMessage - postMessage: true, - - // Dispatches all reveal.js events to the parent window through postMessage - postMessageEvents: false, - - // Focuses body when page changes visibility to ensure keyboard shortcuts work - focusBodyOnPageVisibilityChange: true, - - // Transition style - transition: 'slide', // none/fade/slide/convex/concave/zoom - - // Transition speed - transitionSpeed: 'default', // default/fast/slow - - // Transition style for full page slide backgrounds - backgroundTransition: 'fade', // none/fade/slide/convex/concave/zoom - - // Parallax background image - parallaxBackgroundImage: '', // CSS syntax, e.g. "a.jpg" - - // Parallax background size - parallaxBackgroundSize: '', // CSS syntax, e.g. "3000px 2000px" - - // Parallax background repeat - parallaxBackgroundRepeat: '', // repeat/repeat-x/repeat-y/no-repeat/initial/inherit - - // Parallax background position - parallaxBackgroundPosition: '', // CSS syntax, e.g. "top left" - - // Amount of pixels to move the parallax background per slide step - parallaxBackgroundHorizontal: null, - parallaxBackgroundVertical: null, - - // Can be used to initialize reveal.js in one of the following views: - // - print: Render the presentation so that it can be printed to PDF - // - scroll: Show the presentation as a tall scrollable page with scroll - // triggered animations - view: null, - - // Adjusts the height of each slide in the scroll view. - // - full: Each slide is as tall as the viewport - // - compact: Slides are as small as possible, allowing multiple slides - // to be visible in parallel on tall devices - scrollLayout: 'full', - - // Control how scroll snapping works in the scroll view. - // - false: No snapping, scrolling is continuous - // - proximity: Snap when close to a slide - // - mandatory: Always snap to the closest slide - // - // Only applies to presentations in scroll view. - scrollSnap: 'mandatory', - - // Enables and configure the scroll view progress bar. - // - 'auto': Show the scrollbar while scrolling, hide while idle - // - true: Always show the scrollbar - // - false: Never show the scrollbar - scrollProgress: 'auto', - - // Automatically activate the scroll view when we the viewport falls - // below the given width. - scrollActivationWidth: 435, - - // The maximum number of pages a single slide can expand onto when printing - // to PDF, unlimited by default - pdfMaxPagesPerSlide: Number.POSITIVE_INFINITY, - - // Prints each fragment on a separate slide - pdfSeparateFragments: true, - - // Offset used to reduce the height of content within exported PDF pages. - // This exists to account for environment differences based on how you - // print to PDF. CLI printing options, like phantomjs and wkpdf, can end - // on precisely the total height of the document whereas in-browser - // printing has to end one pixel before. - pdfPageHeightOffset: -1, - - // Number of slides away from the current that are visible - viewDistance: 3, - - // Number of slides away from the current that are visible on mobile - // devices. It is advisable to set this to a lower number than - // viewDistance in order to save resources. - mobileViewDistance: 2, - - // The display mode that will be used to show slides - display: 'block', - - // Hide cursor if inactive - hideInactiveCursor: true, - - // Time before the cursor is hidden (in ms) - hideCursorTime: 5000, - - // Should we automatically sort and set indices for fragments - // at each sync? (See Reveal.sync) - sortFragmentsOnSync: true, - - // Script dependencies to load - dependencies: [], - - // Plugin objects to register and use for this presentation - plugins: [] - -} \ No newline at end of file diff --git a/js/controllers/autoanimate.js b/js/controllers/autoanimate.js deleted file mode 100644 index 3fd2c99..0000000 --- a/js/controllers/autoanimate.js +++ /dev/null @@ -1,640 +0,0 @@ -import { queryAll, extend, createStyleSheet, matches, closest } from '../utils/util.js' -import { FRAGMENT_STYLE_REGEX } from '../utils/constants.js' - -// Counter used to generate unique IDs for auto-animated elements -let autoAnimateCounter = 0; - -/** - * Automatically animates matching elements across - * slides with the [data-auto-animate] attribute. - */ -export default class AutoAnimate { - - constructor( Reveal ) { - - this.Reveal = Reveal; - - } - - /** - * Runs an auto-animation between the given slides. - * - * @param {HTMLElement} fromSlide - * @param {HTMLElement} toSlide - */ - run( fromSlide, toSlide ) { - - // Clean up after prior animations - this.reset(); - - let allSlides = this.Reveal.getSlides(); - let toSlideIndex = allSlides.indexOf( toSlide ); - let fromSlideIndex = allSlides.indexOf( fromSlide ); - - // Ensure that both slides are auto-animate targets with the same data-auto-animate-id value - // (including null if absent on both) and that data-auto-animate-restart isn't set on the - // physically latter slide (independent of slide direction) - if( fromSlide.hasAttribute( 'data-auto-animate' ) && toSlide.hasAttribute( 'data-auto-animate' ) - && fromSlide.getAttribute( 'data-auto-animate-id' ) === toSlide.getAttribute( 'data-auto-animate-id' ) - && !( toSlideIndex > fromSlideIndex ? toSlide : fromSlide ).hasAttribute( 'data-auto-animate-restart' ) ) { - - // Create a new auto-animate sheet - this.autoAnimateStyleSheet = this.autoAnimateStyleSheet || createStyleSheet(); - - let animationOptions = this.getAutoAnimateOptions( toSlide ); - - // Set our starting state - fromSlide.dataset.autoAnimate = 'pending'; - toSlide.dataset.autoAnimate = 'pending'; - - // Flag the navigation direction, needed for fragment buildup - animationOptions.slideDirection = toSlideIndex > fromSlideIndex ? 'forward' : 'backward'; - - // If the from-slide is hidden because it has moved outside - // the view distance, we need to temporarily show it while - // measuring - let fromSlideIsHidden = fromSlide.style.display === 'none'; - if( fromSlideIsHidden ) fromSlide.style.display = this.Reveal.getConfig().display; - - // Inject our auto-animate styles for this transition - let css = this.getAutoAnimatableElements( fromSlide, toSlide ).map( elements => { - return this.autoAnimateElements( elements.from, elements.to, elements.options || {}, animationOptions, autoAnimateCounter++ ); - } ); - - if( fromSlideIsHidden ) fromSlide.style.display = 'none'; - - // Animate unmatched elements, if enabled - if( toSlide.dataset.autoAnimateUnmatched !== 'false' && this.Reveal.getConfig().autoAnimateUnmatched === true ) { - - // Our default timings for unmatched elements - let defaultUnmatchedDuration = animationOptions.duration * 0.8, - defaultUnmatchedDelay = animationOptions.duration * 0.2; - - this.getUnmatchedAutoAnimateElements( toSlide ).forEach( unmatchedElement => { - - let unmatchedOptions = this.getAutoAnimateOptions( unmatchedElement, animationOptions ); - let id = 'unmatched'; - - // If there is a duration or delay set specifically for this - // element our unmatched elements should adhere to those - if( unmatchedOptions.duration !== animationOptions.duration || unmatchedOptions.delay !== animationOptions.delay ) { - id = 'unmatched-' + autoAnimateCounter++; - css.push( `[data-auto-animate="running"] [data-auto-animate-target="${id}"] { transition: opacity ${unmatchedOptions.duration}s ease ${unmatchedOptions.delay}s; }` ); - } - - unmatchedElement.dataset.autoAnimateTarget = id; - - }, this ); - - // Our default transition for unmatched elements - css.push( `[data-auto-animate="running"] [data-auto-animate-target="unmatched"] { transition: opacity ${defaultUnmatchedDuration}s ease ${defaultUnmatchedDelay}s; }` ); - - } - - // Setting the whole chunk of CSS at once is the most - // efficient way to do this. Using sheet.insertRule - // is multiple factors slower. - this.autoAnimateStyleSheet.innerHTML = css.join( '' ); - - // Start the animation next cycle - requestAnimationFrame( () => { - if( this.autoAnimateStyleSheet ) { - // This forces our newly injected styles to be applied in Firefox - getComputedStyle( this.autoAnimateStyleSheet ).fontWeight; - - toSlide.dataset.autoAnimate = 'running'; - } - } ); - - this.Reveal.dispatchEvent({ - type: 'autoanimate', - data: { - fromSlide, - toSlide, - sheet: this.autoAnimateStyleSheet - } - }); - - } - - } - - /** - * Rolls back all changes that we've made to the DOM so - * that as part of animating. - */ - reset() { - - // Reset slides - queryAll( this.Reveal.getRevealElement(), '[data-auto-animate]:not([data-auto-animate=""])' ).forEach( element => { - element.dataset.autoAnimate = ''; - } ); - - // Reset elements - queryAll( this.Reveal.getRevealElement(), '[data-auto-animate-target]' ).forEach( element => { - delete element.dataset.autoAnimateTarget; - } ); - - // Remove the animation sheet - if( this.autoAnimateStyleSheet && this.autoAnimateStyleSheet.parentNode ) { - this.autoAnimateStyleSheet.parentNode.removeChild( this.autoAnimateStyleSheet ); - this.autoAnimateStyleSheet = null; - } - - } - - /** - * Creates a FLIP animation where the `to` element starts out - * in the `from` element position and animates to its original - * state. - * - * @param {HTMLElement} from - * @param {HTMLElement} to - * @param {Object} elementOptions Options for this element pair - * @param {Object} animationOptions Options set at the slide level - * @param {String} id Unique ID that we can use to identify this - * auto-animate element in the DOM - */ - autoAnimateElements( from, to, elementOptions, animationOptions, id ) { - - // 'from' elements are given a data-auto-animate-target with no value, - // 'to' elements are are given a data-auto-animate-target with an ID - from.dataset.autoAnimateTarget = ''; - to.dataset.autoAnimateTarget = id; - - // Each element may override any of the auto-animate options - // like transition easing, duration and delay via data-attributes - let options = this.getAutoAnimateOptions( to, animationOptions ); - - // If we're using a custom element matcher the element options - // may contain additional transition overrides - if( typeof elementOptions.delay !== 'undefined' ) options.delay = elementOptions.delay; - if( typeof elementOptions.duration !== 'undefined' ) options.duration = elementOptions.duration; - if( typeof elementOptions.easing !== 'undefined' ) options.easing = elementOptions.easing; - - let fromProps = this.getAutoAnimatableProperties( 'from', from, elementOptions ), - toProps = this.getAutoAnimatableProperties( 'to', to, elementOptions ); - - // Maintain fragment visibility for matching elements when - // we're navigating forwards, this way the viewer won't need - // to step through the same fragments twice - if( to.classList.contains( 'fragment' ) ) { - - // Don't auto-animate the opacity of fragments to avoid - // conflicts with fragment animations - delete toProps.styles['opacity']; - - if( from.classList.contains( 'fragment' ) ) { - - let fromFragmentStyle = ( from.className.match( FRAGMENT_STYLE_REGEX ) || [''] )[0]; - let toFragmentStyle = ( to.className.match( FRAGMENT_STYLE_REGEX ) || [''] )[0]; - - // Only skip the fragment if the fragment animation style - // remains unchanged - if( fromFragmentStyle === toFragmentStyle && animationOptions.slideDirection === 'forward' ) { - to.classList.add( 'visible', 'disabled' ); - } - - } - - } - - // If translation and/or scaling are enabled, css transform - // the 'to' element so that it matches the position and size - // of the 'from' element - if( elementOptions.translate !== false || elementOptions.scale !== false ) { - - let presentationScale = this.Reveal.getScale(); - - let delta = { - x: ( fromProps.x - toProps.x ) / presentationScale, - y: ( fromProps.y - toProps.y ) / presentationScale, - scaleX: fromProps.width / toProps.width, - scaleY: fromProps.height / toProps.height - }; - - // Limit decimal points to avoid 0.0001px blur and stutter - delta.x = Math.round( delta.x * 1000 ) / 1000; - delta.y = Math.round( delta.y * 1000 ) / 1000; - delta.scaleX = Math.round( delta.scaleX * 1000 ) / 1000; - delta.scaleX = Math.round( delta.scaleX * 1000 ) / 1000; - - let translate = elementOptions.translate !== false && ( delta.x !== 0 || delta.y !== 0 ), - scale = elementOptions.scale !== false && ( delta.scaleX !== 0 || delta.scaleY !== 0 ); - - // No need to transform if nothing's changed - if( translate || scale ) { - - let transform = []; - - if( translate ) transform.push( `translate(${delta.x}px, ${delta.y}px)` ); - if( scale ) transform.push( `scale(${delta.scaleX}, ${delta.scaleY})` ); - - fromProps.styles['transform'] = transform.join( ' ' ); - fromProps.styles['transform-origin'] = 'top left'; - - toProps.styles['transform'] = 'none'; - - } - - } - - // Delete all unchanged 'to' styles - for( let propertyName in toProps.styles ) { - const toValue = toProps.styles[propertyName]; - const fromValue = fromProps.styles[propertyName]; - - if( toValue === fromValue ) { - delete toProps.styles[propertyName]; - } - else { - // If these property values were set via a custom matcher providing - // an explicit 'from' and/or 'to' value, we always inject those values. - if( toValue.explicitValue === true ) { - toProps.styles[propertyName] = toValue.value; - } - - if( fromValue.explicitValue === true ) { - fromProps.styles[propertyName] = fromValue.value; - } - } - } - - let css = ''; - - let toStyleProperties = Object.keys( toProps.styles ); - - // Only create animate this element IF at least one style - // property has changed - if( toStyleProperties.length > 0 ) { - - // Instantly move to the 'from' state - fromProps.styles['transition'] = 'none'; - - // Animate towards the 'to' state - toProps.styles['transition'] = `all ${options.duration}s ${options.easing} ${options.delay}s`; - toProps.styles['transition-property'] = toStyleProperties.join( ', ' ); - toProps.styles['will-change'] = toStyleProperties.join( ', ' ); - - // Build up our custom CSS. We need to override inline styles - // so we need to make our styles vErY IMPORTANT!1!! - let fromCSS = Object.keys( fromProps.styles ).map( propertyName => { - return propertyName + ': ' + fromProps.styles[propertyName] + ' !important;'; - } ).join( '' ); - - let toCSS = Object.keys( toProps.styles ).map( propertyName => { - return propertyName + ': ' + toProps.styles[propertyName] + ' !important;'; - } ).join( '' ); - - css = '[data-auto-animate-target="'+ id +'"] {'+ fromCSS +'}' + - '[data-auto-animate="running"] [data-auto-animate-target="'+ id +'"] {'+ toCSS +'}'; - - } - - return css; - - } - - /** - * Returns the auto-animate options for the given element. - * - * @param {HTMLElement} element Element to pick up options - * from, either a slide or an animation target - * @param {Object} [inheritedOptions] Optional set of existing - * options - */ - getAutoAnimateOptions( element, inheritedOptions ) { - - let options = { - easing: this.Reveal.getConfig().autoAnimateEasing, - duration: this.Reveal.getConfig().autoAnimateDuration, - delay: 0 - }; - - options = extend( options, inheritedOptions ); - - // Inherit options from parent elements - if( element.parentNode ) { - let autoAnimatedParent = closest( element.parentNode, '[data-auto-animate-target]' ); - if( autoAnimatedParent ) { - options = this.getAutoAnimateOptions( autoAnimatedParent, options ); - } - } - - if( element.dataset.autoAnimateEasing ) { - options.easing = element.dataset.autoAnimateEasing; - } - - if( element.dataset.autoAnimateDuration ) { - options.duration = parseFloat( element.dataset.autoAnimateDuration ); - } - - if( element.dataset.autoAnimateDelay ) { - options.delay = parseFloat( element.dataset.autoAnimateDelay ); - } - - return options; - - } - - /** - * Returns an object containing all of the properties - * that can be auto-animated for the given element and - * their current computed values. - * - * @param {String} direction 'from' or 'to' - */ - getAutoAnimatableProperties( direction, element, elementOptions ) { - - let config = this.Reveal.getConfig(); - - let properties = { styles: [] }; - - // Position and size - if( elementOptions.translate !== false || elementOptions.scale !== false ) { - let bounds; - - // Custom auto-animate may optionally return a custom tailored - // measurement function - if( typeof elementOptions.measure === 'function' ) { - bounds = elementOptions.measure( element ); - } - else { - if( config.center ) { - // More precise, but breaks when used in combination - // with zoom for scaling the deck ยฏ\_(ใƒ„)_/ยฏ - bounds = element.getBoundingClientRect(); - } - else { - let scale = this.Reveal.getScale(); - bounds = { - x: element.offsetLeft * scale, - y: element.offsetTop * scale, - width: element.offsetWidth * scale, - height: element.offsetHeight * scale - }; - } - } - - properties.x = bounds.x; - properties.y = bounds.y; - properties.width = bounds.width; - properties.height = bounds.height; - } - - const computedStyles = getComputedStyle( element ); - - // CSS styles - ( elementOptions.styles || config.autoAnimateStyles ).forEach( style => { - let value; - - // `style` is either the property name directly, or an object - // definition of a style property - if( typeof style === 'string' ) style = { property: style }; - - if( typeof style.from !== 'undefined' && direction === 'from' ) { - value = { value: style.from, explicitValue: true }; - } - else if( typeof style.to !== 'undefined' && direction === 'to' ) { - value = { value: style.to, explicitValue: true }; - } - else { - // Use a unitless value for line-height so that it inherits properly - if( style.property === 'line-height' ) { - value = parseFloat( computedStyles['line-height'] ) / parseFloat( computedStyles['font-size'] ); - } - - if( isNaN(value) ) { - value = computedStyles[style.property]; - } - } - - if( value !== '' ) { - properties.styles[style.property] = value; - } - } ); - - return properties; - - } - - /** - * Get a list of all element pairs that we can animate - * between the given slides. - * - * @param {HTMLElement} fromSlide - * @param {HTMLElement} toSlide - * - * @return {Array} Each value is an array where [0] is - * the element we're animating from and [1] is the - * element we're animating to - */ - getAutoAnimatableElements( fromSlide, toSlide ) { - - let matcher = typeof this.Reveal.getConfig().autoAnimateMatcher === 'function' ? this.Reveal.getConfig().autoAnimateMatcher : this.getAutoAnimatePairs; - - let pairs = matcher.call( this, fromSlide, toSlide ); - - let reserved = []; - - // Remove duplicate pairs - return pairs.filter( ( pair, index ) => { - if( reserved.indexOf( pair.to ) === -1 ) { - reserved.push( pair.to ); - return true; - } - } ); - - } - - /** - * Identifies matching elements between slides. - * - * You can specify a custom matcher function by using - * the `autoAnimateMatcher` config option. - */ - getAutoAnimatePairs( fromSlide, toSlide ) { - - let pairs = []; - - const codeNodes = 'pre'; - const textNodes = 'h1, h2, h3, h4, h5, h6, p, li'; - const mediaNodes = 'img, video, iframe'; - - // Explicit matches via data-id - this.findAutoAnimateMatches( pairs, fromSlide, toSlide, '[data-id]', node => { - return node.nodeName + ':::' + node.getAttribute( 'data-id' ); - } ); - - // Text - this.findAutoAnimateMatches( pairs, fromSlide, toSlide, textNodes, node => { - return node.nodeName + ':::' + node.innerText; - } ); - - // Media - this.findAutoAnimateMatches( pairs, fromSlide, toSlide, mediaNodes, node => { - return node.nodeName + ':::' + ( node.getAttribute( 'src' ) || node.getAttribute( 'data-src' ) ); - } ); - - // Code - this.findAutoAnimateMatches( pairs, fromSlide, toSlide, codeNodes, node => { - return node.nodeName + ':::' + node.innerText; - } ); - - pairs.forEach( pair => { - // Disable scale transformations on text nodes, we transition - // each individual text property instead - if( matches( pair.from, textNodes ) ) { - pair.options = { scale: false }; - } - // Animate individual lines of code - else if( matches( pair.from, codeNodes ) ) { - - // Transition the code block's width and height instead of scaling - // to prevent its content from being squished - pair.options = { scale: false, styles: [ 'width', 'height' ] }; - - // Lines of code - this.findAutoAnimateMatches( pairs, pair.from, pair.to, '.hljs .hljs-ln-code', node => { - return node.textContent; - }, { - scale: false, - styles: [], - measure: this.getLocalBoundingBox.bind( this ) - } ); - - // Line numbers - this.findAutoAnimateMatches( pairs, pair.from, pair.to, '.hljs .hljs-ln-numbers[data-line-number]', node => { - return node.getAttribute( 'data-line-number' ); - }, { - scale: false, - styles: [ 'width' ], - measure: this.getLocalBoundingBox.bind( this ) - } ); - - } - - }, this ); - - return pairs; - - } - - /** - * Helper method which returns a bounding box based on - * the given elements offset coordinates. - * - * @param {HTMLElement} element - * @return {Object} x, y, width, height - */ - getLocalBoundingBox( element ) { - - const presentationScale = this.Reveal.getScale(); - - return { - x: Math.round( ( element.offsetLeft * presentationScale ) * 100 ) / 100, - y: Math.round( ( element.offsetTop * presentationScale ) * 100 ) / 100, - width: Math.round( ( element.offsetWidth * presentationScale ) * 100 ) / 100, - height: Math.round( ( element.offsetHeight * presentationScale ) * 100 ) / 100 - }; - - } - - /** - * Finds matching elements between two slides. - * - * @param {Array} pairs List of pairs to push matches to - * @param {HTMLElement} fromScope Scope within the from element exists - * @param {HTMLElement} toScope Scope within the to element exists - * @param {String} selector CSS selector of the element to match - * @param {Function} serializer A function that accepts an element and returns - * a stringified ID based on its contents - * @param {Object} animationOptions Optional config options for this pair - */ - findAutoAnimateMatches( pairs, fromScope, toScope, selector, serializer, animationOptions ) { - - let fromMatches = {}; - let toMatches = {}; - - [].slice.call( fromScope.querySelectorAll( selector ) ).forEach( ( element, i ) => { - const key = serializer( element ); - if( typeof key === 'string' && key.length ) { - fromMatches[key] = fromMatches[key] || []; - fromMatches[key].push( element ); - } - } ); - - [].slice.call( toScope.querySelectorAll( selector ) ).forEach( ( element, i ) => { - const key = serializer( element ); - toMatches[key] = toMatches[key] || []; - toMatches[key].push( element ); - - let fromElement; - - // Retrieve the 'from' element - if( fromMatches[key] ) { - const primaryIndex = toMatches[key].length - 1; - const secondaryIndex = fromMatches[key].length - 1; - - // If there are multiple identical from elements, retrieve - // the one at the same index as our to-element. - if( fromMatches[key][ primaryIndex ] ) { - fromElement = fromMatches[key][ primaryIndex ]; - fromMatches[key][ primaryIndex ] = null; - } - // If there are no matching from-elements at the same index, - // use the last one. - else if( fromMatches[key][ secondaryIndex ] ) { - fromElement = fromMatches[key][ secondaryIndex ]; - fromMatches[key][ secondaryIndex ] = null; - } - } - - // If we've got a matching pair, push it to the list of pairs - if( fromElement ) { - pairs.push({ - from: fromElement, - to: element, - options: animationOptions - }); - } - } ); - - } - - /** - * Returns a all elements within the given scope that should - * be considered unmatched in an auto-animate transition. If - * fading of unmatched elements is turned on, these elements - * will fade when going between auto-animate slides. - * - * Note that parents of auto-animate targets are NOT considered - * unmatched since fading them would break the auto-animation. - * - * @param {HTMLElement} rootElement - * @return {Array} - */ - getUnmatchedAutoAnimateElements( rootElement ) { - - return [].slice.call( rootElement.children ).reduce( ( result, element ) => { - - const containsAnimatedElements = element.querySelector( '[data-auto-animate-target]' ); - - // The element is unmatched if - // - It is not an auto-animate target - // - It does not contain any auto-animate targets - if( !element.hasAttribute( 'data-auto-animate-target' ) && !containsAnimatedElements ) { - result.push( element ); - } - - if( element.querySelector( '[data-auto-animate-target]' ) ) { - result = result.concat( this.getUnmatchedAutoAnimateElements( element ) ); - } - - return result; - - }, [] ); - - } - -} diff --git a/js/controllers/backgrounds.js b/js/controllers/backgrounds.js deleted file mode 100644 index 3277eac..0000000 --- a/js/controllers/backgrounds.js +++ /dev/null @@ -1,439 +0,0 @@ -import { queryAll } from '../utils/util.js' -import { colorToRgb, colorBrightness } from '../utils/color.js' - -/** - * Creates and updates slide backgrounds. - */ -export default class Backgrounds { - - constructor( Reveal ) { - - this.Reveal = Reveal; - - } - - render() { - - this.element = document.createElement( 'div' ); - this.element.className = 'backgrounds'; - this.Reveal.getRevealElement().appendChild( this.element ); - - } - - /** - * Creates the slide background elements and appends them - * to the background container. One element is created per - * slide no matter if the given slide has visible background. - */ - create() { - - // Clear prior backgrounds - this.element.innerHTML = ''; - this.element.classList.add( 'no-transition' ); - - // Iterate over all horizontal slides - this.Reveal.getHorizontalSlides().forEach( slideh => { - - let backgroundStack = this.createBackground( slideh, this.element ); - - // Iterate over all vertical slides - queryAll( slideh, 'section' ).forEach( slidev => { - - this.createBackground( slidev, backgroundStack ); - - backgroundStack.classList.add( 'stack' ); - - } ); - - } ); - - // Add parallax background if specified - if( this.Reveal.getConfig().parallaxBackgroundImage ) { - - this.element.style.backgroundImage = 'url("' + this.Reveal.getConfig().parallaxBackgroundImage + '")'; - this.element.style.backgroundSize = this.Reveal.getConfig().parallaxBackgroundSize; - this.element.style.backgroundRepeat = this.Reveal.getConfig().parallaxBackgroundRepeat; - this.element.style.backgroundPosition = this.Reveal.getConfig().parallaxBackgroundPosition; - - // Make sure the below properties are set on the element - these properties are - // needed for proper transitions to be set on the element via CSS. To remove - // annoying background slide-in effect when the presentation starts, apply - // these properties after short time delay - setTimeout( () => { - this.Reveal.getRevealElement().classList.add( 'has-parallax-background' ); - }, 1 ); - - } - else { - - this.element.style.backgroundImage = ''; - this.Reveal.getRevealElement().classList.remove( 'has-parallax-background' ); - - } - - } - - /** - * Creates a background for the given slide. - * - * @param {HTMLElement} slide - * @param {HTMLElement} container The element that the background - * should be appended to - * @return {HTMLElement} New background div - */ - createBackground( slide, container ) { - - // Main slide background element - let element = document.createElement( 'div' ); - element.className = 'slide-background ' + slide.className.replace( /present|past|future/, '' ); - - // Inner background element that wraps images/videos/iframes - let contentElement = document.createElement( 'div' ); - contentElement.className = 'slide-background-content'; - - element.appendChild( contentElement ); - container.appendChild( element ); - - slide.slideBackgroundElement = element; - slide.slideBackgroundContentElement = contentElement; - - // Syncs the background to reflect all current background settings - this.sync( slide ); - - return element; - - } - - /** - * Renders all of the visual properties of a slide background - * based on the various background attributes. - * - * @param {HTMLElement} slide - */ - sync( slide ) { - - const element = slide.slideBackgroundElement, - contentElement = slide.slideBackgroundContentElement; - - const data = { - background: slide.getAttribute( 'data-background' ), - backgroundSize: slide.getAttribute( 'data-background-size' ), - backgroundImage: slide.getAttribute( 'data-background-image' ), - backgroundVideo: slide.getAttribute( 'data-background-video' ), - backgroundIframe: slide.getAttribute( 'data-background-iframe' ), - backgroundColor: slide.getAttribute( 'data-background-color' ), - backgroundGradient: slide.getAttribute( 'data-background-gradient' ), - backgroundRepeat: slide.getAttribute( 'data-background-repeat' ), - backgroundPosition: slide.getAttribute( 'data-background-position' ), - backgroundTransition: slide.getAttribute( 'data-background-transition' ), - backgroundOpacity: slide.getAttribute( 'data-background-opacity' ), - }; - - const dataPreload = slide.hasAttribute( 'data-preload' ); - - // Reset the prior background state in case this is not the - // initial sync - slide.classList.remove( 'has-dark-background' ); - slide.classList.remove( 'has-light-background' ); - - element.removeAttribute( 'data-loaded' ); - element.removeAttribute( 'data-background-hash' ); - element.removeAttribute( 'data-background-size' ); - element.removeAttribute( 'data-background-transition' ); - element.style.backgroundColor = ''; - - contentElement.style.backgroundSize = ''; - contentElement.style.backgroundRepeat = ''; - contentElement.style.backgroundPosition = ''; - contentElement.style.backgroundImage = ''; - contentElement.style.opacity = ''; - contentElement.innerHTML = ''; - - if( data.background ) { - // Auto-wrap image urls in url(...) - if( /^(http|file|\/\/)/gi.test( data.background ) || /\.(svg|png|jpg|jpeg|gif|bmp|webp)([?#\s]|$)/gi.test( data.background ) ) { - slide.setAttribute( 'data-background-image', data.background ); - } - else { - element.style.background = data.background; - } - } - - // Create a hash for this combination of background settings. - // This is used to determine when two slide backgrounds are - // the same. - if( data.background || data.backgroundColor || data.backgroundGradient || data.backgroundImage || data.backgroundVideo || data.backgroundIframe ) { - element.setAttribute( 'data-background-hash', data.background + - data.backgroundSize + - data.backgroundImage + - data.backgroundVideo + - data.backgroundIframe + - data.backgroundColor + - data.backgroundGradient + - data.backgroundRepeat + - data.backgroundPosition + - data.backgroundTransition + - data.backgroundOpacity ); - } - - // Additional and optional background properties - if( data.backgroundSize ) element.setAttribute( 'data-background-size', data.backgroundSize ); - if( data.backgroundColor ) element.style.backgroundColor = data.backgroundColor; - if( data.backgroundGradient ) element.style.backgroundImage = data.backgroundGradient; - if( data.backgroundTransition ) element.setAttribute( 'data-background-transition', data.backgroundTransition ); - - if( dataPreload ) element.setAttribute( 'data-preload', '' ); - - // Background image options are set on the content wrapper - if( data.backgroundSize ) contentElement.style.backgroundSize = data.backgroundSize; - if( data.backgroundRepeat ) contentElement.style.backgroundRepeat = data.backgroundRepeat; - if( data.backgroundPosition ) contentElement.style.backgroundPosition = data.backgroundPosition; - if( data.backgroundOpacity ) contentElement.style.opacity = data.backgroundOpacity; - - const contrastClass = this.getContrastClass( slide ); - - if( typeof contrastClass === 'string' ) { - slide.classList.add( contrastClass ); - } - - } - - /** - * Returns a class name that can be applied to a slide to indicate - * if it has a light or dark background. - * - * @param {*} slide - * - * @returns {string|null} - */ - getContrastClass( slide ) { - - const element = slide.slideBackgroundElement; - - // If this slide has a background color, we add a class that - // signals if it is light or dark. If the slide has no background - // color, no class will be added - let contrastColor = slide.getAttribute( 'data-background-color' ); - - // If no bg color was found, or it cannot be converted by colorToRgb, check the computed background - if( !contrastColor || !colorToRgb( contrastColor ) ) { - let computedBackgroundStyle = window.getComputedStyle( element ); - if( computedBackgroundStyle && computedBackgroundStyle.backgroundColor ) { - contrastColor = computedBackgroundStyle.backgroundColor; - } - } - - if( contrastColor ) { - const rgb = colorToRgb( contrastColor ); - - // Ignore fully transparent backgrounds. Some browsers return - // rgba(0,0,0,0) when reading the computed background color of - // an element with no background - if( rgb && rgb.a !== 0 ) { - if( colorBrightness( contrastColor ) < 128 ) { - return 'has-dark-background'; - } - else { - return 'has-light-background'; - } - } - } - - return null; - - } - - /** - * Bubble the 'has-light-background'/'has-dark-background' classes. - */ - bubbleSlideContrastClassToElement( slide, target ) { - - [ 'has-light-background', 'has-dark-background' ].forEach( classToBubble => { - if( slide.classList.contains( classToBubble ) ) { - target.classList.add( classToBubble ); - } - else { - target.classList.remove( classToBubble ); - } - }, this ); - - } - - /** - * Updates the background elements to reflect the current - * slide. - * - * @param {boolean} includeAll If true, the backgrounds of - * all vertical slides (not just the present) will be updated. - */ - update( includeAll = false ) { - - let currentSlide = this.Reveal.getCurrentSlide(); - let indices = this.Reveal.getIndices(); - - let currentBackground = null; - - // Reverse past/future classes when in RTL mode - let horizontalPast = this.Reveal.getConfig().rtl ? 'future' : 'past', - horizontalFuture = this.Reveal.getConfig().rtl ? 'past' : 'future'; - - // Update the classes of all backgrounds to match the - // states of their slides (past/present/future) - Array.from( this.element.childNodes ).forEach( ( backgroundh, h ) => { - - backgroundh.classList.remove( 'past', 'present', 'future' ); - - if( h < indices.h ) { - backgroundh.classList.add( horizontalPast ); - } - else if ( h > indices.h ) { - backgroundh.classList.add( horizontalFuture ); - } - else { - backgroundh.classList.add( 'present' ); - - // Store a reference to the current background element - currentBackground = backgroundh; - } - - if( includeAll || h === indices.h ) { - queryAll( backgroundh, '.slide-background' ).forEach( ( backgroundv, v ) => { - - backgroundv.classList.remove( 'past', 'present', 'future' ); - - const indexv = typeof indices.v === 'number' ? indices.v : 0; - - if( v < indexv ) { - backgroundv.classList.add( 'past' ); - } - else if ( v > indexv ) { - backgroundv.classList.add( 'future' ); - } - else { - backgroundv.classList.add( 'present' ); - - // Only if this is the present horizontal and vertical slide - if( h === indices.h ) currentBackground = backgroundv; - } - - } ); - } - - } ); - - // Stop content inside of previous backgrounds - if( this.previousBackground ) { - - this.Reveal.slideContent.stopEmbeddedContent( this.previousBackground, { unloadIframes: !this.Reveal.slideContent.shouldPreload( this.previousBackground ) } ); - - } - - // Start content in the current background - if( currentBackground ) { - - this.Reveal.slideContent.startEmbeddedContent( currentBackground ); - - let currentBackgroundContent = currentBackground.querySelector( '.slide-background-content' ); - if( currentBackgroundContent ) { - - let backgroundImageURL = currentBackgroundContent.style.backgroundImage || ''; - - // Restart GIFs (doesn't work in Firefox) - if( /\.gif/i.test( backgroundImageURL ) ) { - currentBackgroundContent.style.backgroundImage = ''; - window.getComputedStyle( currentBackgroundContent ).opacity; - currentBackgroundContent.style.backgroundImage = backgroundImageURL; - } - - } - - // Don't transition between identical backgrounds. This - // prevents unwanted flicker. - let previousBackgroundHash = this.previousBackground ? this.previousBackground.getAttribute( 'data-background-hash' ) : null; - let currentBackgroundHash = currentBackground.getAttribute( 'data-background-hash' ); - if( currentBackgroundHash && currentBackgroundHash === previousBackgroundHash && currentBackground !== this.previousBackground ) { - this.element.classList.add( 'no-transition' ); - } - - this.previousBackground = currentBackground; - - } - - // If there's a background brightness flag for this slide, - // bubble it to the .reveal container - if( currentSlide ) { - this.bubbleSlideContrastClassToElement( currentSlide, this.Reveal.getRevealElement() ); - } - - // Allow the first background to apply without transition - setTimeout( () => { - this.element.classList.remove( 'no-transition' ); - }, 1 ); - - } - - /** - * Updates the position of the parallax background based - * on the current slide index. - */ - updateParallax() { - - let indices = this.Reveal.getIndices(); - - if( this.Reveal.getConfig().parallaxBackgroundImage ) { - - let horizontalSlides = this.Reveal.getHorizontalSlides(), - verticalSlides = this.Reveal.getVerticalSlides(); - - let backgroundSize = this.element.style.backgroundSize.split( ' ' ), - backgroundWidth, backgroundHeight; - - if( backgroundSize.length === 1 ) { - backgroundWidth = backgroundHeight = parseInt( backgroundSize[0], 10 ); - } - else { - backgroundWidth = parseInt( backgroundSize[0], 10 ); - backgroundHeight = parseInt( backgroundSize[1], 10 ); - } - - let slideWidth = this.element.offsetWidth, - horizontalSlideCount = horizontalSlides.length, - horizontalOffsetMultiplier, - horizontalOffset; - - if( typeof this.Reveal.getConfig().parallaxBackgroundHorizontal === 'number' ) { - horizontalOffsetMultiplier = this.Reveal.getConfig().parallaxBackgroundHorizontal; - } - else { - horizontalOffsetMultiplier = horizontalSlideCount > 1 ? ( backgroundWidth - slideWidth ) / ( horizontalSlideCount-1 ) : 0; - } - - horizontalOffset = horizontalOffsetMultiplier * indices.h * -1; - - let slideHeight = this.element.offsetHeight, - verticalSlideCount = verticalSlides.length, - verticalOffsetMultiplier, - verticalOffset; - - if( typeof this.Reveal.getConfig().parallaxBackgroundVertical === 'number' ) { - verticalOffsetMultiplier = this.Reveal.getConfig().parallaxBackgroundVertical; - } - else { - verticalOffsetMultiplier = ( backgroundHeight - slideHeight ) / ( verticalSlideCount-1 ); - } - - verticalOffset = verticalSlideCount > 0 ? verticalOffsetMultiplier * indices.v : 0; - - this.element.style.backgroundPosition = horizontalOffset + 'px ' + -verticalOffset + 'px'; - - } - - } - - destroy() { - - this.element.remove(); - - } - -} diff --git a/js/controllers/controls.js b/js/controllers/controls.js deleted file mode 100644 index 734eb17..0000000 --- a/js/controllers/controls.js +++ /dev/null @@ -1,266 +0,0 @@ -import { queryAll } from '../utils/util.js' -import { isAndroid } from '../utils/device.js' - -/** - * Manages our presentation controls. This includes both - * the built-in control arrows as well as event monitoring - * of any elements within the presentation with either of the - * following helper classes: - * - .navigate-up - * - .navigate-right - * - .navigate-down - * - .navigate-left - * - .navigate-next - * - .navigate-prev - */ -export default class Controls { - - constructor( Reveal ) { - - this.Reveal = Reveal; - - this.onNavigateLeftClicked = this.onNavigateLeftClicked.bind( this ); - this.onNavigateRightClicked = this.onNavigateRightClicked.bind( this ); - this.onNavigateUpClicked = this.onNavigateUpClicked.bind( this ); - this.onNavigateDownClicked = this.onNavigateDownClicked.bind( this ); - this.onNavigatePrevClicked = this.onNavigatePrevClicked.bind( this ); - this.onNavigateNextClicked = this.onNavigateNextClicked.bind( this ); - - } - - render() { - - const rtl = this.Reveal.getConfig().rtl; - const revealElement = this.Reveal.getRevealElement(); - - this.element = document.createElement( 'aside' ); - this.element.className = 'controls'; - this.element.innerHTML = - ` - - - `; - - this.Reveal.getRevealElement().appendChild( this.element ); - - // There can be multiple instances of controls throughout the page - this.controlsLeft = queryAll( revealElement, '.navigate-left' ); - this.controlsRight = queryAll( revealElement, '.navigate-right' ); - this.controlsUp = queryAll( revealElement, '.navigate-up' ); - this.controlsDown = queryAll( revealElement, '.navigate-down' ); - this.controlsPrev = queryAll( revealElement, '.navigate-prev' ); - this.controlsNext = queryAll( revealElement, '.navigate-next' ); - - // The left, right and down arrows in the standard reveal.js controls - this.controlsRightArrow = this.element.querySelector( '.navigate-right' ); - this.controlsLeftArrow = this.element.querySelector( '.navigate-left' ); - this.controlsDownArrow = this.element.querySelector( '.navigate-down' ); - - } - - /** - * Called when the reveal.js config is updated. - */ - configure( config, oldConfig ) { - - this.element.style.display = config.controls ? 'block' : 'none'; - - this.element.setAttribute( 'data-controls-layout', config.controlsLayout ); - this.element.setAttribute( 'data-controls-back-arrows', config.controlsBackArrows ); - - } - - bind() { - - // Listen to both touch and click events, in case the device - // supports both - let pointerEvents = [ 'touchstart', 'click' ]; - - // Only support touch for Android, fixes double navigations in - // stock browser - if( isAndroid ) { - pointerEvents = [ 'touchstart' ]; - } - - pointerEvents.forEach( eventName => { - this.controlsLeft.forEach( el => el.addEventListener( eventName, this.onNavigateLeftClicked, false ) ); - this.controlsRight.forEach( el => el.addEventListener( eventName, this.onNavigateRightClicked, false ) ); - this.controlsUp.forEach( el => el.addEventListener( eventName, this.onNavigateUpClicked, false ) ); - this.controlsDown.forEach( el => el.addEventListener( eventName, this.onNavigateDownClicked, false ) ); - this.controlsPrev.forEach( el => el.addEventListener( eventName, this.onNavigatePrevClicked, false ) ); - this.controlsNext.forEach( el => el.addEventListener( eventName, this.onNavigateNextClicked, false ) ); - } ); - - } - - unbind() { - - [ 'touchstart', 'click' ].forEach( eventName => { - this.controlsLeft.forEach( el => el.removeEventListener( eventName, this.onNavigateLeftClicked, false ) ); - this.controlsRight.forEach( el => el.removeEventListener( eventName, this.onNavigateRightClicked, false ) ); - this.controlsUp.forEach( el => el.removeEventListener( eventName, this.onNavigateUpClicked, false ) ); - this.controlsDown.forEach( el => el.removeEventListener( eventName, this.onNavigateDownClicked, false ) ); - this.controlsPrev.forEach( el => el.removeEventListener( eventName, this.onNavigatePrevClicked, false ) ); - this.controlsNext.forEach( el => el.removeEventListener( eventName, this.onNavigateNextClicked, false ) ); - } ); - - } - - /** - * Updates the state of all control/navigation arrows. - */ - update() { - - let routes = this.Reveal.availableRoutes(); - - // Remove the 'enabled' class from all directions - [...this.controlsLeft, ...this.controlsRight, ...this.controlsUp, ...this.controlsDown, ...this.controlsPrev, ...this.controlsNext].forEach( node => { - node.classList.remove( 'enabled', 'fragmented' ); - - // Set 'disabled' attribute on all directions - node.setAttribute( 'disabled', 'disabled' ); - } ); - - // Add the 'enabled' class to the available routes; remove 'disabled' attribute to enable buttons - if( routes.left ) this.controlsLeft.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } ); - if( routes.right ) this.controlsRight.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } ); - if( routes.up ) this.controlsUp.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } ); - if( routes.down ) this.controlsDown.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } ); - - // Prev/next buttons - if( routes.left || routes.up ) this.controlsPrev.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } ); - if( routes.right || routes.down ) this.controlsNext.forEach( el => { el.classList.add( 'enabled' ); el.removeAttribute( 'disabled' ); } ); - - // Highlight fragment directions - let currentSlide = this.Reveal.getCurrentSlide(); - if( currentSlide ) { - - let fragmentsRoutes = this.Reveal.fragments.availableRoutes(); - - // Always apply fragment decorator to prev/next buttons - if( fragmentsRoutes.prev ) this.controlsPrev.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } ); - if( fragmentsRoutes.next ) this.controlsNext.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } ); - - // Apply fragment decorators to directional buttons based on - // what slide axis they are in - if( this.Reveal.isVerticalSlide( currentSlide ) ) { - if( fragmentsRoutes.prev ) this.controlsUp.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } ); - if( fragmentsRoutes.next ) this.controlsDown.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } ); - } - else { - if( fragmentsRoutes.prev ) this.controlsLeft.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } ); - if( fragmentsRoutes.next ) this.controlsRight.forEach( el => { el.classList.add( 'fragmented', 'enabled' ); el.removeAttribute( 'disabled' ); } ); - } - - } - - if( this.Reveal.getConfig().controlsTutorial ) { - - let indices = this.Reveal.getIndices(); - - // Highlight control arrows with an animation to ensure - // that the viewer knows how to navigate - if( !this.Reveal.hasNavigatedVertically() && routes.down ) { - this.controlsDownArrow.classList.add( 'highlight' ); - } - else { - this.controlsDownArrow.classList.remove( 'highlight' ); - - if( this.Reveal.getConfig().rtl ) { - - if( !this.Reveal.hasNavigatedHorizontally() && routes.left && indices.v === 0 ) { - this.controlsLeftArrow.classList.add( 'highlight' ); - } - else { - this.controlsLeftArrow.classList.remove( 'highlight' ); - } - - } else { - - if( !this.Reveal.hasNavigatedHorizontally() && routes.right && indices.v === 0 ) { - this.controlsRightArrow.classList.add( 'highlight' ); - } - else { - this.controlsRightArrow.classList.remove( 'highlight' ); - } - } - } - } - } - - destroy() { - - this.unbind(); - this.element.remove(); - - } - - /** - * Event handlers for navigation control buttons. - */ - onNavigateLeftClicked( event ) { - - event.preventDefault(); - this.Reveal.onUserInput(); - - if( this.Reveal.getConfig().navigationMode === 'linear' ) { - this.Reveal.prev(); - } - else { - this.Reveal.left(); - } - - } - - onNavigateRightClicked( event ) { - - event.preventDefault(); - this.Reveal.onUserInput(); - - if( this.Reveal.getConfig().navigationMode === 'linear' ) { - this.Reveal.next(); - } - else { - this.Reveal.right(); - } - - } - - onNavigateUpClicked( event ) { - - event.preventDefault(); - this.Reveal.onUserInput(); - - this.Reveal.up(); - - } - - onNavigateDownClicked( event ) { - - event.preventDefault(); - this.Reveal.onUserInput(); - - this.Reveal.down(); - - } - - onNavigatePrevClicked( event ) { - - event.preventDefault(); - this.Reveal.onUserInput(); - - this.Reveal.prev(); - - } - - onNavigateNextClicked( event ) { - - event.preventDefault(); - this.Reveal.onUserInput(); - - this.Reveal.next(); - - } - - -} \ No newline at end of file diff --git a/js/controllers/focus.js b/js/controllers/focus.js deleted file mode 100644 index 3e68c3f..0000000 --- a/js/controllers/focus.js +++ /dev/null @@ -1,103 +0,0 @@ -import { closest } from '../utils/util.js' - -/** - * Manages focus when a presentation is embedded. This - * helps us only capture keyboard from the presentation - * a user is currently interacting with in a page where - * multiple presentations are embedded. - */ - -const STATE_FOCUS = 'focus'; -const STATE_BLUR = 'blur'; - -export default class Focus { - - constructor( Reveal ) { - - this.Reveal = Reveal; - - this.onRevealPointerDown = this.onRevealPointerDown.bind( this ); - this.onDocumentPointerDown = this.onDocumentPointerDown.bind( this ); - - } - - /** - * Called when the reveal.js config is updated. - */ - configure( config, oldConfig ) { - - if( config.embedded ) { - this.blur(); - } - else { - this.focus(); - this.unbind(); - } - - } - - bind() { - - if( this.Reveal.getConfig().embedded ) { - this.Reveal.getRevealElement().addEventListener( 'pointerdown', this.onRevealPointerDown, false ); - } - - } - - unbind() { - - this.Reveal.getRevealElement().removeEventListener( 'pointerdown', this.onRevealPointerDown, false ); - document.removeEventListener( 'pointerdown', this.onDocumentPointerDown, false ); - - } - - focus() { - - if( this.state !== STATE_FOCUS ) { - this.Reveal.getRevealElement().classList.add( 'focused' ); - document.addEventListener( 'pointerdown', this.onDocumentPointerDown, false ); - } - - this.state = STATE_FOCUS; - - } - - blur() { - - if( this.state !== STATE_BLUR ) { - this.Reveal.getRevealElement().classList.remove( 'focused' ); - document.removeEventListener( 'pointerdown', this.onDocumentPointerDown, false ); - } - - this.state = STATE_BLUR; - - } - - isFocused() { - - return this.state === STATE_FOCUS; - - } - - destroy() { - - this.Reveal.getRevealElement().classList.remove( 'focused' ); - - } - - onRevealPointerDown( event ) { - - this.focus(); - - } - - onDocumentPointerDown( event ) { - - let revealElement = closest( event.target, '.reveal' ); - if( !revealElement || revealElement !== this.Reveal.getRevealElement() ) { - this.blur(); - } - - } - -} \ No newline at end of file diff --git a/js/controllers/fragments.js b/js/controllers/fragments.js deleted file mode 100644 index 8aa597b..0000000 --- a/js/controllers/fragments.js +++ /dev/null @@ -1,375 +0,0 @@ -import { extend, queryAll } from '../utils/util.js' - -/** - * Handles sorting and navigation of slide fragments. - * Fragments are elements within a slide that are - * revealed/animated incrementally. - */ -export default class Fragments { - - constructor( Reveal ) { - - this.Reveal = Reveal; - - } - - /** - * Called when the reveal.js config is updated. - */ - configure( config, oldConfig ) { - - if( config.fragments === false ) { - this.disable(); - } - else if( oldConfig.fragments === false ) { - this.enable(); - } - - } - - /** - * If fragments are disabled in the deck, they should all be - * visible rather than stepped through. - */ - disable() { - - queryAll( this.Reveal.getSlidesElement(), '.fragment' ).forEach( element => { - element.classList.add( 'visible' ); - element.classList.remove( 'current-fragment' ); - } ); - - } - - /** - * Reverse of #disable(). Only called if fragments have - * previously been disabled. - */ - enable() { - - queryAll( this.Reveal.getSlidesElement(), '.fragment' ).forEach( element => { - element.classList.remove( 'visible' ); - element.classList.remove( 'current-fragment' ); - } ); - - } - - /** - * Returns an object describing the available fragment - * directions. - * - * @return {{prev: boolean, next: boolean}} - */ - availableRoutes() { - - let currentSlide = this.Reveal.getCurrentSlide(); - if( currentSlide && this.Reveal.getConfig().fragments ) { - let fragments = currentSlide.querySelectorAll( '.fragment:not(.disabled)' ); - let hiddenFragments = currentSlide.querySelectorAll( '.fragment:not(.disabled):not(.visible)' ); - - return { - prev: fragments.length - hiddenFragments.length > 0, - next: !!hiddenFragments.length - }; - } - else { - return { prev: false, next: false }; - } - - } - - /** - * Return a sorted fragments list, ordered by an increasing - * "data-fragment-index" attribute. - * - * Fragments will be revealed in the order that they are returned by - * this function, so you can use the index attributes to control the - * order of fragment appearance. - * - * To maintain a sensible default fragment order, fragments are presumed - * to be passed in document order. This function adds a "fragment-index" - * attribute to each node if such an attribute is not already present, - * and sets that attribute to an integer value which is the position of - * the fragment within the fragments list. - * - * @param {object[]|*} fragments - * @param {boolean} grouped If true the returned array will contain - * nested arrays for all fragments with the same index - * @return {object[]} sorted Sorted array of fragments - */ - sort( fragments, grouped = false ) { - - fragments = Array.from( fragments ); - - let ordered = [], - unordered = [], - sorted = []; - - // Group ordered and unordered elements - fragments.forEach( fragment => { - if( fragment.hasAttribute( 'data-fragment-index' ) ) { - let index = parseInt( fragment.getAttribute( 'data-fragment-index' ), 10 ); - - if( !ordered[index] ) { - ordered[index] = []; - } - - ordered[index].push( fragment ); - } - else { - unordered.push( [ fragment ] ); - } - } ); - - // Append fragments without explicit indices in their - // DOM order - ordered = ordered.concat( unordered ); - - // Manually count the index up per group to ensure there - // are no gaps - let index = 0; - - // Push all fragments in their sorted order to an array, - // this flattens the groups - ordered.forEach( group => { - group.forEach( fragment => { - sorted.push( fragment ); - fragment.setAttribute( 'data-fragment-index', index ); - } ); - - index ++; - } ); - - return grouped === true ? ordered : sorted; - - } - - /** - * Sorts and formats all of fragments in the - * presentation. - */ - sortAll() { - - this.Reveal.getHorizontalSlides().forEach( horizontalSlide => { - - let verticalSlides = queryAll( horizontalSlide, 'section' ); - verticalSlides.forEach( ( verticalSlide, y ) => { - - this.sort( verticalSlide.querySelectorAll( '.fragment' ) ); - - }, this ); - - if( verticalSlides.length === 0 ) this.sort( horizontalSlide.querySelectorAll( '.fragment' ) ); - - } ); - - } - - /** - * Refreshes the fragments on the current slide so that they - * have the appropriate classes (.visible + .current-fragment). - * - * @param {number} [index] The index of the current fragment - * @param {array} [fragments] Array containing all fragments - * in the current slide - * - * @return {{shown: array, hidden: array}} - */ - update( index, fragments, slide = this.Reveal.getCurrentSlide() ) { - - let changedFragments = { - shown: [], - hidden: [] - }; - - if( slide && this.Reveal.getConfig().fragments ) { - - fragments = fragments || this.sort( slide.querySelectorAll( '.fragment' ) ); - - if( fragments.length ) { - - let maxIndex = 0; - - if( typeof index !== 'number' ) { - let currentFragment = this.sort( slide.querySelectorAll( '.fragment.visible' ) ).pop(); - if( currentFragment ) { - index = parseInt( currentFragment.getAttribute( 'data-fragment-index' ) || 0, 10 ); - } - } - - Array.from( fragments ).forEach( ( el, i ) => { - - if( el.hasAttribute( 'data-fragment-index' ) ) { - i = parseInt( el.getAttribute( 'data-fragment-index' ), 10 ); - } - - maxIndex = Math.max( maxIndex, i ); - - // Visible fragments - if( i <= index ) { - let wasVisible = el.classList.contains( 'visible' ) - el.classList.add( 'visible' ); - el.classList.remove( 'current-fragment' ); - - if( i === index ) { - // Announce the fragments one by one to the Screen Reader - this.Reveal.announceStatus( this.Reveal.getStatusText( el ) ); - - el.classList.add( 'current-fragment' ); - this.Reveal.slideContent.startEmbeddedContent( el ); - } - - if( !wasVisible ) { - changedFragments.shown.push( el ) - this.Reveal.dispatchEvent({ - target: el, - type: 'visible', - bubbles: false - }); - } - } - // Hidden fragments - else { - let wasVisible = el.classList.contains( 'visible' ) - el.classList.remove( 'visible' ); - el.classList.remove( 'current-fragment' ); - - if( wasVisible ) { - this.Reveal.slideContent.stopEmbeddedContent( el ); - changedFragments.hidden.push( el ); - this.Reveal.dispatchEvent({ - target: el, - type: 'hidden', - bubbles: false - }); - } - } - - } ); - - // Write the current fragment index to the slide
. - // This can be used by end users to apply styles based on - // the current fragment index. - index = typeof index === 'number' ? index : -1; - index = Math.max( Math.min( index, maxIndex ), -1 ); - slide.setAttribute( 'data-fragment', index ); - - } - - } - - return changedFragments; - - } - - /** - * Formats the fragments on the given slide so that they have - * valid indices. Call this if fragments are changed in the DOM - * after reveal.js has already initialized. - * - * @param {HTMLElement} slide - * @return {Array} a list of the HTML fragments that were synced - */ - sync( slide = this.Reveal.getCurrentSlide() ) { - - return this.sort( slide.querySelectorAll( '.fragment' ) ); - - } - - /** - * Navigate to the specified slide fragment. - * - * @param {?number} index The index of the fragment that - * should be shown, -1 means all are invisible - * @param {number} offset Integer offset to apply to the - * fragment index - * - * @return {boolean} true if a change was made in any - * fragments visibility as part of this call - */ - goto( index, offset = 0 ) { - - let currentSlide = this.Reveal.getCurrentSlide(); - if( currentSlide && this.Reveal.getConfig().fragments ) { - - let fragments = this.sort( currentSlide.querySelectorAll( '.fragment:not(.disabled)' ) ); - if( fragments.length ) { - - // If no index is specified, find the current - if( typeof index !== 'number' ) { - let lastVisibleFragment = this.sort( currentSlide.querySelectorAll( '.fragment:not(.disabled).visible' ) ).pop(); - - if( lastVisibleFragment ) { - index = parseInt( lastVisibleFragment.getAttribute( 'data-fragment-index' ) || 0, 10 ); - } - else { - index = -1; - } - } - - // Apply the offset if there is one - index += offset; - - let changedFragments = this.update( index, fragments ); - - if( changedFragments.hidden.length ) { - this.Reveal.dispatchEvent({ - type: 'fragmenthidden', - data: { - fragment: changedFragments.hidden[0], - fragments: changedFragments.hidden - } - }); - } - - if( changedFragments.shown.length ) { - this.Reveal.dispatchEvent({ - type: 'fragmentshown', - data: { - fragment: changedFragments.shown[0], - fragments: changedFragments.shown - } - }); - } - - this.Reveal.controls.update(); - this.Reveal.progress.update(); - - if( this.Reveal.getConfig().fragmentInURL ) { - this.Reveal.location.writeURL(); - } - - return !!( changedFragments.shown.length || changedFragments.hidden.length ); - - } - - } - - return false; - - } - - /** - * Navigate to the next slide fragment. - * - * @return {boolean} true if there was a next fragment, - * false otherwise - */ - next() { - - return this.goto( null, 1 ); - - } - - /** - * Navigate to the previous slide fragment. - * - * @return {boolean} true if there was a previous fragment, - * false otherwise - */ - prev() { - - return this.goto( null, -1 ); - - } - -} \ No newline at end of file diff --git a/js/controllers/jumptoslide.js b/js/controllers/jumptoslide.js deleted file mode 100644 index 5a63260..0000000 --- a/js/controllers/jumptoslide.js +++ /dev/null @@ -1,197 +0,0 @@ -import { - SLIDE_NUMBER_FORMAT_CURRENT, - SLIDE_NUMBER_FORMAT_CURRENT_SLASH_TOTAL -} from "../utils/constants"; - -/** - * Makes it possible to jump to a slide by entering its - * slide number or id. - */ -export default class JumpToSlide { - - constructor( Reveal ) { - - this.Reveal = Reveal; - - this.onInput = this.onInput.bind( this ); - this.onBlur = this.onBlur.bind( this ); - this.onKeyDown = this.onKeyDown.bind( this ); - - } - - render() { - - this.element = document.createElement( 'div' ); - this.element.className = 'jump-to-slide'; - - this.jumpInput = document.createElement( 'input' ); - this.jumpInput.type = 'text'; - this.jumpInput.className = 'jump-to-slide-input'; - this.jumpInput.placeholder = 'Jump to slide'; - this.jumpInput.addEventListener( 'input', this.onInput ); - this.jumpInput.addEventListener( 'keydown', this.onKeyDown ); - this.jumpInput.addEventListener( 'blur', this.onBlur ); - - this.element.appendChild( this.jumpInput ); - - } - - show() { - - this.indicesOnShow = this.Reveal.getIndices(); - - this.Reveal.getRevealElement().appendChild( this.element ); - this.jumpInput.focus(); - - } - - hide() { - - if( this.isVisible() ) { - this.element.remove(); - this.jumpInput.value = ''; - - clearTimeout( this.jumpTimeout ); - delete this.jumpTimeout; - } - - } - - isVisible() { - - return !!this.element.parentNode; - - } - - /** - * Parses the current input and jumps to the given slide. - */ - jump() { - - clearTimeout( this.jumpTimeout ); - delete this.jumpTimeout; - - let query = this.jumpInput.value.trim( '' ); - let indices; - - // When slide numbers are formatted to be a single linear mumber - // (instead of showing a separate horizontal/vertical index) we - // use the same format for slide jumps - if( /^\d+$/.test( query ) ) { - const slideNumberFormat = this.Reveal.getConfig().slideNumber; - if( slideNumberFormat === SLIDE_NUMBER_FORMAT_CURRENT || slideNumberFormat === SLIDE_NUMBER_FORMAT_CURRENT_SLASH_TOTAL ) { - const slide = this.Reveal.getSlides()[ parseInt( query, 10 ) - 1 ]; - if( slide ) { - indices = this.Reveal.getIndices( slide ); - } - } - } - - if( !indices ) { - // If the query uses "horizontal.vertical" format, convert to - // "horizontal/vertical" so that our URL parser can understand - if( /^\d+\.\d+$/.test( query ) ) { - query = query.replace( '.', '/' ); - } - - indices = this.Reveal.location.getIndicesFromHash( query, { oneBasedIndex: true } ); - } - - // Still no valid index? Fall back on a text search - if( !indices && /\S+/i.test( query ) && query.length > 1 ) { - indices = this.search( query ); - } - - if( indices && query !== '' ) { - this.Reveal.slide( indices.h, indices.v, indices.f ); - return true; - } - else { - this.Reveal.slide( this.indicesOnShow.h, this.indicesOnShow.v, this.indicesOnShow.f ); - return false; - } - - } - - jumpAfter( delay ) { - - clearTimeout( this.jumpTimeout ); - this.jumpTimeout = setTimeout( () => this.jump(), delay ); - - } - - /** - * A lofi search that looks for the given query in all - * of our slides and returns the first match. - */ - search( query ) { - - const regex = new RegExp( '\\b' + query.trim() + '\\b', 'i' ); - - const slide = this.Reveal.getSlides().find( ( slide ) => { - return regex.test( slide.innerText ); - } ); - - if( slide ) { - return this.Reveal.getIndices( slide ); - } - else { - return null; - } - - } - - /** - * Reverts back to the slide we were on when jump to slide was - * invoked. - */ - cancel() { - - this.Reveal.slide( this.indicesOnShow.h, this.indicesOnShow.v, this.indicesOnShow.f ); - this.hide(); - - } - - confirm() { - - this.jump(); - this.hide(); - - } - - destroy() { - - this.jumpInput.removeEventListener( 'input', this.onInput ); - this.jumpInput.removeEventListener( 'keydown', this.onKeyDown ); - this.jumpInput.removeEventListener( 'blur', this.onBlur ); - - this.element.remove(); - - } - - onKeyDown( event ) { - - if( event.keyCode === 13 ) { - this.confirm(); - } - else if( event.keyCode === 27 ) { - this.cancel(); - - event.stopImmediatePropagation(); - } - - } - - onInput( event ) { - - this.jumpAfter( 200 ); - - } - - onBlur() { - - setTimeout( () => this.hide(), 1 ); - - } - -} \ No newline at end of file diff --git a/js/controllers/keyboard.js b/js/controllers/keyboard.js deleted file mode 100644 index 3dac53b..0000000 --- a/js/controllers/keyboard.js +++ /dev/null @@ -1,386 +0,0 @@ -import { enterFullscreen } from '../utils/util.js' - -/** - * Handles all reveal.js keyboard interactions. - */ -export default class Keyboard { - - constructor( Reveal ) { - - this.Reveal = Reveal; - - // A key:value map of keyboard keys and descriptions of - // the actions they trigger - this.shortcuts = {}; - - // Holds custom key code mappings - this.bindings = {}; - - this.onDocumentKeyDown = this.onDocumentKeyDown.bind( this ); - - } - - /** - * Called when the reveal.js config is updated. - */ - configure( config, oldConfig ) { - - if( config.navigationMode === 'linear' ) { - this.shortcuts['→ , ↓ , SPACE , N , L , J'] = 'Next slide'; - this.shortcuts['← , ↑ , P , H , K'] = 'Previous slide'; - } - else { - this.shortcuts['N , SPACE'] = 'Next slide'; - this.shortcuts['P , Shift SPACE'] = 'Previous slide'; - this.shortcuts['← , H'] = 'Navigate left'; - this.shortcuts['→ , L'] = 'Navigate right'; - this.shortcuts['↑ , K'] = 'Navigate up'; - this.shortcuts['↓ , J'] = 'Navigate down'; - } - - this.shortcuts['Alt + ←/↑/→/↓'] = 'Navigate without fragments'; - this.shortcuts['Shift + ←/↑/→/↓'] = 'Jump to first/last slide'; - this.shortcuts['B , .'] = 'Pause'; - this.shortcuts['F'] = 'Fullscreen'; - this.shortcuts['G'] = 'Jump to slide'; - this.shortcuts['ESC, O'] = 'Slide overview'; - - } - - /** - * Starts listening for keyboard events. - */ - bind() { - - document.addEventListener( 'keydown', this.onDocumentKeyDown, false ); - - } - - /** - * Stops listening for keyboard events. - */ - unbind() { - - document.removeEventListener( 'keydown', this.onDocumentKeyDown, false ); - - } - - /** - * Add a custom key binding with optional description to - * be added to the help screen. - */ - addKeyBinding( binding, callback ) { - - if( typeof binding === 'object' && binding.keyCode ) { - this.bindings[binding.keyCode] = { - callback: callback, - key: binding.key, - description: binding.description - }; - } - else { - this.bindings[binding] = { - callback: callback, - key: null, - description: null - }; - } - - } - - /** - * Removes the specified custom key binding. - */ - removeKeyBinding( keyCode ) { - - delete this.bindings[keyCode]; - - } - - /** - * Programmatically triggers a keyboard event - * - * @param {int} keyCode - */ - triggerKey( keyCode ) { - - this.onDocumentKeyDown( { keyCode } ); - - } - - /** - * Registers a new shortcut to include in the help overlay - * - * @param {String} key - * @param {String} value - */ - registerKeyboardShortcut( key, value ) { - - this.shortcuts[key] = value; - - } - - getShortcuts() { - - return this.shortcuts; - - } - - getBindings() { - - return this.bindings; - - } - - /** - * Handler for the document level 'keydown' event. - * - * @param {object} event - */ - onDocumentKeyDown( event ) { - - let config = this.Reveal.getConfig(); - - // If there's a condition specified and it returns false, - // ignore this event - if( typeof config.keyboardCondition === 'function' && config.keyboardCondition(event) === false ) { - return true; - } - - // If keyboardCondition is set, only capture keyboard events - // for embedded decks when they are focused - if( config.keyboardCondition === 'focused' && !this.Reveal.isFocused() ) { - return true; - } - - // Shorthand - let keyCode = event.keyCode; - - // Remember if auto-sliding was paused so we can toggle it - let autoSlideWasPaused = !this.Reveal.isAutoSliding(); - - this.Reveal.onUserInput( event ); - - // Is there a focused element that could be using the keyboard? - let activeElementIsCE = document.activeElement && document.activeElement.isContentEditable === true; - let activeElementIsInput = document.activeElement && document.activeElement.tagName && /input|textarea/i.test( document.activeElement.tagName ); - let activeElementIsNotes = document.activeElement && document.activeElement.className && /speaker-notes/i.test( document.activeElement.className); - - // Whitelist certain modifiers for slide navigation shortcuts - let keyCodeUsesModifier = [32, 37, 38, 39, 40, 78, 80, 191].indexOf( event.keyCode ) !== -1; - - // Prevent all other events when a modifier is pressed - let unusedModifier = !( keyCodeUsesModifier && event.shiftKey || event.altKey ) && - ( event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ); - - // Disregard the event if there's a focused element or a - // keyboard modifier key is present - if( activeElementIsCE || activeElementIsInput || activeElementIsNotes || unusedModifier ) return; - - // While paused only allow resume keyboard events; 'b', 'v', '.' - let resumeKeyCodes = [66,86,190,191]; - let key; - - // Custom key bindings for togglePause should be able to resume - if( typeof config.keyboard === 'object' ) { - for( key in config.keyboard ) { - if( config.keyboard[key] === 'togglePause' ) { - resumeKeyCodes.push( parseInt( key, 10 ) ); - } - } - } - - if( this.Reveal.isPaused() && resumeKeyCodes.indexOf( keyCode ) === -1 ) { - return false; - } - - // Use linear navigation if we're configured to OR if - // the presentation is one-dimensional - let useLinearMode = config.navigationMode === 'linear' || !this.Reveal.hasHorizontalSlides() || !this.Reveal.hasVerticalSlides(); - - let triggered = false; - - // 1. User defined key bindings - if( typeof config.keyboard === 'object' ) { - - for( key in config.keyboard ) { - - // Check if this binding matches the pressed key - if( parseInt( key, 10 ) === keyCode ) { - - let value = config.keyboard[ key ]; - - // Callback function - if( typeof value === 'function' ) { - value.apply( null, [ event ] ); - } - // String shortcuts to reveal.js API - else if( typeof value === 'string' && typeof this.Reveal[ value ] === 'function' ) { - this.Reveal[ value ].call(); - } - - triggered = true; - - } - - } - - } - - // 2. Registered custom key bindings - if( triggered === false ) { - - for( key in this.bindings ) { - - // Check if this binding matches the pressed key - if( parseInt( key, 10 ) === keyCode ) { - - let action = this.bindings[ key ].callback; - - // Callback function - if( typeof action === 'function' ) { - action.apply( null, [ event ] ); - } - // String shortcuts to reveal.js API - else if( typeof action === 'string' && typeof this.Reveal[ action ] === 'function' ) { - this.Reveal[ action ].call(); - } - - triggered = true; - } - } - } - - // 3. System defined key bindings - if( triggered === false ) { - - // Assume true and try to prove false - triggered = true; - - // P, PAGE UP - if( keyCode === 80 || keyCode === 33 ) { - this.Reveal.prev({skipFragments: event.altKey}); - } - // N, PAGE DOWN - else if( keyCode === 78 || keyCode === 34 ) { - this.Reveal.next({skipFragments: event.altKey}); - } - // H, LEFT - else if( keyCode === 72 || keyCode === 37 ) { - if( event.shiftKey ) { - this.Reveal.slide( 0 ); - } - else if( !this.Reveal.overview.isActive() && useLinearMode ) { - this.Reveal.prev({skipFragments: event.altKey}); - } - else { - this.Reveal.left({skipFragments: event.altKey}); - } - } - // L, RIGHT - else if( keyCode === 76 || keyCode === 39 ) { - if( event.shiftKey ) { - this.Reveal.slide( this.Reveal.getHorizontalSlides().length - 1 ); - } - else if( !this.Reveal.overview.isActive() && useLinearMode ) { - this.Reveal.next({skipFragments: event.altKey}); - } - else { - this.Reveal.right({skipFragments: event.altKey}); - } - } - // K, UP - else if( keyCode === 75 || keyCode === 38 ) { - if( event.shiftKey ) { - this.Reveal.slide( undefined, 0 ); - } - else if( !this.Reveal.overview.isActive() && useLinearMode ) { - this.Reveal.prev({skipFragments: event.altKey}); - } - else { - this.Reveal.up({skipFragments: event.altKey}); - } - } - // J, DOWN - else if( keyCode === 74 || keyCode === 40 ) { - if( event.shiftKey ) { - this.Reveal.slide( undefined, Number.MAX_VALUE ); - } - else if( !this.Reveal.overview.isActive() && useLinearMode ) { - this.Reveal.next({skipFragments: event.altKey}); - } - else { - this.Reveal.down({skipFragments: event.altKey}); - } - } - // HOME - else if( keyCode === 36 ) { - this.Reveal.slide( 0 ); - } - // END - else if( keyCode === 35 ) { - this.Reveal.slide( this.Reveal.getHorizontalSlides().length - 1 ); - } - // SPACE - else if( keyCode === 32 ) { - if( this.Reveal.overview.isActive() ) { - this.Reveal.overview.deactivate(); - } - if( event.shiftKey ) { - this.Reveal.prev({skipFragments: event.altKey}); - } - else { - this.Reveal.next({skipFragments: event.altKey}); - } - } - // TWO-SPOT, SEMICOLON, B, V, PERIOD, LOGITECH PRESENTER TOOLS "BLACK SCREEN" BUTTON - else if( [58, 59, 66, 86, 190].includes( keyCode ) || ( keyCode === 191 && !event.shiftKey ) ) { - this.Reveal.togglePause(); - } - // F - else if( keyCode === 70 ) { - enterFullscreen( config.embedded ? this.Reveal.getViewportElement() : document.documentElement ); - } - // A - else if( keyCode === 65 ) { - if( config.autoSlideStoppable ) { - this.Reveal.toggleAutoSlide( autoSlideWasPaused ); - } - } - // G - else if( keyCode === 71 ) { - if( config.jumpToSlide ) { - this.Reveal.toggleJumpToSlide(); - } - } - // ? - else if( keyCode === 191 && event.shiftKey ) { - this.Reveal.toggleHelp(); - } - else { - triggered = false; - } - - } - - // If the input resulted in a triggered action we should prevent - // the browsers default behavior - if( triggered ) { - event.preventDefault && event.preventDefault(); - } - // ESC or O key - else if( keyCode === 27 || keyCode === 79 ) { - if( this.Reveal.closeOverlay() === false ) { - this.Reveal.overview.toggle(); - } - - event.preventDefault && event.preventDefault(); - } - - // If auto-sliding is enabled we need to cue up - // another timeout - this.Reveal.cueAutoSlide(); - - } - -} \ No newline at end of file diff --git a/js/controllers/location.js b/js/controllers/location.js deleted file mode 100644 index 2299d47..0000000 --- a/js/controllers/location.js +++ /dev/null @@ -1,247 +0,0 @@ -/** - * Reads and writes the URL based on reveal.js' current state. - */ -export default class Location { - - // The minimum number of milliseconds that must pass between - // calls to history.replaceState - MAX_REPLACE_STATE_FREQUENCY = 1000 - - constructor( Reveal ) { - - this.Reveal = Reveal; - - // Delays updates to the URL due to a Chrome thumbnailer bug - this.writeURLTimeout = 0; - - this.replaceStateTimestamp = 0; - - this.onWindowHashChange = this.onWindowHashChange.bind( this ); - - } - - bind() { - - window.addEventListener( 'hashchange', this.onWindowHashChange, false ); - - } - - unbind() { - - window.removeEventListener( 'hashchange', this.onWindowHashChange, false ); - - } - - /** - * Returns the slide indices for the given hash link. - * - * @param {string} [hash] the hash string that we want to - * find the indices for - * - * @returns slide indices or null - */ - getIndicesFromHash( hash=window.location.hash, options={} ) { - - // Attempt to parse the hash as either an index or name - let name = hash.replace( /^#\/?/, '' ); - let bits = name.split( '/' ); - - // If the first bit is not fully numeric and there is a name we - // can assume that this is a named link - if( !/^[0-9]*$/.test( bits[0] ) && name.length ) { - let slide; - - let f; - - // Parse named links with fragments (#/named-link/2) - if( /\/[-\d]+$/g.test( name ) ) { - f = parseInt( name.split( '/' ).pop(), 10 ); - f = isNaN(f) ? undefined : f; - name = name.split( '/' ).shift(); - } - - // Ensure the named link is a valid HTML ID attribute - try { - slide = document - .getElementById( decodeURIComponent( name ) ) - .closest('.slides section'); - } - catch ( error ) { } - - if( slide ) { - return { ...this.Reveal.getIndices( slide ), f }; - } - } - else { - const config = this.Reveal.getConfig(); - let hashIndexBase = config.hashOneBasedIndex || options.oneBasedIndex ? 1 : 0; - - // Read the index components of the hash - let h = ( parseInt( bits[0], 10 ) - hashIndexBase ) || 0, - v = ( parseInt( bits[1], 10 ) - hashIndexBase ) || 0, - f; - - if( config.fragmentInURL ) { - f = parseInt( bits[2], 10 ); - if( isNaN( f ) ) { - f = undefined; - } - } - - return { h, v, f }; - } - - // The hash couldn't be parsed or no matching named link was found - return null - - } - - /** - * Reads the current URL (hash) and navigates accordingly. - */ - readURL() { - - const currentIndices = this.Reveal.getIndices(); - const newIndices = this.getIndicesFromHash(); - - if( newIndices ) { - if( ( newIndices.h !== currentIndices.h || newIndices.v !== currentIndices.v || newIndices.f !== undefined ) ) { - this.Reveal.slide( newIndices.h, newIndices.v, newIndices.f ); - } - } - // If no new indices are available, we're trying to navigate to - // a slide hash that does not exist - else { - this.Reveal.slide( currentIndices.h || 0, currentIndices.v || 0 ); - } - - } - - /** - * Updates the page URL (hash) to reflect the current - * state. - * - * @param {number} delay The time in ms to wait before - * writing the hash - */ - writeURL( delay ) { - - let config = this.Reveal.getConfig(); - let currentSlide = this.Reveal.getCurrentSlide(); - - // Make sure there's never more than one timeout running - clearTimeout( this.writeURLTimeout ); - - // If a delay is specified, timeout this call - if( typeof delay === 'number' ) { - this.writeURLTimeout = setTimeout( this.writeURL, delay ); - } - else if( currentSlide ) { - - let hash = this.getHash(); - - // If we're configured to push to history OR the history - // API is not available. - if( config.history ) { - window.location.hash = hash; - } - // If we're configured to reflect the current slide in the - // URL without pushing to history. - else if( config.hash ) { - // If the hash is empty, don't add it to the URL - if( hash === '/' ) { - this.debouncedReplaceState( window.location.pathname + window.location.search ); - } - else { - this.debouncedReplaceState( '#' + hash ); - } - } - // UPDATE: The below nuking of all hash changes breaks - // anchors on pages where reveal.js is running. Removed - // in 4.0. Why was it here in the first place? ยฏ\_(ใƒ„)_/ยฏ - // - // If history and hash are both disabled, a hash may still - // be added to the URL by clicking on a href with a hash - // target. Counter this by always removing the hash. - // else { - // window.history.replaceState( null, null, window.location.pathname + window.location.search ); - // } - - } - - } - - replaceState( url ) { - - window.history.replaceState( null, null, url ); - this.replaceStateTimestamp = Date.now(); - - } - - debouncedReplaceState( url ) { - - clearTimeout( this.replaceStateTimeout ); - - if( Date.now() - this.replaceStateTimestamp > this.MAX_REPLACE_STATE_FREQUENCY ) { - this.replaceState( url ); - } - else { - this.replaceStateTimeout = setTimeout( () => this.replaceState( url ), this.MAX_REPLACE_STATE_FREQUENCY ); - } - - } - - /** - * Return a hash URL that will resolve to the given slide location. - * - * @param {HTMLElement} [slide=currentSlide] The slide to link to - */ - getHash( slide ) { - - let url = '/'; - - // Attempt to create a named link based on the slide's ID - let s = slide || this.Reveal.getCurrentSlide(); - let id = s ? s.getAttribute( 'id' ) : null; - if( id ) { - id = encodeURIComponent( id ); - } - - let index = this.Reveal.getIndices( slide ); - if( !this.Reveal.getConfig().fragmentInURL ) { - index.f = undefined; - } - - // If the current slide has an ID, use that as a named link, - // but we don't support named links with a fragment index - if( typeof id === 'string' && id.length ) { - url = '/' + id; - - // If there is also a fragment, append that at the end - // of the named link, like: #/named-link/2 - if( index.f >= 0 ) url += '/' + index.f; - } - // Otherwise use the /h/v index - else { - let hashIndexBase = this.Reveal.getConfig().hashOneBasedIndex ? 1 : 0; - if( index.h > 0 || index.v > 0 || index.f >= 0 ) url += index.h + hashIndexBase; - if( index.v > 0 || index.f >= 0 ) url += '/' + (index.v + hashIndexBase ); - if( index.f >= 0 ) url += '/' + index.f; - } - - return url; - - } - - /** - * Handler for the window level 'hashchange' event. - * - * @param {object} [event] - */ - onWindowHashChange( event ) { - - this.readURL(); - - } - -} \ No newline at end of file diff --git a/js/controllers/notes.js b/js/controllers/notes.js deleted file mode 100644 index 8af918c..0000000 --- a/js/controllers/notes.js +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Handles the showing of speaker notes - */ -export default class Notes { - - constructor( Reveal ) { - - this.Reveal = Reveal; - - } - - render() { - - this.element = document.createElement( 'div' ); - this.element.className = 'speaker-notes'; - this.element.setAttribute( 'data-prevent-swipe', '' ); - this.element.setAttribute( 'tabindex', '0' ); - this.Reveal.getRevealElement().appendChild( this.element ); - - } - - /** - * Called when the reveal.js config is updated. - */ - configure( config, oldConfig ) { - - if( config.showNotes ) { - this.element.setAttribute( 'data-layout', typeof config.showNotes === 'string' ? config.showNotes : 'inline' ); - } - - } - - /** - * Pick up notes from the current slide and display them - * to the viewer. - * - * @see {@link config.showNotes} - */ - update() { - - if( this.Reveal.getConfig().showNotes && - this.element && this.Reveal.getCurrentSlide() && - !this.Reveal.isScrollView() && - !this.Reveal.isPrintView() - ) { - this.element.innerHTML = this.getSlideNotes() || 'No notes on this slide.'; - } - - } - - /** - * Updates the visibility of the speaker notes sidebar that - * is used to share annotated slides. The notes sidebar is - * only visible if showNotes is true and there are notes on - * one or more slides in the deck. - */ - updateVisibility() { - - if( this.Reveal.getConfig().showNotes && - this.hasNotes() && - !this.Reveal.isScrollView() && - !this.Reveal.isPrintView() - ) { - this.Reveal.getRevealElement().classList.add( 'show-notes' ); - } - else { - this.Reveal.getRevealElement().classList.remove( 'show-notes' ); - } - - } - - /** - * Checks if there are speaker notes for ANY slide in the - * presentation. - */ - hasNotes() { - - return this.Reveal.getSlidesElement().querySelectorAll( '[data-notes], aside.notes' ).length > 0; - - } - - /** - * Checks if this presentation is running inside of the - * speaker notes window. - * - * @return {boolean} - */ - isSpeakerNotesWindow() { - - return !!window.location.search.match( /receiver/gi ); - - } - - /** - * Retrieves the speaker notes from a slide. Notes can be - * defined in two ways: - * 1. As a data-notes attribute on the slide
- * 2. With