From b5f8def79edd5895a03b1e64098a112e459a1b85 Mon Sep 17 00:00:00 2001 From: Miriam Suzanne Date: Wed, 27 Dec 2023 23:44:49 -0700 Subject: [PATCH 01/18] Add slide parts (and mark private methods) --- CHANGELOG.md | 10 ++ index.html | 13 ++- slide-deck.js | 254 ++++++++++++++++++++++++++++++++------------------ 3 files changed, 182 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 467c1c7..5e6c662 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ Breaking changes will be allowed in minor versions until we achieve a stable v1.0 release +## v0.1.2 - unreleased + +- 🚀 NEW: Add support for slide parts – `slide-frame` & `slide-note` + (these parts require light DOM styles) +- 🚀 NEW: Slide parts can be hidden + with the `hide-parts="note | frame"` attribute + (both parts cannot be hidden at the same time) +- 🚀 NEW: Add support for `hide-part="note | frame"` buttons + to toggle hiding the notes and frames + ## v0.1.1 - 2023-12-26 - 💥 BREAKING: Updated keyboard shortcuts diff --git a/index.html b/index.html index e3624c5..72ddd84 100644 --- a/index.html +++ b/index.html @@ -11,10 +11,15 @@
-

Slide-Deck Web Component

-

- github.com/oddbird/slide-deck/ -

+
+

Slide-Deck Web Component

+

+ github.com/oddbird/slide-deck/ +

+
+
+ We can also add notes to slides. +

No Dependencies

Progressive Enhancement

