1 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
2 |
|
3 |
|
4 | import cn from 'classnames';
|
5 | import { h, Component } from 'preact';
|
6 | import { LogoDark, LogoTextOnly } from './logo';
|
7 | import { Drawer } from './drawer';
|
8 | import { Shield } from './shield';
|
9 | import { Footer } from './footer';
|
10 | import { TapIconButton } from './button';
|
11 | import omit from './utils/omit';
|
12 | import { throttle } from './utils/throttle';
|
13 |
|
14 | class DrawerContentWrapper extends Component {
|
15 | constructor(props) {
|
16 | super(props);
|
17 | this.handleScroll = throttle(this.handleScroll.bind(this), 200);
|
18 | }
|
19 |
|
20 | handleScroll() {
|
21 | if (!this.base) {
|
22 | return;
|
23 | }
|
24 | const { updateScrolledDown, scrolledDown } = this.props;
|
25 | const { scrollTop } = this.base;
|
26 | if (scrollTop === 0 && scrolledDown) {
|
27 | updateScrolledDown(false);
|
28 | }
|
29 | if (!scrolledDown && scrollTop > 0) {
|
30 | updateScrolledDown(true);
|
31 | }
|
32 | }
|
33 |
|
34 | componentDidMount() {
|
35 | this.base.addEventListener('scroll', this.handleScroll, { passive: true });
|
36 | }
|
37 |
|
38 | componentWillUnMount() {
|
39 | this.base.removeEventListener('scroll', this.handleScroll, {
|
40 | passive: true
|
41 | });
|
42 | }
|
43 |
|
44 | render({ style, children }) {
|
45 | return h(
|
46 | 'div',
|
47 | { className: 'v-scroll h-100 w-100', style: style },
|
48 | children
|
49 | );
|
50 | }
|
51 | }
|
52 |
|
53 | export class AppLayout extends Component {
|
54 | constructor(props) {
|
55 | super(props);
|
56 | this.state = {
|
57 | drawerScrolledDown: false
|
58 | };
|
59 | this.updateScrolledDown = this.updateScrolledDown.bind(this);
|
60 | }
|
61 |
|
62 | updateScrolledDown(scrolledDown) {
|
63 | this.setState({ drawerScrolledDown: scrolledDown });
|
64 | }
|
65 |
|
66 | render(props, { drawerScrolledDown }) {
|
67 | const {
|
68 | drawerOpen,
|
69 | screenIsWide,
|
70 | drawerEnabled,
|
71 | drawerContent,
|
72 | statusBarContent,
|
73 | extraContent,
|
74 | drawerWidth = 256,
|
75 | mainContent,
|
76 | doCloseDrawer,
|
77 | hideFooter,
|
78 | version,
|
79 | logoHref,
|
80 | logoOnClick,
|
81 | preventScroll
|
82 | } = props;
|
83 |
|
84 | const rest = omit(props, ['drawerOpen', 'screenIsWide', 'drawerEnabled', 'drawerContent', 'statusBarContent', 'extraContent', 'drawerWidth', 'mainContent', 'doCloseDrawer', 'hideFooter', 'version', 'logoHref', 'logoOnClick', 'preventScroll']);
|
85 |
|
86 | const drawerAlwaysVisible = drawerEnabled && screenIsWide;
|
87 | const useFloatingDrawer = drawerEnabled && !screenIsWide;
|
88 | const showShield = useFloatingDrawer && drawerOpen;
|
89 | const floatingDrawerHidden = useFloatingDrawer && !drawerOpen;
|
90 |
|
91 | const leftMarginStyles = drawerAlwaysVisible ? {
|
92 | width: `calc(100% - ${drawerWidth}px)`,
|
93 | marginLeft: `${drawerWidth}px`
|
94 | } : {
|
95 | width: '100%'
|
96 | };
|
97 |
|
98 | if (showShield || preventScroll) {
|
99 | document.body.classList.add('overflow-hidden');
|
100 | } else {
|
101 | document.body.classList.remove('overflow-hidden');
|
102 | }
|
103 |
|
104 | const drawerHeaderHeightPx = (drawerAlwaysVisible ? 80 : 60) + 'px';
|
105 |
|
106 | const logoClasses = cn({ pointer: logoHref || logoOnClick });
|
107 |
|
108 | return h(
|
109 | 'div',
|
110 | _extends({ className: 'bg-near-white dark-blue sans-serif min-vh-100' }, rest),
|
111 | statusBarContent && h(
|
112 | 'div',
|
113 | {
|
114 | className: 'sticky no-print top-0 bg-light-gray z-1 shadow-1',
|
115 | style: leftMarginStyles
|
116 | },
|
117 | statusBarContent
|
118 | ),
|
119 | drawerEnabled && h(
|
120 | Drawer,
|
121 | {
|
122 | 'aria-hidden': floatingDrawerHidden,
|
123 | className: useFloatingDrawer ? 'z-4 transition' : '',
|
124 | style: {
|
125 | width: `${drawerWidth}px`,
|
126 | transform: floatingDrawerHidden ? `translateX(${-drawerWidth}px)` : null
|
127 | }
|
128 | },
|
129 | h(
|
130 | 'div',
|
131 | {
|
132 | className: cn('absolute left-0 bg-dark-blue z-1 top-0 pa2 pa3-l', { 'shadow-1': drawerScrolledDown }),
|
133 | style: {
|
134 | width: `${drawerWidth}px`,
|
135 | height: drawerHeaderHeightPx
|
136 | }
|
137 | },
|
138 | screenIsWide && h(
|
139 | 'a',
|
140 | {
|
141 | className: cn('db link white', logoClasses),
|
142 | href: logoHref,
|
143 | onClick: logoOnClick
|
144 | },
|
145 | h(LogoDark, null)
|
146 | ),
|
147 | !screenIsWide && h(
|
148 | 'div',
|
149 | { className: 'flex items-center justify-between' },
|
150 | h(TapIconButton, {
|
151 | icon: 'close',
|
152 | color: 'white',
|
153 | className: 'flex-shrink-0',
|
154 | onClick: e => {
|
155 | e.preventDefault();
|
156 | doCloseDrawer();
|
157 | }
|
158 | }),
|
159 | h(
|
160 | 'a',
|
161 | {
|
162 | className: logoClasses,
|
163 | href: logoHref,
|
164 | onClick: logoOnClick
|
165 | },
|
166 | h(LogoTextOnly, {
|
167 | className: 'mh3',
|
168 | style: { paddingTop: '6px', width: '168px' }
|
169 | })
|
170 | )
|
171 | )
|
172 | ),
|
173 | h(
|
174 | DrawerContentWrapper,
|
175 | {
|
176 | scrolledDown: drawerScrolledDown,
|
177 | updateScrolledDown: this.updateScrolledDown,
|
178 | style: {
|
179 | paddingTop: drawerHeaderHeightPx,
|
180 | paddingBottom: '120px'
|
181 | }
|
182 | },
|
183 | drawerContent
|
184 | )
|
185 | ),
|
186 | showShield && h(Shield, {
|
187 | className: 'z-3 dn-l',
|
188 | onClick: () => doCloseDrawer && doCloseDrawer()
|
189 | }),
|
190 | h(
|
191 | 'main',
|
192 | {
|
193 | style: leftMarginStyles,
|
194 | className: 'bg-nearly-white overflow-x-hidden'
|
195 | },
|
196 | mainContent,
|
197 | hideFooter !== true && h(Footer, { version: version })
|
198 | ),
|
199 | extraContent
|
200 | );
|
201 | }
|
202 | } |
\ | No newline at end of file |