@financial-times/n-myft-ui 26.0.0 → 27.2.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/.circleci/config.yml +42 -16
- package/.nvmrc +1 -1
- package/Makefile +0 -1
- package/README.md +2 -48
- package/build-state/npm-shrinkwrap.json +10147 -20187
- package/components/collections/collections.html +85 -0
- package/components/concept-list/concept-list.html +31 -0
- package/components/csrf-token/input.html +5 -0
- package/components/follow-button/follow-button.html +79 -0
- package/components/instant-alert/instant-alert.html +47 -0
- package/components/pin-button/pin-button.html +20 -0
- package/components/save-for-later/save-for-later.html +68 -0
- package/components/unread-articles-indicator/date-fns.js +6 -6
- package/demos/app.js +3 -26
- package/demos/templates/demo.html +11 -10
- package/myft/main.scss +145 -0
- package/myft/ui/lists.js +22 -0
- package/myft/ui/save-article-to-list-variant.js +376 -0
- package/package.json +16 -30
- package/components/collections/collections.jsx +0 -68
- package/components/collections/collections.test.js +0 -83
- package/components/concept-list/concept-list.jsx +0 -69
- package/components/concept-list/concept-list.test.js +0 -116
- package/components/csrf-token/input.jsx +0 -20
- package/components/csrf-token/input.test.js +0 -23
- package/components/follow-button/follow-button.jsx +0 -176
- package/components/follow-button/follow-button.test.js +0 -40
- package/components/index.js +0 -17
- package/components/instant-alert/instant-alert.jsx +0 -73
- package/components/instant-alert/instant-alert.test.js +0 -86
- package/components/pin-button/pin-button.jsx +0 -40
- package/components/pin-button/pin-button.test.js +0 -57
- package/components/save-for-later/save-for-later.jsx +0 -101
- package/components/save-for-later/save-for-later.test.js +0 -59
- package/demos/templates/demo-layout.html +0 -25
- package/demos/templates/demo.jsx +0 -125
- package/dist/bundles/bundle.js +0 -3232
- package/jest.config.js +0 -8
- package/jsx-migration.md +0 -16
- package/webpack.config.js +0 -34
@@ -0,0 +1,85 @@
|
|
1
|
+
<section
|
2
|
+
class="collection {{#if liteStyle}}collection--lite{{else}}collection--regular{{/if}}"
|
3
|
+
data-trackable="{{#if trackable}}{{trackable}}{{else}}collection{{/if}}">
|
4
|
+
<header class="collection__header {{#if liteStyle}}collection__header--lite{{else}}collection__header--regular{{/if}}">
|
5
|
+
<h2 class="collection__title {{#if liteStyle}}collection__title--lite{{else}}collection__title--regular{{/if}}">
|
6
|
+
{{title}}
|
7
|
+
</h2>
|
8
|
+
</header>
|
9
|
+
<ul class="collection__concepts">
|
10
|
+
{{#concepts}}
|
11
|
+
<li class="collection__concept">
|
12
|
+
{{#if ../liteStyle}}
|
13
|
+
{{> n-myft-ui/components/follow-button/follow-button
|
14
|
+
variant="primary"
|
15
|
+
buttonText=name
|
16
|
+
collectionName=../collectionName
|
17
|
+
}}
|
18
|
+
{{else}}
|
19
|
+
{{> n-myft-ui/components/follow-button/follow-button
|
20
|
+
variant="inverse"
|
21
|
+
buttonText=name
|
22
|
+
collectionName=../collectionName
|
23
|
+
}}
|
24
|
+
{{/if}}
|
25
|
+
</li>
|
26
|
+
{{/concepts}}
|
27
|
+
</ul>
|
28
|
+
<div class="collection__meta">
|
29
|
+
<form
|
30
|
+
method="POST"
|
31
|
+
action="#"
|
32
|
+
data-myft-ui="follow"
|
33
|
+
{{#if collectionName}}data-myft-tracking="collectionName={{collectionName}}"{{/if}}
|
34
|
+
data-concept-id="
|
35
|
+
{{~#concepts~}}
|
36
|
+
{{conceptId}}
|
37
|
+
{{~#unless @last~}}
|
38
|
+
,
|
39
|
+
{{~/unless~}}
|
40
|
+
{{~/concepts~}}"
|
41
|
+
class="n-myft-ui n-myft-ui--follow n-ui-hide-core collection-follow-all">
|
42
|
+
<input
|
43
|
+
type="hidden"
|
44
|
+
name="directType"
|
45
|
+
value="
|
46
|
+
{{~#concepts~}}
|
47
|
+
{{directType}}
|
48
|
+
{{~#unless @last~}}
|
49
|
+
,
|
50
|
+
{{~/unless~}}
|
51
|
+
{{~/concepts~}}"
|
52
|
+
/>
|
53
|
+
{{> n-myft-ui/components/csrf-token/input}}
|
54
|
+
<input
|
55
|
+
type="hidden"
|
56
|
+
name="name"
|
57
|
+
value="
|
58
|
+
{{~#concepts~}}
|
59
|
+
{{name}}
|
60
|
+
{{~#unless @last~}}
|
61
|
+
,
|
62
|
+
{{~/unless~}}
|
63
|
+
{{~/concepts~}}"
|
64
|
+
/>
|
65
|
+
<button
|
66
|
+
type="submit"
|
67
|
+
aria-pressed="false"
|
68
|
+
class="collection-follow-all__button {{#if liteStyle}}collection-follow-all__button--lite{{else}}collection-follow-all__button--regular{{/if}}"
|
69
|
+
data-trackable="follow all"
|
70
|
+
data-concept-id="
|
71
|
+
{{~#concepts~}}
|
72
|
+
{{conceptId}}
|
73
|
+
{{~#unless @last~}}
|
74
|
+
,
|
75
|
+
{{~/unless~}}
|
76
|
+
{{~/concepts~}}"
|
77
|
+
aria-label="Add all topics in the {{title}} collection to my F T"
|
78
|
+
data-alternate-label="Remove all topics in the {{title}} collection from my F T"
|
79
|
+
data-alternate-text="Added"
|
80
|
+
title="Add all topics in the {{title}} collection to my F T">
|
81
|
+
Add all to myFT
|
82
|
+
</button>
|
83
|
+
</form>
|
84
|
+
</div>
|
85
|
+
</section>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
{{#ifAll @root.flags.myFtApi @root.flags.myFtApiWrite concepts concepts.length}}
|
2
|
+
<div
|
3
|
+
class="concept-list"
|
4
|
+
data-trackable="{{#if trackable}}{{trackable}}{{else}}concept-list{{/if}}">
|
5
|
+
{{#ifSome contentType conceptListTitle}}
|
6
|
+
<h2 class="concept-list__title">
|
7
|
+
{{#if conceptListTitle}}
|
8
|
+
{{conceptListTitle}}
|
9
|
+
{{else}}
|
10
|
+
Follow the topics in this {{contentType}}
|
11
|
+
{{/if}}
|
12
|
+
</h2>
|
13
|
+
{{/ifSome}}
|
14
|
+
<ul class="concept-list__list">
|
15
|
+
{{#each concepts}}
|
16
|
+
<li class="concept-list__list-item">
|
17
|
+
<a
|
18
|
+
href="{{relativeUrl}}"
|
19
|
+
data-trackable="{{#if conceptTrackable}}{{conceptTrackable}}{{else}}concept{{/if}}"
|
20
|
+
class="concept-list__concept">
|
21
|
+
{{prefLabel}}
|
22
|
+
</a>
|
23
|
+
{{> n-myft-ui/components/follow-button/follow-button
|
24
|
+
conceptId=id
|
25
|
+
name=prefLabel
|
26
|
+
}}
|
27
|
+
</li>
|
28
|
+
{{/each}}
|
29
|
+
</ul>
|
30
|
+
</div>
|
31
|
+
{{/ifAll}}
|
@@ -0,0 +1,79 @@
|
|
1
|
+
{{#if @root.flags.myFtApiWrite}}
|
2
|
+
<form
|
3
|
+
class="n-myft-ui n-myft-ui--follow {{extraClasses}}"
|
4
|
+
method="GET"
|
5
|
+
data-myft-ui="follow"
|
6
|
+
data-concept-id="{{conceptId}}"
|
7
|
+
{{#if collectionName}}data-myft-tracking="collectionName={{collectionName}}"{{/if}}
|
8
|
+
{{#if followPlusDigestEmail}}
|
9
|
+
action="/__myft/api/core/follow-plus-digest-email/{{conceptId}}?method=put"
|
10
|
+
data-myft-ui-variant="followPlusDigestEmail"
|
11
|
+
{{else}}
|
12
|
+
{{#ifAll setFollowButtonStateToSelected @root.cacheablePersonalisedUrl}}
|
13
|
+
action="/myft/remove/{{conceptId}}"
|
14
|
+
data-js-action="/__myft/api/core/followed/concept/{{conceptId}}?method=delete"
|
15
|
+
{{else}}
|
16
|
+
action="/myft/add/{{conceptId}}"
|
17
|
+
data-js-action="/__myft/api/core/followed/concept/{{conceptId}}?method=put"
|
18
|
+
{{/ifAll}}
|
19
|
+
{{/if}}>
|
20
|
+
{{> n-myft-ui/components/csrf-token/input}}
|
21
|
+
<div
|
22
|
+
class="n-myft-ui__announcement o-normalise-visually-hidden"
|
23
|
+
aria-live="assertive"
|
24
|
+
data-pressed-text="Now following {{name}}."
|
25
|
+
data-unpressed-text="No longer following {{name}}."
|
26
|
+
></div>
|
27
|
+
<button
|
28
|
+
{{#ifAll setFollowButtonStateToSelected @root.cacheablePersonalisedUrl}}
|
29
|
+
aria-label="Remove {{name}} from myFT"
|
30
|
+
title="Remove {{name}} from myFT"
|
31
|
+
data-alternate-label="Add {{name}} to myFT"
|
32
|
+
aria-pressed="true"
|
33
|
+
{{#if alternateText}}
|
34
|
+
data-alternate-text="{{alternateText}}"
|
35
|
+
{{else}}
|
36
|
+
{{#if buttonText}}
|
37
|
+
data-alternate-text="{{buttonText}}"
|
38
|
+
{{else}}
|
39
|
+
data-alternate-text="Add to myFT"
|
40
|
+
{{/if}}
|
41
|
+
{{/if}}
|
42
|
+
{{else}}
|
43
|
+
aria-pressed="false"
|
44
|
+
aria-label="Add {{name}} to myFT"
|
45
|
+
title="Add {{name}} to myFT"
|
46
|
+
data-alternate-label="Remove {{name}} from myFT"
|
47
|
+
{{#if alternateText}}
|
48
|
+
data-alternate-text="{{alternateText}}"
|
49
|
+
{{else}}
|
50
|
+
{{#if buttonText}}
|
51
|
+
data-alternate-text="{{buttonText}}"
|
52
|
+
{{else}}
|
53
|
+
data-alternate-text="Added"
|
54
|
+
{{/if}}
|
55
|
+
{{/if}}
|
56
|
+
{{/ifAll}}
|
57
|
+
class="{{extraButtonClasses}}
|
58
|
+
n-myft-follow-button
|
59
|
+
{{~#variant}} n-myft-follow-button--{{this}}{{/variant~}}"
|
60
|
+
data-concept-id="{{conceptId}}" {{! duplicated here for tracking}}
|
61
|
+
{{#if followPlusDigestEmail}}
|
62
|
+
data-trackable-context-messaging="add-to-myft-plus-digest-button"
|
63
|
+
{{/if}}
|
64
|
+
data-trackable="follow"
|
65
|
+
type="submit">
|
66
|
+
{{~#if buttonText~}}
|
67
|
+
{{buttonText}}
|
68
|
+
{{~else~}}
|
69
|
+
{{~#ifAll setFollowButtonStateToSelected @root.cacheablePersonalisedUrl~}}
|
70
|
+
Added
|
71
|
+
{{~else~}}
|
72
|
+
Add to myFT
|
73
|
+
{{~/ifAll~}}
|
74
|
+
{{~/if~}}
|
75
|
+
</button>
|
76
|
+
</form>
|
77
|
+
{{else}}
|
78
|
+
<!-- Add to myFT button hidden due to myFtApiWrite being off -->
|
79
|
+
{{/if}}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
{{#if @root.flags.myFtApiWrite}}
|
2
|
+
<form class="n-myft-ui n-myft-ui--instant{{#if hideButtonText}} n-myft-ui--instant--hide-text{{/if}} {{extraClasses}}"
|
3
|
+
method="GET"
|
4
|
+
data-myft-ui="instant"
|
5
|
+
data-concept-id="{{conceptId}}"
|
6
|
+
action="/myft/add/{{conceptId}}?instant=true"
|
7
|
+
data-js-action="/__myft/api/core/followed/concept/{{conceptId}}?method=put">
|
8
|
+
{{> n-myft-ui/components/csrf-token/input}}
|
9
|
+
<input type="hidden" value="{{name}}" name="name">
|
10
|
+
{{#if directType}}
|
11
|
+
<input type="hidden" value="{{directType}}" name="directType">
|
12
|
+
{{else}}
|
13
|
+
<input type="hidden" value="http://www.ft.com/ontology/concept/Concept" name="directType">
|
14
|
+
{{/if}}
|
15
|
+
<button
|
16
|
+
aria-label="Get instant alerts for {{name}}"
|
17
|
+
{{#ifAll hasInstantAlert @root.cacheablePersonalisedUrl}}
|
18
|
+
aria-pressed="true"
|
19
|
+
{{else}}
|
20
|
+
aria-pressed="false"
|
21
|
+
{{/ifAll}}
|
22
|
+
class="n-myft-ui__button
|
23
|
+
{{#variant}} n-myft-ui__button--{{this}}{{/variant}}
|
24
|
+
{{#size}} n-myft-ui__button--{{this}}{{/size}}
|
25
|
+
n-myft-ui__button--instant
|
26
|
+
n-myft-ui__button--instant-light"
|
27
|
+
data-alternate-label="Stop instant alerts for {{name}}"
|
28
|
+
{{#if alternateText}}
|
29
|
+
data-alternate-text="{{alternateText}}"
|
30
|
+
{{else}}
|
31
|
+
{{#if buttonText}}
|
32
|
+
data-alternate-text="{{buttonText}}"
|
33
|
+
{{else}}
|
34
|
+
data-alternate-text="Instant alerts"
|
35
|
+
{{/if}}
|
36
|
+
{{/if}}
|
37
|
+
data-concept-id="{{conceptId}}" {{! duplicated here for tracking}}
|
38
|
+
data-trackable="instant"
|
39
|
+
title="Get instant alerts for {{name}}"
|
40
|
+
name="_rel.instant"
|
41
|
+
value="{{#if hasInstantAlert}}false{{else}}true{{/if}}"
|
42
|
+
type="submit"
|
43
|
+
>{{#if buttonText}}{{buttonText}}{{else}}Instant alerts{{/if}}</button>
|
44
|
+
</form>
|
45
|
+
{{else}}
|
46
|
+
<!-- Instant alert button hidden due to myFtApiWrite being off -->
|
47
|
+
{{/if}}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
{{#if showPrioritiseButton}}
|
2
|
+
<span class="myft-pin-divider"></span>
|
3
|
+
<div class="myft-pin-button-wrapper">
|
4
|
+
<form method="post" action="/__myft/api/core/prioritised/concept/{{id}}?method={{#if prioritised}}delete{{else}}put{{/if}}" data-myft-prioritise>
|
5
|
+
{{> n-myft-ui/components/csrf-token/input }}
|
6
|
+
<input type="hidden" value="{{name}}" name="name"> {{#if directType}}
|
7
|
+
<input type="hidden" value="{{directType}}" name="directType"> {{else}}
|
8
|
+
<input type="hidden" value="http://www.ft.com/ontology/concept/Concept" name="directType"> {{/if}}
|
9
|
+
<div
|
10
|
+
class="n-myft-ui__announcement o-normalise-visually-hidden"
|
11
|
+
aria-live="assertive"
|
12
|
+
data-pressed-text="{{name}} pinned in myFT."
|
13
|
+
data-unpressed-text="Unpinned {{name}} from myFT."
|
14
|
+
></div>
|
15
|
+
<button id="myft-pin-button__{{id}}" class="myft-pin-button" data-prioritise-button data-trackable="prioritised" data-concept-id="{{id}}" data-prioritised="{{#if prioritised}}true{{else}}false{{/if}}"
|
16
|
+
aria-label="{{#if prioritised}}Unpin{{else}}Pin{{/if}} {{name}} {{#if prioritised}}from{{else}}in{{/if}} myFT" aria-pressed="{{#if prioritised}}true{{else}}false{{/if}}" title="{{#if prioritised}}Unpin{{else}}Pin{{/if}} {{name}}">
|
17
|
+
</button>
|
18
|
+
</form>
|
19
|
+
</div>
|
20
|
+
{{/if}}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
{{#if @root.flags.myFtApiWrite}}
|
2
|
+
<form class="n-myft-ui n-myft-ui--save" method="GET"
|
3
|
+
data-content-id="{{contentId}}"
|
4
|
+
data-myft-ui="saved"
|
5
|
+
action="/myft/save/{{contentId}}"
|
6
|
+
data-js-action="/__myft/api/core/saved/content/{{contentId}}?method=put"
|
7
|
+
{{#ifEquals @root.flags.professorLists 'variant'}}data-myft-ui-variant="createListAndSaveArticleVariant"{{/ifEquals}}>
|
8
|
+
{{> n-myft-ui/components/csrf-token/input}}
|
9
|
+
<div
|
10
|
+
class="n-myft-ui__announcement o-normalise-visually-hidden"
|
11
|
+
aria-live="assertive"
|
12
|
+
data-pressed-text="Article saved in My FT."
|
13
|
+
data-unpressed-text="Removed article from My FT."
|
14
|
+
></div>
|
15
|
+
<button
|
16
|
+
type="submit"
|
17
|
+
class="{{#if saveButtonWithIcon}}n-myft-ui__save-button-with-icon{{else}}n-myft-ui__button{{#variant}} n-myft-ui__button--{{this}}{{/variant}}{{/if}}"
|
18
|
+
data-trackable="{{#if trackableId}}{{trackableId}}{{else}}save-for-later{{/if}}"
|
19
|
+
{{#if isSaved}}
|
20
|
+
{{!-- The value of alternate label needs to be the opposite of label / the current saved state. This allows the client side JS to toggle the labels on state changes --}}
|
21
|
+
title="{{#if title}}{{title}} is{{/if}} Saved to myFT"
|
22
|
+
aria-label="{{#if title}}{{title}} is{{/if}} Saved to myFT"
|
23
|
+
data-alternate-label="{{#if title}}Save {{title}} to myFT for later{{else}}Save this article to myFT for later{{/if}}"
|
24
|
+
aria-pressed="true"
|
25
|
+
{{else}}
|
26
|
+
title="{{#if title}}Save {{title}} to myFT for later{{else}}Save this article to myFT for later{{/if}}"
|
27
|
+
aria-label="{{#if title}}Save {{title}} to myFT for later{{else}}Save this article to myFT for later{{/if}}"
|
28
|
+
data-alternate-label="{{#if title}}{{title}} is{{/if}} Saved to myFT"
|
29
|
+
aria-pressed="false"
|
30
|
+
{{/if}}
|
31
|
+
{{#unlessEquals appIsStreamPage true}}
|
32
|
+
{{#if saveButtonWithIcon}}
|
33
|
+
data-text-variant="save-button-with-icon-copy"
|
34
|
+
{{else}}
|
35
|
+
data-text-variant="save-button-longer-copy"
|
36
|
+
{{/if}}
|
37
|
+
{{/unlessEquals}}
|
38
|
+
{{#if alternateText}}
|
39
|
+
data-alternate-text="{{alternateText}}"
|
40
|
+
{{else}}
|
41
|
+
{{#if isSaved}}
|
42
|
+
data-alternate-text="Save "
|
43
|
+
{{else}}
|
44
|
+
data-alternate-text="Saved "
|
45
|
+
{{/if}}
|
46
|
+
{{/if}}
|
47
|
+
data-content-id="{{contentId}}" {{! duplicated here for tracking}}
|
48
|
+
>
|
49
|
+
{{#if saveButtonWithIcon}}
|
50
|
+
<span class="save-button-with-icon-copy" data-variant-label>{{#if buttonText~}}
|
51
|
+
{{buttonText}}
|
52
|
+
{{~else~}}
|
53
|
+
{{#if isSaved}}Saved{{else}}Save{{/if}}
|
54
|
+
{{~/if}}</span>
|
55
|
+
{{else}}
|
56
|
+
{{#if buttonText}}{{buttonText}}{{else}}
|
57
|
+
{{#unlessEquals appIsStreamPage true}}
|
58
|
+
<span class="save-button-longer-copy" data-variant-label>{{#if isSaved}}Saved {{else}}Save {{/if}}</span><span class="n-myft-ui__button--viewport-large" aria-hidden="true">to myFT</span>
|
59
|
+
{{else}}
|
60
|
+
<span>{{#if isSaved}}Saved{{else}}Save{{/if}}</span>
|
61
|
+
{{/unlessEquals}}
|
62
|
+
{{/if}}
|
63
|
+
{{/if}}
|
64
|
+
</button>
|
65
|
+
</form>
|
66
|
+
{{else}}
|
67
|
+
<!-- Save button hidden due to myFtApiWrite being off -->
|
68
|
+
{{/if }}
|
@@ -2,12 +2,12 @@
|
|
2
2
|
// the detail => https://github.com/date-fns/date-fns/blob/HEAD/CHANGELOG.md#200---2019-08-20
|
3
3
|
// By adding validation for dates before their functions allows us to know it when unexpected value passed.
|
4
4
|
|
5
|
-
import isTodayOriginal from
|
6
|
-
import isAfterOriginal from
|
7
|
-
import addMinutesOriginal from
|
8
|
-
import startOfDayOriginal from
|
9
|
-
import isValidOriginal from
|
10
|
-
import parseISO from
|
5
|
+
import isTodayOriginal from "date-fns/src/isToday";
|
6
|
+
import isAfterOriginal from "date-fns/src/isAfter";
|
7
|
+
import addMinutesOriginal from "date-fns/src/addMinutes";
|
8
|
+
import startOfDayOriginal from "date-fns/src/startOfDay";
|
9
|
+
import isValidOriginal from "date-fns/src/isValid";
|
10
|
+
import parseISO from "date-fns/src/parseISO";
|
11
11
|
|
12
12
|
const isValid = (date) => {
|
13
13
|
if (!isValidOriginal(date)) {
|
package/demos/app.js
CHANGED
@@ -1,17 +1,11 @@
|
|
1
|
-
require('sucrase/register');
|
2
1
|
const nExpress = require('@financial-times/n-express');
|
3
2
|
const chalk = require('chalk');
|
4
3
|
const errorHighlight = chalk.bold.red;
|
5
4
|
const highlight = chalk.bold.green;
|
6
|
-
const { PageKitReactJSX } = require('@financial-times/dotcom-server-react-jsx');
|
7
|
-
const fs = require('fs');
|
8
5
|
const path = require('path');
|
9
6
|
const handlebars = require('handlebars');
|
10
7
|
const { PageKitHandlebars, helpers } = require('@financial-times/dotcom-server-handlebars');
|
11
8
|
|
12
|
-
const demoJSX = require('./templates/demo').default;
|
13
|
-
const demoLayoutSource = fs.readFileSync(path.join(__dirname, './templates/demo-layout.html'),'utf8').toString();
|
14
|
-
|
15
9
|
const fixtures = {
|
16
10
|
followButton: require('./fixtures/follow-button'),
|
17
11
|
saveButton: require('./fixtures/save-button'),
|
@@ -37,43 +31,26 @@ const app = module.exports = nExpress({
|
|
37
31
|
|
38
32
|
app.set('views', path.join(__dirname, '/templates'));
|
39
33
|
app.set('view engine', '.html');
|
40
|
-
|
41
34
|
app.engine('.html', new PageKitHandlebars({
|
42
35
|
cache: false,
|
43
36
|
handlebars,
|
44
|
-
helpers
|
37
|
+
helpers: {
|
38
|
+
...helpers
|
39
|
+
}
|
45
40
|
}).engine);
|
46
41
|
|
47
42
|
app.use('/public', nExpress.static(path.join(__dirname, '../public'), { redirect: false }));
|
48
43
|
|
49
|
-
const jsxRenderer = (new PageKitReactJSX({ includeDoctype: false }));
|
50
|
-
|
51
44
|
app.get('/', (req, res) => {
|
52
45
|
res.render('demo', Object.assign({
|
53
|
-
title: 'n-myft-ui demo',
|
54
|
-
flags: {
|
55
|
-
myFtApi: true,
|
56
|
-
myFtApiWrite: true
|
57
|
-
},
|
58
|
-
}, fixtures));
|
59
|
-
});
|
60
|
-
|
61
|
-
app.get('/demo-jsx', async (req, res) => {
|
62
|
-
let demo = await jsxRenderer.render(demoJSX, Object.assign({
|
63
46
|
title: 'n-myft-ui demo',
|
64
47
|
flags: {
|
65
48
|
myFtApi: true,
|
66
49
|
myFtApiWrite: true
|
67
50
|
}
|
68
51
|
}, fixtures));
|
69
|
-
|
70
|
-
let template = handlebars.compile(demoLayoutSource);
|
71
|
-
let result = template({body: demo});
|
72
|
-
|
73
|
-
res.send(result);
|
74
52
|
});
|
75
53
|
|
76
|
-
|
77
54
|
function runPa11yTests () {
|
78
55
|
const spawn = require('child_process').spawn;
|
79
56
|
const pa11y = spawn('pa11y-ci');
|
@@ -32,7 +32,7 @@
|
|
32
32
|
</h2>
|
33
33
|
|
34
34
|
{{#followButton}}
|
35
|
-
{{
|
35
|
+
{{> n-myft-ui/components/follow-button/follow-button}}
|
36
36
|
{{/followButton}}
|
37
37
|
|
38
38
|
<h2
|
@@ -41,51 +41,52 @@
|
|
41
41
|
</h2>
|
42
42
|
|
43
43
|
{{#followButton}}
|
44
|
-
{{
|
44
|
+
{{> n-myft-ui/components/follow-button/follow-button buttonText=name}}
|
45
45
|
{{/followButton}}
|
46
46
|
|
47
47
|
{{#saveButton}}
|
48
48
|
<h2 class="demo-section__title">
|
49
49
|
Save button
|
50
50
|
</h2>
|
51
|
-
{{
|
51
|
+
{{> n-myft-ui/components/save-for-later/save-for-later }}
|
52
52
|
{{/saveButton}}
|
53
53
|
|
54
54
|
{{#saveButton}}
|
55
55
|
<h2 class="demo-section__title">
|
56
56
|
Unsave button
|
57
57
|
</h2>
|
58
|
-
{{
|
58
|
+
{{> n-myft-ui/components/save-for-later/save-for-later isSaved=true }}
|
59
59
|
{{/saveButton}}
|
60
60
|
|
61
61
|
{{#saveButton}}
|
62
62
|
<h2 class="demo-section__title">
|
63
63
|
Save button with icon
|
64
64
|
</h2>
|
65
|
-
{{
|
65
|
+
{{> n-myft-ui/components/save-for-later/save-for-later saveButtonWithIcon=true }}
|
66
66
|
{{/saveButton}}
|
67
67
|
|
68
68
|
{{#saveButton}}
|
69
69
|
<h2 class="demo-section__title">
|
70
70
|
Unsave button with icon
|
71
71
|
</h2>
|
72
|
-
{{
|
72
|
+
{{> n-myft-ui/components/save-for-later/save-for-later isSaved=true saveButtonWithIcon=true }}
|
73
73
|
{{/saveButton}}
|
74
74
|
|
75
75
|
<h2 class="demo-section__title">
|
76
76
|
Pin button
|
77
77
|
</h2>
|
78
78
|
{{#each pinButton}}
|
79
|
-
{{
|
79
|
+
{{> n-myft-ui/components/pin-button/pin-button }}
|
80
80
|
{{/each}}
|
81
81
|
|
82
82
|
{{#instantAlert}}
|
83
83
|
<h2 class="demo-section__title">
|
84
84
|
Instant Alert
|
85
85
|
</h2>
|
86
|
-
{{
|
86
|
+
{{> n-myft-ui/components/instant-alert/instant-alert }}
|
87
87
|
{{/instantAlert}}
|
88
88
|
|
89
|
+
|
89
90
|
</div>
|
90
91
|
</div>
|
91
92
|
</section>
|
@@ -448,7 +449,7 @@
|
|
448
449
|
|
449
450
|
{{#collections}}
|
450
451
|
<div data-o-grid-colspan="3">
|
451
|
-
{{
|
452
|
+
{{> n-myft-ui/components/collections/collections }}
|
452
453
|
</div>
|
453
454
|
{{/collections}}
|
454
455
|
</div>
|
@@ -470,7 +471,7 @@
|
|
470
471
|
|
471
472
|
{{#each conceptList}}
|
472
473
|
<div data-o-grid-colspan="3">
|
473
|
-
{{
|
474
|
+
{{> n-myft-ui/components/concept-list/concept-list }}
|
474
475
|
</div>
|
475
476
|
{{/each}}
|
476
477
|
</div>
|
package/myft/main.scss
CHANGED
@@ -173,3 +173,148 @@ $spacing-unit: 20px;
|
|
173
173
|
}
|
174
174
|
|
175
175
|
}
|
176
|
+
|
177
|
+
.share-nav {
|
178
|
+
&.data-overlap-initialised {
|
179
|
+
.o-overlay {
|
180
|
+
transition: opacity 0.15s ease-in;
|
181
|
+
opacity: 0;
|
182
|
+
z-index: -1;
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
.myft-ui-create-list-variant {
|
187
|
+
border-radius: 10px;
|
188
|
+
border: 1px solid oColorsByName('black-5');
|
189
|
+
background: oColorsByName('white-80');
|
190
|
+
|
191
|
+
.o-overlay__heading {
|
192
|
+
border-radius: 10px 10px 0 0;
|
193
|
+
background: oColorsByName('white-60');
|
194
|
+
@include oTypographySans($scale: 2);
|
195
|
+
color: oColorsByName('black-80');
|
196
|
+
}
|
197
|
+
|
198
|
+
.o-overlay__content {
|
199
|
+
@include oTypographySans($scale: 0);
|
200
|
+
color: oColorsByName('black-80');
|
201
|
+
padding: 0;
|
202
|
+
}
|
203
|
+
|
204
|
+
.o-overlay__title {
|
205
|
+
margin: 8px 14px 0 8px;
|
206
|
+
}
|
207
|
+
|
208
|
+
&-container {
|
209
|
+
display: block;
|
210
|
+
width: 340px;
|
211
|
+
top: 115.5px;
|
212
|
+
left: 50px;
|
213
|
+
}
|
214
|
+
|
215
|
+
&-add {
|
216
|
+
border: 0;
|
217
|
+
background: none;
|
218
|
+
@include oTypographySans($scale: 1, $weight: 'semibold');
|
219
|
+
color: oColorsByName('black-80');
|
220
|
+
|
221
|
+
padding-left: 0;
|
222
|
+
margin-left: -8px;
|
223
|
+
|
224
|
+
&:hover {
|
225
|
+
text-decoration: underline;
|
226
|
+
}
|
227
|
+
|
228
|
+
&::before {
|
229
|
+
content: '';
|
230
|
+
@include oIconsContent(
|
231
|
+
'plus',
|
232
|
+
oColorsByName('black-80'),
|
233
|
+
28,
|
234
|
+
$iconset-version: 1
|
235
|
+
);
|
236
|
+
vertical-align: middle;
|
237
|
+
margin-top: -2px;
|
238
|
+
}
|
239
|
+
}
|
240
|
+
|
241
|
+
&-add-description {
|
242
|
+
margin: 4px 0;
|
243
|
+
}
|
244
|
+
|
245
|
+
&-heading {
|
246
|
+
&::before {
|
247
|
+
content: '';
|
248
|
+
@include oIconsContent(
|
249
|
+
'tick',
|
250
|
+
oColorsByName('teal'),
|
251
|
+
32,
|
252
|
+
$iconset-version: 1
|
253
|
+
);
|
254
|
+
vertical-align: middle;
|
255
|
+
margin-top: -2px;
|
256
|
+
}
|
257
|
+
}
|
258
|
+
|
259
|
+
&-footer {
|
260
|
+
border-top: 1px solid oColorsByName('black-5');
|
261
|
+
padding: 16px;
|
262
|
+
}
|
263
|
+
|
264
|
+
&-icon {
|
265
|
+
&::before {
|
266
|
+
content: "";
|
267
|
+
display: inline-block;
|
268
|
+
background-repeat: no-repeat;
|
269
|
+
background-size: contain;
|
270
|
+
background-position: 50%;
|
271
|
+
background-color: transparent;
|
272
|
+
background-image: url(https://www.ft.com/__origami/service/image/v2/images/raw/ftlogo-v1:brand-myft?source=next-article);
|
273
|
+
width: 42px;
|
274
|
+
height: 42px;
|
275
|
+
vertical-align: middle;
|
276
|
+
margin-top: -2px;
|
277
|
+
}
|
278
|
+
|
279
|
+
&-visually-hidden {
|
280
|
+
clip: rect(0 0 0 0);
|
281
|
+
clip-path: inset(50%);
|
282
|
+
height: 1px;
|
283
|
+
overflow: hidden;
|
284
|
+
position: absolute;
|
285
|
+
white-space: nowrap;
|
286
|
+
width: 1px;
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
290
|
+
&-form {
|
291
|
+
display: flex;
|
292
|
+
width: calc(100% - 32px);
|
293
|
+
justify-content: space-between;
|
294
|
+
height: 40px;
|
295
|
+
gap: 8px;
|
296
|
+
padding: 0 16px 16px;
|
297
|
+
|
298
|
+
& > * {
|
299
|
+
flex: 1 1 auto;
|
300
|
+
}
|
301
|
+
|
302
|
+
.o-forms-input {
|
303
|
+
margin-top: 0;
|
304
|
+
}
|
305
|
+
}
|
306
|
+
|
307
|
+
&-lists {
|
308
|
+
padding: 16px 16px 0;
|
309
|
+
@include oTypographySans($scale: 1);
|
310
|
+
&-text {
|
311
|
+
@include oTypographySans($weight: 'semibold');
|
312
|
+
color: oColorsByName('black-80');
|
313
|
+
margin-bottom: 16px;
|
314
|
+
}
|
315
|
+
&-container {
|
316
|
+
margin-top: 0;
|
317
|
+
}
|
318
|
+
}
|
319
|
+
}
|
320
|
+
}
|