@arcblock/ux 0.78.25 → 1.6.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +0 -56
  3. package/lib/ActionButton/index.js +6 -4
  4. package/lib/ActivityIndicator/index.js +75 -23
  5. package/lib/Alert/index.js +15 -11
  6. package/lib/Async/index.js +1 -1
  7. package/lib/Badge/index.js +17 -15
  8. package/lib/Blocklet/index.js +261 -0
  9. package/lib/Button/wrap.js +96 -43
  10. package/lib/ButtonGroup/index.js +3 -16
  11. package/lib/Center/index.js +30 -4
  12. package/lib/ClickToCopy/index.js +10 -8
  13. package/lib/CodeBlock/index.js +40 -13
  14. package/lib/Colors/index.js +15 -0
  15. package/lib/Colors/themes/default.js +85 -0
  16. package/lib/ContactForm/index.js +9 -10
  17. package/lib/CookieConsent/index.js +98 -0
  18. package/lib/CountDown/index.js +18 -14
  19. package/lib/Dialog/confirm.js +84 -0
  20. package/lib/Dialog/dialog.js +137 -0
  21. package/lib/Dialog/index.js +23 -0
  22. package/lib/Earth/index.js +33 -33
  23. package/lib/Empty/index.js +61 -0
  24. package/lib/Footer/index.js +16 -18
  25. package/lib/Icon/image.js +10 -13
  26. package/lib/Icon/index.js +10 -8
  27. package/lib/Img/index.js +212 -0
  28. package/lib/InfoRow/index.js +7 -6
  29. package/lib/Layout/dashboard/header.js +60 -42
  30. package/lib/Layout/dashboard/index.js +72 -60
  31. package/lib/Layout/dashboard/sidebar.js +41 -25
  32. package/lib/Layout/index.js +113 -51
  33. package/lib/Locale/browser-lang.js +0 -2
  34. package/lib/Locale/context.js +85 -61
  35. package/lib/Locale/selector.js +33 -20
  36. package/lib/Logo/index.js +15 -13
  37. package/lib/Metric/index.js +5 -6
  38. package/lib/NFTDisplay/README.md +59 -0
  39. package/lib/NFTDisplay/aspect-ratio-container.js +52 -0
  40. package/lib/NFTDisplay/broken.js +25 -0
  41. package/lib/NFTDisplay/index.js +317 -0
  42. package/lib/NFTDisplay/loading.js +23 -0
  43. package/lib/NFTDisplay/svg-embedder/img.js +68 -0
  44. package/lib/NFTDisplay/svg-embedder/inline-svg.js +54 -0
  45. package/lib/PageScroller/index.js +10 -11
  46. package/lib/PageScroller/usePrevValue.js +2 -2
  47. package/lib/PricingTable/PricingPlan.js +12 -15
  48. package/lib/PricingTable/index.js +5 -5
  49. package/lib/Result/common.js +176 -0
  50. package/lib/Result/index.js +61 -0
  51. package/lib/Result/result.js +69 -0
  52. package/lib/Result/translations.js +61 -0
  53. package/lib/Screenshot/index.js +14 -13
  54. package/lib/Spinner/index.js +37 -0
  55. package/lib/SplitButton/index.js +126 -0
  56. package/lib/Switch/index.js +107 -0
  57. package/lib/Tabs/index.js +24 -47
  58. package/lib/Tag/index.js +15 -13
  59. package/lib/Terminal/Player.js +43 -45
  60. package/lib/Terminal/index.js +3 -1
  61. package/lib/Terminal/util.js +2 -3
  62. package/lib/TextCollapse/index.js +21 -14
  63. package/lib/Theme/index.js +79 -63
  64. package/lib/Theme/responsiveFontSizes.js +8 -8
  65. package/lib/Toast/index.js +12 -11
  66. package/lib/Util/index.js +197 -26
  67. package/lib/Video/index.js +8 -11
  68. package/lib/Wallet/Action.js +15 -13
  69. package/lib/Wallet/Download.js +60 -58
  70. package/lib/Wallet/Open.js +2 -2
  71. package/lib/WechatPrompt/index.js +10 -10
  72. package/lib/index.js +6 -6
  73. package/lib/withTheme/index.js +5 -17
  74. package/lib/withTracker/error_boundary.js +3 -3
  75. package/lib/withTracker/index.js +6 -7
  76. package/package.json +22 -17
  77. package/src/ActionButton/index.js +65 -0
  78. package/src/ActivityIndicator/index.js +141 -0
  79. package/src/Alert/index.js +104 -0
  80. package/src/Async/index.js +39 -0
  81. package/src/Badge/index.js +71 -0
  82. package/src/Blocklet/index.js +424 -0
  83. package/src/Button/index.js +4 -0
  84. package/src/Button/wrap.js +101 -0
  85. package/src/ButtonGroup/index.js +6 -0
  86. package/src/Center/index.js +40 -0
  87. package/src/ClickToCopy/index.js +90 -0
  88. package/src/CodeBlock/index.js +160 -0
  89. package/src/Colors/index.js +1 -0
  90. package/src/Colors/themes/default.js +54 -0
  91. package/src/ContactForm/index.js +240 -0
  92. package/src/CookieConsent/index.js +90 -0
  93. package/src/CountDown/index.js +151 -0
  94. package/src/Dialog/confirm.js +76 -0
  95. package/src/Dialog/dialog.js +162 -0
  96. package/src/Dialog/index.js +2 -0
  97. package/src/DriftBot/index.js +81 -0
  98. package/src/Earth/countries.json +8057 -0
  99. package/src/Earth/index.js +511 -0
  100. package/src/Earth/util.js +69 -0
  101. package/src/Empty/index.js +41 -0
  102. package/src/Footer/index.js +110 -0
  103. package/src/Icon/image.js +55 -0
  104. package/src/Icon/index.js +69 -0
  105. package/src/Img/index.js +172 -0
  106. package/src/InfoRow/index.js +83 -0
  107. package/src/Layout/dashboard/header.js +157 -0
  108. package/src/Layout/dashboard/index.js +150 -0
  109. package/src/Layout/dashboard/sidebar.js +122 -0
  110. package/src/Layout/index.js +318 -0
  111. package/src/Locale/browser-lang.js +63 -0
  112. package/src/Locale/context.js +94 -0
  113. package/src/Locale/images/globe-dark.png +0 -0
  114. package/src/Locale/images/globe-light.png +0 -0
  115. package/src/Locale/selector.js +135 -0
  116. package/src/Logo/images/logo-dark-text.svg +3 -0
  117. package/src/Logo/images/logo-dark-top.svg +6 -0
  118. package/src/Logo/images/logo-light-text.svg +3 -0
  119. package/src/Logo/images/logo-light-top.svg +6 -0
  120. package/src/Logo/index.js +47 -0
  121. package/src/Metric/index.js +115 -0
  122. package/src/NFTDisplay/README.md +59 -0
  123. package/src/NFTDisplay/aspect-ratio-container.js +34 -0
  124. package/src/NFTDisplay/broken.js +18 -0
  125. package/src/NFTDisplay/index.js +257 -0
  126. package/src/NFTDisplay/loading.js +17 -0
  127. package/src/NFTDisplay/svg-embedder/img.js +36 -0
  128. package/src/NFTDisplay/svg-embedder/inline-svg.js +37 -0
  129. package/src/PageScroller/index.js +342 -0
  130. package/src/PageScroller/usePrevValue.js +12 -0
  131. package/src/PricingTable/PricingPlan.js +112 -0
  132. package/src/PricingTable/index.js +43 -0
  133. package/src/Result/common.js +116 -0
  134. package/src/Result/index.js +31 -0
  135. package/src/Result/result.js +57 -0
  136. package/src/Result/translations.js +56 -0
  137. package/src/Screenshot/devices.css +1366 -0
  138. package/src/Screenshot/index.js +181 -0
  139. package/src/Spinner/index.js +19 -0
  140. package/src/SplitButton/index.js +112 -0
  141. package/src/Switch/index.js +78 -0
  142. package/src/Tabs/index.js +46 -0
  143. package/src/Tag/index.js +73 -0
  144. package/src/Terminal/Player.js +364 -0
  145. package/src/Terminal/index.js +150 -0
  146. package/src/Terminal/player.css +378 -0
  147. package/src/Terminal/util.js +167 -0
  148. package/src/Terminal/xterm.css +171 -0
  149. package/src/TextCollapse/index.js +92 -0
  150. package/src/Theme/index.js +184 -0
  151. package/src/Theme/responsiveFontSizes.js +94 -0
  152. package/src/Toast/index.js +118 -0
  153. package/src/Util/index.js +281 -0
  154. package/src/Video/index.js +72 -0
  155. package/src/Wallet/Action.js +105 -0
  156. package/src/Wallet/Download.js +130 -0
  157. package/src/Wallet/Open.js +50 -0
  158. package/src/Wallet/images/abtwallet.png +0 -0
  159. package/src/Wallet/images/android_download.svg +23 -0
  160. package/src/Wallet/images/app-store.svg +20 -0
  161. package/src/Wallet/images/google-play.svg +70 -0
  162. package/src/WechatPrompt/images/android.png +0 -0
  163. package/src/WechatPrompt/images/ios.png +0 -0
  164. package/src/WechatPrompt/index.js +81 -0
  165. package/src/index.js +63 -0
  166. package/src/withTheme/index.js +72 -0
  167. package/src/withTracker/README.md +34 -0
  168. package/src/withTracker/error_boundary.js +34 -0
  169. package/src/withTracker/index.js +70 -0
  170. package/lib/GraphQLPlayground/graphiql.css +0 -1850
  171. package/lib/GraphQLPlayground/index.js +0 -302
  172. package/lib/GraphQLPlayground/util.js +0 -55
