Skip to content

Commit

Permalink
AppFrame component (#2147)
Browse files Browse the repository at this point in the history
* Add AppFrame component

* Please stylelint

* Update src/layout/app-frame.scss

Co-authored-by: Katie Langerman <[email protected]>

* Use tokens

* Add changeset

Co-authored-by: Katie Langerman <[email protected]>
  • Loading branch information
vdepizzol and langermank authored Jul 1, 2022
1 parent ee85a4b commit 9dd2a49
Show file tree
Hide file tree
Showing 4 changed files with 303 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/lovely-rivers-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/css": minor
---

Add AppFrame component
142 changes: 142 additions & 0 deletions docs/src/stories/components/Layout/AppFrame.stories.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import React from 'react'
import clsx from 'clsx'
//import { AppHeaderTemplate as AppHeader } from '../App/AppHeader.stories'

export default {
title: 'Components/Layout/AppFrame',
parameters: {
layout: 'fullscreen'
},

excludeStories: ['AppFrameTemplate'],
argTypes: {

// Debug

_debug: {
control: {
type: 'boolean',
}
},

a11yNavItems: {
type: 'array',
},

// Children

headerChildren: {
description: 'creates a slot for header children',
table: {
category: 'HTML'
}
},
subheaderChildren: {
description: 'creates a slot for subheader children',
table: {
category: 'HTML'
}
},
bodyChildren: {
description: 'creates a slot for body children',
table: {
category: 'HTML'
}
},
footerChildren: {
description: 'creates a slot for footer children',
table: {
category: 'HTML'
}
},
},
}

export const AppFrameTemplate = ({
_debug,
a11yNavItems,
headerChildren,
subheaderChildren,
bodyChildren,
footerChildren,
}) => {

// Default values
a11yNavItems = a11yNavItems ?? [
{url: '#start-of-content', label: 'Skip to content'},
{url: '/', label: 'GitHub homepage'},
];

return (
<>
<div className={clsx('AppFrame')}>

<div className={clsx('AppFrame-a11yNav')}>
{a11yNavItems.map(link => (
<a className={clsx('AppFrame-a11yLink')} href={link.url}>{link.label}</a>
))}
</div>

<div className={clsx('AppFrame-main')}>

<div className={clsx('AppFrame-header-wrapper')}>

<div className={clsx('AppFrame-header')}>
{headerChildren}
</div>

<div id="start-of-content"></div>

{subheaderChildren && (
<div className={clsx('AppFrame-subheader')}>
{subheaderChildren}
</div>
)}

</div>
<div className={clsx('AppFrame-body')}>
{bodyChildren}
</div>
</div>
<div className={clsx('AppFrame-footer')}>
{footerChildren}
</div>
</div>

{_debug && (
<>
<style type="text/css">{`
.AppFrame {
}
.AppFrame-header,
.AppFrame-subheader,
.AppFrame-body,
.AppFrame-footer {
padding: 16px;
}
.AppFrame-header {
background: pink;
}
.AppFrame-subheader {
background: lightblue;
}
.AppFrame-footer {
background: pink;
}
`}</style>
</>
)}
</>
);
};

export const Playground = AppFrameTemplate.bind({})

Playground.args = {
_debug: true,
headerChildren: "Header slot",
subheaderChildren: "Subheader slot",
bodyChildren: "Body slot",
footerChildren: "Footer slot",
};
155 changes: 155 additions & 0 deletions src/layout/app-frame.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// stylelint-disable max-nesting-depth
// stylelint-disable primer/spacing
// stylelint-disable primer/borders

.AppFrame {

// AppFrame structure
// ===================
//
// .AppFrame
// ├─ .AppFrame-a11yNav
// │ ├─ .AppFrame-a11yLink
//
// ├─ .AppFrame-main
// │ ├─ .AppFrame-header-wrapper
// │ │ ├─ .AppFrame-header
// │ │ ├─ .AppFrame-subheader
// │ │
// │ ├─ #start-of-content
// │ ├─ .AppFrame-body
// │ ├─ .AppFrame-footer

// Accessibility navigation

.AppFrame-a11yNav {
position: absolute;
z-index: 1000;
display: flex;
width: 100%;
padding: var(--base-size-16, 16px);
background: var(--color-canvas-inset);
padding-block-end: calc(var(--base-size-16, 16px) - var(--primer-borderWidth-thin, 1px));
isolation: isolate;
align-items: center;
gap: var(--base-size-8, 8px);

&:not(:focus-within) {
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
border: 0;
}

&:focus-within {
top: 0;
left: 0;

// Narrow viewport
@media (max-width: #{map-get($breakpoints, 'md') - 0.02px}) {
justify-content: center;
}
}
}

.AppFrame-a11yLink {
transition: none;

&:not(:focus) {
display: block;
width: var(--base-size-8, 8px);
height: var(--base-size-8, 8px);
overflow: hidden;
text-indent: var(--base-size-128, 128px);
pointer-events: none;
background: var(--color-border-default);
border-radius: var(--primer-borderRadius-full, 100vh);
}

&:focus {
z-index: 20;
display: grid;
width: auto;
height: auto;
min-height: var(--primer-control-medium-size, 32px);
padding: 0 var(--primer-control-medium-paddingInline-spacious, 16px);
overflow: auto;
color: var(--color-fg-on-emphasis);
background: var(--color-accent-emphasis);
border-radius: var(--primer-borderRadius-full, 100vh);
align-items: center;

@media (pointer: coarse) {
&::after {
@include minTouchTarget(var(--primer-control-minTarget-coarse, 44px));
}
}

@media (prefers-reduced-motion: no-preference) {
animation: AppFrame-a11yLink-focus 200ms ease-out;
}

@keyframes AppFrame-a11yLink-focus {
0% {
color: var(--color-accent-emphasis);
transform: scale(0.3, 0.25);
}

50% {
color: var(--color-accent-emphasis);
transform: scale(1, 1);
}

55% {
color: var(--color-fg-on-emphasis);
}

100% {
transform: scaleX(1);
}
}
}
}

.AppFrame-main {
display: flex;
min-height: 100vh;
flex-direction: column;

@supports (height: 100dvh) {
min-height: 100dvh;
}
}

.AppFrame-header-wrapper {
position: relative;
height: min-content;
overflow: visible;

.AppFrame-header {
position: sticky;
top: 0;
z-index: 1;
}
}

.AppFrame-header {
flex: 0 0 auto;
}

.AppFrame-subheader {
flex: 0 0 auto;
}

.AppFrame-body {
flex: 1 0;
height: 100%;
}

.AppFrame-footer {
flex: 0 0 auto;
}
}
1 change: 1 addition & 0 deletions src/layout/index.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import '../support/index.scss';
@import './app-frame.scss';
@import './mixins.scss';
@import './container.scss';
@import './grid.scss';
Expand Down

0 comments on commit 9dd2a49

Please sign in to comment.