Skip to content

Commit 3b9bb87

Browse files
authored
Nse 7726 (#37)
* Added prototype application menu. * Updates to application menu. * Updates for handling real data. * Added CSS arrow to application menu. * Comments and cleanup. * Updated comments. * Minor reformatting. * Incremented version. * Generated lib outputs.
1 parent cb47b81 commit 3b9bb87

File tree

12 files changed

+28735
-81
lines changed

12 files changed

+28735
-81
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/// <reference types="react" />
2+
export default function ApplicationMenu(): JSX.Element | null;
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
"use strict";
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.default = ApplicationMenu;
7+
8+
var _react = _interopRequireDefault(require("react"));
9+
10+
var _styles = require("@material-ui/core/styles");
11+
12+
var _IconButton = _interopRequireDefault(require("@material-ui/core/IconButton"));
13+
14+
var _ClickAwayListener = _interopRequireDefault(require("@material-ui/core/ClickAwayListener"));
15+
16+
var _Paper = _interopRequireDefault(require("@material-ui/core/Paper"));
17+
18+
var _Popper = _interopRequireDefault(require("@material-ui/core/Popper"));
19+
20+
var _Tooltip = _interopRequireDefault(require("@material-ui/core/Tooltip"));
21+
22+
var _Apps = _interopRequireDefault(require("@material-ui/icons/Apps"));
23+
24+
var _Fade = _interopRequireDefault(require("@material-ui/core/Fade"));
25+
26+
var _Launch = _interopRequireDefault(require("@material-ui/icons/Launch"));
27+
28+
var _Card = _interopRequireDefault(require("@material-ui/core/Card"));
29+
30+
var _CardContent = _interopRequireDefault(require("@material-ui/core/CardContent"));
31+
32+
var _Typography = _interopRequireDefault(require("@material-ui/core/Typography"));
33+
34+
var _Grid = _interopRequireDefault(require("@material-ui/core/Grid"));
35+
36+
var _NeonContext = _interopRequireDefault(require("../NeonContext/NeonContext"));
37+
38+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
39+
40+
function _extends() { _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; }; return _extends.apply(this, arguments); }
41+
42+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
43+
44+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
45+
46+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
47+
48+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
49+
50+
function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
51+
52+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
53+
54+
// declare styles
55+
var useStyles = (0, _styles.makeStyles)(function (theme) {
56+
return (0, _styles.createStyles)({
57+
menuContainer: {
58+
zIndex: 1000 // be sure to display the menu over other elements
59+
60+
},
61+
toolbarContainer: {
62+
display: 'flex',
63+
justifyContent: 'space-between',
64+
boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.45)',
65+
// match shadow of site header
66+
position: 'relative'
67+
},
68+
toolbarButtons: {
69+
display: 'flex',
70+
marginLeft: 'auto',
71+
// align content right
72+
marginRight: theme.spacing(2.5),
73+
marginTop: theme.spacing(0.5),
74+
marginBottom: theme.spacing(0.5)
75+
},
76+
paper: {
77+
padding: theme.spacing(4),
78+
maxWidth: '500px',
79+
// limit width of menu
80+
marginTop: theme.spacing(1),
81+
// line top of menu up with divider
82+
overflowX: 'unset',
83+
overflowY: 'unset',
84+
'&::before': {
85+
// add tooltip like arrow to top of menu
86+
content: '""',
87+
position: 'absolute',
88+
marginRight: theme.spacing(4),
89+
// center arrow point beneath menu button
90+
top: 0,
91+
right: 0,
92+
width: theme.spacing(2),
93+
// width of arrow
94+
height: theme.spacing(2),
95+
// height of arrow
96+
backgroundColor: theme.palette.background.paper,
97+
// match paper background
98+
boxShadow: theme.shadows[2],
99+
// add arrow shadow
100+
transform: 'rotate(315deg)',
101+
// point arrow up toward menu button
102+
clipPath: 'polygon(-5px -5px, calc(100% + 5px) -5px, calc(100% + 5px) calc(100% + 5px))'
103+
}
104+
},
105+
card: {
106+
transition: '0.4s',
107+
'&:hover': {
108+
// raised hover effect for Cards
109+
transform: 'translateY(-2px)',
110+
// raise Card
111+
boxShadow: theme.shadows[2] // add shadow
112+
113+
},
114+
cursor: 'pointer',
115+
// visually indicate Cards are links
116+
width: '100%',
117+
// ensure Cards are equal width
118+
border: 0 // remove default Card border
119+
120+
},
121+
cardContent: {
122+
textAlign: 'center'
123+
},
124+
gridItem: {
125+
display: 'flex' // so grid items stretch to equal height
126+
127+
}
128+
});
129+
});
130+
131+
var getApps = function getApps() {
132+
var _authData$userData, _authData$userData$da;
133+
134+
var _NeonContext$useNeonC = _NeonContext.default.useNeonContextState(),
135+
_NeonContext$useNeonC2 = _slicedToArray(_NeonContext$useNeonC, 1),
136+
authData = _NeonContext$useNeonC2[0].auth;
137+
138+
return authData === null || authData === void 0 ? void 0 : (_authData$userData = authData.userData) === null || _authData$userData === void 0 ? void 0 : (_authData$userData$da = _authData$userData.data) === null || _authData$userData$da === void 0 ? void 0 : _authData$userData$da.apps;
139+
}; // define the menu component
140+
141+
142+
var Menu = function Menu(props) {
143+
var apps = props.apps;
144+
var classes = useStyles();
145+
146+
var _React$useState = _react.default.useState(false),
147+
_React$useState2 = _slicedToArray(_React$useState, 2),
148+
open = _React$useState2[0],
149+
setOpen = _React$useState2[1];
150+
151+
var anchorRef = _react.default.useRef(null); // handle menu toggle
152+
153+
154+
var handleToggle = function handleToggle() {
155+
setOpen(function (prevOpen) {
156+
return !prevOpen;
157+
});
158+
}; // close the menu
159+
160+
161+
var handleClose = function handleClose(event) {
162+
if (anchorRef.current && anchorRef.current.contains(event.target)) {
163+
return;
164+
}
165+
166+
setOpen(false);
167+
}; // open menu by tab key
168+
169+
170+
function handleMenuKeyDown(event) {
171+
if (event.key === 'Tab') {
172+
event.preventDefault();
173+
setOpen(false);
174+
}
175+
} // handle a menu selection
176+
177+
178+
var handleMenuItemClick = function handleMenuItemClick(event, url) {
179+
window.location.href = url;
180+
};
181+
182+
return /*#__PURE__*/_react.default.createElement("div", {
183+
className: classes.toolbarContainer
184+
}, /*#__PURE__*/_react.default.createElement("div", {
185+
className: classes.toolbarButtons
186+
}, /*#__PURE__*/_react.default.createElement(_Tooltip.default, {
187+
title: "Neon Applications",
188+
"aria-label": "Neon Applications",
189+
placement: "left",
190+
TransitionComponent: _Fade.default,
191+
TransitionProps: {
192+
timeout: 200
193+
},
194+
arrow: true
195+
}, /*#__PURE__*/_react.default.createElement(_IconButton.default, {
196+
ref: anchorRef,
197+
style: {
198+
color: 'black'
199+
},
200+
"aria-label": "more",
201+
"aria-controls": open ? 'neon-application-menu' : undefined,
202+
"aria-haspopup": "true",
203+
onClick: handleToggle,
204+
onKeyDown: handleMenuKeyDown
205+
}, /*#__PURE__*/_react.default.createElement(_Apps.default, null))), /*#__PURE__*/_react.default.createElement(_Popper.default, {
206+
className: classes.menuContainer,
207+
open: open,
208+
anchorEl: anchorRef.current,
209+
role: "presentation",
210+
transition: true
211+
}, function (_ref) {
212+
var TransitionProps = _ref.TransitionProps,
213+
placement = _ref.placement;
214+
return /*#__PURE__*/_react.default.createElement(_Fade.default, _extends({}, TransitionProps, {
215+
style: {
216+
transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom'
217+
},
218+
timeout: 200
219+
}), /*#__PURE__*/_react.default.createElement(_Paper.default, {
220+
elevation: 3,
221+
className: classes.paper
222+
}, /*#__PURE__*/_react.default.createElement(_ClickAwayListener.default, {
223+
onClickAway: handleClose
224+
}, /*#__PURE__*/_react.default.createElement(_Grid.default, {
225+
container: true,
226+
spacing: 4,
227+
alignItems: "stretch"
228+
}, apps.map(function (app) {
229+
return /*#__PURE__*/_react.default.createElement(_Grid.default, {
230+
item: true,
231+
xs: apps.length === 1 ? 12 : 6,
232+
className: classes.gridItem,
233+
key: app.name
234+
}, /*#__PURE__*/_react.default.createElement(_Card.default, {
235+
onClick: function onClick(event) {
236+
return handleMenuItemClick(event, app.url);
237+
},
238+
key: app.url,
239+
className: classes.card
240+
}, /*#__PURE__*/_react.default.createElement(_CardContent.default, {
241+
className: classes.cardContent
242+
}, /*#__PURE__*/_react.default.createElement(_Launch.default, {
243+
fontSize: "large"
244+
}), /*#__PURE__*/_react.default.createElement(_Typography.default, {
245+
variant: "subtitle1",
246+
gutterBottom: true,
247+
style: {
248+
lineHeight: 1
249+
}
250+
}, app.name), app.description)));
251+
})))));
252+
})));
253+
};
254+
255+
function ApplicationMenu() {
256+
var apps = getApps();
257+
258+
if ((apps === null || apps === void 0 ? void 0 : apps.length) > 0) {
259+
return /*#__PURE__*/_react.default.createElement(Menu, {
260+
apps: apps
261+
});
262+
}
263+
264+
return null;
265+
}

