mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 04:09:12 +00:00
add layout toggling (#294)
* Add nav toggling * fix comments * fix comments * prettier * add comments / docs * prettier * fix up page stuff * prettier * Add comment * minor fixes * prettier
This commit is contained in:
@@ -85,7 +85,7 @@
|
||||
</head>
|
||||
<body class="layout-{{ layout | stripExtension }}">
|
||||
<!-- use view="desktop" as default to reduce layout jank on desktop site. -->
|
||||
<wa-page view="desktop">
|
||||
<wa-page view="desktop" disable-navigation-toggle="">
|
||||
<header slot="header">
|
||||
{# Logo #}
|
||||
<div id="docs-branding">
|
||||
@@ -93,6 +93,7 @@
|
||||
<wa-button appearance="text" size="small" data-toggle-nav>
|
||||
<wa-icon name="bars" label="Toggle navigation"></wa-icon>
|
||||
</wa-button>
|
||||
|
||||
<a href="/" aria-label="Web Awesome">
|
||||
<span class="only-desktop">{% include "logo.njk" %}</span>
|
||||
<span class="only-mobile">{% include "logo-simple.njk" %}</span>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<legend>Slots</legend>
|
||||
<div class="options">
|
||||
{% for slot in slots %}
|
||||
{% if slot.name != "skip-to-content" %}
|
||||
{% if (slot.name != "skip-to-content") and (slot.name != "navigation-toggle-icon") %}
|
||||
<wa-checkbox name="slot" value="{{ slot.name }}" {{ 'checked' if slot.name != "menu" | safe}} class="{{ 'default' if not slot.name }}"
|
||||
data-description="{{ slot.description | inlineMarkdown }}" title="{{ slot.description | inlineMarkdown | striptags | safe }}">
|
||||
{{ slot.name or "(default)" }}
|
||||
|
||||
@@ -46,7 +46,7 @@ The following sections of a page are "sticky" by default, meaning they remain in
|
||||
- `banner`
|
||||
- `header`
|
||||
- `sub-header`
|
||||
- `navigation` (or `menu`)
|
||||
- `menu` (`navigation` itself is not sticky, but its parent `menu` is)
|
||||
- `aside`
|
||||
|
||||
This is often desirable, but you can change this behavior using the `disable-sticky` attribute. Use a space-delimited list of names to tell the page which sections should not be sticky.
|
||||
@@ -795,4 +795,4 @@ A sample media app page using `header`, `navigation-header`, `main-header`, and
|
||||
padding: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
```
|
||||
@@ -48,6 +48,7 @@ export default css`
|
||||
flex-wrap: wrap;
|
||||
gap: var(--wa-space-m);
|
||||
padding: var(--wa-space-m);
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
::slotted([slot='subheader']) {
|
||||
@@ -169,6 +170,12 @@ export default css`
|
||||
}
|
||||
[part~='header'] {
|
||||
top: var(--banner-height);
|
||||
|
||||
/** Make the header flex so that you don't unexpectedly have the default toggle button appearing above a slotted div because block elements are fun. */
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
[part~='subheader'] {
|
||||
top: calc(var(--header-height) + var(--banner-height));
|
||||
@@ -246,12 +253,34 @@ export default css`
|
||||
[part~='drawer']::part(dialog) {
|
||||
background-color: var(--wa-color-surface-default);
|
||||
}
|
||||
|
||||
/* Set these on the slot because we don't always control the navigation-toggle since that may be slotted. */
|
||||
slot[name~='navigation-toggle'],
|
||||
:host([disable-navigation-toggle]) slot[name~='navigation-toggle'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Sometimes the media query in the viewport is stubborn in iframes. This is an extra check to make it behave properly. */
|
||||
:host(:not([disable-navigation-toggle])[view='mobile']) slot[name~='navigation-toggle'] {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
[part~='navigation-toggle'] {
|
||||
/* Use only a margin-inline-start because the slotted header is expected to have default padding so it looks really awkward if this sets a margin-inline-end and the slotted header has a padding-inline-start. */
|
||||
margin-inline-start: var(--wa-space-m);
|
||||
}
|
||||
`;
|
||||
|
||||
export const mobileStyles = (breakpoint: number) => `
|
||||
@media screen and (
|
||||
max-width: ${(Number.isSafeInteger(breakpoint) ? breakpoint.toString() : '768') + 'px'}
|
||||
) {
|
||||
[part~='navigation'] { display: none; }
|
||||
[part~='navigation'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host(:not([disable-navigation-toggle])) slot[name~='navigation-toggle'] {
|
||||
display: contents;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -36,6 +36,8 @@ if (typeof ResizeObserver === 'undefined') {
|
||||
* @slot navigation-header - The header for a navigation area. On mobile this will be the header for `<wa-drawer>`.
|
||||
* @slot navigation - The main content to display in the navigation area. This is displayed on the left side of the page, if `menu` is not used. This section "sticks" to the top as the page scrolls.
|
||||
* @slot navigation-footer - The footer for a navigation area. On mobile this will be the footer for `<wa-drawer>`.
|
||||
* @slot navigation-toggle - Use this slot to slot in your own button + icon for toggling the navigation drawer. By default it is a `<wa-button>` + a 3 bars `<wa-icon>`
|
||||
* @slot navigation-toggle-icon - Use this to slot in your own icon for toggling the navigation drawer. By default it is 3 bars `<wa-icon>`.
|
||||
* @slot main-header - Header to display inline above the main content.
|
||||
* @slot main-footer - Footer to display inline below the main content.
|
||||
* @slot aside - Content to be shown on the right side of the page. Typically contains a table of contents, ads, etc. This section "sticks" to the top as the page scrolls.
|
||||
@@ -48,8 +50,11 @@ if (typeof ResizeObserver === 'undefined') {
|
||||
* @csspart subheader - Shown below the header, usually intended for things like breadcrumbs and other page level navigation.
|
||||
* @csspart body - The wrapper around menu, main, and aside.
|
||||
* @csspart menu - The left hand side of the page. Generally intended for navigation.
|
||||
* @csspart navigation - The `<nav>` that wraps the navigation slots on desktop viewports.
|
||||
* @csspart navigation-header - The header for a navigation area. On mobile this will be the header for `<wa-drawer>`.
|
||||
* @csspart navigation-footer - The footer for a navigation area. On mobile this will be the footer for `<wa-drawer>`.
|
||||
* @csspart navigation-toggle - The default `<wa-button>` that will toggle the `<wa-drawer>` for mobile viewports.
|
||||
* @csspart navigation-toggle-icon - The default `<wa-icon>` displayed inside of the navigation-toggle button.
|
||||
* @csspart main-header - The header above main content.
|
||||
* @csspart main-content - The main content.
|
||||
* @csspart main-footer - The footer below main content.
|
||||
@@ -89,10 +94,24 @@ export default class WaPage extends WebAwesomeElement {
|
||||
private handleNavigationToggle = (e: Event) => {
|
||||
// Don't toggle the nav when we're in desktop mode
|
||||
if (this.view === 'desktop') {
|
||||
// Just in case, try to hide the navigation.
|
||||
this.hideNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.composedPath().find((el: Element) => el.hasAttribute?.('data-toggle-nav'))) {
|
||||
const path = e.composedPath();
|
||||
|
||||
const navigationToggleSlot = this.navigationToggleSlot;
|
||||
|
||||
if (
|
||||
path.find((el: Element) => {
|
||||
return (
|
||||
el.hasAttribute?.('data-toggle-nav') ||
|
||||
el.assignedSlot === navigationToggleSlot ||
|
||||
el === navigationToggleSlot
|
||||
);
|
||||
})
|
||||
) {
|
||||
e.preventDefault();
|
||||
this.toggleNavigation();
|
||||
}
|
||||
@@ -103,6 +122,7 @@ export default class WaPage extends WebAwesomeElement {
|
||||
@query("[part~='footer']") footer: HTMLElement;
|
||||
@query("[part~='banner']") banner: HTMLElement;
|
||||
@query("[part~='drawer']") navigationDrawer: WaDrawer;
|
||||
@query("slot[name~='navigation-toggle']") navigationToggleSlot: HTMLSlotElement;
|
||||
|
||||
/**
|
||||
* The view is a reflection of the "mobileBreakpoint", when the page is larger than the `mobile-breakpoint` (768px by
|
||||
@@ -127,6 +147,12 @@ export default class WaPage extends WebAwesomeElement {
|
||||
*/
|
||||
@property({ attribute: 'navigation-placement', reflect: true }) navigationPlacement: 'start' | 'end' = 'start';
|
||||
|
||||
/**
|
||||
* Determines whether or not to hide the default hamburger button. This will automatically flip to "true" if you add an element with `data-toggle-nav` anywhere in the element light DOM. Generally this will be set for you and you don't need to do anything, unless you're using SSR, in which case you should set this manually for initial page loads.
|
||||
*/
|
||||
@property({ attribute: 'disable-navigation-toggle', reflect: true, type: Boolean }) disableNavigationToggle: boolean =
|
||||
false;
|
||||
|
||||
pageResizeObserver = new ResizeObserver(entries => {
|
||||
for (const entry of entries) {
|
||||
if (entry.contentBoxSize) {
|
||||
@@ -168,11 +194,21 @@ export default class WaPage extends WebAwesomeElement {
|
||||
|
||||
this.pageResizeObserver.observe(this);
|
||||
|
||||
const navQuery = ":not([slot='toggle-navigation']) [data-toggle-nav]";
|
||||
|
||||
// check once on initial connect
|
||||
// eslint-disable-next-line
|
||||
this.disableNavigationToggle = Boolean(this.querySelector(navQuery));
|
||||
|
||||
setTimeout(() => {
|
||||
this.headerResizeObserver.observe(this.header);
|
||||
this.subheaderResizeObserver.observe(this.subheader);
|
||||
this.bannerResizeObserver.observe(this.banner);
|
||||
this.footerResizeObserver.observe(this.footer);
|
||||
|
||||
// Check again when the element updates
|
||||
// eslint-disable-next-line
|
||||
this.disableNavigationToggle = Boolean(this.querySelector(navQuery));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -235,6 +271,13 @@ export default class WaPage extends WebAwesomeElement {
|
||||
<slot name="banner"></slot>
|
||||
</div>
|
||||
<div class="header" part="header">
|
||||
<slot name="navigation-toggle">
|
||||
<wa-button part="navigation-toggle" size="small" appearance="text" variant="neutral">
|
||||
<slot name="navigation-toggle-icon">
|
||||
<wa-icon name="bars" part="navigation-toggle-icon" label="Toggle navigation drawer"></wa-icon>
|
||||
</slot>
|
||||
</wa-button>
|
||||
</slot>
|
||||
<slot name="header"></slot>
|
||||
</div>
|
||||
<div class="subheader" part="subheader">
|
||||
|
||||
Reference in New Issue
Block a user