@@ -0,0 +1,150 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import Helmet from 'react-helmet';
4
+ import styled from 'styled-components';
5
+ import Container from '@material-ui/core/Container';
6
+ import Box from '@material-ui/core/Box';
7
+ import Drawer from '@material-ui/core/Drawer';
8
+ import useWindowSize from 'react-use/lib/useWindowSize';
9
+
10
+ import Sidebar from './sidebar';
11
+ import Header from './header';
12
+ import Footer from '../../Footer';
13
+
14
+ const Wrapper = styled.div`
15
+ &.dashboard {
16
+ display: flex;
17
+ flex-direction: column;
18
+ height: 100vh;
19
+ }
20
+ .dashboard__body {
21
+ overflow: hidden;
22
+ flex: 1;
23
+ }
24
+ .dashboard__main {
25
+ display: flex;
26
+ flex-direction: column;
27
+ overflow: auto;
28
+ flex: 1;
29
+ }
30
+ .dashboard__content {
31
+ flex: 1;
32
+ }
33
+ .dashboard__footer {
34
+ padding-left: 30px;
35
+ }
36
+
37
+ .drawerPaper {
38
+ position: relative;
39
+ white-space: nowrap;
40
+ width: 120px;
41
+ background: ${props => props.theme.palette.background.default};
42
+ box-shadow: 2px 16px 10px 0
43
+ rgba(0, 0, 0, ${props => (props.theme.mode === 'light' ? 0.05 : 0.5)});
44
+ border: 0;
45
+ }
46
+ `;
47
+
48
+ export default function Dashboard({
49
+ children,
50
+ title,
51
+ brand,
52
+ description,
53
+ brandAddon,
54
+ headerAddon,
55
+ images,
56
+ links,
57
+ prefix,
58
+ fullWidth,
59
+ contentLayout,
60
+ className,
61
+ homeUrl,
62
+ logo,
63
+ ...rest
64
+ }) {
65
+ const breakpoint = 960;
66
+ const { width } = useWindowSize();
67
+ const [drawerMode, setDrawerMode] = useState(width > breakpoint ? 'permanent' : 'temporary');
68
+ const [drawerOpen, setDrawerOpen] = useState(drawerMode === 'permanent');
69
+
70
+ useEffect(() => {
71
+ const newMode = width > breakpoint ? 'permanent' : 'temporary';
72
+ setDrawerMode(newMode);
73
+ setDrawerOpen(newMode !== 'temporary');
74
+ }, [width]);
75
+
76
+ const onToggleDrawer = () => {
77
+ setDrawerOpen(!drawerOpen);
78
+ };
79
+ const isFullWidth = fullWidth || contentLayout === 'row';
80
+
81
+ return (
82
+ <Wrapper className={`dashboard ${className}`} {...rest}>
83
+ <Helmet title={`${title}-${brand}`} />
84
+
85
+ <Header
86
+ className="dashboard__header"
87
+ onToggleMenu={onToggleDrawer}
88
+ brand={brand}
89
+ brandAddon={brandAddon}
90
+ description={description}
91
+ addons={headerAddon}
92
+ homeUrl={homeUrl}
93
+ logo={logo}
94
+ />
95
+ <Box display="flex" className="dashboard__body">
96
+ <Drawer
97
+ variant={drawerMode}
98
+ className="drawer"
99
+ classes={{ paper: 'drawerPaper' }}
100
+ open={drawerOpen}
101
+ onClose={onToggleDrawer}
102
+ ModalProps={{ disablePortal: true, keepMounted: true }}>
103
+ <Sidebar
104
+ className="dashboard__sidebar"
105
+ images={images}
106
+ links={links}
107
+ prefix={prefix}
108
+ logo={logo}
109
+ />
110
+ </Drawer>
111
+ <Box className="dashboard__main">
112
+ <Container maxWidth={isFullWidth ? false : 'lg'} className="dashboard__content">
113
+ {children}
114
+ </Container>
115
+ <Footer className="dashboard__footer" />
116
+ </Box>
117
+ </Box>
118
+ </Wrapper>
119
+ );
120
+ }
121
+
122
+ Dashboard.propTypes = {
123
+ children: PropTypes.any.isRequired,
124
+ title: PropTypes.string,
125
+ brand: PropTypes.string.isRequired,
126
+ links: PropTypes.array.isRequired,
127
+ images: PropTypes.object.isRequired,
128
+ brandAddon: PropTypes.object,
129
+ description: PropTypes.string.isRequired,
130
+ headerAddon: PropTypes.any,
131
+ prefix: PropTypes.string,
132
+ // 兼容旧版的设置,新版使用 fullWidth 进行设置
133
+ contentLayout: PropTypes.oneOf(['row', 'column']),
134
+ fullWidth: PropTypes.bool,
135
+ className: PropTypes.string,
136
+ homeUrl: PropTypes.string,
137
+ logo: PropTypes.any,
138
+ };
139
+
140
+ Dashboard.defaultProps = {
141
+ title: 'Home',
142
+ contentLayout: 'column',
143
+ headerAddon: null,
144
+ brandAddon: null,
145
+ prefix: '/images',
146
+ fullWidth: false,
147
+ className: '',
148
+ homeUrl: '/',
149
+ logo: null,
150
+ };
@@ -0,0 +1,122 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import styled from 'styled-components';
4
+ import withTheme from '@material-ui/core/styles/withTheme';
5
+
6
+ import { withRouter, Link } from 'react-router-dom';
7
+ import Button from '@material-ui/core/Button';
8
+ import Typography from '@material-ui/core/Typography';
9
+ import teal from '@material-ui/core/colors/teal';
10
+
11
+ import ImageIcon from '../../Icon/image';
12
+ import Logo from '../../Logo';
13
+
14
+ function Sidebar({ location, theme, images, links, prefix, addons, logo, ...rest }) {
15
+ const isSelected = (url, name) => {
16
+ const pattern = new RegExp(`/${name}`);
17
+ return pattern.test(location.pathname);
18
+ };
19
+
20
+ return (
21
+ <MenuItems {...rest}>
22
+ <Link to="/" className="sidebar-logo">
23
+ {logo || <Logo showText={false} size={20} />}
24
+ </Link>
25
+ {links.map(({ url, name, title, showBadge }) => {
26
+ const selected = isSelected(url, name);
27
+ return (
28
+ <MenuItem component={Link} key={url} selected={selected} to={url}>
29
+ <ImageIcon
30
+ name={images[name]}
31
+ size={36}
32
+ color={selected ? '#00c2c4' : theme.typography.color.main}
33
+ prefix={prefix}
34
+ showBadge={showBadge}
35
+ />
36
+ <Typography component="span" className="menu-title">
37
+ {title}
38
+ </Typography>
39
+ </MenuItem>
40
+ );
41
+ })}
42
+ <div style={{ flex: 1 }} />
43
+ {addons}
44
+ </MenuItems>
45
+ );
46
+ }
47
+
48
+ Sidebar.propTypes = {
49
+ location: PropTypes.object.isRequired,
50
+ theme: PropTypes.object.isRequired,
51
+ images: PropTypes.object.isRequired,
52
+ links: PropTypes.array.isRequired,
53
+ prefix: PropTypes.string,
54
+ addons: PropTypes.any,
55
+ logo: PropTypes.any,
56
+ };
57
+
58
+ Sidebar.defaultProps = {
59
+ prefix: '/images',
60
+ addons: null,
61
+ logo: null,
62
+ };
63
+
64
+ const MenuItems = React.memo(styled.div`
65
+ flex: 1;
66
+ display: flex;
67
+ flex-direction: column;
68
+
69
+ && .sidebar-logo {
70
+ display: none;
71
+ border-bottom: 1px solid #eee;
72
+ background: ${props => props.theme.palette.background.default};
73
+ position: sticky;
74
+ top: 0;
75
+ z-index: 1;
76
+ padding: 10px 0;
77
+ text-align: center;
78
+ font-size: 0;
79
+ }
80
+ @media (max-width: ${props => props.theme.breakpoints.values.md}px) {
81
+ && .sidebar-logo {
82
+ display: block;
83
+ }
84
+ }
85
+ `);
86
+
87
+ const gradient = 'linear-gradient(32deg, rgba(144, 255, 230, 0.1), rgba(144, 255, 230, 0))';
88
+
89
+ const MenuItem = styled(Button)`
90
+ && {
91
+ display: block;
92
+ width: 100%;
93
+ transition: all 200ms ease-in-out;
94
+ background: ${props => (props.selected ? gradient : '')};
95
+ padding: 24px 0;
96
+ border-left: 2px solid ${props => (props.selected ? teal.A700 : 'transparent')};
97
+
98
+ &:hover {
99
+ background: ${gradient};
100
+ border-left-color: ${teal.A700};
101
+ }
102
+
103
+ .menu-title {
104
+ margin-top: 8px;
105
+ font-size: 12px;
106
+ font-weight: 500;
107
+ text-align: center;
108
+ text-transform: capitalize;
109
+ letter-spacing: normal;
110
+ width: 80%;
111
+ }
112
+
113
+ .MuiButton-label {
114
+ display: flex;
115
+ flex-direction: column;
116
+ justify-content: center;
117
+ align-items: center;
118
+ }
119
+ }
120
+ `;
121
+
122
+ export default withRouter(withTheme(Sidebar));
@@ -0,0 +1,318 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import styled from 'styled-components';
4
+ import Helmet from 'react-helmet';
5
+ import Link from '@material-ui/core/Link';
6
+
7
+ import AppBar from '@material-ui/core/AppBar';
8
+ import Container from '@material-ui/core/Container';
9
+ import Drawer from '@material-ui/core/Drawer';
10
+ import Divider from '@material-ui/core/Divider';
11
+ import Toolbar from '@material-ui/core/Toolbar';
12
+ import Typography from '@material-ui/core/Typography';
13
+ import List from '@material-ui/core/List';
14
+ import ListItem from '@material-ui/core/ListItem';
15
+ import ListItemText from '@material-ui/core/ListItemText';
16
+ import IconButton from '@material-ui/core/IconButton';
17
+ import MenuIcon from '@material-ui/icons/Menu';
18
+
19
+ import Footer from '../Footer';
20
+ import OpenInWallet from '../Wallet/Open';
21
+ import Icon from '../Icon';
22
+ import Logo from '../Logo';
23
+
24
+ export default function Layout({
25
+ title,
26
+ brand,
27
+ description,
28
+ links,
29
+ logo,
30
+ showLogo,
31
+ addons,
32
+ footer,
33
+ baseUrl,
34
+ homeUrl,
35
+ children,
36
+ variant,
37
+ contentOnly,
38
+ ...rest
39
+ }) {
40
+ const [drawerOpen, setDrawerOpen] = React.useState(false);
41
+ const onToggleDrawer = () => {
42
+ setDrawerOpen(!drawerOpen);
43
+ };
44
+
45
+ if (contentOnly) {
46
+ return <Container>{children}</Container>;
47
+ }
48
+
49
+ let activeLink = '';
50
+ const { pathname: currentPath } = new URL(window.location);
51
+ links.forEach(link => {
52
+ if (currentPath.startsWith(link.url) && link.url.length > activeLink.length) {
53
+ activeLink = link.url;
54
+ }
55
+ });
56
+
57
+ const drawer = (
58
+ <div>
59
+ <Toolbar className="toolbar toolbar--drawer">
60
+ {showLogo ? <div className="menu-logo">{logo}</div> : <></>}
61
+ <div style={{ flexGrow: 1, overflow: 'hidden', textOverflow: 'ellipsis' }}>{brand}</div>
62
+ </Toolbar>
63
+ <Divider />
64
+ <List>
65
+ {links.map(x => (
66
+ <Link className="nav-link" key={x.url} href={x.url}>
67
+ <ListItem button className={activeLink === x.url ? 'drawer-highlight-nav' : ''}>
68
+ <ListItemText>
69
+ {x.icon && (
70
+ <Icon
71
+ name={x.icon}
72
+ size={18 * (x.iconZoom || 1)}
73
+ color="inherit"
74
+ style={{ marginRight: '5px' }}
75
+ />
76
+ )}
77
+ {x.title}
78
+ </ListItemText>
79
+ </ListItem>
80
+ </Link>
81
+ ))}
82
+ </List>
83
+ </div>
84
+ );
85
+
86
+ return (
87
+ <>
88
+ <Div {...rest}>
89
+ <Helmet title={title} />
90
+ <AppBar
91
+ position="fixed"
92
+ className={`appbar appbar--${variant}`}
93
+ color="default"
94
+ style={{ height: 56 }}>
95
+ <Container disableGutters>
96
+ <Toolbar className="toolbar">
97
+ <IconButton
98
+ color="inherit"
99
+ aria-label="open drawer"
100
+ edge="start"
101
+ onClick={onToggleDrawer}
102
+ className="menu-button">
103
+ <MenuIcon />
104
+ </IconButton>
105
+ {showLogo ? <div className="menu-logo">{logo}</div> : <></>}
106
+ <Typography
107
+ href={homeUrl}
108
+ component="a"
109
+ variant="h5"
110
+ color="inherit"
111
+ noWrap
112
+ display="block"
113
+ className="brand">
114
+ {brand}
115
+ </Typography>
116
+ {description && (
117
+ <Typography
118
+ component="small"
119
+ variant="subtitle2"
120
+ color="inherit"
121
+ noWrap
122
+ className="description">
123
+ {description}
124
+ </Typography>
125
+ )}
126
+ <div style={{ flexGrow: 1 }} />
127
+ <div className="nav-links">
128
+ {links.map(x => (
129
+ <Link
130
+ key={x.url}
131
+ href={x.url}
132
+ className={`nav-link ${activeLink === x.url ? 'highlight-nav' : ''}`}
133
+ color={x.color}>
134
+ {x.icon && (
135
+ <Icon
136
+ name={x.icon}
137
+ size={20 * (x.iconZoom || 1)}
138
+ color="inherit"
139
+ style={{ marginRight: '5px' }}
140
+ />
141
+ )}
142
+ {x.title}
143
+ </Link>
144
+ ))}
145
+ </div>
146
+ {addons}
147
+ </Toolbar>
148
+ </Container>
149
+ </AppBar>
150
+ <div className="toolbar" />
151
+ <Container style={{ marginTop: 16, flex: 1 }}>{children}</Container>
152
+ {footer}
153
+ {!!baseUrl && <OpenInWallet locale="zh" link={baseUrl} />}
154
+ </Div>
155
+ <DrawerDiv>
156
+ <Drawer
157
+ variant="temporary"
158
+ open={drawerOpen}
159
+ onClose={onToggleDrawer}
160
+ classes={{
161
+ paper: 'drawer-paper',
162
+ }}
163
+ ModalProps={{
164
+ keepMounted: true, // Better open performance on mobile.
165
+ disablePortal: true,
166
+ }}>
167
+ {drawer}
168
+ </Drawer>
169
+ </DrawerDiv>
170
+ </>
171
+ );
172
+ }
173
+
174
+ Layout.propTypes = {
175
+ title: PropTypes.string.isRequired,
176
+ brand: PropTypes.any.isRequired,
177
+ description: PropTypes.any,
178
+ addons: PropTypes.any,
179
+ showLogo: PropTypes.bool,
180
+ logo: PropTypes.any,
181
+ links: PropTypes.array,
182
+ children: PropTypes.any.isRequired,
183
+ baseUrl: PropTypes.string,
184
+ homeUrl: PropTypes.string,
185
+ variant: PropTypes.oneOf(['shadow', 'border']),
186
+ footer: PropTypes.any,
187
+ contentOnly: PropTypes.bool,
188
+ };
189
+
190
+ Layout.defaultProps = {
191
+ contentOnly: false,
192
+ baseUrl: '',
193
+ homeUrl: '/',
194
+ links: [],
195
+ showLogo: false,
196
+ logo: <Logo showText={false} style={{ width: '40px', height: '40px' }} />,
197
+ variant: 'shadow',
198
+ addons: undefined,
199
+ description: undefined,
200
+ footer: (
201
+ <Container>
202
+ <Footer />
203
+ </Container>
204
+ ),
205
+ };
206
+
207
+ const Div = styled.div`
208
+ width: 100%;
209
+ min-height: 100vh;
210
+ display: flex;
211
+ flex-direction: column;
212
+ .appbar {
213
+ &.appbar--border {
214
+ box-shadow: none;
215
+ &::before {
216
+ content: '';
217
+ position: absolute;
218
+ left: 0;
219
+ right: 0;
220
+ height: 1px;
221
+ bottom: -1px;
222
+ display: block;
223
+ background-color: rgba(0, 0, 0, 0.12);
224
+ }
225
+ }
226
+ }
227
+
228
+ .toolbar {
229
+ min-height: 56px;
230
+ background: inherit;
231
+ white-space: nowrap;
232
+ .menu-logo {
233
+ font-size: 0;
234
+ margin-right: 8px;
235
+ }
236
+
237
+ .nav-links {
238
+ display: flex;
239
+ align-items: center;
240
+ .nav-link {
241
+ margin: 8px 12px;
242
+ font-size: 16px;
243
+ display: flex;
244
+ align-items: center;
245
+ }
246
+
247
+ .highlight-nav {
248
+ font-weight: bolder;
249
+ }
250
+ }
251
+ .brand {
252
+ cursor: pointer;
253
+ text-decoration: none;
254
+ overflow: hidden;
255
+ text-overflow: ellipsis;
256
+ flex-shrink: 1;
257
+ }
258
+ .description {
259
+ color: #999;
260
+ font-size: 15px;
261
+ margin-left: 10px;
262
+ font-weight: normal;
263
+ flex-shrink: 999999;
264
+ }
265
+ }
266
+
267
+ @media (min-width: ${props => props.theme.breakpoints.values.md}px) {
268
+ .toolbar {
269
+ .menu-button {
270
+ display: none;
271
+ }
272
+ .menu-logo {
273
+ & + .brand {
274
+ padding-left: 45px;
275
+ margin-left: -45px;
276
+ }
277
+ }
278
+ }
279
+ }
280
+
281
+ @media (max-width: ${props => props.theme.breakpoints.values.md - 1}px) {
282
+ .toolbar {
283
+ .nav-links,
284
+ .menu-logo,
285
+ .description {
286
+ display: none;
287
+ }
288
+ }
289
+ }
290
+ `;
291
+
292
+ const DrawerDiv = styled.nav`
293
+ width: 240px;
294
+ .drawer-paper {
295
+ width: 240px;
296
+ }
297
+ .toolbar {
298
+ min-height: 56px;
299
+ }
300
+
301
+ a:hover,
302
+ a:active,
303
+ a:visited,
304
+ a:focus {
305
+ text-decoration: none;
306
+ }
307
+
308
+ .drawer-highlight-nav {
309
+ background-color: #eee;
310
+ }
311
+
312
+ .toolbar--drawer {
313
+ font-size: 18px;
314
+ .menu-logo {
315
+ display: inline-flex;
316
+ }
317
+ }
318
+ `;
@@ -0,0 +1,63 @@
1
+ /* eslint-disable no-param-reassign */
2
+ function startsWith(string, target, position) {
3
+ const { length } = string;
4
+ position = position == null ? 0 : position;
5
+ if (position < 0) {
6
+ position = 0;
7
+ } else if (position > length) {
8
+ position = length;
9
+ }
10
+ target = `${target}`;
11
+ // eslint-disable-next-line eqeqeq
12
+ return string.slice(position, position + target.length) == target;
13
+ }
14
+
15
+ function getBrowserLang() {
16
+ if (typeof window === 'undefined') {
17
+ return null;
18
+ }
19
+
20
+ const lang =
21
+ (window.navigator.languages && window.navigator.languages[0]) ||
22
+ window.navigator.language ||
23
+ window.navigator.browserLanguage ||
24
+ window.navigator.userLanguage ||
25
+ window.navigator.systemLanguage ||
26
+ null;
27
+
28
+ return lang;
29
+ }
30
+
31
+ function normalizeCode(code) {
32
+ return (code || '').toLowerCase().replace(/-/, '_');
33
+ }
34
+
35
+ function getPreferredLanguage(options) {
36
+ if (!options) {
37
+ return getBrowserLang();
38
+ }
39
+
40
+ const { languages, fallback } = options;
41
+ if (!options.languages) {
42
+ return fallback;
43
+ }
44
+
45
+ // some browsers report language as en-US instead of en_US
46
+ const browserLanguage = normalizeCode(getBrowserLang());
47
+
48
+ if (!browserLanguage) {
49
+ return fallback;
50
+ }
51
+
52
+ const match = languages.filter(lang => normalizeCode(lang) === browserLanguage);
53
+
54
+ if (match.length > 0) {
55
+ return match[0] || fallback;
56
+ }
57
+
58
+ // en == en_US
59
+ const matchCodeOnly = languages.filter(lang => startsWith(browserLanguage, lang));
60
+ return matchCodeOnly[0] || fallback;
61
+ }
62
+
63
+ export default getPreferredLanguage;