diff --git a/src/App.scss b/src/App.scss index 61c7c71..658d09f 100755 --- a/src/App.scss +++ b/src/App.scss @@ -11,3 +11,5 @@ $input-focus-box-shadow: $input-box-shadow; // hack to get upgrade to paragon 4. @import "~@edx/frontend-component-footer/src/lib/scss/site-footer"; @import "./components/Gradebook/gradebook"; +@import "./components/Drawer/Drawer"; + diff --git a/src/components/Drawer/Drawer.scss b/src/components/Drawer/Drawer.scss new file mode 100644 index 0000000..372d273 --- /dev/null +++ b/src/components/Drawer/Drawer.scss @@ -0,0 +1,48 @@ +$drawer-width: 350px; + +.drawer-contents { + overflow-x: auto; + transition: margin 300ms cubic-bezier(0.4,0,0.2,1); + margin-left: 0; + .drawer.open + & { + margin-left: $drawer-width; + } + &.opened { + width: calc(100vw - #{$drawer-width}); + } +} + +.drawer-contents { + overflow-x: auto; + transition: margin 300ms cubic-bezier(0.4,0,0.2,1); + margin-left: 0; + .drawer.open + & { + margin-left: $drawer-width; + } + &.opened { + width: calc(100vw - #{$drawer-width}); + } +} + +.drawer-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + padding: 15px; +} + +.drawer-container .collapsible { + margin-bottom: 1em; +} + +.drawer { + height: 100%; + width: $drawer-width; + position: absolute; + transform: translateX(-$drawer-width); + flex-direction: column; + transition: transform 300ms cubic-bezier(0.4,0,0.2,1); + &.open { + transform: translateX(0%); + } +} diff --git a/src/components/Drawer/index.jsx b/src/components/Drawer/index.jsx new file mode 100644 index 0000000..d626750 --- /dev/null +++ b/src/components/Drawer/index.jsx @@ -0,0 +1,86 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { Button } from '@edx/paragon'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faTimes } from '@fortawesome/free-solid-svg-icons'; + +export default class Drawer extends React.Component { + constructor(props) { + super(props); + this.state = { + open: props.initiallyOpen, + transitioning: false, + }; + } + + deferToNextRepaint(callback) { + window.requestAnimationFrame(() => + window.setTimeout(callback, 0)); + } + + close = () => { + if (this.state.open) { + this.toggleOpen(); + } + }; + + toggleOpen = () => { + this.setState({ transitioning: true }); + // defer the transition to the next repaint so we can be sure that + // opening drawer is visible before it transitions + // (the start state of the opening animation doesn't work if the element starts hidden) + this.deferToNextRepaint(() => this.setState(prevState => ({ open: !prevState.open }))); + }; + + handleSlideDone = (e) => { + if (e.currentTarget === e.target) { + this.setState({ transitioning: false }); + } + }; + + render() { + return ( +