diff --git a/slide-deck.js b/slide-deck.js index dc8b5e4..8e02545 100644 --- a/slide-deck.js +++ b/slide-deck.js @@ -17,6 +17,10 @@ class slideDeck extends HTMLElement {

View:

+ +

Hide:

+ + @@ -88,18 +92,21 @@ class slideDeck extends HTMLElement { } ::slotted([id^=slide_]) { - aspect-ratio: var(--slide-grid-ratio, var(---slide-grid-ratio)); container-name: slide; container-type: var(--slide-container, inline-size); - border: var(---slide-grid-border); - border-block-end: var(---slide-list-border); - padding: var(---slide-gap); scroll-margin: var( --slide-grid-scroll-margin, var(---slide-grid-scroll-margin) ); } + ::slotted([slide-frame]) { + aspect-ratio: var(--slide-grid-ratio, var(---slide-grid-ratio)); + border: var(---slide-grid-border); + border-block-end: var(---slide-list-border); + padding: var(---slide-gap); + } + ::slotted([id^=slide_]:target) { outline: var( --slide-grid-active-outline, @@ -125,6 +132,7 @@ class slideDeck extends HTMLElement { 'follow-active', 'full-screen', 'slide-view', + 'hide-parts', ]; static attrToPropMap = { @@ -132,6 +140,7 @@ class slideDeck extends HTMLElement { 'follow-active': 'followActive', 'full-screen': 'fullScreen', 'slide-view': 'slideView', + 'hide-parts': 'hideParts', }; static storageKeys = [ @@ -176,12 +185,15 @@ class slideDeck extends HTMLElement { // dynamic store = {}; + slides; + slideNotes; + slideFrames; slideCount; + activeSlide; controlPanel; eventButtons; viewButtons; - activeSlide; - body; + #body; // callbacks attributeChangedCallback(name, oldValue, newValue) { @@ -189,17 +201,22 @@ class slideDeck extends HTMLElement { switch (name) { case 'follow-active': - this.followActiveChange(); + this.#followActiveChange(); + this.#updateEventButtons(); + break; + case 'hide-parts': + this.#hidePartsChange(); + this.#updatePartButtons(); break; case 'slide-view': - this.updateViewButtons(); + this.#updateViewButtons(); this.scrollToActive(); break; default: break; } - this.updateEventButtons(); + this.#updateEventButtons(); } constructor() { @@ -208,21 +225,25 @@ class slideDeck extends HTMLElement { // shadow dom and ID slideDeck.appendShadowTemplate(this); slideDeck.adoptShadowStyles(this); - this.setDeckID(); + this.#setDeckID(); // relevant nodes - this.body = document.querySelector('body'); + this.#body = document.querySelector('body'); this.controlPanel = this.shadowRoot.querySelector(`[part="controls"]`); + this.slides = this.querySelectorAll(':scope > :not([slot=slide-controls])'); + this.slideNotes = this.querySelectorAll('[slide-note]'); + this.slideFrames = this.querySelectorAll('[slide-frame]:not(:scope > *)'); // initial setup - this.slideCount = this.childElementCount; - this.defaultAttrs(); - this.setSlideIDs(); + this.slideCount = this.slides.length; + this.#defaultAttrs(); + this.#setupSlides(); this.goTo(); // buttons - this.setupEventButtons(); - this.setupViewButtons(); + this.#setupEventButtons(); + this.#setupViewButtons(); + this.#setupPartButtons(); // event listeners this.shadowRoot.addEventListener('keydown', (event) => { @@ -242,6 +263,10 @@ class slideDeck extends HTMLElement { this.addEventListener('grid', (e) => this.toggleView('grid')); this.addEventListener('list', (e) => this.toggleView('list')); + this.addEventListener('toggleFrame', (e) => this.togglePart('frame')); + this.addEventListener('toggleNote', (e) => this.togglePart('note')); + this.addEventListener('showAll', (e) => this.removeAttribute('hide-parts')); + this.addEventListener('join', (e) => this.joinEvent()); this.addEventListener('joinWithNotes', (e) => this.joinWithNotesEvent()); this.addEventListener('start', (e) => this.startEvent()); @@ -256,27 +281,27 @@ class slideDeck extends HTMLElement { }; connectedCallback() { - this.body.addEventListener('keydown', this.keyEventActions); + this.#body.addEventListener('keydown', this.#keyEventActions); } disconnectedCallback() { - this.body.removeEventListener('keydown', this.keyEventActions); + this.#body.removeEventListener('keydown', this.#keyEventActions); } // setup methods - newDeckId = (from, count) => { + #newDeckId = (from, count) => { const base = from || window.location.pathname.split('.')[0]; const ID = count ? `${base}-${count}` : base; if (document.getElementById(ID)) { - return this.newDeckId(base, (count || 0) + 1); + return this.#newDeckId(base, (count || 0) + 1); } return ID; }; - setDeckID = () => { - this.id = this.id || this.newDeckId(); + #setDeckID = () => { + this.id = this.id || this.#newDeckId(); // storage keys based on slide ID slideDeck.storageKeys.forEach((key) => { @@ -284,17 +309,22 @@ class slideDeck extends HTMLElement { }); } - slideId = (n) => `slide_${this.id}-${n}`; + #slideId = (n) => `slide_${this.id}-${n}`; - setSlideIDs = () => { + #setupSlides = () => { const slides = this.querySelectorAll(':scope > *'); slides.forEach((slide, index) => { - slide.id = this.slideId(index + 1); + slide.id = this.#slideId(index + 1); + if (slide.querySelector('[slide-frame]')) { + slide.toggleAttribute('slide-group', true); + } else { + slide.toggleAttribute('slide-frame', true); + } }); }; - defaultAttrs = () => { + #defaultAttrs = () => { // view required if (!this.hasAttribute('slide-view')) { this.setAttribute('slide-view', 'grid'); @@ -305,93 +335,125 @@ class slideDeck extends HTMLElement { }; // buttons - getButtonEvent = (btn) => btn.getAttribute('slide-event') || btn.innerText; + #findButtons = (attr) => [ + ...this.querySelectorAll(`button[${attr}]`), + ...this.shadowRoot.querySelectorAll(`button[${attr}]`), + ]; - updateEventButtons = () => { - this.eventButtons.forEach((btn) => { - const btnEvent = this.getButtonEvent(btn); - let isActive = { - 'toggleControl': this.keyControl, - 'toggleFollow': this.followActive, - 'toggleFullscreen': this.fullScreen, - } + #getButtonValue = (btn, attr) => btn.getAttribute(attr) || btn.innerText; - if (Object.keys(isActive).includes(btnEvent)) { - btn.setAttribute('aria-pressed', isActive[btnEvent]); - } - }); + #setToggleState = (btn, attr, state) => { + const isActive = this.#getButtonValue(btn, attr) === state; + btn.setAttribute('aria-pressed', isActive); } - setupEventButtons = () => { - this.eventButtons = [ - ...this.querySelectorAll(`button[slide-event]`), - ...this.shadowRoot.querySelectorAll(`button[slide-event]`), - ]; + #setupViewButtons = () => { + this.slideView = this.slideView || this.getAttribute('slide-view'); + this.viewButtons = this.#findButtons('set-view'); - this.eventButtons.forEach((btn) => { + this.viewButtons.forEach((btn) => { btn.addEventListener('click', (e) => { - const event = this.getButtonEvent(btn); - this.dispatchEvent(new Event(event, { view: window, bubbles: false })); + this.setAttribute('slide-view', this.#getButtonValue(btn, 'set-view')); }); + this.#setToggleState(btn, 'set-view', this.slideView); }); + } - this.updateEventButtons(); + #updateViewButtons = () => { + this.viewButtons.forEach((btn) => { + this.#setToggleState(btn, 'set-view', this.slideView); + }); + } + + #setupPartButtons = () => { + this.hideParts = this.hideParts || this.getAttribute('hide-parts'); + this.partButtons = this.#findButtons('hide-part'); + + this.partButtons.forEach((btn) => { + btn.addEventListener('click', (e) => { + this.togglePart(this.#getButtonValue(btn, 'hide-part')); + }); + this.#setToggleState(btn, 'hide-part', this.hideParts); + }); } - getButtonView = (btn) => btn.getAttribute('set-view') || btn.innerText; + #updatePartButtons = () => { + this.partButtons.forEach((btn) => { + this.#setToggleState(btn, 'hide-part', this.hideParts); + }); + } - setupViewButtons = () => { - this.viewButtons = [ - ...this.querySelectorAll(`button[set-view]`), - ...this.shadowRoot.querySelectorAll(`button[set-view]`), - ]; + // event buttons + #setupEventButtons = () => { + this.eventButtons = this.#findButtons('slide-event'); - this.viewButtons.forEach((btn) => { + this.eventButtons.forEach((btn) => { btn.addEventListener('click', (e) => { - this.setAttribute('slide-view', this.getButtonView(btn)); + const event = this.#getButtonValue(btn, 'slide-event'); + this.dispatchEvent(new Event(event, { view: window, bubbles: false })); }); }); - this.slideView = this.slideView || this.getAttribute('slide-view'); - this.updateViewButtons(); + this.#updateEventButtons(); } - updateViewButtons = () => { - this.viewButtons.forEach((btn) => { - const isActive = this.getButtonView(btn) === this.slideView; - btn.setAttribute('aria-pressed', isActive); + #updateEventButtons = () => { + this.eventButtons.forEach((btn) => { + const btnEvent = this.#getButtonValue(btn, 'slide-event'); + + let isActive = { + 'toggleControl': this.keyControl, + 'toggleFrame': this.hideParts === 'frame', + 'toggleNote': this.hideParts === 'note', + 'toggleFollow': this.followActive, + 'toggleFullscreen': this.fullScreen, + } + + if (Object.keys(isActive).includes(btnEvent)) { + btn.setAttribute('aria-pressed', isActive[btnEvent]); + } }); } // event handlers toggleView = (to) => { + let next; + if (!to) { const current = this.getAttribute('slide-view'); const l = slideDeck.slideViews - 1; // adjust for 0-index const i = slideDeck.slideViews.indexOf(current); - const next = slideDeck.slideViews[(i + 1) % l]; + next = slideDeck.slideViews[(i + 1) % l]; } this.setAttribute('slide-view', to || next || 'grid'); } + togglePart = (type = 'note') => { + this.hideParts === type + ? this.removeAttribute('hide-parts') + : this.setAttribute('hide-parts', type); + } + + #startPresenting = () => { + this.setAttribute('hide-parts', 'note'); + this.setAttribute('slide-view', 'list'); + this.setAttribute('key-control', ''); + this.setAttribute('follow-active', ''); + } + startEvent = () => { this.goTo(1); - this.startPresenting(); + this.#startPresenting(); } resumeEvent = () => { this.goToSaved(); - this.startPresenting(); - } - - startPresenting = () => { - this.setAttribute('slide-view', 'list'); - this.setAttribute('key-control', ''); - this.setAttribute('follow-active', ''); + this.#startPresenting(); } joinWithNotesEvent = () => { + if (this.hideParts === 'note') { this.removeAttribute('hide-parts'); } this.setAttribute('slide-view', 'grid'); this.setAttribute('key-control', ''); this.setAttribute('follow-active', ''); @@ -433,7 +495,7 @@ class slideDeck extends HTMLElement { } // dynamic attribute methods - followActiveChange = () => { + #followActiveChange = () => { if (this.followActive) { this.goToSaved(); window.addEventListener('storage', (e) => this.goToSaved()); @@ -442,22 +504,32 @@ class slideDeck extends HTMLElement { } } + #hidePartsChange = () => { + this.slideNotes.forEach((note) => { + note.toggleAttribute('hidden', this.hideParts === 'note'); + }); + + this.slideFrames.forEach((frame) => { + frame.toggleAttribute('hidden', this.hideParts === 'frame'); + }); + } + // storage - asSlideInt = (string) => parseInt(string, 10); + #asSlideInt = (string) => parseInt(string, 10); - slideFromHash = () => window.location.hash.startsWith('#slide_') - ? this.asSlideInt(window.location.hash.split('-').pop()) + #slideFromHash = () => window.location.hash.startsWith('#slide_') + ? this.#asSlideInt(window.location.hash.split('-').pop()) : null; - slideFromStore = () => this.asSlideInt( + #slideFromStore = () => this.#asSlideInt( localStorage.getItem(this.store.slide) ); - slideToHash = (to) => { + #slideToHash = (to) => { if (to) { - window.location.hash = this.slideId(to); + window.location.hash = this.#slideId(to); } }; - slideToStore = (to) => { + #slideToStore = (to) => { if (to) { localStorage.setItem(this.store.slide, to); } else { @@ -466,11 +538,11 @@ class slideDeck extends HTMLElement { }; // navigation - inRange = (slide) => slide >= 1 && slide <= this.slideCount; - getActive = () => this.slideFromHash() || this.activeSlide; + #inRange = (slide) => slide >= 1 && slide <= this.slideCount; + #getActive = () => this.#slideFromHash() || this.activeSlide; scrollToActive = () => { - const activeEl = document.getElementById(this.slideId(this.activeSlide)); + const activeEl = document.getElementById(this.#slideId(this.activeSlide)); if (activeEl) { activeEl.scrollIntoView(true); @@ -478,15 +550,15 @@ class slideDeck extends HTMLElement { }; goTo = (to) => { - const fromHash = this.slideFromHash(); - const setTo = to || this.getActive(); + const fromHash = this.#slideFromHash(); + const setTo = to || this.#getActive(); - if (setTo && this.inRange(setTo)) { + if (setTo && this.#inRange(setTo)) { this.activeSlide = setTo; - this.slideToStore(setTo); + this.#slideToStore(setTo); if (setTo !== fromHash) { - this.slideToHash(setTo); + this.#slideToHash(setTo); } } } @@ -498,15 +570,15 @@ class slideDeck extends HTMLElement { }; move = (by) => { - const to = (this.getActive() || 0) + by; + const to = (this.#getActive() || 0) + by; this.goTo(to); }; goToSaved = () => { - this.goTo(this.slideFromStore()); + this.goTo(this.#slideFromStore()); } - keyEventActions = (event) => { + #keyEventActions = (event) => { // always available if (event.metaKey) { switch (event.key) { @@ -546,7 +618,7 @@ class slideDeck extends HTMLElement { // only while key-control is active if (this.keyControl) { if (event.key === 'Escape') { - if (event.target !== this.body) { + if (event.target !== this.#body) { event.target.blur(); } else { event.preventDefault(); From 4bf28c0d3f7ec7b2da1b72d74c64b76e49781c54 Mon Sep 17 00:00:00 2001 From: Miriam Suzanne Date: Tue, 2 Jan 2024 21:29:11 -0700 Subject: [PATCH 02/18] Clarify sample slide in demo --- index.html | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/index.html b/index.html index 72ddd84..ee88d0f 100644 --- a/index.html +++ b/index.html @@ -11,15 +11,10 @@
-
-

Slide-Deck Web Component

-

- github.com/oddbird/slide-deck/ -

-
-
- We can also add notes to slides. -
+

Slide-Deck Web Component

+

+ github.com/oddbird/slide-deck/ +

No Dependencies

Progressive Enhancement

@@ -103,12 +98,42 @@

Open Source

github.com/oddbird/slide-deck/

+ +
+ +
+

Speaker Notes

+
<div slide-frame>
+  This slide has both a frame
+</div>
+<div slide-note>
+  And a section for notes
+</div>
+
+
+ We can also add notes to slides. + But the frame can't be styled + by shadow DOM CSS, + so this format is + bring-your-own-styles. + That also means we can use the + parent element as a container! +
+

To Do…

… Speaker Notes

… Slide Templates

… CSS Themes

… More Better Good Stuff

- From fc2ed03796c666e08e36110a0f3dc977ddab6484 Mon Sep 17 00:00:00 2001 From: Stacy Kvernmo Date: Thu, 4 Jan 2024 16:18:32 -0600 Subject: [PATCH 03/18] wip - color modes --- slide-deck.css | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/slide-deck.css b/slide-deck.css index 7fd914a..562251a 100644 --- a/slide-deck.css +++ b/slide-deck.css @@ -1,7 +1,11 @@ slide-deck { + --color-dark: #1e1e1e; + --color-light: white; --gap: clamp(8px, 0.25em + 1vw, 16px); + color: var(--text-color); container: slide-deck / inline-size; display: grid; + min-height: 100vh; &[slide-view=grid] { --slide-ratio: 16/9; @@ -18,13 +22,20 @@ slide-deck { &[blank-slide]::after { content: ''; - background-color: var(--blank-color, black); + background-color: var(--blank-color); position: absolute; inset: 0; + z-index: -1; + } + + &[blank-slide=black] { + --blank-color: var(--color-dark); + --text-color: var(--color-light); } &[blank-slide=white] { - --blank-color: white; + --blank-color: var(--color-light); + --text-color: var(--color-dark); } [slide-canvas] { From 5dea08dbfdcd7b96495023c4f082995c479f93ab Mon Sep 17 00:00:00 2001 From: Stacy Kvernmo Date: Fri, 5 Jan 2024 10:28:25 -0600 Subject: [PATCH 04/18] revert previous commit --- slide-deck.css | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/slide-deck.css b/slide-deck.css index 562251a..7fd914a 100644 --- a/slide-deck.css +++ b/slide-deck.css @@ -1,11 +1,7 @@ slide-deck { - --color-dark: #1e1e1e; - --color-light: white; --gap: clamp(8px, 0.25em + 1vw, 16px); - color: var(--text-color); container: slide-deck / inline-size; display: grid; - min-height: 100vh; &[slide-view=grid] { --slide-ratio: 16/9; @@ -22,20 +18,13 @@ slide-deck { &[blank-slide]::after { content: ''; - background-color: var(--blank-color); + background-color: var(--blank-color, black); position: absolute; inset: 0; - z-index: -1; - } - - &[blank-slide=black] { - --blank-color: var(--color-dark); - --text-color: var(--color-light); } &[blank-slide=white] { - --blank-color: var(--color-light); - --text-color: var(--color-dark); + --blank-color: white; } [slide-canvas] { From ff5053ed873a9d174d0d105a2455d4fb6024b7b3 Mon Sep 17 00:00:00 2001 From: Miriam Suzanne Date: Fri, 5 Jan 2024 10:27:58 -0700 Subject: [PATCH 05/18] Remove notes show/hide, and add script view --- slide-deck.css | 2 +- slide-deck.js | 70 +++++++------------------------------------------- 2 files changed, 10 insertions(+), 62 deletions(-) diff --git a/slide-deck.css b/slide-deck.css index 7fd914a..3237ff0 100644 --- a/slide-deck.css +++ b/slide-deck.css @@ -12,7 +12,7 @@ slide-deck { padding: var(--gap); } - &[slide-view=list] { + &[slide-view=solo] { --slide-height: 100svh; } diff --git a/slide-deck.js b/slide-deck.js index 1b9e6f1..e4a22e2 100644 --- a/slide-deck.js +++ b/slide-deck.js @@ -35,15 +35,10 @@ class slideDeck extends HTMLElement { grid - -

Hide:

- - @@ -59,7 +54,6 @@ class slideDeck extends HTMLElement { 'follow-active', 'full-screen', 'slide-view', - 'hide-parts', ]; static attrToPropMap = { @@ -67,7 +61,6 @@ class slideDeck extends HTMLElement { 'follow-active': 'followActive', 'full-screen': 'fullScreen', 'slide-view': 'slideView', - 'hide-parts': 'hideParts', }; static storageKeys = [ @@ -79,7 +72,8 @@ class slideDeck extends HTMLElement { static slideViews = [ 'grid', - 'list', + 'solo', + 'script', ]; static controlKeys = { @@ -134,10 +128,6 @@ class slideDeck extends HTMLElement { this.#followActiveChange(); this.#updateEventButtons(); break; - case 'hide-parts': - this.#hidePartsChange(); - this.#updatePartButtons(); - break; case 'slide-view': this.#updateViewButtons(); this.scrollToActive(); @@ -173,7 +163,6 @@ class slideDeck extends HTMLElement { // buttons this.#setupEventButtons(); this.#setupViewButtons(); - this.#setupPartButtons(); // event listeners this.shadowRoot.addEventListener('keydown', (event) => { @@ -191,11 +180,8 @@ class slideDeck extends HTMLElement { this.addEventListener('toggleFullscreen', (e) => this.fullScreenEvent()); this.addEventListener('toggleView', (e) => this.toggleView()); this.addEventListener('grid', (e) => this.toggleView('grid')); - this.addEventListener('list', (e) => this.toggleView('list')); - - this.addEventListener('toggleCanvas', (e) => this.togglePart('canvas')); - this.addEventListener('toggleNote', (e) => this.togglePart('note')); - this.addEventListener('showAll', (e) => this.removeAttribute('hide-parts')); + this.addEventListener('solo', (e) => this.toggleView('solo')); + this.addEventListener('script', (e) => this.toggleView('script')); this.addEventListener('join', (e) => this.joinEvent()); this.addEventListener('joinWithNotes', (e) => this.joinWithNotesEvent()); @@ -312,24 +298,6 @@ class slideDeck extends HTMLElement { }); } - #setupPartButtons = () => { - this.hideParts = this.hideParts || this.getAttribute('hide-parts'); - this.partButtons = this.#findButtons('hide-part'); - - this.partButtons.forEach((btn) => { - btn.addEventListener('click', (e) => { - this.togglePart(this.#getButtonValue(btn, 'hide-part')); - }); - this.#setToggleState(btn, 'hide-part', this.hideParts); - }); - } - - #updatePartButtons = () => { - this.partButtons.forEach((btn) => { - this.#setToggleState(btn, 'hide-part', this.hideParts); - }); - } - // event buttons #setupEventButtons = () => { this.eventButtons = this.#findButtons('slide-event'); @@ -350,8 +318,6 @@ class slideDeck extends HTMLElement { let isActive = { 'toggleControl': this.keyControl, - 'toggleCanvas': this.hideParts === 'canvas', - 'toggleNote': this.hideParts === 'note', 'toggleFollow': this.followActive, 'toggleFullscreen': this.fullScreen, } @@ -375,15 +341,8 @@ class slideDeck extends HTMLElement { this.setAttribute('slide-view', next || 'grid'); } - togglePart = (type = 'note') => { - this.hideParts === type - ? this.removeAttribute('hide-parts') - : this.setAttribute('hide-parts', type); - } - #startPresenting = () => { - this.setAttribute('hide-parts', 'note'); - this.setAttribute('slide-view', 'list'); + this.setAttribute('slide-view', 'solo'); this.setAttribute('key-control', ''); this.setAttribute('follow-active', ''); } @@ -399,8 +358,7 @@ class slideDeck extends HTMLElement { } joinWithNotesEvent = () => { - if (this.hideParts === 'note') { this.removeAttribute('hide-parts'); } - this.setAttribute('slide-view', 'grid'); + this.setAttribute('slide-view', 'script'); this.setAttribute('key-control', ''); this.setAttribute('follow-active', ''); } @@ -456,16 +414,6 @@ class slideDeck extends HTMLElement { } } - #hidePartsChange = () => { - this.slideNotes.forEach((note) => { - note.toggleAttribute('hidden', this.hideParts === 'note'); - }); - - this.slideCanvas.forEach((canvas) => { - canvas.toggleAttribute('hidden', this.hideParts === 'canvas'); - }); - } - // storage #asSlideInt = (string) => parseInt(string, 10); From e83e3cb7dea9644456755d7d073471a4e0765784 Mon Sep 17 00:00:00 2001 From: Miriam Suzanne Date: Fri, 5 Jan 2024 10:32:09 -0700 Subject: [PATCH 06/18] Remove view-specific events --- slide-deck.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/slide-deck.js b/slide-deck.js index e4a22e2..1d06b53 100644 --- a/slide-deck.js +++ b/slide-deck.js @@ -178,10 +178,6 @@ class slideDeck extends HTMLElement { this.addEventListener('toggleControl', (e) => this.toggleAttribute('key-control')); this.addEventListener('toggleFollow', (e) => this.toggleAttribute('follow-active')); this.addEventListener('toggleFullscreen', (e) => this.fullScreenEvent()); - this.addEventListener('toggleView', (e) => this.toggleView()); - this.addEventListener('grid', (e) => this.toggleView('grid')); - this.addEventListener('solo', (e) => this.toggleView('solo')); - this.addEventListener('script', (e) => this.toggleView('script')); this.addEventListener('join', (e) => this.joinEvent()); this.addEventListener('joinWithNotes', (e) => this.joinWithNotesEvent()); @@ -329,18 +325,6 @@ class slideDeck extends HTMLElement { } // event handlers - toggleView = (to) => { - let next = to; - if (!next) { - const current = this.getAttribute('slide-view'); - const l = slideDeck.slideViews.length; - const i = slideDeck.slideViews.indexOf(current) || 0; - next = slideDeck.slideViews[(i + 1) % l]; - } - - this.setAttribute('slide-view', next || 'grid'); - } - #startPresenting = () => { this.setAttribute('slide-view', 'solo'); this.setAttribute('key-control', ''); From c92f022584a9b078672405476d44c25085cb935c Mon Sep 17 00:00:00 2001 From: Miriam Suzanne Date: Fri, 5 Jan 2024 18:00:53 -0700 Subject: [PATCH 07/18] Set aria-current for active slides, and clarify part attributes --- CHANGELOG.md | 15 ++++++++------- index.html | 29 ++++++++--------------------- slide-deck.js | 44 ++++++++++++++++++++++++++++++++++---------- 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34b41a3..d1253a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,17 +6,18 @@ until we achieve a stable v1.0 release ## v0.1.2 - unreleased +- 🚀 NEW: Set `aria-current='true'` on active slide - 🚀 NEW: Add support for slide parts – `slide-canvas` & `slide-note` - (these parts require light DOM styles) -- 🚀 NEW: Slide parts can be hidden - with the `hide-parts="note | canvas"` attribute - (both parts cannot be hidden at the same time) -- 🚀 NEW: Add support for `hide-part="note | canvas"` buttons - to toggle hiding the notes and canvass +- 🚀 NEW: Each slide is labeled with either + `slide-item='container'` (if it has nested parts) + or `slide-item='canvas' slide-canvas` (if there are no nested parts) +- 🚀 NEW: The slide-deck has a `--slide-count` property, + and each slide has a `--slide-index` - 💥 BREAKING: Removed the shadow DOM content wrapper, and all shadow DOM styles -- 💥 BREAKING: Renamed and added control-panel parts, +- 🚀 NEW / 💥 BREAKING: Renamed and added control-panel parts, to allow for more customization of the default panel + including pressed buttons with `:part(button pressed)` - 🚀 NEW: Default styles are in `slide-deck.css` and can be applied from the light DOM - 🚀 NEW: The entire control panel can be replaced diff --git a/index.html b/index.html index cae4e39..7d66581 100644 --- a/index.html +++ b/index.html @@ -83,14 +83,14 @@

<button slide-event>previous<button>

-
-

<button set-view>list<button>

+

<button set-view>solo<button>

- + +
@@ -125,31 +125,18 @@

Speaker Notes

  • - A slide without nested parts + A slide with internal parts will be labeled - with the slide-canvas attribute + as a slide-item="container"
  • - A slide with internal parts - will be labeled - as a slide-container instead + A slide without nested parts + will get both slide-item="canvas" + and also the slide-canvas attribute
-
-
-

Hiding parts

- - -
-
-

- These parts can be shown or hidden separately, - but you can never hide both at once. -

-
-

To Do…

… Slide Templates

… CSS Themes

diff --git a/slide-deck.js b/slide-deck.js index 1d06b53..9bb87ed 100644 --- a/slide-deck.js +++ b/slide-deck.js @@ -150,12 +150,8 @@ class slideDeck extends HTMLElement { this.#body = document.querySelector('body'); this.controlPanel = this.querySelector(`[slot="control-panel"]`) ?? this.shadowRoot.querySelector(`[part="control-panel"]`); - this.slides = this.querySelectorAll(':scope > :not([slot])'); - this.slideNotes = this.querySelectorAll('[slide-note]'); - this.slideCanvas = this.querySelectorAll('[slide-canvas]:not(:scope > *)'); // initial setup - this.slideCount = this.slides.length; this.#defaultAttrs(); this.#setupSlides(); this.goTo(); @@ -224,14 +220,32 @@ class slideDeck extends HTMLElement { #slideId = (n) => `slide_${this.id}-${n}`; #setupSlides = () => { + this.slides = this.querySelectorAll(':scope > :not([slot])'); + this.slideCount = this.slides.length; + this.style.setProperty('--slide-count', this.slideCount); + this.slides.forEach((slide, index) => { - slide.id = this.#slideId(index + 1); - if (slide.querySelector('[slide-canvas]')) { - slide.toggleAttribute('slide-container', true); + const slideIndex = index + 1; + slide.id = this.#slideId(slideIndex); + slide.style.setProperty('--slide-index', slideIndex); + + if (slide.querySelector(':scope [slide-canvas]')) { + if (!slide.hasAttribute('slide-item')) { + slide.setAttribute('slide-item', 'container'); + } } else { - slide.toggleAttribute('slide-canvas', true); + if (!slide.hasAttribute('slide-item')) { + slide.setAttribute('slide-item', 'canvas'); + } + + if (!slide.hasAttribute('slide-canvas')) { + slide.toggleAttribute('slide-canvas', true); + } } }); + + this.slideNotes = this.querySelectorAll(':scope [slide-note]'); + this.slideCanvas = this.querySelectorAll(':scope [slide-canvas]'); }; #defaultAttrs = () => { @@ -246,7 +260,7 @@ class slideDeck extends HTMLElement { // buttons #findButtons = (attr) => [ - ...this.querySelectorAll(`button[${attr}]`), + ...this.querySelectorAll(`:scope button[${attr}]`), ...this.shadowRoot.querySelectorAll(`button[${attr}]`), ]; @@ -400,9 +414,10 @@ class slideDeck extends HTMLElement { // storage #asSlideInt = (string) => parseInt(string, 10); + #indexFromId = (string) => this.#asSlideInt(string.split('-').pop()); #slideFromHash = () => window.location.hash.startsWith('#slide_') - ? this.#asSlideInt(window.location.hash.split('-').pop()) + ? this.#indexFromId(window.location.hash) : null; #slideFromStore = (fallback = 1) => this.#asSlideInt( @@ -445,6 +460,15 @@ class slideDeck extends HTMLElement { if (setTo !== fromHash) { this.#slideToHash(setTo); } + + // update aria-current + this.querySelectorAll( + ':scope [slide-item][aria-current]' + ).forEach((slide) => { + slide.removeAttribute('aria-current'); + }); + + this.querySelector(`:scope #${this.#slideId(setTo)}`).setAttribute('aria-current', 'true'); } } From 20b8e36162f4485cea6692e989f4da79aa317c21 Mon Sep 17 00:00:00 2001 From: Stacy Kvernmo Date: Fri, 5 Jan 2024 23:33:05 -0600 Subject: [PATCH 08/18] add very basic styles for script view --- custom-panel.html | 3 ++- slide-deck.css | 55 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/custom-panel.html b/custom-panel.html index 604b1a0..0512346 100644 --- a/custom-panel.html +++ b/custom-panel.html @@ -14,7 +14,8 @@
- + +
diff --git a/slide-deck.css b/slide-deck.css index 3237ff0..8843b61 100644 --- a/slide-deck.css +++ b/slide-deck.css @@ -3,19 +3,57 @@ slide-deck { container: slide-deck / inline-size; display: grid; - &[slide-view=grid] { + &[slide-view=grid], + &[slide-view=script] { --slide-ratio: 16/9; - --target-outline: medium dotted; --target-margin: var(--gap); + --target-outline: medium dotted; + --target-outline-offset: calc(var(--gap) * 0.5); gap: var(--gap); - grid-template-columns: repeat(auto-fill, minmax(min(50ch, 100%), 1fr)); padding: var(--gap); } + &[slide-view=grid] { + grid-template-columns: repeat(auto-fill, minmax(min(50ch, 100%), 1fr)); + } + &[slide-view=solo] { --slide-height: 100svh; } + &[slide-view=script] { + display: grid; + grid-template-columns: 65ch 1fr; + + [slide-container] { + display: grid; + grid-column: 1 / -1; + grid-template-columns: subgrid; + scroll-margin-block: var(--target-margin); + } + + [slide-canvas] { + grid-column: 1; + scale: var(--scaled-slide, 0.80); + } + + [slide-note] { + font-size: var(--note-font-size, 120%); + grid-column: 2; + max-width: 65ch; + padding: var(--gap); + } + + [slide-canvas]:target, + [slide-container]:target [slide-canvas] { + --scaled-slide: 1; + } + + [slide-container]:target { + --note-font-size: 150%; + } + } + &[blank-slide]::after { content: ''; background-color: var(--blank-color, black); @@ -27,6 +65,12 @@ slide-deck { --blank-color: white; } + [slide-canvas]:target, + [slide-container]:target [slide-canvas] { + outline: var(--target-outline); + outline-offset: var(--target-outline-offset); + } + [slide-canvas] { aspect-ratio: var(--slide-ratio); border: thin solid; @@ -35,11 +79,6 @@ slide-deck { min-height: var(--slide-height); padding: var(--gap); scroll-margin-block: var(--target-margin); - - &:target { - outline: var(--target-outline); - outline-offset: calc(var(--gap) * 0.5); - } } [slide-note] { From 26f76ddf30c4f12d99851d9d21caf75652452dca Mon Sep 17 00:00:00 2001 From: Stacy Kvernmo Date: Sat, 6 Jan 2024 00:28:37 -0600 Subject: [PATCH 09/18] styles for slide-item in script view --- index.html | 45 +++++++++++++++++++++++++++++++++++++++++++-- slide-deck.css | 25 ++++++++++++------------- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/index.html b/index.html index 7d66581..18e8c4c 100644 --- a/index.html +++ b/index.html @@ -18,8 +18,49 @@

Slide-Deck Web Component

No Dependencies

-

Progressive Enhancement

-

Just HTML

+
+
+

Progressive Enhancement

+
+
+

+ Some slide notes are very short. Little reminders. +

+
+
+
+
+

Just HTML

+
+
+

+ Slide notes are also HTML +

+

+ In script view the active slide-item will have a larger canvas size + and the font-size of an active slides speaker notes is increased + for easier readability. +

+ +

+ This is a heading level 3 +

+ +

+ This paragraph exists to test a variety of content + within slide-notes. While some slides may not have any + notes at all, others may have extremely verbose notes and may + contain many details. +

+ +
+

+ Blockquote example within the slide-notes to test a few different + content types. +

+
+
+

Keyboard Shortcuts

Always available:

diff --git a/slide-deck.css b/slide-deck.css index 8843b61..b3f0c04 100644 --- a/slide-deck.css +++ b/slide-deck.css @@ -14,6 +14,7 @@ slide-deck { } &[slide-view=grid] { + --slide-note-margin-block: var(--gap); grid-template-columns: repeat(auto-fill, minmax(min(50ch, 100%), 1fr)); } @@ -25,11 +26,10 @@ slide-deck { display: grid; grid-template-columns: 65ch 1fr; - [slide-container] { + [slide-item='container'] { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; - scroll-margin-block: var(--target-margin); } [slide-canvas] { @@ -41,17 +41,13 @@ slide-deck { font-size: var(--note-font-size, 120%); grid-column: 2; max-width: 65ch; - padding: var(--gap); + padding-inline: var(--gap); } - [slide-canvas]:target, - [slide-container]:target [slide-canvas] { + [slide-item]:target { + --note-font-size: 160%; --scaled-slide: 1; } - - [slide-container]:target { - --note-font-size: 150%; - } } &[blank-slide]::after { @@ -65,8 +61,12 @@ slide-deck { --blank-color: white; } - [slide-canvas]:target, - [slide-container]:target [slide-canvas] { + [slide-item] { + scroll-margin-block: var(--target-margin); + } + + [aria-current='true'][slide-canvas], + [aria-current='true'] [slide-canvas] { outline: var(--target-outline); outline-offset: var(--target-outline-offset); } @@ -78,11 +78,10 @@ slide-deck { container: slide-item / inline-size; min-height: var(--slide-height); padding: var(--gap); - scroll-margin-block: var(--target-margin); } [slide-note] { - margin-block: var(--gap); + margin-block: var(--slide-note-margin-block); } &::part(control-panel) { From 504bdefddb4720e584db9908c5638cd60106d641 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Mon, 8 Jan 2024 13:20:51 -0500 Subject: [PATCH 10/18] Privatizion --- slide-deck.js | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/slide-deck.js b/slide-deck.js index 9bb87ed..acd7ea1 100644 --- a/slide-deck.js +++ b/slide-deck.js @@ -1,6 +1,7 @@ +// @ts-check class slideDeck extends HTMLElement { // template - static appendShadowTemplate = (node) => { + #appendShadowTemplate = () => { const template = document.createElement("template"); template.innerHTML = ` @@ -44,7 +45,7 @@ class slideDeck extends HTMLElement { `; - const shadowRoot = node.attachShadow({ mode: "open" }); + const shadowRoot = this.attachShadow({ mode: "open" }); shadowRoot.appendChild(template.content.cloneNode(true)); } @@ -105,15 +106,15 @@ class slideDeck extends HTMLElement { } // dynamic - store = {}; + #store = {}; slides; slideNotes; slideCanvas; slideCount; activeSlide; - controlPanel; - eventButtons; - viewButtons; + #controlPanel; + #eventButtons; + #viewButtons; #body; // callbacks @@ -143,12 +144,12 @@ class slideDeck extends HTMLElement { super(); // shadow dom and ID - slideDeck.appendShadowTemplate(this); + this.#appendShadowTemplate(); this.#setDeckID(); // relevant nodes this.#body = document.querySelector('body'); - this.controlPanel = this.querySelector(`[slot="control-panel"]`) ?? + this.#controlPanel = this.querySelector(`[slot="control-panel"]`) ?? this.shadowRoot.querySelector(`[part="control-panel"]`); // initial setup @@ -166,7 +167,7 @@ class slideDeck extends HTMLElement { if ((event.key === 'k' && event.metaKey) || event.key === 'Escape') { event.preventDefault(); - this.controlPanel.close(); + this.#controlPanel.close(); } }); @@ -213,7 +214,7 @@ class slideDeck extends HTMLElement { // storage keys based on slide ID slideDeck.storageKeys.forEach((key) => { - this.store[key] = `${this.id}.${key}`; + this.#store[key] = `${this.id}.${key}`; }); } @@ -292,9 +293,9 @@ class slideDeck extends HTMLElement { #setupViewButtons = () => { this.slideView = this.slideView || this.getAttribute('slide-view'); - this.viewButtons = this.#findButtons('set-view'); + this.#viewButtons = this.#findButtons('set-view'); - this.viewButtons.forEach((btn) => { + this.#viewButtons.forEach((btn) => { btn.addEventListener('click', (e) => { this.setAttribute('slide-view', this.#getButtonValue(btn, 'set-view')); }); @@ -303,16 +304,16 @@ class slideDeck extends HTMLElement { } #updateViewButtons = () => { - this.viewButtons.forEach((btn) => { + this.#viewButtons.forEach((btn) => { this.#setToggleState(btn, 'set-view', this.slideView); }); } // event buttons #setupEventButtons = () => { - this.eventButtons = this.#findButtons('slide-event'); + this.#eventButtons = this.#findButtons('slide-event'); - this.eventButtons.forEach((btn) => { + this.#eventButtons.forEach((btn) => { btn.addEventListener('click', (e) => { const event = this.#getButtonValue(btn, 'slide-event'); this.dispatchEvent(new Event(event, { view: window, bubbles: false })); @@ -323,7 +324,7 @@ class slideDeck extends HTMLElement { } #updateEventButtons = () => { - this.eventButtons.forEach((btn) => { + this.#eventButtons.forEach((btn) => { const btnEvent = this.#getButtonValue(btn, 'slide-event'); let isActive = { @@ -421,7 +422,7 @@ class slideDeck extends HTMLElement { : null; #slideFromStore = (fallback = 1) => this.#asSlideInt( - localStorage.getItem(this.store.slide) + localStorage.getItem(this.#store.slide) ) || fallback; #slideToHash = (to) => { @@ -431,9 +432,9 @@ class slideDeck extends HTMLElement { }; #slideToStore = (to) => { if (to) { - localStorage.setItem(this.store.slide, to); + localStorage.setItem(this.#store.slide, to); } else { - localStorage.removeItem(this.store.slide); + localStorage.removeItem(this.#store.slide); } }; @@ -475,7 +476,7 @@ class slideDeck extends HTMLElement { resetActive = () => { this.activeSlide = null; window.location.hash = this.id; - localStorage.removeItem(this.store.slide); + localStorage.removeItem(this.#store.slide); }; move = (by) => { @@ -493,7 +494,7 @@ class slideDeck extends HTMLElement { switch (event.key) { case 'k': event.preventDefault(); - this.controlPanel.showModal(); + this.#controlPanel.showModal(); break; case 'f': if (event.shiftKey) { From f5cdd61b26d3295eea8921273f10585879ccec29 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Mon, 8 Jan 2024 13:38:32 -0500 Subject: [PATCH 11/18] Move attribute state to getters --- slide-deck.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/slide-deck.js b/slide-deck.js index acd7ea1..5063b5d 100644 --- a/slide-deck.js +++ b/slide-deck.js @@ -1,4 +1,3 @@ -// @ts-check class slideDeck extends HTMLElement { // template #appendShadowTemplate = () => { @@ -57,12 +56,18 @@ class slideDeck extends HTMLElement { 'slide-view', ]; - static attrToPropMap = { - 'key-control': 'keyControl', - 'follow-active': 'followActive', - 'full-screen': 'fullScreen', - 'slide-view': 'slideView', - }; + get keyControl(){ + return this.hasAttribute('key-control'); + } + get followActive(){ + return this.hasAttribute('follow-active'); + } + get fullScreen(){ + return this.hasAttribute('full-screen'); + } + get slideView(){ + return this.getAttribute('slide-view'); + } static storageKeys = [ 'control', @@ -118,8 +123,7 @@ class slideDeck extends HTMLElement { #body; // callbacks - attributeChangedCallback(name, oldValue, newValue) { - this[slideDeck.attrToPropMap[name]] = newValue || this.hasAttribute(name); + attributeChangedCallback(name) { switch (name) { case 'key-control': @@ -292,7 +296,6 @@ class slideDeck extends HTMLElement { } #setupViewButtons = () => { - this.slideView = this.slideView || this.getAttribute('slide-view'); this.#viewButtons = this.#findButtons('set-view'); this.#viewButtons.forEach((btn) => { From fb1b1f6a3a232d30296232ddf467680d4b39a9a4 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Tue, 9 Jan 2024 11:40:56 -0500 Subject: [PATCH 12/18] Static appendShadowTemplate --- slide-deck.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/slide-deck.js b/slide-deck.js index 5063b5d..20ccbcc 100644 --- a/slide-deck.js +++ b/slide-deck.js @@ -1,6 +1,6 @@ class slideDeck extends HTMLElement { // template - #appendShadowTemplate = () => { + static #appendShadowTemplate = (node) => { const template = document.createElement("template"); template.innerHTML = ` @@ -44,7 +44,7 @@ class slideDeck extends HTMLElement { `; - const shadowRoot = this.attachShadow({ mode: "open" }); + const shadowRoot = node.attachShadow({ mode: "open" }); shadowRoot.appendChild(template.content.cloneNode(true)); } @@ -148,7 +148,7 @@ class slideDeck extends HTMLElement { super(); // shadow dom and ID - this.#appendShadowTemplate(); + slideDeck.#appendShadowTemplate(this); this.#setDeckID(); // relevant nodes From c375e08c17ea475c171136c73c3cb0ecb3a10928 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Tue, 9 Jan 2024 11:46:37 -0500 Subject: [PATCH 13/18] Make slideNotes and slideCanvas private --- slide-deck.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/slide-deck.js b/slide-deck.js index 20ccbcc..f1020fd 100644 --- a/slide-deck.js +++ b/slide-deck.js @@ -113,8 +113,8 @@ class slideDeck extends HTMLElement { // dynamic #store = {}; slides; - slideNotes; - slideCanvas; + #slideNotes; + #slideCanvas; slideCount; activeSlide; #controlPanel; @@ -212,7 +212,7 @@ class slideDeck extends HTMLElement { return ID; }; - +x #setDeckID = () => { this.id = this.id || this.#newDeckId(); @@ -249,8 +249,8 @@ class slideDeck extends HTMLElement { } }); - this.slideNotes = this.querySelectorAll(':scope [slide-note]'); - this.slideCanvas = this.querySelectorAll(':scope [slide-canvas]'); + this.#slideNotes = this.querySelectorAll(':scope [slide-note]'); + this.#slideCanvas = this.querySelectorAll(':scope [slide-canvas]'); }; #defaultAttrs = () => { From 14de1039e9d8c59ba02986bdf76c30da1bf87242 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Tue, 9 Jan 2024 16:30:32 -0500 Subject: [PATCH 14/18] Add CSS to usage examples, remove version --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 985dc55..fbee859 100644 --- a/README.md +++ b/README.md @@ -108,22 +108,25 @@ Make sure you include the ` ``` ```html + ``` ```html + ``` From 66852dc1ca3446348c137965d44cc574047dca6c Mon Sep 17 00:00:00 2001 From: Stacy Kvernmo Date: Wed, 10 Jan 2024 13:36:39 -0600 Subject: [PATCH 15/18] Make script view better for smaller screens --- slide-deck.css | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/slide-deck.css b/slide-deck.css index b3f0c04..74578be 100644 --- a/slide-deck.css +++ b/slide-deck.css @@ -9,7 +9,7 @@ slide-deck { --target-margin: var(--gap); --target-outline: medium dotted; --target-outline-offset: calc(var(--gap) * 0.5); - gap: var(--gap); + gap: var(--row-gap, var(--gap)) var(--column-gap, var(--gap)); padding: var(--gap); } @@ -23,10 +23,16 @@ slide-deck { } &[slide-view=script] { + --column-gap: calc(1.25em + 2vw); + --row-gap: 5em; display: grid; - grid-template-columns: 65ch 1fr; + + @media (width >= 60em) { + grid-template-columns: minmax(30vw, auto) minmax(65vw, 1fr); + } [slide-item='container'] { + align-items: center; display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; @@ -40,7 +46,7 @@ slide-deck { [slide-note] { font-size: var(--note-font-size, 120%); grid-column: 2; - max-width: 65ch; + max-width: 75ch; padding-inline: var(--gap); } From 15a6c55b3a519055eeb0fed14b94df82cc2ab554 Mon Sep 17 00:00:00 2001 From: Stacy Kvernmo Date: Thu, 11 Jan 2024 11:00:09 -0600 Subject: [PATCH 16/18] order by alpha --- slide-deck.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/slide-deck.css b/slide-deck.css index 74578be..719761e 100644 --- a/slide-deck.css +++ b/slide-deck.css @@ -57,10 +57,10 @@ slide-deck { } &[blank-slide]::after { - content: ''; background-color: var(--blank-color, black); - position: absolute; + content: ''; inset: 0; + position: absolute; } &[blank-slide=white] { @@ -109,9 +109,9 @@ slide-deck { button, &::part(button) { + border: medium solid transparent; font: inherit; padding-inline: var(--gap); - border: medium solid transparent; } [aria-pressed=true], From a4e2519a5876aa345c8956a6428babff9728a389 Mon Sep 17 00:00:00 2001 From: Stacy Kvernmo Date: Thu, 11 Jan 2024 11:00:36 -0600 Subject: [PATCH 17/18] adjust solo grid rows for testing, still need slide height though --- slide-deck.css | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/slide-deck.css b/slide-deck.css index 719761e..972dc42 100644 --- a/slide-deck.css +++ b/slide-deck.css @@ -19,7 +19,15 @@ slide-deck { } &[slide-view=solo] { - --slide-height: 100svh; + grid-auto-rows: 100svh; + + [slide-item] { + --slide-height: 100svh; + } + + [slide-note] { + display: none; + } } &[slide-view=script] { From baa85a5a1342e1a574922df750b81552a668f335 Mon Sep 17 00:00:00 2001 From: Miriam Suzanne Date: Thu, 11 Jan 2024 10:13:27 -0700 Subject: [PATCH 18/18] Stretch slide canvas to fill container in solo view --- slide-deck.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/slide-deck.css b/slide-deck.css index 972dc42..29c202f 100644 --- a/slide-deck.css +++ b/slide-deck.css @@ -21,8 +21,8 @@ slide-deck { &[slide-view=solo] { grid-auto-rows: 100svh; - [slide-item] { - --slide-height: 100svh; + [slide-item='container'] { + display: grid; } [slide-note] { @@ -90,7 +90,6 @@ slide-deck { border: thin solid; box-sizing: border-box; container: slide-item / inline-size; - min-height: var(--slide-height); padding: var(--gap); }