diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 2f07eda..a2fcf9f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,6 +1,6 @@ module.exports = { parserOptions: { - ecmaVersion: 2021, + ecmaVersion: 2022, sourceType: 'module' }, env: { diff --git a/README.md b/README.md index 0c0233a..244b569 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # greenwood-starter-presentation -Greenwood plugin and kickstarter repo for creating and authoring a slide deck from markdown, powered by [**GreenwoodJS**](https://www.greenwoodjs.io/)! ♻️ +Greenwood plugin and kick-starter repo for creating and authoring a slide deck from markdown, powered by [**GreenwoodJS**](https://www.greenwoodjs.io/)! ♻️ ![greenwood-starter-presentation](./.github/images/greenwood-starter-presentation.png) @@ -18,23 +18,19 @@ This project is principally intended to be consumed by a Greenwood project as a To add this plugin to an _existing_ Greenwood project (where `@greenwood/cli` has already been installed), please do the following: -1. Install the plugin and its dependencies +1. Install the plugin as a dev dependency ```sh - $ npm install @greenwood/plugin-import-css greenwood-starter-presentation --save-dev - $ npm install lit + $ npm install greenwood-starter-presentation --save-dev ``` 1. Add this plugin and all dependent plugins to your _greenwood.config.js_ ```js - import { greenwoodPluginImportCss } from '@greenwood/plugin-import-css'; import { greenwoodThemeStarterPresentation } from 'greenwood-starter-presentation'; export default { - . - . + // ... plugins: [ - ...greenwoodPluginImportCss(), - ...greenwoodThemeStarterPresentation() + greenwoodThemeStarterPresentation() ] }; @@ -109,7 +105,7 @@ When you are running the app, the following controls and behaviors are available ### Slide Templates and Layouts -To organize your slide content, this plugin provides the following template that can be specificed in markdown file's frontmatter. +To organize your slide content, this plugin provides the following template that can be specified in markdown file's frontmatter. ex. ```md @@ -216,7 +212,7 @@ Empty page body with an h1 at the top with `--color-secondary` color behind it a ---- -> _Remember, you can always add your own HTML and - .fullscreen-container-on { - background-color: var(--color-primary); - display: block; - z-index: 100; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - } + - iframe { - background-color: var(--color-primary); - min-width: 100%; - min-height: 100%; - width: 100%; - height: 100%; - } - `; +
+ +
+`; + +class PresenterMode extends HTMLElement { + static get observedAttributes() { + return ['slides']; } constructor() { @@ -48,18 +45,27 @@ class PresenterMode extends LitElement { } connectedCallback() { - super.connectedCallback(); - window.addEventListener('message', (postMessage) => { - this.slideNavigationKeyHander(postMessage.data); + this.slideNavigationKeyHandler(postMessage.data); }); document.addEventListener('keydown', (event) => { - this.slideNavigationKeyHander(event.key); + this.slideNavigationKeyHandler(event.key); }); + + if (!this.shadowRoot) { + this.attachShadow({ mode: 'open' }); + this.shadowRoot.appendChild(template.content.cloneNode(true)); + } } - enablePresenterMode() { + attributeChangedCallback(name, oldValue, newValue) { + if (name === 'slides' && newValue) { + this.slides = JSON.parse(newValue); + } + } + + enablePresenterMode() { this.setCurrentSlide(); this.shadowRoot.querySelector('div').classList.add('fullscreen-container-on'); } @@ -68,7 +74,7 @@ class PresenterMode extends LitElement { this.shadowRoot.querySelector('iframe').setAttribute('src', this.slides[index].route); } - slideNavigationKeyHander(keyName) { + slideNavigationKeyHandler(keyName) { if (keyName === 'ArrowRight' || keyName === 'Spacebar' || keyName === 'Enter') { if ((this.index + 1) !== this.slides.length) { this.index = this.index += 1; @@ -83,16 +89,6 @@ class PresenterMode extends LitElement { this.shadowRoot.querySelector('div').classList.remove('fullscreen-container-on'); } } - - render() { - return html` - - -
- -
- `; - } } customElements.define('presenter-mode', PresenterMode); \ No newline at end of file diff --git a/src/components/slide-list.js b/src/components/slide-list.js index 9766bc0..62851ae 100644 --- a/src/components/slide-list.js +++ b/src/components/slide-list.js @@ -1,65 +1,60 @@ -import { css, html, LitElement } from 'lit'; +const template = document.createElement('template'); -class SlideList extends LitElement { +template.innerHTML = ` + +`; + +class SlideList extends HTMLElement { + static get observedAttributes() { + return ['slides']; } constructor() { @@ -67,20 +62,28 @@ class SlideList extends LitElement { this.slides = []; } - slideSelected(slide) { + attributeChangedCallback(name, oldValue, newValue) { + if (name === 'slides' && newValue) { + this.slides = JSON.parse(newValue); + this.render(); + } + } + + slideSelected(slideId) { try { + const slide = this.slides.find(slide => slide.id === slideId); const { protocol, host, pathname } = window.location; - const newurl = `${protocol}//${host}${pathname}?selectedSlideId=${slide.id}`; + const newUrl = `${protocol}//${host}${pathname}?selectedSlideId=${slide.id}`; - window.history.pushState({ path: newurl }, '', newurl); + window.history.pushState({ path: newUrl }, '', newUrl); + document.dispatchEvent(new CustomEvent('slide-selected', { detail: slide })); } catch (e) { console.error(e); } - - document.dispatchEvent(new CustomEvent('slide-selected', { detail: slide })); } - slideLoaded(slide) { + slideLoaded(slideId) { + const slide = this.slides.find(slide => slide.id === slideId); const frame = this.shadowRoot.getElementById(`slide_${slide.id}`); const style = document.createElement('style'); @@ -94,19 +97,19 @@ class SlideList extends LitElement { } render() { - const { slides } = this; - const list = slides.map((slide, index) => { + const content = this.slides.map((slide, index) => { const slideNum = index += 1; + const { id, route } = slide; - return html` + return ` ${slideNum}) -
+
@@ -115,9 +118,12 @@ class SlideList extends LitElement { `; }); - return html` - ${list} - `; + template.innerHTML = template.innerHTML + content.join(''); + + if (!this.shadowRoot) { + this.attachShadow({ mode: 'open' }); + this.shadowRoot.appendChild(template.content.cloneNode(true)); + } } } diff --git a/src/components/slide-viewer.js b/src/components/slide-viewer.js index 9aa711c..1818106 100644 --- a/src/components/slide-viewer.js +++ b/src/components/slide-viewer.js @@ -1,23 +1,20 @@ -import { css, html, LitElement } from 'lit'; +const template = document.createElement('template'); -class SlideViewer extends LitElement { +template.innerHTML = ` + - static get properties() { - return { - slide: { - type: Object - } - }; - } + +`; - static get styles() { - return css` - iframe { - width: 90%; - height: 700px; - filter: drop-shadow(5px 10px 3px gray); - } - `; +class SlideViewer extends HTMLElement { + static get observedAttributes() { + return ['slide']; } constructor() { @@ -25,13 +22,22 @@ class SlideViewer extends LitElement { this.slide = {}; } - render() { - const { slide } = this; - const url = slide && slide.route ? slide.route : ''; + connectedCallback() { + if (!this.shadowRoot) { + this.attachShadow({ mode: 'open' }); + this.shadowRoot.appendChild(template.content.cloneNode(true)); + } + } - return html` - - `; + attributeChangedCallback(name, oldValue, newValue) { + if (name === 'slide' && newValue) { + this.slide = JSON.parse(newValue); + this.render(); + } + } + + render() { + this.shadowRoot.querySelector('iframe').setAttribute('src', this.slide.route); } } diff --git a/src/layouts/index.html b/src/layouts/index.html index f123546..56ad09d 100644 --- a/src/layouts/index.html +++ b/src/layouts/index.html @@ -26,8 +26,8 @@ diff --git a/src/styles/theme.css b/src/styles/theme.css index 7edc425..16c80a5 100644 --- a/src/styles/theme.css +++ b/src/styles/theme.css @@ -1,14 +1,4 @@ -:root { - --color-primary: #135; - --color-secondary: #74b238; - --color-tertiary: #2b85da; - --color-text-light: #efefef; - --color-text-dark: #020202; - --font-family: 'Optima', sans-serif; - --font-size: 2rem; - --backgroundUrl: url('../assets/background.jpg'); -} - +:root, :host { --color-primary: #135; --color-secondary: #74b238; diff --git a/yarn.lock b/yarn.lock index 15b1bea..0cfaaae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -237,11 +237,6 @@ unified "^9.2.0" wc-compiler "~0.9.0" -"@greenwood/plugin-import-css@~0.29.0": - version "0.29.0" - resolved "https://registry.yarnpkg.com/@greenwood/plugin-import-css/-/plugin-import-css-0.29.0.tgz#bed9959e80d84f43ee28cc5ca6de6209691427fc" - integrity sha512-2FMk3qs8umOuR4bb4xSuW1bRGV1Pk1QS1QY6sk5BNhOIO5+ZphtuIrVTJUcfxHzLw4BBOG4Xws6LJCs5XfNfjw== - "@humanwhocodes/config-array@^0.9.2": version "0.9.2" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" @@ -296,11 +291,6 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@lit/reactive-element@^1.3.0": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-1.3.2.tgz#43e470537b6ec2c23510c07812616d5aa27a17cd" - integrity sha512-A2e18XzPMrIh35nhIdE4uoqRzoIpEU5vZYuQN4S3Ee1zkGdYC27DP12pewbw/RLgPHzaE4kx/YqxMzebOpm0dA== - "@nodelib/fs.scandir@2.1.4": version "2.1.4" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69" @@ -587,11 +577,6 @@ "@types/mime" "*" "@types/node" "*" -"@types/trusted-types@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756" - integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg== - "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" @@ -2360,30 +2345,6 @@ list-item@^1.1.1: is-number "^2.1.0" repeat-string "^1.5.2" -lit-element@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.2.0.tgz#9c981c55dfd9a8f124dc863edb62cc529d434db7" - integrity sha512-HbE7yt2SnUtg5DCrWt028oaU4D5F4k/1cntAFHTkzY8ZIa8N0Wmu92PxSxucsQSOXlODFrICkQ5x/tEshKi13g== - dependencies: - "@lit/reactive-element" "^1.3.0" - lit-html "^2.2.0" - -lit-html@^2.2.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.2.3.tgz#dcb2744d0f0c1800b2eb2de37bc42384434a74f7" - integrity sha512-vI4j3eWwtQaR8q/O63juZVliBIFMio716X719/lSsGH4UWPy2/7Qf377jsNs4cx3gCHgIbx8yxFgXFQ/igZyXQ== - dependencies: - "@types/trusted-types" "^2.0.2" - -lit@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/lit/-/lit-2.2.3.tgz#77203d8f247de7c0d4955817f89e40c927349b9c" - integrity sha512-5/v+r9dH3Pw/o0rhp/qYk3ERvOUclNF31bWb0FiW6MPgwdQIr+/KCt/p3zcd8aPl8lIGnxdGrVcZA+gWS6oFOQ== - dependencies: - "@lit/reactive-element" "^1.3.0" - lit-element "^3.2.0" - lit-html "^2.2.0" - livereload-js@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-3.3.2.tgz#c88b009c6e466b15b91faa26fd7c99d620e12651"