Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add two sidecar layouts to layout component #586

Merged
merged 20 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/dry-elephants-provide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@microsoft/atlas-site': minor
'@microsoft/atlas-css': minor
---

Add sidecar-left and sidecar-right layouts and relevant documentation.
107 changes: 92 additions & 15 deletions css/src/components/layout.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
@use 'sass:math';

$quarter-widescreen: math.div($breakpoint-widescreen, 4);
$half-widescreen: math.div($breakpoint-widescreen, 2);
$three-quarters-widescreen: math.div($breakpoint-widescreen, 4) * 3;

.layout {
display: flex;
flex-direction: column;
Expand All @@ -15,6 +19,14 @@
}
}

.layout-padding {
padding-inline: var(#{$layout-gap-custom-property-name}) !important;
}

.layout-margin {
margin-inline: var(#{$layout-gap-scalable-custom-property-name}) !important;
}

.layout-body {
display: grid;
width: 100%;
Expand Down Expand Up @@ -47,6 +59,16 @@
grid-area: footer;
}

.layout-body-hero,
.layout-body-main,
.layout-body-footer,
.layout-body-aside,
.layout-body-menu {
&:empty {
display: none;
}
}

.layout,
.layout.layout-single {
.layout-body {
Expand Down Expand Up @@ -79,11 +101,8 @@
'footer footer footer';
}

$widescreen-side-columns-width: math.div($breakpoint-widescreen, 4);
$widescreen-main-width: math.div($breakpoint-widescreen, 2);

@include widescreen {
grid-template: auto auto 1fr auto / auto #{$widescreen-side-columns-width} #{$widescreen-main-width} #{$widescreen-side-columns-width} auto;
grid-template: auto auto 1fr auto / auto #{$quarter-widescreen} #{$half-widescreen} #{$quarter-widescreen} auto;
grid-template-areas:
'header header header header header'
'hero hero hero hero hero'
Expand All @@ -93,20 +112,78 @@
}
}

.layout-padding {
padding-inline: var(#{$layout-gap-custom-property-name}) !important;
}
.layout.layout-sidecar-left {
.layout-body-aside {
display: none;
}

.layout-margin {
margin-inline: var(#{$layout-gap-scalable-custom-property-name}) !important;
.layout-body {
grid-template: auto auto auto 1fr auto / 1fr;
grid-template-areas: 'header' 'hero' 'menu' 'main' 'footer';

@include tablet {
grid-template: auto auto 1fr auto / 1fr 2fr;
grid-template-areas:
'header header'
'hero hero'
'menu main'
'footer footer';
}

@include desktop {
grid-template: auto auto 1fr auto / 1fr 3fr;
grid-template-areas:
'header header'
'hero hero'
'menu main'
'footer footer';
}

@include widescreen {
grid-template: auto auto 1fr auto / auto #{$quarter-widescreen} #{$three-quarters-widescreen} auto;
grid-template-areas:
'header header header header'
'hero hero hero hero'
'. menu main .'
'footer footer footer footer';
}
}
}

.layout-body-hero,
.layout-body-main,
.layout-body-footer,
.layout-body-aside,
.layout-body-menu {
&:empty {
.layout.layout-sidecar-right {
.layout-body-menu {
display: none;
}

.layout-body {
grid-template: auto auto auto 1fr auto / 1fr;
grid-template-areas: 'header' 'hero' 'main' 'aside' 'footer';

@include tablet {
grid-template: auto auto 1fr auto / 2fr 1fr;
grid-template-areas:
'header header'
'hero hero'
'main aside '
'footer footer';
}

@include desktop {
grid-template: auto auto 1fr auto / 3fr 1fr;
grid-template-areas:
'header header'
'hero hero'
'main aside '
'footer footer';
}

@include widescreen {
grid-template: auto auto 1fr auto / auto #{$three-quarters-widescreen} #{$quarter-widescreen} auto;
grid-template-areas:
'header header header header'
'hero hero hero hero'
'. main aside .'
'footer footer footer footer';
}
}
}
88 changes: 85 additions & 3 deletions site/src/components/layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ This page is utilizing the holy grail layout, but you can use the buttons below
<div class="buttons buttons-addons margin-top-sm display-inline-flex">
<button class="button" data-set-layout="layout-holy-grail" aria-pressed="true">Holy grail</button>
<button class="button" data-set-layout="layout-single">Single</button>
<button class="button" data-set-layout="layout-sidecar-left">Sidecar left</button>
<button class="button" data-set-layout="layout-sidecar-right">Sidecar right</button>
</div>
<button class="button margin-top-sm" data-toggle-debug aria-pressed="false">Toggle container labels</button>

Expand Down Expand Up @@ -68,18 +70,21 @@ There are two available layouts.

- [`layout-single`](#layout-single)
- [`layout-holy-grail`](#holy-grail-layout)
- [`layout-sidecar-left`](#sidecar-left-layout)
- [`layout-sidecar-right`](#sidecar-right-layout)

### Layout Single

The `layout-single` class provides a simple stacked layout. It is equivalent to a series of marginless and paddingless stacked block level elements. All elements in a single layout should set their own margin somewhere within their nested containers. Most likely, you'll want to apply `.layout-margin` or some other container-like class to elements within the single layout. This is also the default layout that will render if no other class is provide.

How do I apply it? `layout-single` to the `layout` element.

Required elements: all, except `layout-body-hero`.
Required elements: all except `layout-body-hero`.

Allowed elements: all.

```Text
Narrow
┌────────────┐
│ Header │
├────────────┤
Expand All @@ -106,12 +111,15 @@ The specification for this layout is as follows.
Named after a layout that [historically was difficult to implement](<https://en.wikipedia.org/wiki/Holy_grail_(web_design)>) the holy grail is stacked on narrow widths and progressively shows up to three columns as the screen widens.

How do I apply it? `layout-holy-grail` to the `layout` element.
Required elements: all, except `layout-body-hero`.

Required elements: all except `layout-body-hero`.

Allowed elements: all.

The following block is arranged from narrow widths on the left to wider widths on the right.

```Text
Narrow Tablet Widescreen
┌────────────┐ ┌──────────────┐ ┌──────────────────────┐
│ Header │ │Header │ │ Header │
├────────────┤ ├──────────────┤ ├──────────────────────┤
Expand All @@ -136,6 +144,80 @@ The specification for this layout is as follows.
| Desktop | Menu, main, aside are side by side. Main is wider than menu. |
| Widescreen | Same as desktop with scaling gutter that keeps combined width of menu, main, aside to the width of the widescreen breakpoint. |

### Sidecar left layout

A "sidecar" is a smaller companion container that sits beside the main content container on tablet screens and wider. In `layout-sidecar-left` the sidecar refers to the `layout-body-menu` element, which sits to the left of `layout-body-main`. Unlike other layouts, this layout does not allow the usage of the `layout-body-aside` containers.

How do I apply it? `layout-sidecar-left` to the `layout` element.
wibjorn marked this conversation as resolved.
Show resolved Hide resolved

Required elements: all except `layout-body-hero` and `layout-body-aside` (see allowed elements).

Allowed elements: all except `layout-body-aside`.

The following block is arranged from narrow widths on the left to wider widths on the right.

```txt
homing1 marked this conversation as resolved.
Show resolved Hide resolved
Narrow Tablet Widescreen
┌────────────┐ ┌──────────────┐ ┌──────────────────────┐
│ Header │ │Header │ │ Header │
├────────────┤ ├──────────────┤ ├──────────────────────┤
│ Hero │ │Hero │ │ Hero │
├────────────┤ ├─────┬────────┤ ├──────┬───────────────┤
│ Menu │ │Menu │ Main │ │ Menu │ Main │
├────────────┤ │ │ │ │ │ │
│ Main │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
├────────────┤ ├─────┴────────┤ ├──────┴───────────────┤
│ Footer │ │Footer │ │ Footer │
└────────────┘ └──────────────┘ └──────────────────────┘
```

The specification for this layout is as follows.

| Screensize | Behavior |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Narrow | All elements are stacked. |
| Tablet - desktop | Menu and main are side by side. Main is wider than menu. |
| Widescreen | Same as tablet-desktop with scaling gutter that keeps combined width of menu and main to the width of the widescreen breakpoint. |

### Sidecar right layout

The "sidecar" remains as defined in the section above, but in `layout-sidecar-right` the sidecar refers to the `layout-body-aside` element, which sits to the right of `layout-body-main` on tablet screens and wider. Unlike other layouts, this layout does not allow the usage of the `layout-body-menu` containers.

How do I apply it? `layout-sidecar-right` to the `layout` element.

Required elements: all except `layout-body-hero` and `layout-body-menu` (see allowed elements).

Allowed elements: all except `layout-body-menu`.

The following block is arranged from narrow widths on the left to wider widths on the right.

```txt
Narrow Tablet Widescreen
┌──────────────┐ ┌──────────────────────┐ ┌──────────────────────┐
disimmon marked this conversation as resolved.
Show resolved Hide resolved
│Header │ │ Header │ │ Header │
├──────────────┤ ├──────────────────────┤ ├──────────────────────┤
│Hero │ │ Hero │ │ Hero │
├──────────────┤ ├───────────────┬──────┤ ├───────────────┬──────┤
│Main │ │ Main │ Aside│ │ Main │ Aside│
│ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
├──────────────┤ │ │ │ │ │ │
│Aside │ │ │ │ │ │ │
├──────────────┤ ├───────────────┴──────┤ ├───────────────┴──────┤
│Footer │ │ Footer │ │ Footer │
└──────────────┘ └──────────────────────┘ └──────────────────────┘
```

The specification for this layout is as follows.

| Screensize | Behavior |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Narrow | All elements are stacked. |
| Tablet - desktop | Main and aside are side by side. Main is wider than aside. |
| Widescreen | Same as tablet-desktop with scaling gutter that keeps combined width of main and aside to the width of the widescreen breakpoint. |

## Accessibility Concerns

### ARIA landmarks
Expand All @@ -161,7 +243,7 @@ Because layouts generally contain the same elements and because the current layo

```JavaScript
document.documentElement.classList.remove('layout-single');
document.documentElement.classList.remove('layout-holy-grail');
document.documentElement.classList.add('layout-holy-grail');
```

You'll seldom have occasion to do this in the middle of a user's visit, but it can be useful for things like opening a code editor in a wider layout or adopting a focused reading mode.
15 changes: 1 addition & 14 deletions site/src/scaffold/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,11 @@
@import './styles/overflow.scss';
@import './styles/code-block.scss';
@import './styles/burger.scss';
@import './styles/layout-buttons.scss';

// hack to mark markdown logo on '/' look a tad different, excludes header logo
main img[src^='/atlas-light.'] {
width: 64px;
height: auto;
margin-bottom: 18px;
}

.layout-single {
[data-set-layout='layout-single'] {
@extend .button-primary;
@extend .button-filled;
}
}

.layout-holy-grail {
[data-set-layout='layout-holy-grail'] {
@extend .button-primary;
@extend .button-filled;
}
}
7 changes: 6 additions & 1 deletion site/src/scaffold/scripts/layout-page.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
const layoutsClasses = ['layout-single', 'layout-holy-grail'];
const layoutsClasses = [
'layout-single',
'layout-holy-grail',
'layout-sidecar-left',
'layout-sidecar-right'
];

// A function that removes all classes that begin with layout- on the html element
function setLayoutClass(layoutToSet: string) {
Expand Down
18 changes: 9 additions & 9 deletions site/src/scaffold/scripts/mobile-navigation.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
export function handleFullScreenNavButton() {
addEventListener('fullscreenchange', () => {
const isFullScreened = !document.fullscreenElement;
const navContent = document.getElementById('nav-content') as HTMLElement;
const nav = document.getElementById('nav');
const navContent = document.getElementById('menu-content') as HTMLElement;
const nav = document.getElementById('menu');
if (!nav) {
throw new Error('Need an element with an id of #nav before we can show a mobile menu');
}
if (!navContent) {
throw new Error('Trying to modify classes on #nav-content, which does not exist.');
throw new Error('Trying to modify classes on #menu-content, which does not exist.');
}
const innerNavButton = nav.querySelector('[data-full-screen-nav]') as HTMLElement;
if (!innerNavButton) {
Expand All @@ -27,7 +27,7 @@ export function handleFullScreenNavButton() {
document.addEventListener(
'fullscreenchange',
() => {
const nav = document.getElementById('nav');
const nav = document.getElementById('menu');
if (!nav) {
throw new Error('Need an element with an id of #nav before we can show a mobile menu');
}
Expand All @@ -43,9 +43,9 @@ export function handleFullScreenNavButton() {
return;
}

const navContent = document.getElementById('nav-content') as HTMLElement;
const navContent = document.getElementById('menu-content') as HTMLElement;
if (!navContent) {
throw new Error('Trying to modify classes on #nav-content, which does not exist.');
throw new Error('Trying to modify classes on #menu-content, which does not exist.');
}

const innerNavButton = nav.querySelector('[data-full-screen-nav]') as HTMLElement;
Expand All @@ -67,14 +67,14 @@ export function handleFullScreenNavButton() {
if (!trigger) {
return;
}
const nav = document.getElementById('nav');
const nav = document.getElementById('menu');
if (!nav) {
throw new Error('Need an element with an id of #nav before we can show a mobile menu');
}

const navContent = document.getElementById('nav-content') as HTMLElement;
const navContent = document.getElementById('menu-content') as HTMLElement;
if (!navContent) {
throw new Error('Trying to modify classes on #nav-content, which does not exist.');
throw new Error('Trying to modify classes on #menu-content, which does not exist.');
}

const innerNavButton = nav.querySelector('[data-full-screen-nav]') as HTMLElement;
Expand Down
2 changes: 1 addition & 1 deletion site/src/scaffold/standard.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ <h1 class="font-size-h1 font-weight-semibold">Missing h1</h1>

<nav id="menu" class="layout-body-menu background-color-body">
{{#toc}}
<div id="nav-content" class="display-none display-block-tablet layout-padding padding-block-md">
<div id="menu-content" class="display-none display-block-tablet layout-padding padding-block-md">
<button data-full-screen-nav class="display-none burger button button-clear position-fixed margin-right-sm margin-top-sm top-0 right-0" aria-label="Mobile menu toggle">
<span class="burger-top"></span>
<span class="burger-middle"></span>
Expand Down
4 changes: 4 additions & 0 deletions site/src/scaffold/styles/layout-buttons.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[data-set-layout][aria-pressed='true'] {
@extend .button-primary;
@extend .button-filled;
}
Loading
Loading