From 7f3dfc8738adfa8cf230a86ced750abbc023dd3c Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Fri, 1 May 2026 17:58:16 -0400 Subject: [PATCH 01/19] GAUD-9165 - Implement the d2l-page skeleton --- components/page/README.md | 5 + components/page/demo/page-component.js | 191 ++++++++++++++++++++ components/page/demo/page.html | 15 ++ components/page/demo/temp-nav-styles.js | 217 +++++++++++++++++++++++ components/page/page.js | 223 ++++++++++++++++++++++++ components/page/test/page.axe.js | 40 +++++ components/page/test/page.test.js | 10 ++ index.html | 1 + lang/ar.js | 2 + lang/ca.js | 2 + lang/cy.js | 2 + lang/da.js | 2 + lang/de.js | 2 + lang/en-gb.js | 2 + lang/en.js | 2 + lang/es-es.js | 2 + lang/es.js | 2 + lang/fr-fr.js | 2 + lang/fr.js | 2 + lang/haw.js | 2 + lang/hi.js | 2 + lang/ja.js | 2 + lang/ko.js | 2 + lang/mi.js | 2 + lang/nl.js | 2 + lang/pt.js | 2 + lang/sv.js | 2 + lang/th.js | 2 + lang/tr.js | 2 + lang/vi.js | 2 + lang/zh-cn.js | 2 + lang/zh-tw.js | 2 + 32 files changed, 750 insertions(+) create mode 100644 components/page/README.md create mode 100644 components/page/demo/page-component.js create mode 100644 components/page/demo/page.html create mode 100644 components/page/demo/temp-nav-styles.js create mode 100644 components/page/page.js create mode 100644 components/page/test/page.axe.js create mode 100644 components/page/test/page.test.js diff --git a/components/page/README.md b/components/page/README.md new file mode 100644 index 00000000000..11d630c5402 --- /dev/null +++ b/components/page/README.md @@ -0,0 +1,5 @@ +# Page + +The `d2l-page` and page layout components are in progress. + +Please reach out before using them! diff --git a/components/page/demo/page-component.js b/components/page/demo/page-component.js new file mode 100644 index 00000000000..5aa62dc03e5 --- /dev/null +++ b/components/page/demo/page-component.js @@ -0,0 +1,191 @@ +import '../../collapsible-panel/collapsible-panel.js'; +import '../page.js'; +import { css, html, LitElement, nothing } from 'lit'; +import { navStyles } from './temp-nav-styles.js'; +import { selectStyles } from '../../inputs/input-select-styles.js'; + +/** + * Component for d2l-page demos and tests + */ +class PageDemo extends LitElement { + + static properties = { + demoMode: { type: Boolean, attribute: 'demo-mode' }, + hasFooter: { type: Boolean, attribute: 'has-footer' }, + hasSideNavPanel: { type: Boolean, attribute: 'has-side-nav-panel' }, + hasSupportingPanel: { type: Boolean, attribute: 'has-supporting-panel' }, + navType: { type: String, attribute: 'nav-type' }, + widthType: { type: String, attribute: 'width-type' }, + _allowThreePanels: { state: true } + }; + + static styles = [navStyles, selectStyles, css` + .demo-controls { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + } + `]; + + constructor() { + super(); + this._allowThreePanels = false; // Temp for dev/testing + this.demoMode = false; + this.hasFooter = false; + this.hasSideNavPanel = false; + this.hasSupportingPanel = false; + this.navType = 'full'; + /** @type {'normal'|'wide'|'fullscreen'} */ + this.widthType = 'normal'; + } + + render() { + return html` + + ${this.navType === 'full' ? this.#renderFullNav() : this.#renderImmersiveNav()} + ${this.#renderSideNavPanel()} + ${this.#renderMainPanel()} + ${this.#renderSupportingPanel()} + ${this.#renderFooter()} + + `; + } + + #handleAllowThreePanelsChange(e) { + this._allowThreePanels = e.target.on; + if (!this._allowThreePanels && this.hasSideNavPanel && this.hasSupportingPanel) { + this.shadowRoot.querySelector('#switch-supporting-panel').on = false; + this.hasSupportingPanel = false; + } + } + + #handleNavTypeChange(e) { + this.navType = e.target.on ? 'immersive' : 'full'; + } + + #handleVisibilityChange(e) { + const key = e.target.dataset.key; + this[key] = e.target.on; + + if (this._allowThreePanels) return; + if (e.target.on && key === 'hasSideNavPanel' && this.hasSupportingPanel) { + this.shadowRoot.querySelector('#switch-supporting-panel').on = false; + this.hasSupportingPanel = false; + } else if (e.target.on && key === 'hasSupportingPanel' && this.hasSideNavPanel) { + this.shadowRoot.querySelector('#switch-side-nav-panel').on = false; + this.hasSideNavPanel = false; + } + } + + #handleWidthTypeChange(e) { + this.widthType = e.target.value; + } + + #renderFooter() { + return this.hasFooter ? html` +
+ I'm in the footer slot of the d2l-page component! +
+ ` : nothing; + } + + #renderFullNav() { + // Update with navigation components once available + return html` +
+ +
+
+ +
+ +
+
+
+ + + +
+
+ + +
+ `; + } + + #renderImmersiveNav() { + // Update with navigation components once available + return html` +
+ +
+ +
+ Assignment 1 - Introduction to Economics +
+
+ + +
+
+ +
+ `; + } + + #renderMainPanel() { + return html` +
+ ${this.demoMode ? html` + +
+ + + + + + +
+
+ ` : nothing} +

I'm in the default slot of the d2l-page component!

