@financial-times/dotcom-ui-header 4.1.0 → 5.1.0
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.
- package/dist/node/components/drawer/additionalPartials.js +3 -1
- package/dist/node/components/drawer/topLevelPartials.js +2 -0
- package/dist/node/components/navigation/partials.js +2 -21
- package/dist/node/components/sticky/partials.js +17 -7
- package/dist/node/components/top/partials.js +42 -6
- package/dist/node/index.js +1 -1
- package/package.json +5 -5
- package/src/components/drawer/additionalPartials.tsx +9 -1
- package/src/components/drawer/topLevelPartials.tsx +9 -1
- package/src/components/navigation/partials.tsx +16 -40
- package/src/components/sticky/partials.tsx +42 -15
- package/src/components/top/partials.tsx +103 -10
- package/src/index.tsx +1 -1
- package/src/interfaces.d.ts +1 -0
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.EditionsSwitcher = exports.DrawerSpecialItem = exports.DrawerSingleItem = exports.DrawerParentItem = void 0;
|
|
6
|
+
exports.SubscribeButton = exports.EditionsSwitcher = exports.DrawerSpecialItem = exports.DrawerSingleItem = exports.DrawerParentItem = void 0;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const utils_1 = require("../../utils");
|
|
9
9
|
exports.DrawerParentItem = ({ item, idSuffix }) => {
|
|
@@ -34,3 +34,5 @@ exports.EditionsSwitcher = (editions) => (react_1.default.createElement("ul", {
|
|
|
34
34
|
name,
|
|
35
35
|
" Edition")));
|
|
36
36
|
})));
|
|
37
|
+
exports.SubscribeButton = (action) => (react_1.default.createElement("div", { className: "o-header__drawer-actions" },
|
|
38
|
+
react_1.default.createElement("a", { className: "o-header__drawer-button", role: "button", href: action.url, "data-trackable": "subscribe-button" }, action.name)));
|
|
@@ -10,11 +10,13 @@ const IncludeDrawer = (props) => react_1.default.createElement(Drawer, Object.as
|
|
|
10
10
|
exports.IncludeDrawer = IncludeDrawer;
|
|
11
11
|
const Drawer = (props) => {
|
|
12
12
|
const editions = props.data.editions;
|
|
13
|
+
const subscribeAction = props.data.subscribeAction;
|
|
13
14
|
const [primary, secondary, tertiary] = props.data.drawer.items;
|
|
14
15
|
const user = props.userIsLoggedIn ? props.data.user : props.data.anon;
|
|
15
16
|
return (react_1.default.createElement("div", { className: "o-header__drawer", id: "o-header-drawer", role: "navigation", "aria-label": "Drawer menu", "data-o-header-drawer": true, "data-o-header-drawer--no-js": true, "data-trackable": "drawer", "data-trackable-terminate": true },
|
|
16
17
|
react_1.default.createElement("div", { className: "o-header__drawer-inner" },
|
|
17
18
|
react_1.default.createElement(DrawerTools, Object.assign({}, editions)),
|
|
19
|
+
!props.userIsSubscribed && subscribeAction && react_1.default.createElement(additionalPartials_1.SubscribeButton, Object.assign({}, subscribeAction)),
|
|
18
20
|
react_1.default.createElement(Search, null),
|
|
19
21
|
react_1.default.createElement("nav", { className: "o-header__drawer-menu o-header__drawer-menu--primary o-header__drawer-menu--border" },
|
|
20
22
|
editions && react_1.default.createElement(additionalPartials_1.EditionsSwitcher, Object.assign({}, editions)),
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.MobileNav = exports.UserActionsNav = exports.
|
|
6
|
+
exports.MobileNav = exports.UserActionsNav = exports.NavListRight = exports.NavListLeft = exports.NavDesktop = void 0;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const utils_1 = require("../../utils");
|
|
9
9
|
const MobileNav = (props) => {
|
|
@@ -25,32 +25,13 @@ const NavListLeft = (props) => (react_1.default.createElement("ul", { className:
|
|
|
25
25
|
props.showMegaNav && Array.isArray(item.meganav) ? (react_1.default.createElement(MegaNav, { meganav: item.meganav, label: item.label, index: index })) : null)))));
|
|
26
26
|
exports.NavListLeft = NavListLeft;
|
|
27
27
|
const NavListRight = (props) => {
|
|
28
|
-
|
|
29
|
-
return react_1.default.createElement(NavListRightLoggedIn, { items: props.data['navbar-right'].items });
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
return react_1.default.createElement(NavListRightAnon, { items: props.data['navbar-right-anon'].items });
|
|
33
|
-
}
|
|
28
|
+
return props.userIsLoggedIn ? react_1.default.createElement(NavListRightLoggedIn, { items: props.data['navbar-right'].items }) : null;
|
|
34
29
|
};
|
|
35
30
|
exports.NavListRight = NavListRight;
|
|
36
31
|
const NavListRightLoggedIn = ({ items }) => {
|
|
37
32
|
return (react_1.default.createElement("ul", { className: "o-header__nav-list o-header__nav-list--right", "data-trackable": "user-nav" }, items.map((item, index) => (react_1.default.createElement("li", { className: "o-header__nav-item", key: `link-${index}` },
|
|
38
33
|
react_1.default.createElement("a", { className: "o-header__nav-link", href: item.url, "data-trackable": item.label }, item.label))))));
|
|
39
34
|
};
|
|
40
|
-
const NavListRightAnon = ({ items, variant }) => {
|
|
41
|
-
// If user is anonymous the second list item is styled as a button
|
|
42
|
-
const [first, second] = items;
|
|
43
|
-
const setTabIndex = variant === 'sticky' ? { tabIndex: -1 } : null;
|
|
44
|
-
return (react_1.default.createElement("ul", { className: "o-header__nav-list o-header__nav-list--right", "data-trackable": "user-nav" },
|
|
45
|
-
react_1.default.createElement("li", { className: "o-header__nav-item" },
|
|
46
|
-
react_1.default.createElement("a", Object.assign({ className: "o-header__nav-link", href: first.url, "data-trackable": first.label }, setTabIndex), first.label)),
|
|
47
|
-
react_1.default.createElement("li", { className: "o-header__nav-item o-header__nav-item--hide-s" },
|
|
48
|
-
react_1.default.createElement("a", Object.assign({ className: "o-header__nav-button",
|
|
49
|
-
// Added as the result of a DAC audit. This will be confusing for users of voice activation software
|
|
50
|
-
// as it looks like a button but behaves like a link without this role.
|
|
51
|
-
role: "button", href: second.url, "data-trackable": second.label }, setTabIndex), second.label))));
|
|
52
|
-
};
|
|
53
|
-
exports.NavListRightAnon = NavListRightAnon;
|
|
54
35
|
const MegaNav = ({ label, meganav, index }) => {
|
|
55
36
|
const sections = meganav.find(({ component }) => component === 'sectionlist');
|
|
56
37
|
const articles = meganav.find(({ component }) => component === 'articlelist');
|
|
@@ -7,12 +7,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.TopColumnRightSticky = exports.TopColumnCenterSticky = exports.TopColumnLeftSticky = exports.TopWrapperSticky = exports.StickyHeaderWrapper = void 0;
|
|
9
9
|
const react_1 = __importDefault(require("react"));
|
|
10
|
-
const partials_1 = require("../
|
|
10
|
+
const partials_1 = require("../top/partials");
|
|
11
11
|
const StickyHeaderWrapper = (props) => (react_1.default.createElement("header", { className: `o-header o-header--simple o-header--sticky o--if-js`, "data-o-component": "o-header", "data-o-header--sticky": true, "aria-hidden": "true" }, props.children));
|
|
12
12
|
exports.StickyHeaderWrapper = StickyHeaderWrapper;
|
|
13
|
-
const DrawerIconSticky = () => (react_1.default.createElement("a", { href: "#", className: "o-header__top-link o-header__top-link--menu", "aria-controls": "o-header-drawer", "data-trackable": "drawer-toggle", tabIndex: -1 },
|
|
13
|
+
const DrawerIconSticky = () => (react_1.default.createElement("a", { href: "#", className: "o-header__top-icon-link o-header__top-icon-link--menu", "aria-controls": "o-header-drawer", "data-trackable": "drawer-toggle", tabIndex: -1 },
|
|
14
14
|
react_1.default.createElement("span", { className: "o-header__top-link-label" }, "Menu")));
|
|
15
|
-
const SearchIconSticky = () => (react_1.default.createElement("a", { href: "#", className: "o-header__top-link o-header__top-link--search", "aria-controls": "o-header-search-sticky", "data-trackable": "search-toggle", tabIndex: -1 },
|
|
15
|
+
const SearchIconSticky = () => (react_1.default.createElement("a", { href: "#", className: "o-header__top-icon-link o-header__top-icon-link--search", "aria-controls": "o-header-search-sticky", "data-trackable": "search-toggle", tabIndex: -1 },
|
|
16
16
|
react_1.default.createElement("span", { className: "o-header__top-link-label" }, "Search")));
|
|
17
17
|
const Navigation = (props) => (react_1.default.createElement("div", { className: "o-header__top-takeover" },
|
|
18
18
|
react_1.default.createElement("div", { className: "o-header__nav" },
|
|
@@ -21,11 +21,14 @@ const Navigation = (props) => (react_1.default.createElement("div", { className:
|
|
|
21
21
|
const Logo = () => (react_1.default.createElement("a", { className: "o-header__top-logo o-header__hide--L", "data-trackable": "logo", href: "/", title: "Go to Financial Times homepage", tabIndex: -1 },
|
|
22
22
|
react_1.default.createElement("span", { className: "o-header__visually-hidden" }, "Financial Times")));
|
|
23
23
|
const NavListRightAnonSticky = (props) => {
|
|
24
|
-
|
|
24
|
+
// If user is anonymous the second list item is styled as a button
|
|
25
|
+
const [signInAction, subscribeAction] = props.data['navbar-right-anon'].items;
|
|
25
26
|
return (react_1.default.createElement("div", { className: "o-header__nav" },
|
|
26
|
-
react_1.default.createElement(
|
|
27
|
+
react_1.default.createElement("div", { className: "o-header__top-column o-header__top-column--right" },
|
|
28
|
+
subscribeAction && (react_1.default.createElement(partials_1.SubscribeButton, { item: subscribeAction, variant: "sticky", className: "o-header__top-button--hide-m" })),
|
|
29
|
+
signInAction && react_1.default.createElement(partials_1.SignInLink, { item: signInAction, variant: "sticky", className: "" }))));
|
|
27
30
|
};
|
|
28
|
-
const MyFtSticky = () => (react_1.default.createElement("a", { className:
|
|
31
|
+
const MyFtSticky = ({ className }) => (react_1.default.createElement("a", { className: `o-header__top-icon-link o-header__top-icon-link--myft ${className}`, href: "/myft", "data-trackable": "my-ft", tabIndex: -1 },
|
|
29
32
|
react_1.default.createElement("span", { className: "o-header__visually-hidden" }, "myFT")));
|
|
30
33
|
const TopWrapperSticky = (props) => (react_1.default.createElement("div", { className: "o-header__row o-header__top", "data-trackable": "header-sticky" },
|
|
31
34
|
react_1.default.createElement("div", { className: "o-header__container" },
|
|
@@ -43,13 +46,20 @@ const TopColumnCenterSticky = (props) => {
|
|
|
43
46
|
react_1.default.createElement(Logo, null)));
|
|
44
47
|
};
|
|
45
48
|
exports.TopColumnCenterSticky = TopColumnCenterSticky;
|
|
49
|
+
const NavListRightLoggedInSticky = (props) => {
|
|
50
|
+
var _a;
|
|
51
|
+
const subscribeAction = (_a = props.data['navbar-right-anon'].items) === null || _a === void 0 ? void 0 : _a[1];
|
|
52
|
+
return (react_1.default.createElement("div", { className: "o-header__top-column o-header__top-column--right" },
|
|
53
|
+
!props.userIsSubscribed && subscribeAction && (react_1.default.createElement(partials_1.SubscribeButton, { item: subscribeAction, variant: props.variant, className: "o-header__top-button--hide-m" })),
|
|
54
|
+
react_1.default.createElement(MyFtSticky, { className: "" })));
|
|
55
|
+
};
|
|
46
56
|
// This behaviour is similar to `NavListRight` in '../navigation/partials' but:
|
|
47
57
|
// - The sticky header renders either the `navbar-right-anon` data or the myFT component
|
|
48
58
|
// - The normal header renders either the `navbar-right-anon` or the `navbar-right` data
|
|
49
59
|
const TopColumnRightSticky = (props) => {
|
|
50
60
|
let children = null;
|
|
51
61
|
if (props.userIsLoggedIn) {
|
|
52
|
-
children = react_1.default.createElement(
|
|
62
|
+
children = react_1.default.createElement(NavListRightLoggedInSticky, Object.assign({}, props));
|
|
53
63
|
}
|
|
54
64
|
else if (props.showUserNavigation) {
|
|
55
65
|
children = react_1.default.createElement(NavListRightAnonSticky, Object.assign({}, props));
|
|
@@ -3,16 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.TopColumnRight = exports.TopColumnCenterNoLink = exports.TopColumnCenter = exports.TopColumnLeft = exports.TopWrapper = exports.HeaderWrapper = void 0;
|
|
6
|
+
exports.SignInLink = exports.SubscribeButton = exports.TopColumnRightAnon = exports.TopColumnRight = exports.TopColumnCenterNoLink = exports.TopColumnCenter = exports.TopColumnLeft = exports.TopWrapper = exports.HeaderWrapper = void 0;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const BrandFtMasthead_1 = __importDefault(require("../svg-components/BrandFtMasthead"));
|
|
9
9
|
const HeaderWrapper = (props) => (react_1.default.createElement("header", { id: "site-navigation", className: `o-header o-header--${props.variant || 'simple'}`, "data-o-component": "o-header", "data-o-header--no-js": true, tabIndex: -1 }, props.children));
|
|
10
10
|
exports.HeaderWrapper = HeaderWrapper;
|
|
11
|
-
const DrawerIcon = () => (react_1.default.createElement("a", { href: "#o-header-drawer", className: "o-header__top-link o-header__top-link--menu", "aria-controls": "o-header-drawer", title: "Open side navigation menu", "data-trackable": "drawer-toggle" },
|
|
11
|
+
const DrawerIcon = () => (react_1.default.createElement("a", { href: "#o-header-drawer", className: "o-header__top-icon-link o-header__top-icon-link--menu", "aria-controls": "o-header-drawer", title: "Open side navigation menu", "data-trackable": "drawer-toggle" },
|
|
12
12
|
react_1.default.createElement("span", { className: "o-header__top-link-label" }, "Open side navigation menu")));
|
|
13
|
-
const SearchIcon = () => (react_1.default.createElement("a", { href: `#o-header-search-primary`, className: "o-header__top-link o-header__top-link--search", "aria-controls": `o-header-search-primary`, title: "Open search bar", "data-trackable": "search-toggle" },
|
|
13
|
+
const SearchIcon = () => (react_1.default.createElement("a", { href: `#o-header-search-primary`, className: "o-header__top-icon-link o-header__top-icon-link--search", "aria-controls": `o-header-search-primary`, title: "Open search bar", "data-trackable": "search-toggle" },
|
|
14
14
|
react_1.default.createElement("span", { className: "o-header__top-link-label" }, "Open search bar")));
|
|
15
|
-
const MyFt = () => (react_1.default.createElement("a", { className:
|
|
15
|
+
const MyFt = ({ className }) => (react_1.default.createElement("a", { className: `o-header__top-icon-link o-header__top-icon-link--myft ${className}`, id: "o-header-top-link-myft", href: "/myft", "data-trackable": "my-ft", "data-tour-stage": "myFt", "aria-label": "My F T" },
|
|
16
16
|
react_1.default.createElement("span", { className: "o-header__visually-hidden" }, "myFT")));
|
|
17
17
|
const TopWrapper = (props) => (react_1.default.createElement("div", { className: "o-header__row o-header__top", "data-trackable": "header-top" },
|
|
18
18
|
react_1.default.createElement("div", { className: "o-header__container" },
|
|
@@ -30,6 +30,42 @@ const TopColumnCenterNoLink = () => (react_1.default.createElement("div", { clas
|
|
|
30
30
|
react_1.default.createElement("div", { className: "o-header__top-logo", style: { backgroundImage: 'none' } },
|
|
31
31
|
react_1.default.createElement(BrandFtMasthead_1.default, { title: "Financial Times" }))));
|
|
32
32
|
exports.TopColumnCenterNoLink = TopColumnCenterNoLink;
|
|
33
|
-
const
|
|
34
|
-
|
|
33
|
+
const TopColumnRightLoggedIn = (props) => {
|
|
34
|
+
var _a, _b;
|
|
35
|
+
const subscribeAction = (_b = (_a = props.data['navbar-right-anon']) === null || _a === void 0 ? void 0 : _a.items) === null || _b === void 0 ? void 0 : _b[1];
|
|
36
|
+
return (react_1.default.createElement("div", { className: "o-header__top-column o-header__top-column--right" },
|
|
37
|
+
!props.userIsSubscribed && subscribeAction && (react_1.default.createElement(SubscribeButton, { item: subscribeAction, variant: props.variant, className: "o-header__top-button--hide-m" })),
|
|
38
|
+
react_1.default.createElement(MyFt, { className: "" })));
|
|
39
|
+
};
|
|
40
|
+
const SignInLink = ({ item, variant, className }) => {
|
|
41
|
+
const setTabIndex = variant === 'sticky' ? { tabIndex: -1 } : null;
|
|
42
|
+
return (react_1.default.createElement("a", Object.assign({ className: `o-header__top-link ${className}`, href: item.url, "data-trackable": item.label }, setTabIndex), item.label));
|
|
43
|
+
};
|
|
44
|
+
exports.SignInLink = SignInLink;
|
|
45
|
+
const SubscribeButton = ({ item, variant, className }) => {
|
|
46
|
+
const setTabIndex = variant === 'sticky' ? { tabIndex: -1 } : null;
|
|
47
|
+
return (react_1.default.createElement("a", Object.assign({ className: `o-header__top-button ${className}`,
|
|
48
|
+
// Added as the result of a DAC audit. This will be confusing for users of voice activation software
|
|
49
|
+
// as it looks like a button but behaves like a link without this role.
|
|
50
|
+
role: "button", href: item.url, "data-trackable": item.label }, setTabIndex), item.label));
|
|
51
|
+
};
|
|
52
|
+
exports.SubscribeButton = SubscribeButton;
|
|
53
|
+
const TopColumnRightAnon = ({ items, variant }) => {
|
|
54
|
+
// If user is anonymous the second list item is styled as a button
|
|
55
|
+
const [signInAction, subscribeAction] = items;
|
|
56
|
+
return (react_1.default.createElement("div", { className: "o-header__top-column o-header__top-column--right" },
|
|
57
|
+
subscribeAction && (react_1.default.createElement(SubscribeButton, { item: subscribeAction, variant: variant, className: "o-header__top-button--hide-m" })),
|
|
58
|
+
signInAction && (react_1.default.createElement(SignInLink, { item: signInAction, variant: variant, className: "o-header__top-link--hide-m" })),
|
|
59
|
+
react_1.default.createElement(MyFt, { className: "o-header__top-icon-link--show-m" })));
|
|
60
|
+
};
|
|
61
|
+
exports.TopColumnRightAnon = TopColumnRightAnon;
|
|
62
|
+
const TopColumnRight = (props) => {
|
|
63
|
+
if (props.userIsLoggedIn) {
|
|
64
|
+
return react_1.default.createElement(TopColumnRightLoggedIn, Object.assign({}, props));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const userNavAnonItems = props.data['navbar-right-anon'].items;
|
|
68
|
+
return react_1.default.createElement(TopColumnRightAnon, { items: userNavAnonItems, variant: props.variant });
|
|
69
|
+
}
|
|
70
|
+
};
|
|
35
71
|
exports.TopColumnRight = TopColumnRight;
|
package/dist/node/index.js
CHANGED
|
@@ -27,7 +27,7 @@ function MainHeader(props) {
|
|
|
27
27
|
react_1.default.createElement(partials_1.TopWrapper, null,
|
|
28
28
|
react_1.default.createElement(partials_1.TopColumnLeft, null),
|
|
29
29
|
props.showLogoLink ? react_1.default.createElement(partials_1.TopColumnCenter, null) : react_1.default.createElement(partials_1.TopColumnCenterNoLink, null),
|
|
30
|
-
react_1.default.createElement(partials_1.TopColumnRight,
|
|
30
|
+
react_1.default.createElement(partials_1.TopColumnRight, Object.assign({}, props))),
|
|
31
31
|
react_1.default.createElement(partials_5.Search, { instance: "primary" }),
|
|
32
32
|
react_1.default.createElement(partials_2.MobileNav, Object.assign({}, props)),
|
|
33
33
|
react_1.default.createElement(partials_2.NavDesktop, null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@financial-times/dotcom-ui-header",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"browser": "browser.js",
|
|
6
6
|
"main": "component.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"author": "",
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@financial-times/dotcom-types-navigation": "^
|
|
26
|
+
"@financial-times/dotcom-types-navigation": "^5.1.0",
|
|
27
27
|
"n-topic-search": "^3.2.3",
|
|
28
28
|
"n-ui-foundations": "^7.0.0"
|
|
29
29
|
},
|
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
"@svgr/core": "^5.0.0",
|
|
33
33
|
"camelcase": "^6.0.0",
|
|
34
34
|
"check-engine": "^1.10.1",
|
|
35
|
-
"@financial-times/o-header": "^
|
|
35
|
+
"@financial-times/o-header": "^10.0.0",
|
|
36
36
|
"react": "^16.8.6"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@financial-times/o-header": "^
|
|
39
|
+
"@financial-times/o-header": "^10.0.0",
|
|
40
40
|
"@financial-times/logo-images": "^1.10.1",
|
|
41
41
|
"react": "16.x || 17.x"
|
|
42
42
|
},
|
|
43
43
|
"engines": {
|
|
44
|
-
"node": ">=
|
|
44
|
+
"node": ">= 14.0.0",
|
|
45
45
|
"npm": "7.x || 8.x"
|
|
46
46
|
},
|
|
47
47
|
"repository": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { ariaSelected } from '../../utils'
|
|
3
|
-
import { TNavMenuItem, TNavEditions } from '@financial-times/dotcom-types-navigation'
|
|
3
|
+
import { TNavMenuItem, TNavEditions, TNavAction } from '@financial-times/dotcom-types-navigation'
|
|
4
4
|
|
|
5
5
|
export type TDrawerParentItemProps = {
|
|
6
6
|
item: TNavMenuItem
|
|
@@ -95,3 +95,11 @@ export const EditionsSwitcher = (editions: TNavEditions) => (
|
|
|
95
95
|
})}
|
|
96
96
|
</ul>
|
|
97
97
|
)
|
|
98
|
+
|
|
99
|
+
export const SubscribeButton = (action: TNavAction) => (
|
|
100
|
+
<div className="o-header__drawer-actions">
|
|
101
|
+
<a className="o-header__drawer-button" role="button" href={action.url} data-trackable="subscribe-button">
|
|
102
|
+
{action.name}
|
|
103
|
+
</a>
|
|
104
|
+
</div>
|
|
105
|
+
)
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
DrawerParentItem,
|
|
4
|
+
DrawerSingleItem,
|
|
5
|
+
DrawerSpecialItem,
|
|
6
|
+
EditionsSwitcher,
|
|
7
|
+
SubscribeButton
|
|
8
|
+
} from './additionalPartials'
|
|
3
9
|
import { THeaderProps } from '../../interfaces'
|
|
4
10
|
import { TNavMenuItem, TNavMenu, TNavEditions } from '@financial-times/dotcom-types-navigation'
|
|
5
11
|
|
|
@@ -7,6 +13,7 @@ const IncludeDrawer = (props) => <Drawer {...props} />
|
|
|
7
13
|
|
|
8
14
|
const Drawer = (props: THeaderProps) => {
|
|
9
15
|
const editions = props.data.editions
|
|
16
|
+
const subscribeAction = props.data.subscribeAction
|
|
10
17
|
const [primary, secondary, tertiary] = props.data.drawer.items
|
|
11
18
|
const user = props.userIsLoggedIn ? props.data.user : props.data.anon
|
|
12
19
|
|
|
@@ -23,6 +30,7 @@ const Drawer = (props: THeaderProps) => {
|
|
|
23
30
|
>
|
|
24
31
|
<div className="o-header__drawer-inner">
|
|
25
32
|
<DrawerTools {...editions} />
|
|
33
|
+
{!props.userIsSubscribed && subscribeAction && <SubscribeButton {...subscribeAction} />}
|
|
26
34
|
<Search />
|
|
27
35
|
<nav className="o-header__drawer-menu o-header__drawer-menu--primary o-header__drawer-menu--border">
|
|
28
36
|
{editions && <EditionsSwitcher {...editions} />}
|
|
@@ -23,7 +23,8 @@ const NavMobile = ({ items }: { items: TNavMenuItem[] }) => {
|
|
|
23
23
|
id="o-header-nav-mobile"
|
|
24
24
|
className="o-header__row o-header__nav o-header__nav--mobile"
|
|
25
25
|
aria-hidden="true"
|
|
26
|
-
data-trackable="header-nav:mobile"
|
|
26
|
+
data-trackable="header-nav:mobile"
|
|
27
|
+
>
|
|
27
28
|
<ul className="o-header__nav-list">
|
|
28
29
|
{items.map((item, index) => (
|
|
29
30
|
<li className="o-header__nav-item" key={`link-${index}`}>
|
|
@@ -31,7 +32,8 @@ const NavMobile = ({ items }: { items: TNavMenuItem[] }) => {
|
|
|
31
32
|
className="o-header__nav-link o-header__nav-link--primary"
|
|
32
33
|
href={item.url}
|
|
33
34
|
{...ariaSelected(item)}
|
|
34
|
-
data-trackable={item.label}
|
|
35
|
+
data-trackable={item.label}
|
|
36
|
+
>
|
|
35
37
|
{item.label}
|
|
36
38
|
</a>
|
|
37
39
|
</li>
|
|
@@ -47,7 +49,8 @@ const NavDesktop = (props) => (
|
|
|
47
49
|
className="o-header__row o-header__nav o-header__nav--desktop"
|
|
48
50
|
role="navigation"
|
|
49
51
|
aria-label="Primary navigation"
|
|
50
|
-
data-trackable="header-nav:desktop"
|
|
52
|
+
data-trackable="header-nav:desktop"
|
|
53
|
+
>
|
|
51
54
|
<div className="o-header__container">{props.children}</div>
|
|
52
55
|
</nav>
|
|
53
56
|
)
|
|
@@ -61,7 +64,8 @@ const NavListLeft = (props: THeaderProps) => (
|
|
|
61
64
|
href={item.url}
|
|
62
65
|
id={`o-header-link-${index}`}
|
|
63
66
|
{...ariaSelected(item)}
|
|
64
|
-
data-trackable={item.label}
|
|
67
|
+
data-trackable={item.label}
|
|
68
|
+
>
|
|
65
69
|
{item.label}
|
|
66
70
|
</a>
|
|
67
71
|
{props.showMegaNav && Array.isArray(item.meganav) ? (
|
|
@@ -73,11 +77,7 @@ const NavListLeft = (props: THeaderProps) => (
|
|
|
73
77
|
)
|
|
74
78
|
|
|
75
79
|
const NavListRight = (props: THeaderProps) => {
|
|
76
|
-
|
|
77
|
-
return <NavListRightLoggedIn items={props.data['navbar-right'].items} />
|
|
78
|
-
} else {
|
|
79
|
-
return <NavListRightAnon items={props.data['navbar-right-anon'].items} />
|
|
80
|
-
}
|
|
80
|
+
return props.userIsLoggedIn ? <NavListRightLoggedIn items={props.data['navbar-right'].items} /> : null
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
const NavListRightLoggedIn = ({ items }: { items: TNavMenuItem[] }) => {
|
|
@@ -94,33 +94,6 @@ const NavListRightLoggedIn = ({ items }: { items: TNavMenuItem[] }) => {
|
|
|
94
94
|
)
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
const NavListRightAnon = ({ items, variant }: { items: TNavMenuItem[]; variant?: string }) => {
|
|
98
|
-
// If user is anonymous the second list item is styled as a button
|
|
99
|
-
const [first, second] = items
|
|
100
|
-
const setTabIndex = variant === 'sticky' ? { tabIndex: -1 } : null
|
|
101
|
-
return (
|
|
102
|
-
<ul className="o-header__nav-list o-header__nav-list--right" data-trackable="user-nav">
|
|
103
|
-
<li className="o-header__nav-item">
|
|
104
|
-
<a className="o-header__nav-link" href={first.url} data-trackable={first.label} {...setTabIndex}>
|
|
105
|
-
{first.label}
|
|
106
|
-
</a>
|
|
107
|
-
</li>
|
|
108
|
-
<li className="o-header__nav-item o-header__nav-item--hide-s">
|
|
109
|
-
<a
|
|
110
|
-
className="o-header__nav-button"
|
|
111
|
-
// Added as the result of a DAC audit. This will be confusing for users of voice activation software
|
|
112
|
-
// as it looks like a button but behaves like a link without this role.
|
|
113
|
-
role="button"
|
|
114
|
-
href={second.url}
|
|
115
|
-
data-trackable={second.label}
|
|
116
|
-
{...setTabIndex}>
|
|
117
|
-
{second.label}
|
|
118
|
-
</a>
|
|
119
|
-
</li>
|
|
120
|
-
</ul>
|
|
121
|
-
)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
97
|
const MegaNav = ({ label, meganav, index }: { label: string; meganav: TNavMeganav[]; index: number }) => {
|
|
125
98
|
const sections = meganav.find(({ component }) => component === 'sectionlist')
|
|
126
99
|
const articles = meganav.find(({ component }) => component === 'articlelist')
|
|
@@ -132,7 +105,8 @@ const MegaNav = ({ label, meganav, index }: { label: string; meganav: TNavMegana
|
|
|
132
105
|
role="group"
|
|
133
106
|
aria-labelledby={`o-header-link-${index}`}
|
|
134
107
|
data-o-header-mega
|
|
135
|
-
data-trackable={`meganav | ${label}`}
|
|
108
|
+
data-trackable={`meganav | ${label}`}
|
|
109
|
+
>
|
|
136
110
|
<div className="o-header__container">
|
|
137
111
|
<div className="o-header__mega-wrapper">
|
|
138
112
|
{sections ? <SectionList {...(sections as INavMeganavSections)} /> : null}
|
|
@@ -156,7 +130,8 @@ const SectionList = ({ title, data }: INavMeganavSections) => {
|
|
|
156
130
|
className="o-header__mega-link"
|
|
157
131
|
href={item.url}
|
|
158
132
|
{...ariaSelected(item)}
|
|
159
|
-
data-trackable="link"
|
|
133
|
+
data-trackable="link"
|
|
134
|
+
>
|
|
160
135
|
{item.label}
|
|
161
136
|
</a>
|
|
162
137
|
</li>
|
|
@@ -180,7 +155,8 @@ const ArticleList = ({ title, data }: INavMeganavArticles) => {
|
|
|
180
155
|
className="o-header__mega-link"
|
|
181
156
|
href={item.url}
|
|
182
157
|
{...ariaSelected(item)}
|
|
183
|
-
data-trackable="link"
|
|
158
|
+
data-trackable="link"
|
|
159
|
+
>
|
|
184
160
|
{item.label}
|
|
185
161
|
</a>
|
|
186
162
|
</li>
|
|
@@ -209,4 +185,4 @@ const UserActionsNav = (props: THeaderProps) => {
|
|
|
209
185
|
)
|
|
210
186
|
}
|
|
211
187
|
|
|
212
|
-
export { NavDesktop, NavListLeft, NavListRight,
|
|
188
|
+
export { NavDesktop, NavListLeft, NavListRight, UserActionsNav, MobileNav }
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/* This is the sticky header variant */
|
|
3
3
|
|
|
4
4
|
import React from 'react'
|
|
5
|
-
import {
|
|
5
|
+
import { SubscribeButton, SignInLink } from '../top/partials'
|
|
6
6
|
import { THeaderProps } from '../../interfaces'
|
|
7
7
|
|
|
8
8
|
const StickyHeaderWrapper = (props: THeaderProps & { children: React.ReactNode }) => (
|
|
@@ -10,7 +10,8 @@ const StickyHeaderWrapper = (props: THeaderProps & { children: React.ReactNode }
|
|
|
10
10
|
className={`o-header o-header--simple o-header--sticky o--if-js`}
|
|
11
11
|
data-o-component="o-header"
|
|
12
12
|
data-o-header--sticky
|
|
13
|
-
aria-hidden="true"
|
|
13
|
+
aria-hidden="true"
|
|
14
|
+
>
|
|
14
15
|
{props.children}
|
|
15
16
|
</header>
|
|
16
17
|
)
|
|
@@ -18,10 +19,11 @@ const StickyHeaderWrapper = (props: THeaderProps & { children: React.ReactNode }
|
|
|
18
19
|
const DrawerIconSticky = () => (
|
|
19
20
|
<a
|
|
20
21
|
href="#"
|
|
21
|
-
className="o-header__top-link o-header__top-link--menu"
|
|
22
|
+
className="o-header__top-icon-link o-header__top-icon-link--menu"
|
|
22
23
|
aria-controls="o-header-drawer"
|
|
23
24
|
data-trackable="drawer-toggle"
|
|
24
|
-
tabIndex={-1}
|
|
25
|
+
tabIndex={-1}
|
|
26
|
+
>
|
|
25
27
|
<span className="o-header__top-link-label">Menu</span>
|
|
26
28
|
</a>
|
|
27
29
|
)
|
|
@@ -29,10 +31,11 @@ const DrawerIconSticky = () => (
|
|
|
29
31
|
const SearchIconSticky = () => (
|
|
30
32
|
<a
|
|
31
33
|
href="#"
|
|
32
|
-
className="o-header__top-link o-header__top-link--search"
|
|
34
|
+
className="o-header__top-icon-link o-header__top-icon-link--search"
|
|
33
35
|
aria-controls="o-header-search-sticky"
|
|
34
36
|
data-trackable="search-toggle"
|
|
35
|
-
tabIndex={-1}
|
|
37
|
+
tabIndex={-1}
|
|
38
|
+
>
|
|
36
39
|
<span className="o-header__top-link-label">Search</span>
|
|
37
40
|
</a>
|
|
38
41
|
)
|
|
@@ -47,7 +50,8 @@ const Navigation = (props: THeaderProps) => (
|
|
|
47
50
|
className="o-header__nav-link o-header__nav-link--primary"
|
|
48
51
|
href={item.url}
|
|
49
52
|
data-trackable={item.label}
|
|
50
|
-
tabIndex={-1}
|
|
53
|
+
tabIndex={-1}
|
|
54
|
+
>
|
|
51
55
|
{item.label}
|
|
52
56
|
</a>
|
|
53
57
|
</li>
|
|
@@ -63,27 +67,34 @@ const Logo = () => (
|
|
|
63
67
|
data-trackable="logo"
|
|
64
68
|
href="/"
|
|
65
69
|
title="Go to Financial Times homepage"
|
|
66
|
-
tabIndex={-1}
|
|
70
|
+
tabIndex={-1}
|
|
71
|
+
>
|
|
67
72
|
<span className="o-header__visually-hidden">Financial Times</span>
|
|
68
73
|
</a>
|
|
69
74
|
)
|
|
70
75
|
|
|
71
76
|
const NavListRightAnonSticky = (props: THeaderProps) => {
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
// If user is anonymous the second list item is styled as a button
|
|
78
|
+
const [signInAction, subscribeAction] = props.data['navbar-right-anon'].items
|
|
74
79
|
return (
|
|
75
80
|
<div className="o-header__nav">
|
|
76
|
-
<
|
|
81
|
+
<div className="o-header__top-column o-header__top-column--right">
|
|
82
|
+
{subscribeAction && (
|
|
83
|
+
<SubscribeButton item={subscribeAction} variant="sticky" className="o-header__top-button--hide-m" />
|
|
84
|
+
)}
|
|
85
|
+
{signInAction && <SignInLink item={signInAction} variant="sticky" className="" />}
|
|
86
|
+
</div>
|
|
77
87
|
</div>
|
|
78
88
|
)
|
|
79
89
|
}
|
|
80
90
|
|
|
81
|
-
const MyFtSticky = () => (
|
|
91
|
+
const MyFtSticky = ({ className }: { className?: string }) => (
|
|
82
92
|
<a
|
|
83
|
-
className=
|
|
93
|
+
className={`o-header__top-icon-link o-header__top-icon-link--myft ${className}`}
|
|
84
94
|
href="/myft"
|
|
85
95
|
data-trackable="my-ft"
|
|
86
|
-
tabIndex={-1}
|
|
96
|
+
tabIndex={-1}
|
|
97
|
+
>
|
|
87
98
|
<span className="o-header__visually-hidden">myFT</span>
|
|
88
99
|
</a>
|
|
89
100
|
)
|
|
@@ -113,6 +124,22 @@ const TopColumnCenterSticky = (props: THeaderProps) => {
|
|
|
113
124
|
)
|
|
114
125
|
}
|
|
115
126
|
|
|
127
|
+
const NavListRightLoggedInSticky = (props: THeaderProps) => {
|
|
128
|
+
const subscribeAction = props.data['navbar-right-anon'].items?.[1]
|
|
129
|
+
return (
|
|
130
|
+
<div className="o-header__top-column o-header__top-column--right">
|
|
131
|
+
{!props.userIsSubscribed && subscribeAction && (
|
|
132
|
+
<SubscribeButton
|
|
133
|
+
item={subscribeAction}
|
|
134
|
+
variant={props.variant}
|
|
135
|
+
className="o-header__top-button--hide-m"
|
|
136
|
+
/>
|
|
137
|
+
)}
|
|
138
|
+
<MyFtSticky className="" />
|
|
139
|
+
</div>
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
116
143
|
// This behaviour is similar to `NavListRight` in '../navigation/partials' but:
|
|
117
144
|
// - The sticky header renders either the `navbar-right-anon` data or the myFT component
|
|
118
145
|
// - The normal header renders either the `navbar-right-anon` or the `navbar-right` data
|
|
@@ -120,7 +147,7 @@ const TopColumnRightSticky = (props: THeaderProps) => {
|
|
|
120
147
|
let children = null
|
|
121
148
|
|
|
122
149
|
if (props.userIsLoggedIn) {
|
|
123
|
-
children = <
|
|
150
|
+
children = <NavListRightLoggedInSticky {...props} />
|
|
124
151
|
} else if (props.showUserNavigation) {
|
|
125
152
|
children = <NavListRightAnonSticky {...props} />
|
|
126
153
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import { THeaderProps } from '../../interfaces'
|
|
2
3
|
import BrandFtMastheadSvg from '../svg-components/BrandFtMasthead'
|
|
4
|
+
import { TNavMenuItem } from '@financial-times/dotcom-types-navigation'
|
|
3
5
|
|
|
4
6
|
const HeaderWrapper = (props) => (
|
|
5
7
|
<header
|
|
@@ -16,7 +18,7 @@ const HeaderWrapper = (props) => (
|
|
|
16
18
|
const DrawerIcon = () => (
|
|
17
19
|
<a
|
|
18
20
|
href="#o-header-drawer"
|
|
19
|
-
className="o-header__top-link o-header__top-link--menu"
|
|
21
|
+
className="o-header__top-icon-link o-header__top-icon-link--menu"
|
|
20
22
|
aria-controls="o-header-drawer"
|
|
21
23
|
title="Open side navigation menu"
|
|
22
24
|
data-trackable="drawer-toggle"
|
|
@@ -28,7 +30,7 @@ const DrawerIcon = () => (
|
|
|
28
30
|
const SearchIcon = () => (
|
|
29
31
|
<a
|
|
30
32
|
href={`#o-header-search-primary`}
|
|
31
|
-
className="o-header__top-link o-header__top-link--search"
|
|
33
|
+
className="o-header__top-icon-link o-header__top-icon-link--search"
|
|
32
34
|
aria-controls={`o-header-search-primary`}
|
|
33
35
|
title="Open search bar"
|
|
34
36
|
data-trackable="search-toggle"
|
|
@@ -37,9 +39,9 @@ const SearchIcon = () => (
|
|
|
37
39
|
</a>
|
|
38
40
|
)
|
|
39
41
|
|
|
40
|
-
const MyFt = () => (
|
|
42
|
+
const MyFt = ({ className }: { className?: string }) => (
|
|
41
43
|
<a
|
|
42
|
-
className=
|
|
44
|
+
className={`o-header__top-icon-link o-header__top-icon-link--myft ${className}`}
|
|
43
45
|
id="o-header-top-link-myft"
|
|
44
46
|
href="/myft"
|
|
45
47
|
data-trackable="my-ft"
|
|
@@ -87,10 +89,101 @@ const TopColumnCenterNoLink = () => (
|
|
|
87
89
|
</div>
|
|
88
90
|
)
|
|
89
91
|
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
const TopColumnRightLoggedIn = (props: THeaderProps) => {
|
|
93
|
+
const subscribeAction = props.data['navbar-right-anon']?.items?.[1]
|
|
94
|
+
return (
|
|
95
|
+
<div className="o-header__top-column o-header__top-column--right">
|
|
96
|
+
{!props.userIsSubscribed && subscribeAction && (
|
|
97
|
+
<SubscribeButton
|
|
98
|
+
item={subscribeAction}
|
|
99
|
+
variant={props.variant}
|
|
100
|
+
className="o-header__top-button--hide-m"
|
|
101
|
+
/>
|
|
102
|
+
)}
|
|
103
|
+
<MyFt className="" />
|
|
104
|
+
</div>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const SignInLink = ({
|
|
109
|
+
item,
|
|
110
|
+
variant,
|
|
111
|
+
className
|
|
112
|
+
}: {
|
|
113
|
+
item: TNavMenuItem
|
|
114
|
+
variant?: string
|
|
115
|
+
className?: string
|
|
116
|
+
}) => {
|
|
117
|
+
const setTabIndex = variant === 'sticky' ? { tabIndex: -1 } : null
|
|
118
|
+
return (
|
|
119
|
+
<a
|
|
120
|
+
className={`o-header__top-link ${className}`}
|
|
121
|
+
href={item.url}
|
|
122
|
+
data-trackable={item.label}
|
|
123
|
+
{...setTabIndex}
|
|
124
|
+
>
|
|
125
|
+
{item.label}
|
|
126
|
+
</a>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
const SubscribeButton = ({
|
|
130
|
+
item,
|
|
131
|
+
variant,
|
|
132
|
+
className
|
|
133
|
+
}: {
|
|
134
|
+
item: TNavMenuItem
|
|
135
|
+
variant?: string
|
|
136
|
+
className?: string
|
|
137
|
+
}) => {
|
|
138
|
+
const setTabIndex = variant === 'sticky' ? { tabIndex: -1 } : null
|
|
139
|
+
return (
|
|
140
|
+
<a
|
|
141
|
+
className={`o-header__top-button ${className}`}
|
|
142
|
+
// Added as the result of a DAC audit. This will be confusing for users of voice activation software
|
|
143
|
+
// as it looks like a button but behaves like a link without this role.
|
|
144
|
+
role="button"
|
|
145
|
+
href={item.url}
|
|
146
|
+
data-trackable={item.label}
|
|
147
|
+
{...setTabIndex}
|
|
148
|
+
>
|
|
149
|
+
{item.label}
|
|
150
|
+
</a>
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const TopColumnRightAnon = ({ items, variant }: { items: TNavMenuItem[]; variant?: string }) => {
|
|
155
|
+
// If user is anonymous the second list item is styled as a button
|
|
156
|
+
const [signInAction, subscribeAction] = items
|
|
157
|
+
return (
|
|
158
|
+
<div className="o-header__top-column o-header__top-column--right">
|
|
159
|
+
{subscribeAction && (
|
|
160
|
+
<SubscribeButton item={subscribeAction} variant={variant} className="o-header__top-button--hide-m" />
|
|
161
|
+
)}
|
|
162
|
+
{signInAction && (
|
|
163
|
+
<SignInLink item={signInAction} variant={variant} className="o-header__top-link--hide-m" />
|
|
164
|
+
)}
|
|
165
|
+
<MyFt className="o-header__top-icon-link--show-m" />
|
|
166
|
+
</div>
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const TopColumnRight = (props: THeaderProps) => {
|
|
171
|
+
if (props.userIsLoggedIn) {
|
|
172
|
+
return <TopColumnRightLoggedIn {...props} />
|
|
173
|
+
} else {
|
|
174
|
+
const userNavAnonItems = props.data['navbar-right-anon'].items
|
|
175
|
+
return <TopColumnRightAnon items={userNavAnonItems} variant={props.variant} />
|
|
176
|
+
}
|
|
177
|
+
}
|
|
95
178
|
|
|
96
|
-
export {
|
|
179
|
+
export {
|
|
180
|
+
HeaderWrapper,
|
|
181
|
+
TopWrapper,
|
|
182
|
+
TopColumnLeft,
|
|
183
|
+
TopColumnCenter,
|
|
184
|
+
TopColumnCenterNoLink,
|
|
185
|
+
TopColumnRight,
|
|
186
|
+
TopColumnRightAnon,
|
|
187
|
+
SubscribeButton,
|
|
188
|
+
SignInLink
|
|
189
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -46,7 +46,7 @@ function MainHeader(props: THeaderProps) {
|
|
|
46
46
|
<TopWrapper>
|
|
47
47
|
<TopColumnLeft />
|
|
48
48
|
{props.showLogoLink ? <TopColumnCenter /> : <TopColumnCenterNoLink />}
|
|
49
|
-
<TopColumnRight />
|
|
49
|
+
<TopColumnRight {...props} />
|
|
50
50
|
</TopWrapper>
|
|
51
51
|
<Search instance="primary" />
|
|
52
52
|
<MobileNav {...props} />
|