@financial-times/dotcom-ui-header 2.6.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/README.md +125 -0
- package/bower.json +9 -0
- package/browser.js +25 -0
- package/component.js +1 -0
- package/dist/node/components/drawer/additionalPartials.js +36 -0
- package/dist/node/components/drawer/topLevelPartials.js +56 -0
- package/dist/node/components/navigation/partials.js +83 -0
- package/dist/node/components/search/partials.js +20 -0
- package/dist/node/components/sticky/partials.js +59 -0
- package/dist/node/components/sub-navigation/partials.js +36 -0
- package/dist/node/components/svg-components/BrandFtMasthead.js +11 -0
- package/dist/node/components/top/partials.js +35 -0
- package/dist/node/index.js +78 -0
- package/dist/node/utils.js +6 -0
- package/package.json +44 -0
- package/screenshots/header-navigation.png +0 -0
- package/screenshots/header-sub-navigation.png +0 -0
- package/screenshots/header-top-search.png +0 -0
- package/scripts/convertSvgsToReactComponents.js +23 -0
- package/src/components/drawer/additionalPartials.tsx +97 -0
- package/src/components/drawer/topLevelPartials.tsx +153 -0
- package/src/components/navigation/partials.tsx +212 -0
- package/src/components/search/partials.tsx +52 -0
- package/src/components/sticky/partials.tsx +137 -0
- package/src/components/sub-navigation/partials.tsx +101 -0
- package/src/components/svg-components/BrandFtMasthead.tsx +16 -0
- package/src/components/top/partials.tsx +90 -0
- package/src/header.scss +29 -0
- package/src/index.tsx +123 -0
- package/src/interfaces.d.ts +18 -0
- package/src/utils.ts +5 -0
- package/styles.scss +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# @financial-times/dotcom-ui-header
|
|
2
|
+
|
|
3
|
+
This package provides templates which render variants of the FT.com header and navigation.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Getting started
|
|
7
|
+
|
|
8
|
+
This package is compatible with Node 12+ and is distributed on npm.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install --save @financial-times/dotcom-ui-header
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
After installing the package you will need to configure your application to fetch data from the [Next Navigation API] required to render these UI components. Page Kit provides two packages for this:
|
|
15
|
+
|
|
16
|
+
1. [`dotcom-middleware-navigation`] (if you are using Express)
|
|
17
|
+
2. [`dotcom-server-navigation`] (if you are not using Express)
|
|
18
|
+
|
|
19
|
+
[Next Navigation API]: http://github.com/Financial-Times/next-navigation-api
|
|
20
|
+
[`dotcom-middleware-navigation`]: ../dotcom-middleware-navigation/README.md
|
|
21
|
+
[`dotcom-server-navigation`]: ../dotcom-server-navigation/README.md
|
|
22
|
+
|
|
23
|
+
### Server-side
|
|
24
|
+
|
|
25
|
+
This package provides several UI components to render different parts and styles of the FT.com header:
|
|
26
|
+
|
|
27
|
+
- `<Header />` the full header with navigation with lots of options. See [header elements](#header-elements) for a breakdown of its parts.
|
|
28
|
+
- `<Drawer />` the navigation drawer which should be rendered separately from the header, preferably near the bottom of the document.
|
|
29
|
+
- `<LogoOnly />` a simple masthead displaying the logo image which doesn't require any configuration. Doesn't link to the homepage by default, pass in a `showLogoLink={true}` prop to make it link through.
|
|
30
|
+
- `<NoOutboundLinksHeader />` a stripped back masthead displaying the logo image, user actions and optional sub-navigation. Aimed at reducing the possibility of a user clicking through to content related pages.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
```jsx
|
|
34
|
+
import { Header, Drawer } from '@financial-times/dotcom-ui-header'
|
|
35
|
+
|
|
36
|
+
const SiteHeader = (props) => (
|
|
37
|
+
<Header data={props.navigationData} userIsLoggedIn={props.userIsLoggedIn} />
|
|
38
|
+
<Drawer data={props.navigationData} userIsLoggedIn={props.userIsLoggedIn} />
|
|
39
|
+
)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
_Please note_ that the header components are designed to be used on the server-side and should not be rendered on the client-side. Although it is possible to render them on the client-side there is usually no reason to do so and is not supported.
|
|
43
|
+
|
|
44
|
+
### Client-side
|
|
45
|
+
|
|
46
|
+
Once you are rendering the header components in your page you will need to initialise the client-side code to add styles and interactive behaviour.
|
|
47
|
+
|
|
48
|
+
To initialise the client-side JavaScript import the package and call the `.init()` method:
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
import * as header from '@financial-times/dotcom-ui-header'
|
|
52
|
+
|
|
53
|
+
header.init()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This component includes styles written in Sass which can be imported into your application's main Sass stylesheet.
|
|
57
|
+
|
|
58
|
+
```scss
|
|
59
|
+
@import '@financial-times/dotcom-ui-header/styles';
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
_Please note_ that the exact usage of styles will depend on how you configure your Sass compiler and whether or not you are using Bower to install dependencies.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## Options
|
|
66
|
+
|
|
67
|
+
All header components with the exception of `<LogoOnly />` require the following options:
|
|
68
|
+
|
|
69
|
+
| OPTION | TYPE | OPTIONAL | DEFAULT | DESCRIPTION |
|
|
70
|
+
|--------------------|------------------------------------|----------|----------|--------------------------------------------------------------------------------|
|
|
71
|
+
| variant | 'simple' \| 'large-logo' \| string | true | 'simple' | Adds a class name to the header element
|
|
72
|
+
| userIsAnonymous | boolean | true | true | Marks a user as anonymous - can be set by middleware included with n-express |
|
|
73
|
+
| userIsLoggedIn | boolean | true | false | Marks a user as logged in - can be set by middleware included with n-express |
|
|
74
|
+
| showUserNavigation | boolean | true | true | Show user navigation options such as `Sign out` or `Subscribe` |
|
|
75
|
+
| showSubNavigation | boolean | true | true | Show the sub-navigation component which may include the crumbtrail |
|
|
76
|
+
| showStickyHeader | boolean | true | true | Enable rendering of the sticky header component |
|
|
77
|
+
| showMegaNav | boolean | true | true | Enable rendering of the drop-down "mega-nav" |
|
|
78
|
+
| data | object | false | | Navigation data for rendering the header links fetched from the navigation API |
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
## Header Elements
|
|
82
|
+
|
|
83
|
+
### Top
|
|
84
|
+
|
|
85
|
+
The topmost element - or masthead - contains the logo, toggle buttons for the [drawer](#drawer) and search bar, and the MyFT indicator if logged in.
|
|
86
|
+
|
|
87
|
+
By default the logo serves as a home page link, which can be deactivated by providing prop `showLogoLink: false`.
|
|
88
|
+
|
|
89
|
+

|
|
90
|
+
|
|
91
|
+
_Please note_ that the myFT unread articles indicator code lives outside this package in [`n-myft-ui`].
|
|
92
|
+
|
|
93
|
+
[`n-myft-ui`]: https://github.com/Financial-Times/n-myft-ui/blob/HEAD/components/unread-articles-indicator
|
|
94
|
+
|
|
95
|
+
### Navigation
|
|
96
|
+
|
|
97
|
+
The navigation element contains links for navigating the top-level sections of FT.com. Some of the sections may include subsections which are presented in "mega-nav" dropdown elements.
|
|
98
|
+
|
|
99
|
+

|
|
100
|
+
|
|
101
|
+
_Please note_ that the data for this menu is regionally-specific and changes depending on the selected FT edition.
|
|
102
|
+
|
|
103
|
+
### Sub-navigation
|
|
104
|
+
|
|
105
|
+
If enabled the sub-navigation element will be rendered if either crumbtrail or subsection navigation data is provided. This is usually page specific and will be automatically set when using the[`dotcom-middleware-navigation`] package.
|
|
106
|
+
|
|
107
|
+

|
|
108
|
+
|
|
109
|
+
### Drawer
|
|
110
|
+
|
|
111
|
+
The drawer menu is a separate component and is not included within the header. It is the primary navigation on small screens and supplementary on large screens. It mostly re-uses the data from the [navigation](#navigation) element but can also have extra groups of links.
|
|
112
|
+
|
|
113
|
+
To support a non-JS, or core experience, the drawer component should be rendered near the bottom of the document.
|
|
114
|
+
|
|
115
|
+
### Sticky header
|
|
116
|
+
|
|
117
|
+
If enabled the sticky header is shown when users scroll down on both small and large screens. It combines similar components to the [top](#top) and [navigation](#navigation) elements.
|
|
118
|
+
|
|
119
|
+
### SVG logos
|
|
120
|
+
|
|
121
|
+
These are SVG logos as React components, which can be imported for inclusion by other components.
|
|
122
|
+
|
|
123
|
+
Rendering logos as SVGs allows them to be visible faster than as external images, so is an approach best applied to logos that need to be displayed as quickly as possible upon visiting a page.
|
|
124
|
+
|
|
125
|
+
The React components are auto-generated using a script - `npm run build:svg-to-react` - which converts the source SVG file acquired from dev dependency `@financial-times/logo-images`.
|
package/bower.json
ADDED
package/browser.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import Header from 'o-header'
|
|
2
|
+
import TopicSearch from 'n-topic-search'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef HeaderOptions
|
|
6
|
+
* @property { HTMLElement } [rootElement] - the root element passed to o-header
|
|
7
|
+
* @property { string } [hostName]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Initialise the header
|
|
12
|
+
* @param { HeaderOptions } headerOptions
|
|
13
|
+
*/
|
|
14
|
+
export const init = (headerOptions = {}) => {
|
|
15
|
+
const topicSearchElements = document.querySelectorAll(
|
|
16
|
+
'.o-header [data-n-topic-search], .o-header__drawer [data-n-topic-search]'
|
|
17
|
+
)
|
|
18
|
+
topicSearchElements.forEach((element) => {
|
|
19
|
+
new TopicSearch(element, headerOptions)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
Header.init(headerOptions.rootElement)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { Header as OrigamiHeader }
|
package/component.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./dist/node')
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.EditionsSwitcher = exports.DrawerSpecialItem = exports.DrawerSingleItem = exports.DrawerParentItem = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const utils_1 = require("../../utils");
|
|
9
|
+
exports.DrawerParentItem = ({ item, idSuffix }) => {
|
|
10
|
+
const selected = item.selected ? 'selected' : 'unselected';
|
|
11
|
+
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
12
|
+
react_1.default.createElement("div", { key: item.url, className: "o-header__drawer-menu-toggle-wrapper" },
|
|
13
|
+
react_1.default.createElement("a", Object.assign({ className: `o-header__drawer-menu-link o-header__drawer-menu-link--${selected} o-header__drawer-menu-link--parent`, href: item.url }, utils_1.ariaSelected(item), { "data-trackable": item.label }), item.label),
|
|
14
|
+
react_1.default.createElement("button", { className: `o-header__drawer-menu-toggle o-header__drawer-menu-toggle--${selected}`, "aria-controls": `o-header-drawer-child-${idSuffix}`, "data-trackable": `sub-level-toggle | ${item.label}` }, `Show more ${item.label}`)),
|
|
15
|
+
react_1.default.createElement("ul", { className: "o-header__drawer-menu-list o-header__drawer-menu-list--child", id: `o-header-drawer-child-${idSuffix}`, "data-trackable": "sub-level" }, item.submenu.items.map((item) => {
|
|
16
|
+
const selected = item.selected ? 'selected' : 'unselected';
|
|
17
|
+
return (react_1.default.createElement("li", { key: item.url, className: "o-header__drawer-menu-item" },
|
|
18
|
+
react_1.default.createElement("a", Object.assign({ className: `o-header__drawer-menu-link o-header__drawer-menu-link--${selected} o-header__drawer-menu-link--child`, href: item.url, "data-trackable": item.label }, utils_1.ariaSelected(item)), item.label)));
|
|
19
|
+
}))));
|
|
20
|
+
};
|
|
21
|
+
exports.DrawerSingleItem = (item) => {
|
|
22
|
+
const selected = item.selected ? 'selected' : 'unselected';
|
|
23
|
+
return (react_1.default.createElement("a", Object.assign({ className: `o-header__drawer-menu-link o-header__drawer-menu-link--${selected}`, href: item.url, "data-trackable": item.label }, utils_1.ariaSelected(item)), item.label));
|
|
24
|
+
};
|
|
25
|
+
exports.DrawerSpecialItem = (item) => {
|
|
26
|
+
const selected = item.selected ? 'selected' : 'unselected';
|
|
27
|
+
return (react_1.default.createElement("a", Object.assign({ className: `o-header__drawer-menu-link o-header__drawer-menu-link--${selected} o-header__drawer-menu-link--secondary`, href: item.url, "data-trackable": item.label }, utils_1.ariaSelected(item)), item.label));
|
|
28
|
+
};
|
|
29
|
+
exports.EditionsSwitcher = (editions) => (react_1.default.createElement("ul", { className: "o-header__drawer-menu-list" }, editions.others.map(({ id, name, url }) => {
|
|
30
|
+
const href = `${url}?edition=${id}`;
|
|
31
|
+
return (react_1.default.createElement("li", { key: id, className: "o-header__drawer-menu-item", "data-trackable": "edition-switcher" },
|
|
32
|
+
react_1.default.createElement("a", { className: "o-header__drawer-menu-link", href: href, "data-trackable": id },
|
|
33
|
+
"Switch to ",
|
|
34
|
+
name,
|
|
35
|
+
" Edition")));
|
|
36
|
+
})));
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.IncludeDrawer = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const additionalPartials_1 = require("./additionalPartials");
|
|
9
|
+
const IncludeDrawer = (props) => react_1.default.createElement(Drawer, Object.assign({}, props));
|
|
10
|
+
exports.IncludeDrawer = IncludeDrawer;
|
|
11
|
+
const Drawer = (props) => {
|
|
12
|
+
const editions = props.data.editions;
|
|
13
|
+
const [primary, secondary, tertiary] = props.data.drawer.items;
|
|
14
|
+
const user = props.userIsLoggedIn ? props.data.user : props.data.anon;
|
|
15
|
+
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
|
+
react_1.default.createElement("div", { className: "o-header__drawer-inner" },
|
|
17
|
+
react_1.default.createElement(DrawerTools, Object.assign({}, editions)),
|
|
18
|
+
react_1.default.createElement(Search, null),
|
|
19
|
+
react_1.default.createElement("nav", { className: "o-header__drawer-menu o-header__drawer-menu--primary o-header__drawer-menu--border" },
|
|
20
|
+
editions && react_1.default.createElement(additionalPartials_1.EditionsSwitcher, Object.assign({}, editions)),
|
|
21
|
+
react_1.default.createElement("ul", { className: "o-header__drawer-menu-list" },
|
|
22
|
+
primary ? react_1.default.createElement(SectionPrimary, Object.assign({}, primary)) : null,
|
|
23
|
+
secondary ? react_1.default.createElement(SectionSecondary, Object.assign({}, secondary)) : null,
|
|
24
|
+
tertiary ? react_1.default.createElement(SectionTertiary, Object.assign({}, tertiary)) : null)),
|
|
25
|
+
react_1.default.createElement(UserMenu, Object.assign({}, user)))));
|
|
26
|
+
};
|
|
27
|
+
const DrawerTools = (props) => (react_1.default.createElement("div", { className: "o-header__drawer-tools" },
|
|
28
|
+
react_1.default.createElement("button", { type: "button", className: "o-header__drawer-tools-close", title: "Close drawer menu", "aria-controls": "o-header-drawer", "data-trackable": "close" },
|
|
29
|
+
react_1.default.createElement("span", { className: "o-header__visually-hidden" }, "Close drawer menu")),
|
|
30
|
+
react_1.default.createElement("a", { className: "o-header__drawer-tools-logo", href: "/", "data-trackable": "logo" },
|
|
31
|
+
react_1.default.createElement("span", { className: "o-header__visually-hidden" }, "Financial Times")),
|
|
32
|
+
props.current && react_1.default.createElement("p", { className: "o-header__drawer-current-edition" }, `${props.current.name} Edition`)));
|
|
33
|
+
const Search = () => (react_1.default.createElement("div", { className: "o-header__drawer-search" },
|
|
34
|
+
react_1.default.createElement("form", { className: "o-header__drawer-search-form", action: "/search", role: "search", "aria-label": "Site search", "data-n-topic-search": true, "data-n-topic-search-categories": "concepts,equities", "data-n-topic-search-view-all": true },
|
|
35
|
+
react_1.default.createElement("label", { className: "o-header__visually-hidden", htmlFor: "o-header-drawer-search-term" },
|
|
36
|
+
"Search the ",
|
|
37
|
+
react_1.default.createElement("abbr", { title: "Financial Times" }, "FT")),
|
|
38
|
+
react_1.default.createElement("input", { className: "o-header__drawer-search-term", id: "o-header-drawer-search-term", name: "q", type: "text", autoComplete: "off", autoCorrect: "off", autoCapitalize: "off", spellCheck: false, placeholder: "Search the FT", "data-trackable": "search-term", "data-n-topic-search-input": true }),
|
|
39
|
+
react_1.default.createElement("button", { className: "o-header__drawer-search-submit", type: "submit", "data-trackable": "search-submit" },
|
|
40
|
+
react_1.default.createElement("span", { className: "o-header__visually-hidden" }, "Search")))));
|
|
41
|
+
const SectionPrimary = (props) => {
|
|
42
|
+
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
43
|
+
react_1.default.createElement("li", { className: "o-header__drawer-menu-item o-header__drawer-menu-item--heading" }, props.label),
|
|
44
|
+
props.submenu.items.map((item, index) => (react_1.default.createElement("li", { key: item.url, className: "o-header__drawer-menu-item" }, item.submenu ? (react_1.default.createElement(additionalPartials_1.DrawerParentItem, { item: item, idSuffix: `${index}` })) : (react_1.default.createElement(additionalPartials_1.DrawerSingleItem, Object.assign({}, item))))))));
|
|
45
|
+
};
|
|
46
|
+
const SectionSecondary = (props) => (react_1.default.createElement(react_1.default.Fragment, null,
|
|
47
|
+
react_1.default.createElement("li", { className: "o-header__drawer-menu-item o-header__drawer-menu-item--heading" }, props.label),
|
|
48
|
+
props.submenu.items.map((item, index) => (react_1.default.createElement("li", { key: item.url, className: "o-header__drawer-menu-item" }, item.submenu ? (react_1.default.createElement(additionalPartials_1.DrawerParentItem, { item: item, idSuffix: 'inner' + index })) : (react_1.default.createElement(additionalPartials_1.DrawerSingleItem, Object.assign({}, item))))))));
|
|
49
|
+
const SectionTertiary = (props) => (react_1.default.createElement(react_1.default.Fragment, null, props.submenu.items.map((item, index) => {
|
|
50
|
+
const divideItem = index === 0 ? 'o-header__drawer-menu-item--divide' : '';
|
|
51
|
+
return (react_1.default.createElement("li", { key: item.url, className: `o-header__drawer-menu-item ${divideItem}` },
|
|
52
|
+
react_1.default.createElement(additionalPartials_1.DrawerSpecialItem, Object.assign({}, item))));
|
|
53
|
+
})));
|
|
54
|
+
const UserMenu = (props) => (react_1.default.createElement("nav", { className: "o-header__drawer-menu o-header__drawer-menu--user", "data-trackable": "user-nav" },
|
|
55
|
+
react_1.default.createElement("ul", { className: "o-header__drawer-menu-list" }, props.items.map((item) => (react_1.default.createElement("li", { key: item.url, className: "o-header__drawer-menu-item" },
|
|
56
|
+
react_1.default.createElement("a", { className: "o-header__drawer-menu-link", href: item.url, "data-trackable": item.label }, item.label)))))));
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MobileNav = exports.UserActionsNav = exports.NavListRightAnon = exports.NavListRight = exports.NavListLeft = exports.NavDesktop = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const utils_1 = require("../../utils");
|
|
9
|
+
const MobileNav = (props) => {
|
|
10
|
+
// Only display navigation on pages which are included in this menu
|
|
11
|
+
const targetUrls = props.data['navbar-simple'].items.map((item) => item.url);
|
|
12
|
+
return targetUrls.includes(props.data.currentPath) ? (react_1.default.createElement(NavMobile, { items: props.data['navbar-simple'].items })) : null;
|
|
13
|
+
};
|
|
14
|
+
exports.MobileNav = MobileNav;
|
|
15
|
+
const NavMobile = ({ items }) => {
|
|
16
|
+
return (react_1.default.createElement("nav", { id: "o-header-nav-mobile", className: "o-header__row o-header__nav o-header__nav--mobile", "aria-hidden": "true", "data-trackable": "header-nav:mobile" },
|
|
17
|
+
react_1.default.createElement("ul", { className: "o-header__nav-list" }, items.map((item, index) => (react_1.default.createElement("li", { className: "o-header__nav-item", key: `link-${index}` },
|
|
18
|
+
react_1.default.createElement("a", Object.assign({ className: "o-header__nav-link o-header__nav-link--primary", href: item.url }, utils_1.ariaSelected(item), { "data-trackable": item.label }), item.label)))))));
|
|
19
|
+
};
|
|
20
|
+
const NavDesktop = (props) => (react_1.default.createElement("nav", { id: "o-header-nav-desktop", className: "o-header__row o-header__nav o-header__nav--desktop", role: "navigation", "aria-label": "Primary navigation", "data-trackable": "header-nav:desktop" },
|
|
21
|
+
react_1.default.createElement("div", { className: "o-header__container" }, props.children)));
|
|
22
|
+
exports.NavDesktop = NavDesktop;
|
|
23
|
+
const NavListLeft = (props) => (react_1.default.createElement("ul", { className: "o-header__nav-list o-header__nav-list--left", "data-trackable": "primary-nav" }, props.data.navbar.items.map((item, index) => (react_1.default.createElement("li", { className: "o-header__nav-item", key: `link-${index}` },
|
|
24
|
+
react_1.default.createElement("a", Object.assign({ className: "o-header__nav-link o-header__nav-link--primary", href: item.url, id: `o-header-link-${index}` }, utils_1.ariaSelected(item), { "data-trackable": item.label }), item.label),
|
|
25
|
+
props.showMegaNav && Array.isArray(item.meganav) ? (react_1.default.createElement(MegaNav, { meganav: item.meganav, label: item.label, index: index })) : null)))));
|
|
26
|
+
exports.NavListLeft = NavListLeft;
|
|
27
|
+
const NavListRight = (props) => {
|
|
28
|
+
if (props.userIsLoggedIn) {
|
|
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
|
+
}
|
|
34
|
+
};
|
|
35
|
+
exports.NavListRight = NavListRight;
|
|
36
|
+
const NavListRightLoggedIn = ({ items }) => {
|
|
37
|
+
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
|
+
react_1.default.createElement("a", { className: "o-header__nav-link", href: item.url, "data-trackable": item.label }, item.label))))));
|
|
39
|
+
};
|
|
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
|
+
const MegaNav = ({ label, meganav, index }) => {
|
|
55
|
+
const sections = meganav.find(({ component }) => component === 'sectionlist');
|
|
56
|
+
const articles = meganav.find(({ component }) => component === 'articlelist');
|
|
57
|
+
return (react_1.default.createElement("div", { className: "o-header__mega", id: `o-header-mega-${index}`, role: "group", "aria-labelledby": `o-header-link-${index}`, "data-o-header-mega": true, "data-trackable": `meganav | ${label}` },
|
|
58
|
+
react_1.default.createElement("div", { className: "o-header__container" },
|
|
59
|
+
react_1.default.createElement("div", { className: "o-header__mega-wrapper" },
|
|
60
|
+
sections ? react_1.default.createElement(SectionList, Object.assign({}, sections)) : null,
|
|
61
|
+
articles ? react_1.default.createElement(ArticleList, Object.assign({}, articles)) : null))));
|
|
62
|
+
};
|
|
63
|
+
const SectionList = ({ title, data }) => {
|
|
64
|
+
return (react_1.default.createElement("div", { className: "o-header__mega-column o-header__mega-column--subsections", "data-trackable": "sections" },
|
|
65
|
+
react_1.default.createElement("div", { className: "o-header__mega-heading" }, title),
|
|
66
|
+
react_1.default.createElement("div", { className: "o-header__mega-content" },
|
|
67
|
+
react_1.default.createElement("ul", { className: "o-header__mega-list" }, data.map((column) => column.map((item, index) => (react_1.default.createElement("li", { className: "o-header__mega-item", key: `link-${index}` },
|
|
68
|
+
react_1.default.createElement("a", Object.assign({ className: "o-header__mega-link", href: item.url }, utils_1.ariaSelected(item), { "data-trackable": "link" }), item.label)))))))));
|
|
69
|
+
};
|
|
70
|
+
const ArticleList = ({ title, data }) => {
|
|
71
|
+
return (react_1.default.createElement("div", { className: "o-header__mega-column o-header__mega-column--articles", "data-trackable": "popular" },
|
|
72
|
+
react_1.default.createElement("div", { className: "o-header__mega-heading" }, title),
|
|
73
|
+
react_1.default.createElement("div", { className: "o-header__mega-content" },
|
|
74
|
+
react_1.default.createElement("ul", { className: "o-header__mega-list" }, data.map((item, index) => (react_1.default.createElement("li", { className: "o-header__mega-item", key: `link-${index}` },
|
|
75
|
+
react_1.default.createElement("a", Object.assign({ className: "o-header__mega-link", href: item.url }, utils_1.ariaSelected(item), { "data-trackable": "link" }), item.label))))))));
|
|
76
|
+
};
|
|
77
|
+
const UserActionsNav = (props) => {
|
|
78
|
+
const userNavItems = props.data['navbar-right-anon'].items;
|
|
79
|
+
return (react_1.default.createElement("div", { className: "o-header__row o-header__anon", "data-trackable": "header-anon" },
|
|
80
|
+
react_1.default.createElement("ul", { className: "o-header__anon-list" }, userNavItems.map((item, index) => (react_1.default.createElement("li", { className: "o-header__anon-item", key: `link-${index}` },
|
|
81
|
+
react_1.default.createElement("a", { className: "o-header__anon-link", href: item.url, "data-trackable": item.label }, item.label)))))));
|
|
82
|
+
};
|
|
83
|
+
exports.UserActionsNav = UserActionsNav;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Search = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const Search = ({ instance }) => {
|
|
9
|
+
return (react_1.default.createElement("div", { id: `o-header-search-${instance}`, className: `o-header__row o-header__search o-header__search--${instance}`, "data-trackable": "header-search", "data-o-header-search": true },
|
|
10
|
+
react_1.default.createElement("div", { className: "o-header__container" },
|
|
11
|
+
react_1.default.createElement("form", { className: "o-header__search-form", action: "/search", role: "search", "aria-label": "Site search", "data-n-topic-search": true, "data-n-topic-search-categories": "concepts,equities", "data-n-topic-search-view-all": true },
|
|
12
|
+
react_1.default.createElement("label", { className: "o-header__visually-hidden", htmlFor: `o-header-search-term-${instance}` },
|
|
13
|
+
"Search the ",
|
|
14
|
+
react_1.default.createElement("abbr", { title: "Financial Times" }, "FT")),
|
|
15
|
+
react_1.default.createElement("input", { className: "o-header__search-term", id: `o-header-search-term-${instance}`, name: "q", type: "text", autoComplete: "off", autoCorrect: "off", autoCapitalize: "off", spellCheck: false, "data-trackable": "search-term", placeholder: "Search the FT", "data-n-topic-search-input": true }),
|
|
16
|
+
react_1.default.createElement("button", { className: "o-header__search-submit", type: "submit", "data-trackable": "search-submit" }, "Search"),
|
|
17
|
+
react_1.default.createElement("button", { className: "o-header__search-close o--if-js", type: "button", "aria-controls": `o-header-search-${instance}`, title: "Close search bar", "data-trackable": "close" },
|
|
18
|
+
react_1.default.createElement("span", { className: "o-header__visually-hidden" }, "Close search bar"))))));
|
|
19
|
+
};
|
|
20
|
+
exports.Search = Search;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* WARN: This file looks similar to ../top/partials */
|
|
3
|
+
/* This is the sticky header variant */
|
|
4
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
+
};
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.TopColumnRightSticky = exports.TopColumnCenterSticky = exports.TopColumnLeftSticky = exports.TopWrapperSticky = exports.StickyHeaderWrapper = void 0;
|
|
9
|
+
const react_1 = __importDefault(require("react"));
|
|
10
|
+
const partials_1 = require("../navigation/partials");
|
|
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
|
+
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 },
|
|
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 },
|
|
16
|
+
react_1.default.createElement("span", { className: "o-header__top-link-label" }, "Search")));
|
|
17
|
+
const Navigation = (props) => (react_1.default.createElement("div", { className: "o-header__top-takeover" },
|
|
18
|
+
react_1.default.createElement("div", { className: "o-header__nav" },
|
|
19
|
+
react_1.default.createElement("ul", { className: "o-header__nav-list o-header__nav-list--left", "data-trackable": "primary-nav" }, props.data.navbar.items.map((item, index) => (react_1.default.createElement("li", { className: "o-header__nav-item", key: `link-${index}` },
|
|
20
|
+
react_1.default.createElement("a", { className: "o-header__nav-link o-header__nav-link--primary", href: item.url, "data-trackable": item.label, tabIndex: -1 }, item.label))))))));
|
|
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
|
+
react_1.default.createElement("span", { className: "o-header__visually-hidden" }, "Financial Times")));
|
|
23
|
+
const NavListRightAnonSticky = (props) => {
|
|
24
|
+
const navbarItems = props.data['navbar-right-anon'].items;
|
|
25
|
+
return (react_1.default.createElement("div", { className: "o-header__nav" },
|
|
26
|
+
react_1.default.createElement(partials_1.NavListRightAnon, { items: navbarItems, variant: "sticky" })));
|
|
27
|
+
};
|
|
28
|
+
const MyFtSticky = () => (react_1.default.createElement("a", { className: "o-header__top-link o-header__top-link--myft", href: "/myft", "data-trackable": "my-ft", tabIndex: -1 },
|
|
29
|
+
react_1.default.createElement("span", { className: "o-header__visually-hidden" }, "myFT")));
|
|
30
|
+
const TopWrapperSticky = (props) => (react_1.default.createElement("div", { className: "o-header__row o-header__top", "data-trackable": "header-sticky" },
|
|
31
|
+
react_1.default.createElement("div", { className: "o-header__container" },
|
|
32
|
+
react_1.default.createElement("div", { className: "o-header__top-wrapper" }, props.children))));
|
|
33
|
+
exports.TopWrapperSticky = TopWrapperSticky;
|
|
34
|
+
const TopColumnLeftSticky = () => {
|
|
35
|
+
return (react_1.default.createElement("div", { className: "o-header__top-column o-header__top-column--left" },
|
|
36
|
+
react_1.default.createElement(DrawerIconSticky, null),
|
|
37
|
+
react_1.default.createElement(SearchIconSticky, null)));
|
|
38
|
+
};
|
|
39
|
+
exports.TopColumnLeftSticky = TopColumnLeftSticky;
|
|
40
|
+
const TopColumnCenterSticky = (props) => {
|
|
41
|
+
return (react_1.default.createElement("div", { className: "o-header__top-column o-header__top-column--center" },
|
|
42
|
+
react_1.default.createElement(Navigation, Object.assign({}, props)),
|
|
43
|
+
react_1.default.createElement(Logo, null)));
|
|
44
|
+
};
|
|
45
|
+
exports.TopColumnCenterSticky = TopColumnCenterSticky;
|
|
46
|
+
// This behaviour is similar to `NavListRight` in '../navigation/partials' but:
|
|
47
|
+
// - The sticky header renders either the `navbar-right-anon` data or the myFT component
|
|
48
|
+
// - The normal header renders either the `navbar-right-anon` or the `navbar-right` data
|
|
49
|
+
const TopColumnRightSticky = (props) => {
|
|
50
|
+
let children = null;
|
|
51
|
+
if (props.userIsLoggedIn) {
|
|
52
|
+
children = react_1.default.createElement(MyFtSticky, null);
|
|
53
|
+
}
|
|
54
|
+
else if (props.showUserNavigation) {
|
|
55
|
+
children = react_1.default.createElement(NavListRightAnonSticky, Object.assign({}, props));
|
|
56
|
+
}
|
|
57
|
+
return react_1.default.createElement("div", { className: "o-header__top-column o-header__top-column--right" }, children);
|
|
58
|
+
};
|
|
59
|
+
exports.TopColumnRightSticky = TopColumnRightSticky;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SubNavigation = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const utils_1 = require("../../utils");
|
|
9
|
+
const SubNavigation = (props) => (react_1.default.createElement(SubNavigationWrapper, null,
|
|
10
|
+
react_1.default.createElement(BreadCrumb, { items: props.data.breadcrumb }),
|
|
11
|
+
react_1.default.createElement(SubSections, { items: props.data.subsections }),
|
|
12
|
+
react_1.default.createElement(SubSections, { items: props.data['subsections-right'], rightAlignment: true })));
|
|
13
|
+
exports.SubNavigation = SubNavigation;
|
|
14
|
+
const SubNavigationWrapper = (props) => (react_1.default.createElement("div", { className: "o-header__subnav", role: "navigation", "aria-label": "Sub navigation", "data-o-header-subnav": true, "data-trackable": "header-subnav" },
|
|
15
|
+
react_1.default.createElement("div", { className: "o-header__container" },
|
|
16
|
+
react_1.default.createElement("div", { className: "o-header__subnav-wrap-outside" },
|
|
17
|
+
react_1.default.createElement("div", { className: "o-header__subnav-wrap-inside", "data-o-header-subnav-wrapper": true },
|
|
18
|
+
react_1.default.createElement("div", { className: "o-header__subnav-content" }, props.children)),
|
|
19
|
+
react_1.default.createElement("button", { className: "o-header__subnav-button o-header__subnav-button--left", title: "scroll left", "aria-label": "scroll left", "aria-hidden": "true", disabled: true }),
|
|
20
|
+
react_1.default.createElement("button", { className: "o-header__subnav-button o-header__subnav-button--right", title: "scroll right", "aria-label": "scroll right", "aria-hidden": "true", disabled: true })))));
|
|
21
|
+
const BreadCrumb = ({ items }) => (react_1.default.createElement("ol", { className: "o-header__subnav-list o-header__subnav-list--breadcrumb", "aria-label": "Breadcrumb", "data-trackable": "breadcrumb" }, items.map((item, index) => {
|
|
22
|
+
const selected = item.selected ? 'o-header__subnav-link--highlight' : '';
|
|
23
|
+
return (react_1.default.createElement("li", { className: "o-header__subnav-item", key: `item-${index}` },
|
|
24
|
+
react_1.default.createElement("a", Object.assign({ className: `o-header__subnav-link ${selected}`, href: item.url }, utils_1.ariaSelected(item), { "data-trackable": item.label }), item.label)));
|
|
25
|
+
})));
|
|
26
|
+
const SubSections = ({ items, rightAlignment }) => {
|
|
27
|
+
if (!items || items.length === 0) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return (react_1.default.createElement("ul", { className: 'o-header__subnav-list o-header__subnav-list--children' +
|
|
31
|
+
(rightAlignment ? ' o-header__subnav-list--right' : ''), "aria-label": rightAlignment ? 'Additional Sub Navigation' : 'Subsections', "data-trackable": "subsections" }, items.map((item, index) => {
|
|
32
|
+
const selected = item.selected ? 'o-header__subnav-link--highlight' : '';
|
|
33
|
+
return (react_1.default.createElement("li", { className: "o-header__subnav-item", key: `item-${index}` },
|
|
34
|
+
react_1.default.createElement("a", Object.assign({ className: `o-header__subnav-link ${selected}`, href: item.url }, utils_1.ariaSelected(item), { "data-trackable": item.label }), item.label)));
|
|
35
|
+
})));
|
|
36
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// **THIS IS AN AUTO-GENERATED FILE (`npm run build:svg-to-react`) - DO NOT EDIT MANUALLY.**
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const BrandFtMasthead = ({ title, ...props }) => (react_1.default.createElement("svg", Object.assign({ viewBox: "0 0 1054 86" }, props),
|
|
9
|
+
title === undefined ? react_1.default.createElement("title", null, 'brand-ft-masthead') : title ? react_1.default.createElement("title", null, title) : null,
|
|
10
|
+
react_1.default.createElement("path", { d: "M26.177 72.609c0 5.938 1.697 7.295 12.554 7.295v3.732H.9v-3.732c7.464 0 10.01-.679 10.01-7.125V12.215c0-6.447-2.546-7.126-10.01-7.126V1.357h63.448l.34 22.563h-3.054C59.937 6.956 55.696 5.43 39.919 5.43H26.008v33.59h11.196c10.688 0 11.367-1.697 12.215-10.179h3.054v24.599h-3.054c-.848-8.482-1.527-10.01-12.215-10.01H26.008v29.18h.17zm46.314 11.027v-3.732c7.465 0 10.01-.679 10.01-7.125V12.215c0-6.447-2.545-7.126-10.01-7.126V1.357h35.287V5.09c-7.465 0-10.01.679-10.01 7.126v60.564c0 6.446 2.545 7.125 10.01 7.125v3.732H72.49zm115.36 1.357l-56.323-69.725V72.44c0 6.617 4.58 7.634 12.385 7.634v3.733h-29.858v-3.733c7.803 0 12.045-1.017 12.045-7.634V8.991c-3.563-3.732-6.108-3.902-12.045-3.902V1.357h26.465l43.09 55.475V12.554c0-6.616-4.58-7.634-12.384-7.634V1.357h30.027V5.09c-7.803 0-12.045 1.018-12.045 7.635v72.27h-1.357zm40.207-1.357h-29.689v-3.732c7.804 0 11.367-1.018 13.911-7.804L239.085.509h7.464l28.84 72.1c2.545 6.447 3.732 7.125 9.67 7.125v3.732h-34.438v-3.732c10.518 0 11.536-.848 8.99-7.125l-8.481-21.884h-25.787L217.71 71.93c-2.375 6.447 1.357 7.804 10.518 7.804v3.902h-.17zm-1.188-37.153h22.393l-11.705-29.518-10.688 29.518zm135.548 38.51l-56.153-69.725V72.44c0 6.617 4.58 7.634 12.384 7.634v3.733h-29.18v-3.733c7.126 0 11.367-1.017 11.367-7.634V9.161c-4.071-3.732-7.125-4.072-13.91-4.072V1.357h28.16l43.09 55.475V12.554c0-6.616-4.58-7.634-12.383-7.634V1.357h29.858V5.09c-7.804 0-12.045 1.018-12.045 7.635v72.27h-1.188zm83.297-83.805h2.036l1.187 24.598-3.053.17c-2.036-14.08-9.5-21.545-23.242-21.545-15.268 0-26.804 13.063-26.804 33.081 0 25.617 16.116 40.206 33.08 40.206 7.296 0 13.912-2.035 20.358-8.99l2.376 2.374c-5.26 7.465-15.608 13.742-29.52 13.742-20.696 0-41.732-15.608-41.732-41.734C380.4 17.813 399.57 0 422.813 0c11.027 0 16.795 4.75 19.848 4.75 1.357 0 2.375-1.187 3.054-3.562zm12.723 82.448v-3.732c7.465 0 10.01-.679 10.01-7.125V12.215c0-6.447-2.545-7.126-10.01-7.126V1.357h35.287V5.09c-7.464 0-10.01.679-10.01 7.126v60.564c0 6.446 2.546 7.125 10.01 7.125v3.732h-35.287zm68.538 0h-27.653v-3.732c6.108 0 9.331-1.018 11.876-7.804L538.003.509h7.464l28.84 72.1c2.545 6.447 3.733 7.125 9.67 7.125v3.732H549.54v-3.732c10.518 0 11.536-.848 8.991-7.125l-8.482-21.884h-25.786l-7.635 21.205c-2.375 6.447 1.358 7.804 10.519 7.804v3.902h-.17zm-1.188-37.153h22.394l-11.536-29.518-10.858 29.518zm63.957 37.153v-3.732c7.465 0 10.01-.679 10.01-7.125V12.215c0-6.447-2.545-7.126-10.01-7.126V1.357h35.117V5.09c-7.464 0-9.84.679-9.84 7.126v61.073c0 5.428 2.715 6.107 7.126 6.107h4.241c15.947 0 21.036-2.375 25.447-20.527l3.054.339-2.545 24.26h-62.6v.17zM760.75 1.357l.339 23.92h-3.054C756.34 7.634 752.098 5.43 736.32 5.43h-5.089v67.18c0 6.447 2.375 7.295 12.554 7.295v3.732h-40.376v-3.732c10.179 0 12.723-1.018 12.723-7.295V5.429h-5.089c-15.777 0-20.018 2.205-21.715 19.848h-3.053l.339-23.92h74.136zm7.973 82.28v-3.733c7.465 0 10.01-.679 10.01-7.125V12.215c0-6.447-2.545-7.126-10.01-7.126V1.357h35.287V5.09c-7.465 0-10.01.679-10.01 7.126v60.564c0 6.446 2.545 7.125 10.01 7.125v3.732h-35.287zM910.21 1.356V5.09c-7.465 0-10.688.34-10.01 6.956l6.447 61.073c.679 6.277 3.054 6.955 10.518 6.955v3.733h-35.117v-3.733c7.295 0 9.84-.678 9.331-6.955L884.762 8.99l-25.956 76.172h-1.018L832.34 8.822l-6.108 64.126c-.678 6.447 3.733 7.125 11.197 7.125v3.733h-27.483v-3.733c7.465 0 10.01-1.187 10.518-7.125l6.447-61.073c.679-6.446-2.545-6.955-10.01-6.955V1.357h28.84l17.305 56.153 18.661-56.153h28.5zm65.653 52.082h-3.053c-.849-8.482-1.527-10.01-12.215-10.01H948.04v29.859c0 5.428 2.715 6.107 7.125 6.107h6.786c15.947 0 21.036-2.375 25.447-20.527l3.054.339-2.884 24.26h-64.805v-3.733c7.464 0 10.009-.678 10.009-7.125V12.215c0-6.447-2.545-7.126-10.01-7.126V1.357h62.261l.34 20.527h-3.054c-1.866-14.59-5.598-16.286-21.885-16.286H948.21v33.42h12.554c10.687 0 11.366-1.696 12.214-10.178h3.054v24.599h-.17zm65.484 13.232c0-7.464-4.75-11.196-12.893-15.777l-13.063-6.786c-9.84-5.259-15.607-11.027-15.607-21.375C999.783 9.84 1010.81 0 1025.23 0c9.84 0 14.929 4.75 17.813 4.75 1.866 0 2.714-1.187 3.562-3.562h2.375l1.188 23.072-3.054.17c-1.696-11.198-9.67-19.85-20.866-19.85-8.483 0-14.081 5.09-14.081 12.215 0 7.804 5.937 11.027 12.554 14.59l11.196 5.937c10.519 5.768 17.983 11.536 17.983 22.563 0 14.59-12.554 24.939-28.161 24.939-11.028 0-16.456-5.26-19.34-5.26-1.866 0-2.884 1.697-3.732 4.242h-2.376l-1.696-24.43 3.054-.339c2.375 15.268 12.893 21.545 23.411 21.545 8.822-.17 16.286-4.071 16.286-13.91z", fill: "#231F20", fillRule: "evenodd" })));
|
|
11
|
+
exports.default = BrandFtMasthead;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TopColumnRight = exports.TopColumnCenterNoLink = exports.TopColumnCenter = exports.TopColumnLeft = exports.TopWrapper = exports.HeaderWrapper = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const BrandFtMasthead_1 = __importDefault(require("../svg-components/BrandFtMasthead"));
|
|
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
|
+
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" },
|
|
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" },
|
|
14
|
+
react_1.default.createElement("span", { className: "o-header__top-link-label" }, "Open search bar")));
|
|
15
|
+
const MyFt = () => (react_1.default.createElement("a", { className: "o-header__top-link o-header__top-link--myft", href: "/myft", "data-trackable": "my-ft", "data-tour-stage": "myFt", "aria-label": "My F T" },
|
|
16
|
+
react_1.default.createElement("span", { className: "o-header__visually-hidden" }, "myFT")));
|
|
17
|
+
const TopWrapper = (props) => (react_1.default.createElement("div", { className: "o-header__row o-header__top", "data-trackable": "header-top" },
|
|
18
|
+
react_1.default.createElement("div", { className: "o-header__container" },
|
|
19
|
+
react_1.default.createElement("div", { className: "o-header__top-wrapper" }, props.children))));
|
|
20
|
+
exports.TopWrapper = TopWrapper;
|
|
21
|
+
const TopColumnLeft = () => (react_1.default.createElement("div", { className: "o-header__top-column o-header__top-column--left" },
|
|
22
|
+
react_1.default.createElement(DrawerIcon, null),
|
|
23
|
+
react_1.default.createElement(SearchIcon, null)));
|
|
24
|
+
exports.TopColumnLeft = TopColumnLeft;
|
|
25
|
+
const TopColumnCenter = () => (react_1.default.createElement("div", { className: "o-header__top-column o-header__top-column--center" },
|
|
26
|
+
react_1.default.createElement("a", { className: "o-header__top-logo", style: { backgroundImage: 'none' }, "data-trackable": "logo", href: "/", title: "Go to Financial Times homepage" },
|
|
27
|
+
react_1.default.createElement(BrandFtMasthead_1.default, { title: "Financial Times" }))));
|
|
28
|
+
exports.TopColumnCenter = TopColumnCenter;
|
|
29
|
+
const TopColumnCenterNoLink = () => (react_1.default.createElement("div", { className: "o-header__top-column o-header__top-column--center" },
|
|
30
|
+
react_1.default.createElement("div", { className: "o-header__top-logo", style: { backgroundImage: 'none' } },
|
|
31
|
+
react_1.default.createElement(BrandFtMasthead_1.default, { title: "Financial Times" }))));
|
|
32
|
+
exports.TopColumnCenterNoLink = TopColumnCenterNoLink;
|
|
33
|
+
const TopColumnRight = () => (react_1.default.createElement("div", { className: "o-header__top-column o-header__top-column--right" },
|
|
34
|
+
react_1.default.createElement(MyFt, null)));
|
|
35
|
+
exports.TopColumnRight = TopColumnRight;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Drawer = exports.NoOutboundLinksHeader = exports.LogoOnly = exports.StickyHeader = exports.MainHeader = exports.Header = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const partials_1 = require("./components/top/partials");
|
|
9
|
+
const partials_2 = require("./components/navigation/partials");
|
|
10
|
+
const partials_3 = require("./components/sticky/partials");
|
|
11
|
+
const partials_4 = require("./components/sub-navigation/partials");
|
|
12
|
+
const topLevelPartials_1 = require("./components/drawer/topLevelPartials");
|
|
13
|
+
const partials_5 = require("./components/search/partials");
|
|
14
|
+
const defaultProps = {
|
|
15
|
+
showSubNavigation: true,
|
|
16
|
+
showUserNavigation: true,
|
|
17
|
+
userIsAnonymous: true,
|
|
18
|
+
userIsLoggedIn: false,
|
|
19
|
+
showStickyHeader: true,
|
|
20
|
+
showMegaNav: true
|
|
21
|
+
};
|
|
22
|
+
function MainHeader(props) {
|
|
23
|
+
const includeUserActionsNav = props.showUserNavigation && !props.userIsLoggedIn;
|
|
24
|
+
const includeSubNavigation = props.showSubNavigation && (props.data.breadcrumb || props.data.subsections);
|
|
25
|
+
return (react_1.default.createElement(partials_1.HeaderWrapper, Object.assign({}, props),
|
|
26
|
+
includeUserActionsNav ? react_1.default.createElement(partials_2.UserActionsNav, Object.assign({}, props)) : null,
|
|
27
|
+
react_1.default.createElement(partials_1.TopWrapper, null,
|
|
28
|
+
react_1.default.createElement(partials_1.TopColumnLeft, null),
|
|
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, null)),
|
|
31
|
+
react_1.default.createElement(partials_5.Search, { instance: "primary" }),
|
|
32
|
+
react_1.default.createElement(partials_2.MobileNav, Object.assign({}, props)),
|
|
33
|
+
react_1.default.createElement(partials_2.NavDesktop, null,
|
|
34
|
+
react_1.default.createElement(partials_2.NavListLeft, Object.assign({}, props)),
|
|
35
|
+
props.showUserNavigation ? react_1.default.createElement(partials_2.NavListRight, Object.assign({}, props)) : null),
|
|
36
|
+
includeSubNavigation ? react_1.default.createElement(partials_4.SubNavigation, Object.assign({}, props)) : null));
|
|
37
|
+
}
|
|
38
|
+
exports.MainHeader = MainHeader;
|
|
39
|
+
MainHeader.defaultProps = { ...defaultProps, showLogoLink: true };
|
|
40
|
+
function StickyHeader(props) {
|
|
41
|
+
return props.showStickyHeader ? (react_1.default.createElement(partials_3.StickyHeaderWrapper, Object.assign({}, props),
|
|
42
|
+
react_1.default.createElement(partials_3.TopWrapperSticky, null,
|
|
43
|
+
react_1.default.createElement(partials_3.TopColumnLeftSticky, null),
|
|
44
|
+
react_1.default.createElement(partials_3.TopColumnCenterSticky, Object.assign({}, props)),
|
|
45
|
+
react_1.default.createElement(partials_3.TopColumnRightSticky, Object.assign({}, props))),
|
|
46
|
+
react_1.default.createElement(partials_5.Search, { instance: "sticky" }))) : null;
|
|
47
|
+
}
|
|
48
|
+
exports.StickyHeader = StickyHeader;
|
|
49
|
+
StickyHeader.defaultProps = defaultProps;
|
|
50
|
+
function Header(props) {
|
|
51
|
+
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
52
|
+
react_1.default.createElement(MainHeader, Object.assign({}, props)),
|
|
53
|
+
react_1.default.createElement(StickyHeader, Object.assign({}, props))));
|
|
54
|
+
}
|
|
55
|
+
exports.Header = Header;
|
|
56
|
+
Header.defaultProps = defaultProps;
|
|
57
|
+
function LogoOnly(props) {
|
|
58
|
+
return (react_1.default.createElement(partials_1.HeaderWrapper, Object.assign({}, props),
|
|
59
|
+
react_1.default.createElement(partials_1.TopWrapper, null, props.showLogoLink ? react_1.default.createElement(partials_1.TopColumnCenter, null) : react_1.default.createElement(partials_1.TopColumnCenterNoLink, null))));
|
|
60
|
+
}
|
|
61
|
+
exports.LogoOnly = LogoOnly;
|
|
62
|
+
LogoOnly.defaultProps = defaultProps;
|
|
63
|
+
function Drawer(props) {
|
|
64
|
+
return react_1.default.createElement(topLevelPartials_1.IncludeDrawer, Object.assign({}, props));
|
|
65
|
+
}
|
|
66
|
+
exports.Drawer = Drawer;
|
|
67
|
+
Drawer.defaultProps = defaultProps;
|
|
68
|
+
function NoOutboundLinksHeader(props) {
|
|
69
|
+
const includeUserActionsNav = props.showUserNavigation && !props.userIsLoggedIn;
|
|
70
|
+
const includeSubNavigation = props.showSubNavigation && (props.data.breadcrumb || props.data.subsections);
|
|
71
|
+
return (react_1.default.createElement(partials_1.HeaderWrapper, Object.assign({}, props),
|
|
72
|
+
includeUserActionsNav ? react_1.default.createElement(partials_2.UserActionsNav, Object.assign({}, props)) : null,
|
|
73
|
+
react_1.default.createElement(partials_1.TopWrapper, null, props.showLogoLink ? react_1.default.createElement(partials_1.TopColumnCenter, null) : react_1.default.createElement(partials_1.TopColumnCenterNoLink, null)),
|
|
74
|
+
react_1.default.createElement(partials_2.NavDesktop, null, props.showUserNavigation ? react_1.default.createElement(partials_2.NavListRight, Object.assign({}, props)) : null),
|
|
75
|
+
includeSubNavigation ? react_1.default.createElement(partials_4.SubNavigation, Object.assign({}, props)) : null));
|
|
76
|
+
}
|
|
77
|
+
exports.NoOutboundLinksHeader = NoOutboundLinksHeader;
|
|
78
|
+
NoOutboundLinksHeader.defaultProps = defaultProps;
|