+
+
End of Content
+ `; + } + + #renderSideNavPanel() { + return this.hasSideNavPanel ? html` +
+ I'm in the side-nav slot of the d2l-page component! +
+ ` : nothing; + } + + #renderSupportingPanel() { + return this.hasSupportingPanel ? html` +
+ I'm in the supporting slot of the d2l-page component! +
+ ` : nothing; + } +} + +customElements.define('d2l-page-demo', PageDemo); diff --git a/components/page/demo/page.html b/components/page/demo/page.html new file mode 100644 index 00000000000..f31638807b9 --- /dev/null +++ b/components/page/demo/page.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/components/page/demo/temp-nav-styles.js b/components/page/demo/temp-nav-styles.js new file mode 100644 index 00000000000..98d89148ef5 --- /dev/null +++ b/components/page/demo/temp-nav-styles.js @@ -0,0 +1,217 @@ +/** + * Temporary navigation demo styles + * These can be removed once we have official navigation components to use + */ + +import { css } from 'lit'; + +export const navStyles = css` + + /* Shared Styles */ + .nav-shadow { + background-color: rgba(0, 0, 0, 0.02); + bottom: -4px; + display: block; + height: 4px; + pointer-events: none; + position: absolute; + width: 100%; + z-index: 1; + } + .nav-band { + background: linear-gradient(180deg, var(--d2l-color-celestine) 1.5rem, #ffffff 0%); + min-height: 4px; + } + .nav-icon-btn { + align-items: center; + background: none; + border: none; + border-radius: 4px; + color: var(--d2l-color-ferrite); + cursor: pointer; + display: inline-flex; + font-size: 0.8rem; + gap: 4px; + justify-content: center; + min-height: 42px; + min-width: 42px; + padding: 6px; + } + .nav-icon-btn:hover, + .nav-icon-btn:focus-visible { + background-color: var(--d2l-color-gypsum); + color: var(--d2l-color-celestine); + } + + /* Full Nav Styles */ + .full-nav-wrapper { + position: relative; + } + .full-nav-header { + align-items: center; + display: flex; + height: 90px; + margin-inline: var(--d2l-page-margin-inline); + max-width: var(--d2l-page-header-max-width); + padding: 0 30px; + } + @media (max-width: 767px) { + .full-nav-header { + height: 72px; + } + } + @media (max-width: 615px) { + .full-nav-header { + padding: 0 15px; + } + } + .full-nav-header-left { + align-items: center; + display: flex; + flex: 0 1 auto; + gap: 12px; + height: 100%; + } + .full-nav-header-spacer { + flex: 1 1 auto; + min-width: 30px; + } + @media (max-width: 615px) { + .full-nav-header-spacer { + min-width: 15px; + } + } + .full-nav-header-right { + align-items: center; + display: flex; + flex: 0 0 auto; + gap: 6px; + height: 100%; + } + .full-nav-logo { + background-color: var(--d2l-color-celestine); + border-radius: 4px; + color: white; + font-size: 0.8rem; + font-weight: 700; + padding: 8px 14px; + } + .full-nav-separator { + background-color: var(--d2l-color-mica); + height: 26px; + margin: 0 6px; + width: 1px; + } + .full-nav-footer { + border-bottom: 1px solid rgba(124, 134, 149, 0.18); + border-top: 1px solid rgba(124, 134, 149, 0.18); + } + .full-nav-footer-inner { + align-items: center; + display: flex; + gap: 4px; + margin-inline: var(--d2l-page-margin-inline); + max-width: var(--d2l-page-header-max-width); + padding: 0 30px; + } + @media (max-width: 615px) { + .full-nav-footer-inner { + padding: 0 15px; + } + } + .full-nav-footer-link { + border-bottom: 4px solid transparent; + color: var(--d2l-color-ferrite); + display: inline-block; + font-size: 0.7rem; + padding: 8px 12px; + text-decoration: none; + } + .full-nav-footer-link:hover, + .full-nav-footer-link:focus-visible { + border-bottom-color: var(--d2l-color-celestine); + color: var(--d2l-color-celestine); + } + + /* Immersive Nav Styles */ + .immersive-wrapper { + background-color: white; + border-bottom: 1px solid var(--d2l-color-mica); + position: relative; + } + .immersive-container { + align-items: center; + display: flex; + height: 3.1rem; + justify-content: space-between; + margin-inline: var(--d2l-page-margin-inline); + max-width: var(--d2l-page-header-max-width); + overflow: hidden; + padding: 0 30px; + } + @media (max-width: 929px) { + .immersive-container { + padding: 0 24px; + } + } + @media (max-width: 767px) { + .immersive-container { + padding: 0 18px; + } + } + @media (max-width: 615px) { + .immersive-container { + height: 2.8rem; + } + } + .immersive-left { + align-items: center; + color: var(--d2l-color-tungsten); + display: flex; + flex: 0 0 auto; + font-size: 0.8rem; + letter-spacing: 0.2px; + } + .immersive-back-link { + align-items: center; + color: var(--d2l-color-tungsten); + display: inline-flex; + gap: 4px; + text-decoration: none; + } + .immersive-back-link:hover, + .immersive-back-link:focus-visible { + color: var(--d2l-color-celestine); + } + .immersive-back-icon { + font-size: 1rem; + } + .immersive-middle { + border-inline-end: 1px solid var(--d2l-color-gypsum); + border-inline-start: 1px solid var(--d2l-color-gypsum); + flex: 0 1 auto; + font-size: 0.8rem; + margin: 0 24px; + min-width: 0; + overflow: hidden; + padding: 0 24px; + text-overflow: ellipsis; + white-space: nowrap; + width: 100%; + } + @media (max-width: 615px) { + .immersive-middle { + margin: 0 18px; + padding: 0 18px; + } + } + .immersive-right { + align-items: center; + display: flex; + flex: 0 0 auto; + gap: 8px; + } + .immersive-right .nav-icon-btn { + font-size: 0.7rem; + } +`; diff --git a/components/page/page.js b/components/page/page.js new file mode 100644 index 00000000000..8e73b05a63e --- /dev/null +++ b/components/page/page.js @@ -0,0 +1,223 @@ +import '../button/floating-buttons.js'; +import { css, html, LitElement, nothing } from 'lit'; +import { classMap } from 'lit/directives/class-map.js'; +import { LocalizeCoreElement } from '../../helpers/localize-core-element.js'; + +/** + * Page template with header, optional footer and optional navigation panel or supporting panel + * @slot - The main content of the page (expecting d2l-page-main) + * @slot header - The header content of the page (expecting d2l-page-header-*) + * @slot side-nav - The side navigation content of the page (expecting d2l-page-side-nav) + * @slot supporting - The supporting content of the page (expecting d2l-page-supporting) + * @slot footer - The footer content of the page (expecting d2l-page-footer) + */ +class Page extends LocalizeCoreElement(LitElement) { + + static properties = { + /** + * Width type of the page and its underlying pieces + * @type {'normal'|'wide'|'fullscreen'} + */ + widthType: { type: String, attribute: 'width-type' }, + _headerIsSticky: { state: true }, + _slotVisibility: { state: true } + }; + + static styles = css` + :host { + --d2l-page-header-max-width: 1230px; + --d2l-page-content-max-width: 1230px; + --d2l-page-footer-max-width: 1230px; + --d2l-page-margin-inline: auto; + } + + :host([width-type="wide"]) { + --d2l-page-header-max-width: 1440px; + --d2l-page-content-max-width: 1440px; + --d2l-page-footer-max-width: 1440px; + } + + :host([width-type="fullscreen"]) { + --d2l-page-header-max-width: 100%; + --d2l-page-content-max-width: 100%; + --d2l-page-footer-max-width: 100%; + } + + .header { + background-color: white; + z-index: 2; /* To be over divider and main contents */ + } + .page.header-sticky .header { + position: sticky; + top: 0; + } + + .content { + display: flex; + margin-inline: var(--d2l-page-margin-inline, 0); + max-width: var(--d2l-page-content-max-width, 100%); + padding-bottom: var(--d2l-page-footer-height, 0px); /* Reserve space for fixed footer */ + } + + main { + flex: 1; + min-width: 400px; /* TBD */ + } + + .side-nav-panel, + .supporting-panel { + overflow-y: auto; + position: sticky; + top: 0; + height: calc(100vh - var(--d2l-page-footer-height, 0px)); + } + .page.header-sticky .side-nav-panel, + .page.header-sticky .supporting-panel { + top: var(--d2l-page-header-height, 0px); + height: calc(100vh - var(--d2l-page-header-height, 0px) - var(--d2l-page-footer-height, 0px)); + } + + .divider { + background-color: var(--d2l-color-gypsum); + flex: none; + width: 4px; + z-index: 1; + } + + .footer:not([hidden]), + .floating-buttons-container { + display: inline; + } + .fixed-footer { + background-color: white; + box-shadow: 0 -2px 4px rgba(32, 33, 34, 0.2); /* ferrite */ + inset: auto 0 0; + padding: 0.75rem 0; + position: fixed; + z-index: 1; /* To be over divider and main contents */ + } + .floating-footer { + padding-block-end: 0.75rem; + } + .footer-contents { + margin-inline: var(--d2l-page-margin-inline, 0); + max-width: var(--d2l-page-footer-max-width, 100%); + } + `; + + constructor() { + super(); + + this.widthType = 'normal'; + this._headerIsSticky = false; + this._slotVisibility = {}; + this.#resizeObserver = new ResizeObserver(entries => { + for (const entry of entries) { + if (entry.target.classList.contains('header')) { + const height = entry.target.offsetHeight; + this.style.setProperty('--d2l-page-header-height', `${height}px`); + } else if (entry.target.classList.contains('footer')) { + const height = entry.target.classList.contains('fixed-footer') ? entry.target.offsetHeight : 0; + this.style.setProperty('--d2l-page-footer-height', `${height}px`); + } + } + }); + } + + connectedCallback() { + super.connectedCallback(); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.#resizeObserver.disconnect(); + } + + firstUpdated() { + const header = this.shadowRoot.querySelector('.header'); + const footer = this.shadowRoot.querySelector('.footer'); + if (header) this.#resizeObserver.observe(header); + if (footer) this.#resizeObserver.observe(footer); + } + + render() { + const pageClasses = { + 'page': true, + 'header-sticky': this._headerIsSticky + }; + + const header = html` +
+ +
`; + + const mainContent = html` +
+ +
`; + + const sideNavPanel = html` + + ${this._slotVisibility['side-nav'] ? html`
` : nothing} + `; + + const supportingPanel = html` + ${this._slotVisibility['supporting'] ? html`
` : nothing} + `; + + const fixedFooter = this._slotVisibility['side-nav'] || this._slotVisibility['supporting']; + const footerContainerClasses = { 'footer': true, 'fixed-footer': fixedFooter }; + const footerContents = html``; + const footer = html` +
+ ${fixedFooter ? footerContents : this.#renderFloatingButtons(footerContents)} +
`; + + return html` +
+ ${header} +
+ ${sideNavPanel} + ${mainContent} + ${supportingPanel} +
+ ${footer} +
+ `; + } + + #resizeObserver; + + #handleHeaderSlotChange(e) { + const nodes = e.target.assignedNodes(); + //this._headerIsSticky = nodes.some(node => node.tagName.toLowerCase() === 'd2l-page-header-immersive'); + this._headerIsSticky = nodes.some(node => node.id === 'immersive-nav'); // temp until the official component exists + } + + #handleSlotVisibilityChange(e) { + const key = e.target.name; + const nodes = e.target.assignedNodes(); + this._slotVisibility = { ...this._slotVisibility, [key]: nodes.length !== 0 }; + this.requestUpdate(); + } + + #renderFloatingButtons(footerContents) { + // Floating buttons needs to be wrapped as it spawns a sibling element that should be cleaned up as one by Lit + return html` +
+ + + +
+ `; + } + +} + +customElements.define('d2l-page', Page); diff --git a/components/page/test/page.axe.js b/components/page/test/page.axe.js new file mode 100644 index 00000000000..0cb23386687 --- /dev/null +++ b/components/page/test/page.axe.js @@ -0,0 +1,40 @@ +import '../page.js'; +import { expect, fixture, html } from '@brightspace-ui/testing'; + +describe('page', () => { + + it('single panel', async() => { + const elem = await fixture(html` + +
Header
+
Content
+
Footer
+
+ `); + await expect(elem).to.be.accessible(); + }); + + it('with side-nav panel', async() => { + const elem = await fixture(html` + +
Header
+
Content
+
Side Nav
+
Footer
+
+ `); + await expect(elem).to.be.accessible(); + }); + + it('with supporting panel', async() => { + const elem = await fixture(html` + +
Header
+
Content
+
Supporting
+
Footer
+
+ `); + await expect(elem).to.be.accessible(); + }); +}); diff --git a/components/page/test/page.test.js b/components/page/test/page.test.js new file mode 100644 index 00000000000..2b8bce6f0e7 --- /dev/null +++ b/components/page/test/page.test.js @@ -0,0 +1,10 @@ +import '../page.js'; +import { runConstructor } from '@brightspace-ui/testing'; + +describe('page', () => { + + it('should construct', () => { + runConstructor('d2l-page'); + }); + +}); diff --git a/index.html b/index.html index fdc60242b71..517691d84f9 100644 --- a/index.html +++ b/index.html @@ -153,6 +153,7 @@

Components

  • d2l-more-less
  • d2l-object-property-list
  • d2l-offscreen
  • +
  • d2l-page
  • d2l-progress
  • d2l-overflow-group
  • d2l-pager-load-more
  • diff --git a/lang/ar.js b/lang/ar.js index e76318e0c36..fe4a4c0d3a6 100644 --- a/lang/ar.js +++ b/lang/ar.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "المزيد", "components.object-property-list.item-placeholder-text": "عنصر نائب", "components.overflow-group.moreActions": "مزيد من الإجراءات", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} مادة واحد} diff --git a/lang/ca.js b/lang/ca.js index 569d4558a69..7b465df428a 100644 --- a/lang/ca.js +++ b/lang/ca.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "more", "components.object-property-list.item-placeholder-text": "Placeholder Item", "components.overflow-group.moreActions": "More Actions", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} item} diff --git a/lang/cy.js b/lang/cy.js index 4a2343d3c01..80f1dedb897 100644 --- a/lang/cy.js +++ b/lang/cy.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "mwy", "components.object-property-list.item-placeholder-text": "Eitem Dalfan", "components.overflow-group.moreActions": "Rhagor o Gamau Gweithredu", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} eitem} diff --git a/lang/da.js b/lang/da.js index 5d1b1c5e6df..37c60f9326d 100644 --- a/lang/da.js +++ b/lang/da.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "flere", "components.object-property-list.item-placeholder-text": "Pladsholder-element", "components.overflow-group.moreActions": "Flere handlinger", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} element} diff --git a/lang/de.js b/lang/de.js index 89d29dc533b..80e362ab3a0 100644 --- a/lang/de.js +++ b/lang/de.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "mehr", "components.object-property-list.item-placeholder-text": "Platzhalterelement", "components.overflow-group.moreActions": "Weitere Aktionen", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} Element} diff --git a/lang/en-gb.js b/lang/en-gb.js index 4830e2e5336..26ca60cb2f9 100644 --- a/lang/en-gb.js +++ b/lang/en-gb.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "more", "components.object-property-list.item-placeholder-text": "Placeholder Item", "components.overflow-group.moreActions": "More Actions", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} item} diff --git a/lang/en.js b/lang/en.js index 569d4558a69..7b465df428a 100644 --- a/lang/en.js +++ b/lang/en.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "more", "components.object-property-list.item-placeholder-text": "Placeholder Item", "components.overflow-group.moreActions": "More Actions", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} item} diff --git a/lang/es-es.js b/lang/es-es.js index fff3d714103..cfb60447b5a 100644 --- a/lang/es-es.js +++ b/lang/es-es.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "más", "components.object-property-list.item-placeholder-text": "Elemento de marcador de posición", "components.overflow-group.moreActions": "Más acciones", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} elemento} diff --git a/lang/es.js b/lang/es.js index 22356ee0d91..8a848f05bb4 100644 --- a/lang/es.js +++ b/lang/es.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "más", "components.object-property-list.item-placeholder-text": "Elemento de marcador de posición", "components.overflow-group.moreActions": "Más acciones", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} elemento} diff --git a/lang/fr-fr.js b/lang/fr-fr.js index 6b15ef59e1e..a87745a48b3 100644 --- a/lang/fr-fr.js +++ b/lang/fr-fr.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "plus", "components.object-property-list.item-placeholder-text": "Élément d’espace réservé", "components.overflow-group.moreActions": "Plus d’actions", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} élément} diff --git a/lang/fr.js b/lang/fr.js index 0f3cc881a93..f8979e193f2 100644 --- a/lang/fr.js +++ b/lang/fr.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "plus", "components.object-property-list.item-placeholder-text": "Élément de paramètre fictif", "components.overflow-group.moreActions": "Plus d’actions", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} élément} diff --git a/lang/haw.js b/lang/haw.js index de2d20a99b9..846b1a0ee09 100644 --- a/lang/haw.js +++ b/lang/haw.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "hou aku", "components.object-property-list.item-placeholder-text": "Mea Paʻa Wahi", "components.overflow-group.moreActions": "Nā Hana Hou", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} mea} diff --git a/lang/hi.js b/lang/hi.js index d4a5947e1f7..16303fc1082 100644 --- a/lang/hi.js +++ b/lang/hi.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "अधिक", "components.object-property-list.item-placeholder-text": "प्लेसहोल्डर आइटम", "components.overflow-group.moreActions": "अधिक क्रियाएँ", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} आइटम} diff --git a/lang/ja.js b/lang/ja.js index c8195d72ca8..57ee858f7fb 100644 --- a/lang/ja.js +++ b/lang/ja.js @@ -147,6 +147,8 @@ export default { "components.more-less.more": "増やす", "components.object-property-list.item-placeholder-text": "プレースホルダの項目", "components.overflow-group.moreActions": "その他のアクション", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, other {{countFormatted} 個の項目} diff --git a/lang/ko.js b/lang/ko.js index f4bcf45798a..a32f2ebbc33 100644 --- a/lang/ko.js +++ b/lang/ko.js @@ -147,6 +147,8 @@ export default { "components.more-less.more": "더 보기", "components.object-property-list.item-placeholder-text": "자리표시자 항목", "components.overflow-group.moreActions": "추가 작업", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, other {해당 항목 수 {countFormatted}개} diff --git a/lang/mi.js b/lang/mi.js index 322c2cb3d8a..7dbfbef6103 100644 --- a/lang/mi.js +++ b/lang/mi.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "ētahi atu", "components.object-property-list.item-placeholder-text": "Tūemi Puriwāhi", "components.overflow-group.moreActions": "Ētahi atu Hohenga", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} Tūemi} diff --git a/lang/nl.js b/lang/nl.js index 3d3e9401311..35ca1a3fe25 100644 --- a/lang/nl.js +++ b/lang/nl.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "meer", "components.object-property-list.item-placeholder-text": "Item tijdelijke aanduiding", "components.overflow-group.moreActions": "Meer acties", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} item} diff --git a/lang/pt.js b/lang/pt.js index 9da99f9b552..26ede4348b6 100644 --- a/lang/pt.js +++ b/lang/pt.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "mais", "components.object-property-list.item-placeholder-text": "Item de espaço reservado", "components.overflow-group.moreActions": "Mais ações", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} item} diff --git a/lang/sv.js b/lang/sv.js index 7d107505040..1e9f65dd9b1 100644 --- a/lang/sv.js +++ b/lang/sv.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "mer", "components.object-property-list.item-placeholder-text": "Platshållarobjekt", "components.overflow-group.moreActions": "Fler åtgärder", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} objekt} diff --git a/lang/th.js b/lang/th.js index 69e39a595ce..899f502c5a6 100644 --- a/lang/th.js +++ b/lang/th.js @@ -148,6 +148,8 @@ export default { "components.more-less.more": "เพิ่มเติม", "components.object-property-list.item-placeholder-text": "รายการตัวแทน", "components.overflow-group.moreActions": "การดำเนินการเพิ่มเติม", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, other {{countFormatted} รายการ} diff --git a/lang/tr.js b/lang/tr.js index 9dfe17ae411..e090ada5e4d 100644 --- a/lang/tr.js +++ b/lang/tr.js @@ -152,6 +152,8 @@ export default { "components.more-less.more": "daha fazla", "components.object-property-list.item-placeholder-text": "Yer Tutucu Öğesi", "components.overflow-group.moreActions": "Daha Fazla Eylem", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, one {{countFormatted} öğe} diff --git a/lang/vi.js b/lang/vi.js index 4d038ec17f0..587270ad2de 100644 --- a/lang/vi.js +++ b/lang/vi.js @@ -146,6 +146,8 @@ export default { "components.more-less.more": "thêm", "components.object-property-list.item-placeholder-text": "Mục giữ chỗ", "components.overflow-group.moreActions": "Thêm các Tác vụ", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, other {{countFormatted} mục} diff --git a/lang/zh-cn.js b/lang/zh-cn.js index 3658b14a471..0129e96669a 100644 --- a/lang/zh-cn.js +++ b/lang/zh-cn.js @@ -147,6 +147,8 @@ export default { "components.more-less.more": "更多", "components.object-property-list.item-placeholder-text": "占位符项目", "components.overflow-group.moreActions": "更多操作", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, other {{countFormatted} 项} diff --git a/lang/zh-tw.js b/lang/zh-tw.js index ac27fda0215..54d8b207006 100644 --- a/lang/zh-tw.js +++ b/lang/zh-tw.js @@ -148,6 +148,8 @@ export default { "components.more-less.more": "較多", "components.object-property-list.item-placeholder-text": "預留位置項目", "components.overflow-group.moreActions": "其他動作", + "components.page.header-nav-label": "Main", + "components.page.side-nav-label": "Side", "components.pageable.info": `{count, plural, other {{countFormatted} 個項目} From 5994bb77d5aaa848098cd52378bc3bc6d99a8a68 Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Fri, 1 May 2026 18:33:34 -0400 Subject: [PATCH 02/19] Linting fixes --- components/page/page.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/page/page.js b/components/page/page.js index 8e73b05a63e..a7efbf969b2 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -56,7 +56,7 @@ class Page extends LocalizeCoreElement(LitElement) { display: flex; margin-inline: var(--d2l-page-margin-inline, 0); max-width: var(--d2l-page-content-max-width, 100%); - padding-bottom: var(--d2l-page-footer-height, 0px); /* Reserve space for fixed footer */ + padding-bottom: var(--d2l-page-footer-height, 0); /* Reserve space for fixed footer */ } main { @@ -66,15 +66,15 @@ class Page extends LocalizeCoreElement(LitElement) { .side-nav-panel, .supporting-panel { + height: calc(100vh - var(--d2l-page-footer-height, 0)); overflow-y: auto; position: sticky; top: 0; - height: calc(100vh - var(--d2l-page-footer-height, 0px)); } .page.header-sticky .side-nav-panel, .page.header-sticky .supporting-panel { - top: var(--d2l-page-header-height, 0px); - height: calc(100vh - var(--d2l-page-header-height, 0px) - var(--d2l-page-footer-height, 0px)); + height: calc(100vh - var(--d2l-page-header-height, 0) - var(--d2l-page-footer-height, 0)); + top: var(--d2l-page-header-height, 0); } .divider { From 4c09b8bae2bcedaba8d4324544b94083053b4b4d Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Mon, 4 May 2026 14:45:13 -0400 Subject: [PATCH 03/19] Stacking context adjustments --- components/page/page.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/page/page.js b/components/page/page.js index a7efbf969b2..85618b4b849 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -62,14 +62,18 @@ class Page extends LocalizeCoreElement(LitElement) { main { flex: 1; min-width: 400px; /* TBD */ + overflow: clip; + position: relative; + z-index: 0; } .side-nav-panel, .supporting-panel { height: calc(100vh - var(--d2l-page-footer-height, 0)); - overflow-y: auto; + overflow: clip auto; position: sticky; top: 0; + z-index: 0; } .page.header-sticky .side-nav-panel, .page.header-sticky .supporting-panel { @@ -94,7 +98,7 @@ class Page extends LocalizeCoreElement(LitElement) { inset: auto 0 0; padding: 0.75rem 0; position: fixed; - z-index: 1; /* To be over divider and main contents */ + z-index: 1; /* To be over divider */ } .floating-footer { padding-block-end: 0.75rem; From 3d988dbadc66c8ebc57d856271f0d97992212ec8 Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 17:34:33 -0400 Subject: [PATCH 04/19] Move background to nav --- components/page/demo/temp-nav-styles.js | 1 + components/page/page.js | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/page/demo/temp-nav-styles.js b/components/page/demo/temp-nav-styles.js index 98d89148ef5..6c8163d44f2 100644 --- a/components/page/demo/temp-nav-styles.js +++ b/components/page/demo/temp-nav-styles.js @@ -45,6 +45,7 @@ export const navStyles = css` /* Full Nav Styles */ .full-nav-wrapper { + background-color: white; position: relative; } .full-nav-header { diff --git a/components/page/page.js b/components/page/page.js index 85618b4b849..544400509dd 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -44,7 +44,6 @@ class Page extends LocalizeCoreElement(LitElement) { } .header { - background-color: white; z-index: 2; /* To be over divider and main contents */ } .page.header-sticky .header { From afe40b1e212c9cd4faaaee001d3e071810448a16 Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 17:45:52 -0400 Subject: [PATCH 05/19] Remove stacking contexts and any z-index values not proven to be needed yet --- components/page/page.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/components/page/page.js b/components/page/page.js index 544400509dd..dc62fb8e2d3 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -43,12 +43,10 @@ class Page extends LocalizeCoreElement(LitElement) { --d2l-page-footer-max-width: 100%; } - .header { - z-index: 2; /* To be over divider and main contents */ - } .page.header-sticky .header { position: sticky; top: 0; + z-index: 15; /* To be over sticky content of our core components */ } .content { @@ -62,8 +60,6 @@ class Page extends LocalizeCoreElement(LitElement) { flex: 1; min-width: 400px; /* TBD */ overflow: clip; - position: relative; - z-index: 0; } .side-nav-panel, @@ -72,7 +68,6 @@ class Page extends LocalizeCoreElement(LitElement) { overflow: clip auto; position: sticky; top: 0; - z-index: 0; } .page.header-sticky .side-nav-panel, .page.header-sticky .supporting-panel { @@ -84,7 +79,6 @@ class Page extends LocalizeCoreElement(LitElement) { background-color: var(--d2l-color-gypsum); flex: none; width: 4px; - z-index: 1; } .footer:not([hidden]), @@ -97,7 +91,6 @@ class Page extends LocalizeCoreElement(LitElement) { inset: auto 0 0; padding: 0.75rem 0; position: fixed; - z-index: 1; /* To be over divider */ } .floating-footer { padding-block-end: 0.75rem; From cb0fe913ae5c2e67866e425bc01f1efc1d15516e Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 18:02:03 -0400 Subject: [PATCH 06/19] Unset overflow for main --- components/page/page.js | 1 - 1 file changed, 1 deletion(-) diff --git a/components/page/page.js b/components/page/page.js index dc62fb8e2d3..450d71a8744 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -59,7 +59,6 @@ class Page extends LocalizeCoreElement(LitElement) { main { flex: 1; min-width: 400px; /* TBD */ - overflow: clip; } .side-nav-panel, From b1eb358266c468cf57be26b6a7a394e658712e7d Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 18:02:21 -0400 Subject: [PATCH 07/19] Better min behaviour for now --- components/page/demo/temp-nav-styles.js | 1 + components/page/page.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/page/demo/temp-nav-styles.js b/components/page/demo/temp-nav-styles.js index 6c8163d44f2..da3a126dd38 100644 --- a/components/page/demo/temp-nav-styles.js +++ b/components/page/demo/temp-nav-styles.js @@ -110,6 +110,7 @@ export const navStyles = css` .full-nav-footer-inner { align-items: center; display: flex; + flex-wrap: wrap; gap: 4px; margin-inline: var(--d2l-page-margin-inline); max-width: var(--d2l-page-header-max-width); diff --git a/components/page/page.js b/components/page/page.js index 450d71a8744..ef417d34ef0 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -58,7 +58,7 @@ class Page extends LocalizeCoreElement(LitElement) { main { flex: 1; - min-width: 400px; /* TBD */ + min-width: min(400px, 100%); /* Actual min width TBD */ } .side-nav-panel, From 398112c5af3617fd73ebc41aaf85dae05cc55ab4 Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 18:11:47 -0400 Subject: [PATCH 08/19] Add demo title --- components/page/demo/page.html | 1 + 1 file changed, 1 insertion(+) diff --git a/components/page/demo/page.html b/components/page/demo/page.html index f31638807b9..b1638548781 100644 --- a/components/page/demo/page.html +++ b/components/page/demo/page.html @@ -1,6 +1,7 @@ + d2l-page From 7bb5ab3cd23a0a08a97c26cd37d9f4c64705352e Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 18:12:04 -0400 Subject: [PATCH 09/19] Cleanup demo controls --- components/page/demo/page-component.js | 39 +++++++++++++------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/components/page/demo/page-component.js b/components/page/demo/page-component.js index 5aa62dc03e5..6483266d547 100644 --- a/components/page/demo/page-component.js +++ b/components/page/demo/page-component.js @@ -54,7 +54,6 @@ class PageDemo extends LitElement { #handleAllowThreePanelsChange(e) { this._allowThreePanels = e.target.on; if (!this._allowThreePanels && this.hasSideNavPanel && this.hasSupportingPanel) { - this.shadowRoot.querySelector('#switch-supporting-panel').on = false; this.hasSupportingPanel = false; } } @@ -69,10 +68,8 @@ class PageDemo extends LitElement { if (this._allowThreePanels) return; if (e.target.on && key === 'hasSideNavPanel' && this.hasSupportingPanel) { - this.shadowRoot.querySelector('#switch-supporting-panel').on = false; this.hasSupportingPanel = false; } else if (e.target.on && key === 'hasSupportingPanel' && this.hasSideNavPanel) { - this.shadowRoot.querySelector('#switch-side-nav-panel').on = false; this.hasSideNavPanel = false; } } @@ -81,6 +78,25 @@ class PageDemo extends LitElement { this.widthType = e.target.value; } + #renderDemoMainControls() { + return this.demoMode ? html` + +
    + + + + + + +
    +
    + ` : nothing; + } + #renderFooter() { return this.hasFooter ? html`
    @@ -149,22 +165,7 @@ class PageDemo extends LitElement { #renderMainPanel() { return html`
    - ${this.demoMode ? html` - -
    - - - - - - -
    -
    - ` : nothing} + ${this.#renderDemoMainControls()}

    I'm in the default slot of the d2l-page component!

    End of Content
    From 59495f89a5a7c9fab7f76af527098c15d50f743f Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 18:26:41 -0400 Subject: [PATCH 10/19] Set --d2l-page-header-height to 0 when header is not sticky --- components/page/page.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/components/page/page.js b/components/page/page.js index ef417d34ef0..f31acd92714 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -63,14 +63,9 @@ class Page extends LocalizeCoreElement(LitElement) { .side-nav-panel, .supporting-panel { - height: calc(100vh - var(--d2l-page-footer-height, 0)); + height: calc(100vh - var(--d2l-page-header-height, 0) - var(--d2l-page-footer-height, 0)); overflow: clip auto; position: sticky; - top: 0; - } - .page.header-sticky .side-nav-panel, - .page.header-sticky .supporting-panel { - height: calc(100vh - var(--d2l-page-header-height, 0) - var(--d2l-page-footer-height, 0)); top: var(--d2l-page-header-height, 0); } @@ -109,7 +104,7 @@ class Page extends LocalizeCoreElement(LitElement) { this.#resizeObserver = new ResizeObserver(entries => { for (const entry of entries) { if (entry.target.classList.contains('header')) { - const height = entry.target.offsetHeight; + const height = this._headerIsSticky ? entry.target.offsetHeight : 0; this.style.setProperty('--d2l-page-header-height', `${height}px`); } else if (entry.target.classList.contains('footer')) { const height = entry.target.classList.contains('fixed-footer') ? entry.target.offsetHeight : 0; From d04f7d67dd8c2a1312e05734468e27391d87f9d4 Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 18:31:41 -0400 Subject: [PATCH 11/19] requestUpdate not needed since we're replacing the object --- components/page/page.js | 1 - 1 file changed, 1 deletion(-) diff --git a/components/page/page.js b/components/page/page.js index f31acd92714..4df1c36aaf4 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -194,7 +194,6 @@ class Page extends LocalizeCoreElement(LitElement) { const key = e.target.name; const nodes = e.target.assignedNodes(); this._slotVisibility = { ...this._slotVisibility, [key]: nodes.length !== 0 }; - this.requestUpdate(); } #renderFloatingButtons(footerContents) { From 551d5c72d87a45b8b7873d9a88f331a903ed540a Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 18:32:08 -0400 Subject: [PATCH 12/19] Move observe to connectedCallback --- components/page/page.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/components/page/page.js b/components/page/page.js index 4df1c36aaf4..2186d186b91 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -116,20 +116,18 @@ class Page extends LocalizeCoreElement(LitElement) { connectedCallback() { super.connectedCallback(); - } - - disconnectedCallback() { - super.disconnectedCallback(); - this.#resizeObserver.disconnect(); - } - firstUpdated() { const header = this.shadowRoot.querySelector('.header'); const footer = this.shadowRoot.querySelector('.footer'); if (header) this.#resizeObserver.observe(header); if (footer) this.#resizeObserver.observe(footer); } + disconnectedCallback() { + super.disconnectedCallback(); + this.#resizeObserver.disconnect(); + } + render() { const pageClasses = { 'page': true, From 93af9b4ce58d70d2c27162bbfffe87cadf604714 Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 18:38:47 -0400 Subject: [PATCH 13/19] Pull render pieces out into their own functions --- components/page/page.js | 82 ++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/components/page/page.js b/components/page/page.js index 2186d186b91..52ba8a31f45 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -134,48 +134,15 @@ class Page extends LocalizeCoreElement(LitElement) { 'header-sticky': this._headerIsSticky }; - const header = html` -
    - -
    `; - - const mainContent = html` -
    - -
    `; - - const sideNavPanel = html` - - ${this._slotVisibility['side-nav'] ? html`
    ` : nothing} - `; - - const supportingPanel = html` - ${this._slotVisibility['supporting'] ? html`
    ` : nothing} - `; - - const fixedFooter = this._slotVisibility['side-nav'] || this._slotVisibility['supporting']; - const footerContainerClasses = { 'footer': true, 'fixed-footer': fixedFooter }; - const footerContents = html``; - const footer = html` -
    - ${fixedFooter ? footerContents : this.#renderFloatingButtons(footerContents)} -
    `; - return html`
    - ${header} + ${this.#renderHeader()}
    - ${sideNavPanel} - ${mainContent} - ${supportingPanel} + ${this.#renderSideNavPanel()} +
    + ${this.#renderSupportingPanel()}
    - ${footer} + ${this.#renderFooter()}
    `; } @@ -205,6 +172,45 @@ class Page extends LocalizeCoreElement(LitElement) { `; } + #renderFooter() { + const fixedFooter = this._slotVisibility['side-nav'] || this._slotVisibility['supporting']; + const footerContainerClasses = { 'footer': true, 'fixed-footer': fixedFooter }; + const footerContents = html``; + return html` +
    + ${fixedFooter ? footerContents : this.#renderFloatingButtons(footerContents)} +
    + `; + } + + #renderHeader() { + return html` +
    + +
    + `; + } + + #renderSideNavPanel() { + return html` + + ${this._slotVisibility['side-nav'] ? html`
    ` : nothing} + `; + } + + #renderSupportingPanel() { + return html` + ${this._slotVisibility['supporting'] ? html`
    ` : nothing} + + `; + } + } customElements.define('d2l-page', Page); From e66ae7135deb38443fe6663ef9ee430e6bfd5a07 Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 18:48:20 -0400 Subject: [PATCH 14/19] Revert "Move observe to connectedCallback" This reverts commit 551d5c72d87a45b8b7873d9a88f331a903ed540a. --- components/page/page.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/page/page.js b/components/page/page.js index 52ba8a31f45..b1ff21b7c48 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -116,11 +116,6 @@ class Page extends LocalizeCoreElement(LitElement) { connectedCallback() { super.connectedCallback(); - - const header = this.shadowRoot.querySelector('.header'); - const footer = this.shadowRoot.querySelector('.footer'); - if (header) this.#resizeObserver.observe(header); - if (footer) this.#resizeObserver.observe(footer); } disconnectedCallback() { @@ -128,6 +123,13 @@ class Page extends LocalizeCoreElement(LitElement) { this.#resizeObserver.disconnect(); } + firstUpdated() { + const header = this.shadowRoot.querySelector('.header'); + const footer = this.shadowRoot.querySelector('.footer'); + if (header) this.#resizeObserver.observe(header); + if (footer) this.#resizeObserver.observe(footer); + } + render() { const pageClasses = { 'page': true, From 919577eeb514be303647dfb881ba040fcf05adf5 Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 19:11:24 -0400 Subject: [PATCH 15/19] Save padding for the d2l-page-footer component --- components/page/page.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/components/page/page.js b/components/page/page.js index b1ff21b7c48..cc17e0fc0b5 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -86,9 +86,6 @@ class Page extends LocalizeCoreElement(LitElement) { padding: 0.75rem 0; position: fixed; } - .floating-footer { - padding-block-end: 0.75rem; - } .footer-contents { margin-inline: var(--d2l-page-margin-inline, 0); max-width: var(--d2l-page-footer-max-width, 100%); @@ -168,7 +165,7 @@ class Page extends LocalizeCoreElement(LitElement) { return html`
    - + ${footerContents}
    `; From d609d926db47a71cf421f8244acd0cfca232eead Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 19:11:54 -0400 Subject: [PATCH 16/19] Adjust description Co-authored-by: Dave Lockhart --- components/page/page.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/page/page.js b/components/page/page.js index cc17e0fc0b5..9b3efef9acd 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -4,7 +4,7 @@ import { classMap } from 'lit/directives/class-map.js'; import { LocalizeCoreElement } from '../../helpers/localize-core-element.js'; /** - * Page template with header, optional footer and optional navigation panel or supporting panel + * Component for laying out a page, with header, optional footer and optional navigation or supporting panels * @slot - The main content of the page (expecting d2l-page-main) * @slot header - The header content of the page (expecting d2l-page-header-*) * @slot side-nav - The side navigation content of the page (expecting d2l-page-side-nav) From 20a6859912289ff858a9f752ceec29ae639d134c Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 22:21:48 -0400 Subject: [PATCH 17/19] Re-arrange demo to make cleaner next PR --- components/page/demo/page-component.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/page/demo/page-component.js b/components/page/demo/page-component.js index 6483266d547..03fd59ddc2b 100644 --- a/components/page/demo/page-component.js +++ b/components/page/demo/page-component.js @@ -164,11 +164,11 @@ class PageDemo extends LitElement { #renderMainPanel() { return html` -
    - ${this.#renderDemoMainControls()} +

    I'm in the default slot of the d2l-page component!

    + ${this.#renderDemoMainControls()} +
    End of Content
    -
    End of Content
    `; } From c86d89018c0088cdac5ac471c1ab10ea6a8ad286 Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Tue, 5 May 2026 22:32:59 -0400 Subject: [PATCH 18/19] Footer needs z-index --- components/page/page.js | 1 + 1 file changed, 1 insertion(+) diff --git a/components/page/page.js b/components/page/page.js index 9b3efef9acd..1ad2ee4c90c 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -85,6 +85,7 @@ class Page extends LocalizeCoreElement(LitElement) { inset: auto 0 0; padding: 0.75rem 0; position: fixed; + z-index: 10; /* To be over sticky content of our core components */ } .footer-contents { margin-inline: var(--d2l-page-margin-inline, 0); From 1a9239338713c5612a5cec6f563f113d603d57cd Mon Sep 17 00:00:00 2001 From: Stacey Van Herk <13419300+svanherk@users.noreply.github.com> Date: Wed, 6 May 2026 09:30:30 -0400 Subject: [PATCH 19/19] Add colors import, remove empty constructor --- components/page/page.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/components/page/page.js b/components/page/page.js index 1ad2ee4c90c..9157c2a78af 100644 --- a/components/page/page.js +++ b/components/page/page.js @@ -1,3 +1,4 @@ +import '../colors/colors.js'; import '../button/floating-buttons.js'; import { css, html, LitElement, nothing } from 'lit'; import { classMap } from 'lit/directives/class-map.js'; @@ -112,10 +113,6 @@ class Page extends LocalizeCoreElement(LitElement) { }); } - connectedCallback() { - super.connectedCallback(); - } - disconnectedCallback() { super.disconnectedCallback(); this.#resizeObserver.disconnect();