<Layout />

A responsive layout that adapts to screen size and orientation, ensuring consistency. Comes with an flexible Side Drawer out of the box.

Component

1import React, { Fragment, useState, useEffect, useMemo } from "react";
2import Header from "./Components/Header";
3import Main from "./Components/Main";
4import Sidebar from "./Components/Sidebar";
5import "./Styles/_layout.scss";
6
7export default function Layout({ children, ...props }) {
8 const { type, header, sidebar, main } = props.Components;
9
10 const [visible, setVisible] = useState(type === "PERSISTENT" ? true : false);
11
12 const isLarge = useMediaMatch("(min-width: 1040px)");
13
14 return (
15 <Fragment>
16 <Header callback={() => setVisible((visible) => !visible)}>
17 {header.component}
18 </Header>
19 <div className="Layout">
20 <Sidebar
21 callback={() => setVisible(false)}
22 isLarge={isLarge}
23 type={type}
24 backdrop={false}
25 visible={visible}>
26 {sidebar.component}
27 </Sidebar>
28
29 <Main type={type} visible={visible}>
30 {main.component}
31 </Main>
32 </div>
33 </Fragment>
34 );
35}
36
37Layout.defaultProps = {
38 Components: {
39 type: "PERSISTENT",
40 header: {
41 component: <></>,
42 },
43 sidebar: {
44 component: <></>,
45 },
46 main: {
47 component: <></>,
48 },
49 },
50};
51
52function useMediaMatch(query) {
53 const matchMedia = useMemo(() => window.matchMedia(query), [query]);
54 const [matches, setMatches] = useState(() => matchMedia.matches);
55
56 useEffect(() => {
57 setMatches(matchMedia.matches);
58 const listener = (event_) => setMatches(event_.matches);
59
60 if (matchMedia.addEventListener) {
61 matchMedia.addEventListener("change", listener);
62
63 return () => matchMedia.removeEventListener("change", listener);
64 } else {
65 matchMedia.addEventListener(listener);
66
67 return () => matchMedia.removeListener(listener);
68 }
69 }, [matchMedia]);
70
71 return matches;
72}

Styles

1$properties: (
2 breakpoints: (
3 medium: 65em,
4 ),
5 header: (
6 min-height: 50px,
7 height: 50px,
8 bgclr: hsl(156, 7%, 14%),
9 ),
10 sidebar: (
11 width: 280px,
12 max-width: 70%,
13 bgclr: hsl(40, 89%, 61%),
14 zIndex: 150,
15 ),
16 main: (
17 bgclr: hsl(199, 53%, 79%),
18 ),
19 navbar: (
20 min-height: 40px,
21 height: 45px,
22 max-height: 50px,
23 ),
24);
25
26.Layout {
27 display: flex;
28 margin-top: map-get($properties, header, height);
29 min-height: calc(100vh - map-get($properties, header, height));
30
31 @media only screen and (min-width: map-get($properties, breakpoints, medium)) {
32 }
33}
34
35.Header {
36 position: fixed;
37 top: 0;
38 right: 0;
39 left: 0;
40 z-index: 100;
41 min-height: map-get($properties, header, min-height);
42 height: map-get($properties, header, height);
43 background: map-get($properties, header, bgclr);
44
45 @media only screen and (min-width: map-get($properties, breakpoints, medium)) {
46 }
47}
48
49.Drawer {
50 position: fixed;
51 left: 0px;
52 height: 100%;
53 width: map-get($properties, sidebar, width);
54 max-width: map-get($properties, sidebar, max-width);
55 background: map-get($properties, sidebar, bgclr);
56 z-index: map-get($properties, sidebar, zIndex);
57
58 transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1),
59 visibility 0s linear 0.25s;
60
61 &__Toggle {
62 height: 100%;
63 width: 50px;
64 display: flex;
65 align-items: center;
66 justify-content: center;
67
68 & > i {
69 color: white;
70 font-size: x-large;
71 cursor: pointer;
72 }
73 }
74
75 &__Backdrop {
76 position: fixed;
77 top: 0;
78 left: 0;
79 bottom: 0;
80 right: 0;
81 z-index: 100;
82 background-color: hsla(0, 0%, 96%, 0.502);
83
84 @media only screen and (min-width: map-get($properties, breakpoints, medium)) {
85 display: none;
86 }
87 }
88}
89
90.Persistent,
91.Temporary {
92 @extend .Drawer;
93}
94
95.Persistent {
96 transform: translateX(0);
97 &.close {
98 transform: translateX(-100%);
99 }
100}
101
102.Temporary {
103 top: 0px;
104 transform: translateX(-100%);
105
106 &.open {
107 transform: translateX(0);
108 transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1),
109 visibility 0s linear 0s;
110 }
111}
112
113.Main {
114 background: map-get($properties, main, bgclr);
115 margin-left: 0;
116 width: 100%;
117
118 @media only screen and (min-width: map-get($properties, breakpoints, medium)) {
119 }
120
121 &.persitent-active {
122 transition: margin-left 0.25s cubic-bezier(0.4, 0, 0.2, 1),
123 visibility 0s linear 0s;
124 @media only screen and (min-width: map-get($properties, breakpoints, medium)) {
125 margin-left: map-get($properties, sidebar, width);
126 }
127 }
128
129 &.persitent-inactive {
130 transition: margin-left 0.25s cubic-bezier(0.4, 0, 0.2, 1),
131 visibility 0s linear 0.25s;
132 }
133}

Usage

1