lib/components/NeonHeader/NeonHeader.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ var _NeonEnvironment = _interopRequireDefault(require("../NeonEnvironment/NeonEn
3333

3434
var _NeonContext = _interopRequireWildcard(require("../NeonContext/NeonContext"));
3535

36+
var _ApplicationMenu = _interopRequireDefault(require("./ApplicationMenu"));
37+
3638
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
3739

3840
function _extends() { _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; }; return _extends.apply(this, arguments); }
@@ -64,6 +66,7 @@ var useStyles = (0, _styles.makeStyles)(function (theme) {
6466
skeletonHeader: {
6567
boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.25), 0px 1px 1px rgba(0, 0, 0, 0.25)'
6668
},
69+
// positioning of sign-in and sign-out buttons
6770
coreAuthContainer: (_coreAuthContainer = {
6871
// common styles
6972
textAlign: 'right',
@@ -111,13 +114,20 @@ var useStyles = (0, _styles.makeStyles)(function (theme) {
111114
// Injecting these styles as a means of fixing up the search display
112115
// Ideally, this CSS comes from Drupal and is removed from here...
113116
headerContainer: (_headerContainer = {
117+
// Added menu__link to more closely mimic Drupal site links.
118+
'& .menu__link': {
119+
fontSize: '1.1rem !important',
120+
fontWeight: '700 !important'
121+
},
114122
'& .header__search': {
115123
background: '#f5f6f7',
116124
position: 'relative',
117125
zIndex: 1,
118126
transition: 'all 0.2s ease-in-out',
119127
opacity: 1,
120-
visibility: 'visible'
128+
visibility: 'visible',
129+
fontSize: '1.1rem' // Added, font sizes look bigger on Drupal site.
130+
121131
},
122132
'& .header__search.visually-hidden': {
123133
visibility: 'hidden',
@@ -141,13 +151,16 @@ var useStyles = (0, _styles.makeStyles)(function (theme) {
141151
alignItems: 'center'
142152
},
143153
'& .header__search--inner > .header__search--title': {
144-
fontWeight: '600 !important',
145-
fontSize: '0.9rem !important',
154+
fontWeight: '700 !important',
155+
// Changed from 600 to match Drupal site.
156+
fontSize: '1.2rem !important',
157+
// Changed from 0.9 to match Drupal site.
146158
margin: '0 2.6rem 0 0 !important'
147159
}
148160
}, _defineProperty(_headerContainer, theme.breakpoints.up('lg'), {
149161
'& .header__search--inner > .header__search--title': {
150-
fontSize: '1rem !important'
162+
fontSize: '1.2rem !important' // Changed from 1.0 to match Drupal site.
163+
151164
}
152165
}), _defineProperty(_headerContainer, '& .header__search--inner > .form-item', {
153166
width: '100%',
@@ -416,11 +429,11 @@ var NeonHeader = /*#__PURE__*/(0, _react.forwardRef)(function (props, headerRef)
416429
}
417430
};
418431
var html = renderMode === 'drupal' ? headerHTML : _drupalHeader.default;
419-
return /*#__PURE__*/_react.default.createElement("header", {
432+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("header", {
420433
ref: headerRef,
421434
id: "header",
422435
className: unstickyDrupalHeader ? "".concat(classes.unstickyHeader, " ").concat(classes.headerContainer) : classes.headerContainer
423-
}, (0, _htmlReactParser.default)(html, injectAuth));
436+
}, (0, _htmlReactParser.default)(html, injectAuth)), /*#__PURE__*/_react.default.createElement(_ApplicationMenu.default, null));
424437
});
425438
NeonHeader.propTypes = {
426439
drupalCssLoaded: _propTypes.default.bool,

lib/components/NeonPage/NeonPage.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ var isAtMaxScroll = function isAtMaxScroll() {
128128
return scrollTop / trackLength >= 0.99;
129129
}; // Google Tag Manager Data Layer
130130
// Define if not already defined. This must be set in the public/index.html for any apps/pages that
131-
// would seek top use it. More info: https://developers.google.com/tag-manager/devguide
131+
// would seek to use it. More info: https://developers.google.com/tag-manager/devguide
132132

133133

134134
if (!window.gtmDataLayer) {

lib/remoteAssets/drupal-header.html.d.ts

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

lib/remoteAssets/drupal-header.html.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)