@kids-reporter/draft-renderer 0.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/README.md +86 -0
- package/lib/assets/annotation-arrow.png +0 -0
- package/lib/assets/audio-pause.png +0 -0
- package/lib/assets/audio-play.png +0 -0
- package/lib/assets/citation-download.png +0 -0
- package/lib/assets/default-og-img.png +0 -0
- package/lib/assets/slideshow-arrow-down-dark.png +0 -0
- package/lib/assets/slideshow-arrow-down.png +0 -0
- package/lib/assets/slideshow-arrow-up.png +0 -0
- package/lib/assets/slideshow-close-cross.png +0 -0
- package/lib/block-renderer-fn.js +123 -0
- package/lib/block-renderers/audio-block.js +162 -0
- package/lib/block-renderers/background-image-block.js +257 -0
- package/lib/block-renderers/background-video-block.js +272 -0
- package/lib/block-renderers/color-box-block.js +94 -0
- package/lib/block-renderers/divider-block.js +27 -0
- package/lib/block-renderers/embedded-code-block.js +121 -0
- package/lib/block-renderers/image-block.js +72 -0
- package/lib/block-renderers/index.js +53 -0
- package/lib/block-renderers/info-box-block.js +124 -0
- package/lib/block-renderers/media-block.js +65 -0
- package/lib/block-renderers/related-post-block.js +73 -0
- package/lib/block-renderers/side-index-block.js +49 -0
- package/lib/block-renderers/slideshow-block.js +253 -0
- package/lib/block-renderers/table-block.js +455 -0
- package/lib/block-renderers/video-block.js +37 -0
- package/lib/components/slideshow-lightbox.js +134 -0
- package/lib/components/slideshow-sidebar.js +148 -0
- package/lib/const.js +10 -0
- package/lib/draft-renderer.js +234 -0
- package/lib/entity-decorator.js +18 -0
- package/lib/entity-decorators/annotation-decorator.js +155 -0
- package/lib/entity-decorators/index.js +16 -0
- package/lib/entity-decorators/link-decorator.js +48 -0
- package/lib/index.js +30 -0
- package/lib/public/07d1287fd390346af0c15b930148a5e4.png +0 -0
- package/lib/public/5b3cb1a908786c8750f1041860699cc1.png +0 -0
- package/lib/public/679d63b1846e81ada28c2f76edbd2931.png +0 -0
- package/lib/public/722f90c535fa64c27555ec6ee5f22393.png +0 -0
- package/lib/public/903cf84ef5c5ad76634c30bdc0ff8c49.png +0 -0
- package/lib/public/dc249b3412c5af890a004508287a3c3d.png +0 -0
- package/lib/public/dd45f0788d9c70cabe72430bf08e7413.png +0 -0
- package/lib/public/f96d4b486ba2061c460962ae694f4670.png +0 -0
- package/lib/shared-style/content-type.js +163 -0
- package/lib/shared-style/index.js +108 -0
- package/lib/theme/index.js +39 -0
- package/lib/types/index.js +32 -0
- package/lib/utils/common.js +44 -0
- package/lib/utils/post.js +147 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# [@mirrormedia/lilith-core](https://www.npmjs.com/package/@mirrormedia/lilith-draft-editor) · 
|
|
2
|
+
|
|
3
|
+
### Installation
|
|
4
|
+
|
|
5
|
+
`yarn install`
|
|
6
|
+
|
|
7
|
+
### Introduction
|
|
8
|
+
|
|
9
|
+
本套件是由 `@mirrormedia/lilith-draft-editor` 將其 maintain 的 buttons 對應的 block renderers 和 entity decorators 的邏輯 decouple,
|
|
10
|
+
以應用在 Next.js 專案以及 CMS 上。
|
|
11
|
+
|
|
12
|
+
### Development
|
|
13
|
+
|
|
14
|
+
在開發順序上,一開始各網站會有一套 default 的 block renderers 和 entity decorators,這些預設的 components 將會被 export 給 lilith-draft-editor 使用並在 CMS 上呈現出各 button 新增的 content。
|
|
15
|
+
|
|
16
|
+
#### For Next.js to use
|
|
17
|
+
|
|
18
|
+
在各網站開發時,工程師將因應設計將會針對 block renderers 和 entity decorators 修改樣式,因此會在各個網站的資料夾中修改網站專屬的 block renderers 和 entity decorators,這個套件將直接用在該 Next.js 專案上,當作 React component 直接使用,只要帶入 CMS 上拿到的 draft.js 相關的 contentBlock 的資料即可呈現樣式。
|
|
19
|
+
|
|
20
|
+
除了 block renderers 和 entity decorators 等檔案可以針對 block type 修改之外,built-in 的 draft.js block type 可以透過 `src/website/${website}/draft-renderer.tsx`中的 styled-components `DraftEditorWrapper` 中的 css 來修改
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
/* Draft built-in buttons' style */
|
|
24
|
+
.public-DraftStyleDefault-header-two {
|
|
25
|
+
}
|
|
26
|
+
.public-DraftStyleDefault-header-three {
|
|
27
|
+
}
|
|
28
|
+
.public-DraftStyleDefault-header-four {
|
|
29
|
+
}
|
|
30
|
+
.public-DraftStyleDefault-blockquote {
|
|
31
|
+
}
|
|
32
|
+
.public-DraftStyleDefault-ul {
|
|
33
|
+
}
|
|
34
|
+
.public-DraftStyleDefault-unorderedListItem {
|
|
35
|
+
}
|
|
36
|
+
.public-DraftStyleDefault-ol {
|
|
37
|
+
}
|
|
38
|
+
.public-DraftStyleDefault-orderedListItem {
|
|
39
|
+
}
|
|
40
|
+
/* code-block */
|
|
41
|
+
.public-DraftStyleDefault-pre {
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
修改完成後修改 package version, 跑 `yarn build` 和 `npm publish` 即可以發布新版套件並在 Next.js 中 `yarn install` 使用。
|
|
46
|
+
|
|
47
|
+
#### For CMS to use
|
|
48
|
+
|
|
49
|
+
在特定網站的 block renderers 和 entity decorators 改動之後,為了保持 CMS 上的 draft-editorn 所見即所得呈現和 Next.js 端同樣的樣式,
|
|
50
|
+
在完成 `npm publish` 後需要到 `packages/draft-editor` 去更新 `@mirrormedia/lilith-draft-renderer` 的版本,並依照該套件的 README.md 的指示在該網站的 CMS 中測試。
|
|
51
|
+
|
|
52
|
+
### File Structure
|
|
53
|
+
|
|
54
|
+
在 `src` 資料夾下有兩大類的檔案
|
|
55
|
+
|
|
56
|
+
1. 共用的 draft.js 程式碼: 主要是 draft.js button UI, draft-converter 和其他 helper function
|
|
57
|
+
2. 各網站客製化的改動:
|
|
58
|
+
|
|
59
|
+
依照各網站需求修改`src/website/${website}/`中的檔案
|
|
60
|
+
|
|
61
|
+
- block-renderer : 在既有(注 1)的 block-renderer 上附加可編輯的 wrapper,僅有部分 block renderers 適用
|
|
62
|
+
- selector: 依照各網站 keystone list 來調整 photo, video 和 post 的 gql query
|
|
63
|
+
- draft-editor: 主要 export 出 RichTextEditor 的檔案,實際使用在 lilith-core 對應的 webiste 中,可直接決定 RichTextEditor 樣式(注 2)
|
|
64
|
+
|
|
65
|
+
\*注 1: lilith-draft-editor 各個 buttons 對應的 block-renderers, entity-decorators 會 maintain 在 lilith-draft-renderer,由各網站 Next.js 專案開發人員實作,在本專案中會直接將 lilith-draft-renderer 中定義好的 block-renderers, entity-decorators 直接使用(除了少數需要再編輯的 block-renderer,參考 `src/website/${website}/block-renderer`中的 editor wrapper component)。
|
|
66
|
+
|
|
67
|
+
\*注 2: 雖然各個網站都 maintain 了一個 draft-editor,可以自行決定 import 進來的 buttons,不過因為 lilith-core 中實作 disalbedButtons 的功能,所以目前一率將所有的 buttons 加入 RichTextEditor 中,由 lilith-(mirrormedia|readr|mesh|editools) 來控制所使用的 buttons。
|
|
68
|
+
|
|
69
|
+
### Build
|
|
70
|
+
|
|
71
|
+
`yarn build`
|
|
72
|
+
|
|
73
|
+
### Publish
|
|
74
|
+
|
|
75
|
+
`npm run publish`
|
|
76
|
+
|
|
77
|
+
在 publish 前,請根據 conventional commits 的規範,將 package.json#version 升版。
|
|
78
|
+
|
|
79
|
+
### Notable Details
|
|
80
|
+
|
|
81
|
+
#### For those files under `views/` folder, we transpile them specifically.
|
|
82
|
+
|
|
83
|
+
For those files under `views/` folder, we transpile them by babel according to different configuation.
|
|
84
|
+
The specific babel configuration is `.views.babelrc.js`.
|
|
85
|
+
In `.views.babelrc.js`, we tell babel not to transpile `import` and `export` es6 codes into commonJS codes.
|
|
86
|
+
The Keystone server won't start server well if those files under `views/` are transpiled into commonJS codes.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.atomicBlockRenderer = atomicBlockRenderer;
|
|
7
|
+
|
|
8
|
+
var _blockRenderers = require("./block-renderers");
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
EmbeddedCodeBlock,
|
|
12
|
+
MediaBlock,
|
|
13
|
+
ImageBlock,
|
|
14
|
+
InfoBoxBlock,
|
|
15
|
+
SlideshowBlock,
|
|
16
|
+
SlideshowBlockV2,
|
|
17
|
+
DividerBlock,
|
|
18
|
+
TableBlock,
|
|
19
|
+
ColorBoxBlock,
|
|
20
|
+
BGImageBlock,
|
|
21
|
+
BGVideoBlock,
|
|
22
|
+
RelatedPostBlock,
|
|
23
|
+
SideIndexBlock,
|
|
24
|
+
VideoBlock,
|
|
25
|
+
AudioBlock
|
|
26
|
+
} = _blockRenderers.blockRenderers;
|
|
27
|
+
|
|
28
|
+
const AtomicBlock = props => {
|
|
29
|
+
const entity = props.contentState.getEntity(props.block.getEntityAt(0));
|
|
30
|
+
const entityType = entity.getType();
|
|
31
|
+
|
|
32
|
+
switch (entityType) {
|
|
33
|
+
case 'audioLink':
|
|
34
|
+
case 'imageLink':
|
|
35
|
+
case 'videoLink':
|
|
36
|
+
{
|
|
37
|
+
return MediaBlock(entity);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
case 'image':
|
|
41
|
+
{
|
|
42
|
+
return ImageBlock(entity);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
case 'slideshow':
|
|
46
|
+
{
|
|
47
|
+
return SlideshowBlock(entity);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
case 'slideshow-v2':
|
|
51
|
+
{
|
|
52
|
+
return SlideshowBlockV2(entity);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
case 'EMBEDDEDCODE':
|
|
56
|
+
{
|
|
57
|
+
return EmbeddedCodeBlock(entity);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
case 'INFOBOX':
|
|
61
|
+
{
|
|
62
|
+
return InfoBoxBlock(props);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
case 'DIVIDER':
|
|
66
|
+
{
|
|
67
|
+
return DividerBlock();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
case 'TABLE':
|
|
71
|
+
{
|
|
72
|
+
return TableBlock(props);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
case 'COLORBOX':
|
|
76
|
+
{
|
|
77
|
+
return ColorBoxBlock(props);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
case 'BACKGROUNDIMAGE':
|
|
81
|
+
{
|
|
82
|
+
return BGImageBlock(props);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
case 'BACKGROUNDVIDEO':
|
|
86
|
+
{
|
|
87
|
+
return BGVideoBlock(props);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
case 'RELATEDPOST':
|
|
91
|
+
{
|
|
92
|
+
return RelatedPostBlock(entity);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
case 'SIDEINDEX':
|
|
96
|
+
{
|
|
97
|
+
return SideIndexBlock(props);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
case 'VIDEO':
|
|
101
|
+
{
|
|
102
|
+
return VideoBlock(entity);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
case 'AUDIO':
|
|
106
|
+
{
|
|
107
|
+
return AudioBlock(entity);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return null;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
function atomicBlockRenderer(block) {
|
|
115
|
+
if (block.getType() === 'atomic') {
|
|
116
|
+
return {
|
|
117
|
+
component: AtomicBlock,
|
|
118
|
+
editable: false
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.AudioBlock = AudioBlock;
|
|
7
|
+
|
|
8
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
+
|
|
10
|
+
var _styledComponents = _interopRequireWildcard(require("styled-components"));
|
|
11
|
+
|
|
12
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
13
|
+
|
|
14
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
15
|
+
|
|
16
|
+
const audioPlay = "https://unpkg.com/@kids-reporter/draft-renderer@0.1.0/lib/public/dc249b3412c5af890a004508287a3c3d.png";
|
|
17
|
+
const audioPause = "https://unpkg.com/@kids-reporter/draft-renderer@0.1.0/lib/public/5b3cb1a908786c8750f1041860699cc1.png";
|
|
18
|
+
const buttonShareStyle = (0, _styledComponents.css)`
|
|
19
|
+
width: 64px;
|
|
20
|
+
height: 64px;
|
|
21
|
+
border-radius: 50%;
|
|
22
|
+
background-repeat: no-repeat;
|
|
23
|
+
background-position: center center;
|
|
24
|
+
background-size: 22px;
|
|
25
|
+
|
|
26
|
+
&:hover {
|
|
27
|
+
opacity: 0.8;
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
const audioTimeShareStyle = (0, _styledComponents.css)`
|
|
31
|
+
color: rgba(0, 9, 40, 0.5);
|
|
32
|
+
font-weight: 400;
|
|
33
|
+
font-size: 11px;
|
|
34
|
+
line-height: 1em;
|
|
35
|
+
position: absolute;
|
|
36
|
+
bottom: 0px;
|
|
37
|
+
|
|
38
|
+
${({
|
|
39
|
+
theme
|
|
40
|
+
}) => theme.breakpoint.md} {
|
|
41
|
+
font-size: 13px;
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
const AudioWrapper = _styledComponents.default.div`
|
|
45
|
+
position: relative;
|
|
46
|
+
outline: 1px solid rgba(0, 9, 40, 0.1);
|
|
47
|
+
padding: 16px 0px 16px 16px;
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: space-between;
|
|
51
|
+
max-width: 480px;
|
|
52
|
+
${({
|
|
53
|
+
theme
|
|
54
|
+
}) => theme.margin.default}
|
|
55
|
+
|
|
56
|
+
${({
|
|
57
|
+
theme
|
|
58
|
+
}) => theme.breakpoint.md} {
|
|
59
|
+
padding: 24px 0px 28px 24px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
audio {
|
|
63
|
+
max-height: 40px;
|
|
64
|
+
width: 100%;
|
|
65
|
+
position: relative;
|
|
66
|
+
pointer-events: none;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
audio::-webkit-media-controls-panel {
|
|
70
|
+
background: #ffffff;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//remove default audio style: volume, mute, play
|
|
74
|
+
audio::-webkit-media-controls-volume-slider,
|
|
75
|
+
audio::-webkit-media-controls-mute-button,
|
|
76
|
+
audio::-webkit-media-controls-play-button {
|
|
77
|
+
display: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//時間進度條
|
|
81
|
+
audio::-webkit-media-controls-timeline {
|
|
82
|
+
height: 4px;
|
|
83
|
+
opacity: 0.3;
|
|
84
|
+
padding: 0;
|
|
85
|
+
margin-bottom: 10px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//目前播放時間
|
|
89
|
+
audio::-webkit-media-controls-current-time-display {
|
|
90
|
+
${audioTimeShareStyle}
|
|
91
|
+
left: 5px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//總時長
|
|
95
|
+
audio::-webkit-media-controls-time-remaining-display {
|
|
96
|
+
${audioTimeShareStyle}
|
|
97
|
+
left: 36px;
|
|
98
|
+
}
|
|
99
|
+
`;
|
|
100
|
+
const AudioInfo = _styledComponents.default.div`
|
|
101
|
+
width: calc(100% - 70px);
|
|
102
|
+
`;
|
|
103
|
+
const AudioTitle = _styledComponents.default.div`
|
|
104
|
+
font-family: 'Noto Sans TC';
|
|
105
|
+
font-style: normal;
|
|
106
|
+
font-weight: 400;
|
|
107
|
+
font-size: 14px;
|
|
108
|
+
line-height: 1.4em;
|
|
109
|
+
color: rgba(0, 9, 40, 0.87);
|
|
110
|
+
padding: 0 40px 0px 10px;
|
|
111
|
+
|
|
112
|
+
${({
|
|
113
|
+
theme
|
|
114
|
+
}) => theme.breakpoint.md} {
|
|
115
|
+
font-size: 16px;
|
|
116
|
+
}
|
|
117
|
+
`;
|
|
118
|
+
const PlayButton = _styledComponents.default.button`
|
|
119
|
+
${buttonShareStyle}
|
|
120
|
+
background-color: #f6f6fb;
|
|
121
|
+
background-image: url(${audioPlay});
|
|
122
|
+
|
|
123
|
+
&:hover {
|
|
124
|
+
opacity: 0.66;
|
|
125
|
+
}
|
|
126
|
+
`;
|
|
127
|
+
const PauseButton = _styledComponents.default.button`
|
|
128
|
+
${buttonShareStyle}
|
|
129
|
+
background-color: rgba(0, 9, 40, 0.87);
|
|
130
|
+
background-image: url(${audioPause});
|
|
131
|
+
`;
|
|
132
|
+
|
|
133
|
+
function AudioBlock(entity) {
|
|
134
|
+
const {
|
|
135
|
+
audio
|
|
136
|
+
} = entity.getData();
|
|
137
|
+
const audioRef = (0, _react.useRef)(null);
|
|
138
|
+
const [isPlaying, setIsPlaying] = (0, _react.useState)(false);
|
|
139
|
+
|
|
140
|
+
const handlePlay = () => {
|
|
141
|
+
audioRef === null || audioRef === void 0 ? void 0 : audioRef.current.play();
|
|
142
|
+
setIsPlaying(true);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const handlePause = () => {
|
|
146
|
+
audioRef === null || audioRef === void 0 ? void 0 : audioRef.current.pause();
|
|
147
|
+
setIsPlaying(false);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
return /*#__PURE__*/_react.default.createElement(AudioWrapper, null, isPlaying ? /*#__PURE__*/_react.default.createElement(PauseButton, {
|
|
151
|
+
onClick: handlePause
|
|
152
|
+
}) : /*#__PURE__*/_react.default.createElement(PlayButton, {
|
|
153
|
+
onClick: handlePlay
|
|
154
|
+
}), /*#__PURE__*/_react.default.createElement(AudioInfo, null, /*#__PURE__*/_react.default.createElement(AudioTitle, null, audio === null || audio === void 0 ? void 0 : audio.name), /*#__PURE__*/_react.default.createElement("audio", {
|
|
155
|
+
controls: true,
|
|
156
|
+
id: "player",
|
|
157
|
+
ref: audioRef,
|
|
158
|
+
src: audio === null || audio === void 0 ? void 0 : audio.url,
|
|
159
|
+
controlsList: "nodownload noremoteplayback noplaybackrate nofullscreen",
|
|
160
|
+
preload: "auto"
|
|
161
|
+
})));
|
|
162
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.BGImageBlock = BGImageBlock;
|
|
7
|
+
|
|
8
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
+
|
|
10
|
+
var _styledComponents = _interopRequireDefault(require("styled-components"));
|
|
11
|
+
|
|
12
|
+
var _reactImage = _interopRequireDefault(require("@readr-media/react-image"));
|
|
13
|
+
|
|
14
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
+
|
|
16
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
17
|
+
|
|
18
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
19
|
+
|
|
20
|
+
const BackgroundContainer = _styledComponents.default.section`
|
|
21
|
+
clear: both;
|
|
22
|
+
position: relative;
|
|
23
|
+
margin: 32px calc(50% - 50vw) 0 !important;
|
|
24
|
+
width: 100vw;
|
|
25
|
+
min-height: 100vh;
|
|
26
|
+
`;
|
|
27
|
+
const BackgroundImage = _styledComponents.default.div`
|
|
28
|
+
position: absolute;
|
|
29
|
+
z-index: 1;
|
|
30
|
+
top: 0;
|
|
31
|
+
bottom: unset;
|
|
32
|
+
left: 0;
|
|
33
|
+
width: 100%;
|
|
34
|
+
height: 100vh;
|
|
35
|
+
`;
|
|
36
|
+
const BackgroundContentRow = _styledComponents.default.div``;
|
|
37
|
+
const BackgroundContent = _styledComponents.default.div`
|
|
38
|
+
position: relative;
|
|
39
|
+
z-index: 1;
|
|
40
|
+
&.static {
|
|
41
|
+
height: 100vh;
|
|
42
|
+
${BackgroundContentRow} {
|
|
43
|
+
position: absolute;
|
|
44
|
+
bottom: 20px;
|
|
45
|
+
left: 20px;
|
|
46
|
+
right: 20px;
|
|
47
|
+
text-shadow: 0px 0px 1px #000000;
|
|
48
|
+
${({
|
|
49
|
+
theme
|
|
50
|
+
}) => theme.breakpoint.sm} {
|
|
51
|
+
bottom: 40px;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
&.parallax {
|
|
56
|
+
${BackgroundContentRow} {
|
|
57
|
+
> div {
|
|
58
|
+
background: rgba(169, 118, 118, 0.1);
|
|
59
|
+
border-radius: 8px;
|
|
60
|
+
padding: 20px;
|
|
61
|
+
${({
|
|
62
|
+
theme
|
|
63
|
+
}) => theme.breakpoint.xl} {
|
|
64
|
+
width: 480px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
> * + * {
|
|
68
|
+
margin: 27px 0 0;
|
|
69
|
+
}
|
|
70
|
+
h2 {
|
|
71
|
+
font-size: 1.44em;
|
|
72
|
+
${({
|
|
73
|
+
theme
|
|
74
|
+
}) => theme.breakpoint.md} {
|
|
75
|
+
font-size: 1.77em;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
h3 {
|
|
79
|
+
font-size: 1.33em;
|
|
80
|
+
${({
|
|
81
|
+
theme
|
|
82
|
+
}) => theme.breakpoint.md} {
|
|
83
|
+
font-size: 1.55em;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
h4 {
|
|
87
|
+
font-size: 1.11em;
|
|
88
|
+
${({
|
|
89
|
+
theme
|
|
90
|
+
}) => theme.breakpoint.md} {
|
|
91
|
+
font-size: 1.33em;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
ul {
|
|
95
|
+
list-style-type: disc;
|
|
96
|
+
list-style-position: inside;
|
|
97
|
+
}
|
|
98
|
+
ol {
|
|
99
|
+
list-style-type: decimal;
|
|
100
|
+
list-style-position: inside;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
&.left {
|
|
104
|
+
padding: 0 20px 97px;
|
|
105
|
+
${({
|
|
106
|
+
theme
|
|
107
|
+
}) => theme.breakpoint.md} {
|
|
108
|
+
padding: 0 40px 335px;
|
|
109
|
+
}
|
|
110
|
+
${({
|
|
111
|
+
theme
|
|
112
|
+
}) => theme.breakpoint.xl} {
|
|
113
|
+
padding: 0 80px 169px;
|
|
114
|
+
padding-right: calc(100% - 480px - 80px);
|
|
115
|
+
}
|
|
116
|
+
${({
|
|
117
|
+
theme
|
|
118
|
+
}) => theme.breakpoint.xxl} {
|
|
119
|
+
padding-bottom: 296px;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
&.right {
|
|
123
|
+
padding: 0 20px 97px;
|
|
124
|
+
${({
|
|
125
|
+
theme
|
|
126
|
+
}) => theme.breakpoint.md} {
|
|
127
|
+
padding: 0 40px 335px;
|
|
128
|
+
}
|
|
129
|
+
${({
|
|
130
|
+
theme
|
|
131
|
+
}) => theme.breakpoint.xl} {
|
|
132
|
+
padding: 0 80px 169px;
|
|
133
|
+
padding-left: calc(100% - 480px - 80px);
|
|
134
|
+
}
|
|
135
|
+
${({
|
|
136
|
+
theme
|
|
137
|
+
}) => theme.breakpoint.xxl} {
|
|
138
|
+
padding-bottom: 296px;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
&.bottom {
|
|
142
|
+
padding: 0 20px 20px;
|
|
143
|
+
${({
|
|
144
|
+
theme
|
|
145
|
+
}) => theme.breakpoint.md} {
|
|
146
|
+
padding: 0 40px 40px;
|
|
147
|
+
}
|
|
148
|
+
${({
|
|
149
|
+
theme
|
|
150
|
+
}) => theme.breakpoint.xl} {
|
|
151
|
+
padding: 0 calc(50% - 240px) 40px;
|
|
152
|
+
}
|
|
153
|
+
${({
|
|
154
|
+
theme
|
|
155
|
+
}) => theme.breakpoint.xxl} {
|
|
156
|
+
padding-bottom: 80px;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
`;
|
|
162
|
+
const BackgroundEmptyRow = _styledComponents.default.div`
|
|
163
|
+
height: 100vh;
|
|
164
|
+
`;
|
|
165
|
+
|
|
166
|
+
function BGImageBlock(props) {
|
|
167
|
+
const {
|
|
168
|
+
block,
|
|
169
|
+
contentState
|
|
170
|
+
} = props;
|
|
171
|
+
const entityKey = block.getEntityAt(0);
|
|
172
|
+
const entity = contentState.getEntity(entityKey);
|
|
173
|
+
const {
|
|
174
|
+
textBlockAlign,
|
|
175
|
+
image,
|
|
176
|
+
body
|
|
177
|
+
} = entity.getData();
|
|
178
|
+
const {
|
|
179
|
+
resized,
|
|
180
|
+
name
|
|
181
|
+
} = image; // 滾動視差
|
|
182
|
+
|
|
183
|
+
const isParallax = textBlockAlign !== 'fixed';
|
|
184
|
+
const [bgImageCss, setBgImageCss] = (0, _react.useState)({});
|
|
185
|
+
const bgRef = (0, _react.useRef)(null);
|
|
186
|
+
const topRef = (0, _react.useRef)(null);
|
|
187
|
+
const bottomRef = (0, _react.useRef)(null);
|
|
188
|
+
(0, _react.useEffect)(() => {
|
|
189
|
+
if (bgRef.current && topRef.current && bottomRef.current) {
|
|
190
|
+
const intersectionObserver = new IntersectionObserver(entries => {
|
|
191
|
+
entries.forEach(({
|
|
192
|
+
boundingClientRect
|
|
193
|
+
}) => {
|
|
194
|
+
if (!boundingClientRect.width || !bgRef.current) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const bounding = bgRef.current.getBoundingClientRect();
|
|
199
|
+
|
|
200
|
+
if (bounding.height) {
|
|
201
|
+
if (bounding.y > 0) {
|
|
202
|
+
setBgImageCss({
|
|
203
|
+
position: 'absolute',
|
|
204
|
+
top: 0,
|
|
205
|
+
bottom: 'unset'
|
|
206
|
+
});
|
|
207
|
+
} else if (bounding.y + bounding.height > window.innerHeight) {
|
|
208
|
+
setBgImageCss({
|
|
209
|
+
position: 'fixed',
|
|
210
|
+
top: 0,
|
|
211
|
+
bottom: 'unset'
|
|
212
|
+
});
|
|
213
|
+
} else {
|
|
214
|
+
setBgImageCss({
|
|
215
|
+
position: 'absolute',
|
|
216
|
+
top: 'unset',
|
|
217
|
+
bottom: 0
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
intersectionObserver.observe(topRef.current);
|
|
224
|
+
intersectionObserver.observe(bottomRef.current);
|
|
225
|
+
return () => {
|
|
226
|
+
intersectionObserver.disconnect();
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}, []);
|
|
230
|
+
return /*#__PURE__*/_react.default.createElement(BackgroundContainer, {
|
|
231
|
+
ref: bgRef,
|
|
232
|
+
className: "bg"
|
|
233
|
+
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
234
|
+
ref: topRef
|
|
235
|
+
}), /*#__PURE__*/_react.default.createElement(BackgroundImage, {
|
|
236
|
+
style: bgImageCss
|
|
237
|
+
}, /*#__PURE__*/_react.default.createElement(_reactImage.default, {
|
|
238
|
+
images: resized,
|
|
239
|
+
alt: name,
|
|
240
|
+
rwd: {
|
|
241
|
+
mobile: '100vw',
|
|
242
|
+
tablet: '640px',
|
|
243
|
+
default: '100%'
|
|
244
|
+
},
|
|
245
|
+
priority: true
|
|
246
|
+
})), /*#__PURE__*/_react.default.createElement(BackgroundContent, {
|
|
247
|
+
className: isParallax ? 'parallax' : 'static'
|
|
248
|
+
}, isParallax && /*#__PURE__*/_react.default.createElement(BackgroundEmptyRow, null), /*#__PURE__*/_react.default.createElement(BackgroundContentRow, {
|
|
249
|
+
className: textBlockAlign
|
|
250
|
+
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
251
|
+
dangerouslySetInnerHTML: {
|
|
252
|
+
__html: body
|
|
253
|
+
}
|
|
254
|
+
}))), /*#__PURE__*/_react.default.createElement("div", {
|
|
255
|
+
ref: bottomRef
|
|
256
|
+
}));
|
|
257
|
+
}
|