@performant-software/semantic-components 0.5.15 → 0.5.16-beta.2
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/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/main.css +43 -0
- package/package.json +3 -3
- package/src/components/AudioPlayer.css +3 -0
- package/src/components/AudioPlayer.js +54 -0
- package/src/components/DownloadButton.js +63 -12
- package/src/components/LazyAudio.css +23 -0
- package/src/components/LazyAudio.js +150 -0
- package/src/components/LazyDocument.css +2 -0
- package/src/components/LazyDocument.js +25 -18
- package/src/components/LazyImage.css +3 -1
- package/src/components/LazyImage.js +40 -11
- package/src/components/LazyLoader.css +7 -0
- package/src/components/LazyLoader.js +28 -0
- package/src/components/LazyVideo.css +8 -1
- package/src/components/LazyVideo.js +40 -5
- package/src/components/PhotoViewer.js +38 -25
- package/src/components/VideoPlayer.js +23 -2
- package/src/i18n/en.json +27 -2
- package/src/index.js +2 -0
- package/types/components/AudioPlayer.js.flow +54 -0
- package/types/components/DownloadButton.js.flow +63 -12
- package/types/components/LazyAudio.js.flow +150 -0
- package/types/components/LazyDocument.js.flow +25 -18
- package/types/components/LazyImage.js.flow +40 -11
- package/types/components/LazyLoader.js.flow +28 -0
- package/types/components/LazyVideo.js.flow +40 -5
- package/types/components/PhotoViewer.js.flow +38 -25
- package/types/components/VideoPlayer.js.flow +23 -2
- package/types/index.js.flow +2 -0
package/build/main.css
CHANGED
|
@@ -146,6 +146,10 @@
|
|
|
146
146
|
color: rgba(95, 95, 95, 0.86);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
.audio-player.ui.modal > .content > audio {
|
|
150
|
+
width: 100%;
|
|
151
|
+
}
|
|
152
|
+
|
|
149
153
|
.color-button.ui.button {
|
|
150
154
|
border: 1px solid rgba(34, 36, 38, 0.15);
|
|
151
155
|
vertical-align: middle;
|
|
@@ -418,7 +422,38 @@ div.react-calendar {
|
|
|
418
422
|
left: 4px;
|
|
419
423
|
}
|
|
420
424
|
|
|
425
|
+
.lazy-loader {
|
|
426
|
+
background-color: #f9fafb;
|
|
427
|
+
box-shadow: 0 1px 3px 0 #d4d4d5, 0 0 0 1px #d4d4d5;
|
|
428
|
+
padding-top: 20%;
|
|
429
|
+
padding-bottom: 20%;
|
|
430
|
+
text-align: center;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.lazy-audio.ui.segment {
|
|
434
|
+
display: inline-block !important;
|
|
435
|
+
max-width: 100%;
|
|
436
|
+
padding: 0;
|
|
437
|
+
}
|
|
438
|
+
.lazy-audio.ui.segment .buttons {
|
|
439
|
+
display: flex;
|
|
440
|
+
flex-direction: column;
|
|
441
|
+
}
|
|
442
|
+
.lazy-audio.ui.segment .buttons .ui.button {
|
|
443
|
+
margin-top: 5px;
|
|
444
|
+
margin-bottom: 5px;
|
|
445
|
+
}
|
|
446
|
+
.lazy-audio .placeholder-image.ui.image {
|
|
447
|
+
background-color: #f9fafb;
|
|
448
|
+
box-shadow: 0 1px 3px 0 #d4d4d5, 0 0 0 1px #d4d4d5;
|
|
449
|
+
padding-top: 20%;
|
|
450
|
+
padding-bottom: 20%;
|
|
451
|
+
text-align: center;
|
|
452
|
+
}
|
|
453
|
+
|
|
421
454
|
.lazy-document.ui.segment {
|
|
455
|
+
display: inline-block !important;
|
|
456
|
+
max-width: 100%;
|
|
422
457
|
padding: 0;
|
|
423
458
|
}
|
|
424
459
|
.lazy-document.ui.segment .buttons {
|
|
@@ -446,6 +481,8 @@ div.react-calendar {
|
|
|
446
481
|
}
|
|
447
482
|
|
|
448
483
|
.lazy-image.ui.segment {
|
|
484
|
+
display: inline-block !important;
|
|
485
|
+
max-width: 100%;
|
|
449
486
|
padding: 0;
|
|
450
487
|
}
|
|
451
488
|
.lazy-image.ui.segment .buttons {
|
|
@@ -469,6 +506,8 @@ div.react-calendar {
|
|
|
469
506
|
}
|
|
470
507
|
|
|
471
508
|
.lazy-video.ui.segment {
|
|
509
|
+
display: inline-block !important;
|
|
510
|
+
max-width: 100%;
|
|
472
511
|
padding: 0;
|
|
473
512
|
}
|
|
474
513
|
.lazy-video.ui.segment .buttons {
|
|
@@ -486,6 +525,10 @@ div.react-calendar {
|
|
|
486
525
|
padding-bottom: 20%;
|
|
487
526
|
text-align: center;
|
|
488
527
|
}
|
|
528
|
+
.lazy-video.ui.segment > .image > video {
|
|
529
|
+
display: table;
|
|
530
|
+
width: 100%;
|
|
531
|
+
}
|
|
489
532
|
|
|
490
533
|
.listLoader.ui.segment {
|
|
491
534
|
position: absolute;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@performant-software/semantic-components",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.16-beta.2",
|
|
4
4
|
"description": "A package of shared components based on the Semantic UI Framework.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./build/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"build": "webpack --mode production && flow-copy-source -v src types"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@performant-software/shared-components": "^0.5.
|
|
15
|
+
"@performant-software/shared-components": "^0.5.16-beta.2",
|
|
16
16
|
"@react-google-maps/api": "^2.8.1",
|
|
17
17
|
"axios": "^0.26.1",
|
|
18
18
|
"i18next": "^19.4.4",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"react-dom": ">= 16.13.1 < 18.0.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@performant-software/webpack-config": "^0.5.
|
|
36
|
+
"@performant-software/webpack-config": "^0.5.16-beta.2",
|
|
37
37
|
"flow-copy-source": "^2.0.9",
|
|
38
38
|
"less": "^4.1.2",
|
|
39
39
|
"less-loader": "^11.0.0",
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { Button, Message, Modal } from 'semantic-ui-react';
|
|
5
|
+
import i18n from '../i18n/i18n';
|
|
6
|
+
import ModalContext from '../context/ModalContext';
|
|
7
|
+
import './AudioPlayer.css';
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
centered?: boolean,
|
|
11
|
+
onClose: () => void,
|
|
12
|
+
open: boolean,
|
|
13
|
+
src: string
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const AudioPlayer = (props: Props) => {
|
|
17
|
+
const [error, setError] = useState(false);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<ModalContext.Consumer>
|
|
21
|
+
{(mountNode) => (
|
|
22
|
+
<Modal
|
|
23
|
+
centered={props.centered}
|
|
24
|
+
className='audio-player'
|
|
25
|
+
mountNode={mountNode}
|
|
26
|
+
open={props.open}
|
|
27
|
+
>
|
|
28
|
+
<Modal.Content>
|
|
29
|
+
{ error && (
|
|
30
|
+
<Message
|
|
31
|
+
content={i18n.t('AudioPlayer.errors.path.content', { path: props.src })}
|
|
32
|
+
header={i18n.t('AudioPlayer.errors.path.header')}
|
|
33
|
+
icon='exclamation circle'
|
|
34
|
+
/>
|
|
35
|
+
)}
|
|
36
|
+
<audio
|
|
37
|
+
controls
|
|
38
|
+
onError={() => setError(true)}
|
|
39
|
+
src={props.src}
|
|
40
|
+
/>
|
|
41
|
+
</Modal.Content>
|
|
42
|
+
<Modal.Actions>
|
|
43
|
+
<Button
|
|
44
|
+
content={i18n.t('Common.buttons.close')}
|
|
45
|
+
onClick={props.onClose}
|
|
46
|
+
/>
|
|
47
|
+
</Modal.Actions>
|
|
48
|
+
</Modal>
|
|
49
|
+
)}
|
|
50
|
+
</ModalContext.Consumer>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default AudioPlayer;
|
|
@@ -1,23 +1,74 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import React from 'react';
|
|
3
|
+
import React, { useMemo } from 'react';
|
|
4
4
|
import uuid from 'react-uuid';
|
|
5
|
-
import {
|
|
5
|
+
import { Icon } from 'semantic-ui-react';
|
|
6
|
+
import i18n from '../i18n/i18n';
|
|
6
7
|
|
|
7
8
|
type Props = {
|
|
9
|
+
basic?: boolean,
|
|
10
|
+
className?: string,
|
|
11
|
+
color?: string,
|
|
12
|
+
compact?: boolean,
|
|
8
13
|
filename?: string,
|
|
14
|
+
primary?: boolean,
|
|
15
|
+
size?: string,
|
|
16
|
+
secondary?: boolean,
|
|
9
17
|
url: string
|
|
10
18
|
};
|
|
11
19
|
|
|
12
|
-
const DownloadButton = (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
)
|
|
20
|
+
const DownloadButton = (props: Props) => {
|
|
21
|
+
/**
|
|
22
|
+
* Sets the appropriate class names based on the formatting props.
|
|
23
|
+
*
|
|
24
|
+
* @type {string}
|
|
25
|
+
*/
|
|
26
|
+
const className = useMemo(() => {
|
|
27
|
+
const classNames = ['ui', 'button'];
|
|
28
|
+
|
|
29
|
+
if (props.basic) {
|
|
30
|
+
classNames.push('basic');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (props.className) {
|
|
34
|
+
classNames.push(...props.className.split(' '));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (props.color) {
|
|
38
|
+
classNames.push(props.color);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (props.compact) {
|
|
42
|
+
classNames.push('compact');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (props.primary) {
|
|
46
|
+
classNames.push('primary');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (props.secondary) {
|
|
50
|
+
classNames.push('secondary');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (props.size) {
|
|
54
|
+
classNames.push(props.size);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return classNames.join(' ');
|
|
58
|
+
}, [props.basic, props.color]);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<a
|
|
62
|
+
className={className}
|
|
63
|
+
download={props.filename || uuid()}
|
|
64
|
+
href={props.url}
|
|
65
|
+
>
|
|
66
|
+
<Icon
|
|
67
|
+
name='cloud download'
|
|
68
|
+
/>
|
|
69
|
+
{ i18n.t('Common.buttons.download') }
|
|
70
|
+
</a>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
22
73
|
|
|
23
74
|
export default DownloadButton;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.lazy-audio.ui.segment {
|
|
2
|
+
display: inline-block !important;
|
|
3
|
+
max-width: 100%;
|
|
4
|
+
padding: 0;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.lazy-audio.ui.segment .buttons {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.lazy-audio.ui.segment .buttons .ui.button {
|
|
13
|
+
margin-top: 5px;
|
|
14
|
+
margin-bottom: 5px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.lazy-audio .placeholder-image.ui.image {
|
|
18
|
+
background-color: #f9fafb;
|
|
19
|
+
box-shadow: 0 1px 3px 0 #d4d4d5, 0 0 0 1px #d4d4d5;
|
|
20
|
+
padding-top: 20%;
|
|
21
|
+
padding-bottom: 20%;
|
|
22
|
+
text-align: center;
|
|
23
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { useState, type Node } from 'react';
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Dimmer,
|
|
7
|
+
Icon,
|
|
8
|
+
Image,
|
|
9
|
+
Loader,
|
|
10
|
+
Segment,
|
|
11
|
+
Transition,
|
|
12
|
+
Visibility
|
|
13
|
+
} from 'semantic-ui-react';
|
|
14
|
+
import i18n from '../i18n/i18n';
|
|
15
|
+
import AudioPlayer from './AudioPlayer';
|
|
16
|
+
import DownloadButton from './DownloadButton';
|
|
17
|
+
import LazyLoader from './LazyLoader';
|
|
18
|
+
import './LazyAudio.css';
|
|
19
|
+
|
|
20
|
+
type Props = {
|
|
21
|
+
children?: Node,
|
|
22
|
+
dimmable: boolean,
|
|
23
|
+
download?: string,
|
|
24
|
+
duration?: number,
|
|
25
|
+
image?: any,
|
|
26
|
+
name?: string,
|
|
27
|
+
preview?: string,
|
|
28
|
+
size?: string,
|
|
29
|
+
src?: string
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const LazyAudio = (props: Props) => {
|
|
33
|
+
const [dimmer, setDimmer] = useState(false);
|
|
34
|
+
const [error, setError] = useState(false);
|
|
35
|
+
const [loaded, setLoaded] = useState(!props.preview);
|
|
36
|
+
const [modal, setModal] = useState(false);
|
|
37
|
+
const [visible, setVisible] = useState(false);
|
|
38
|
+
|
|
39
|
+
if (!visible) {
|
|
40
|
+
return (
|
|
41
|
+
<Visibility
|
|
42
|
+
as='span'
|
|
43
|
+
fireOnMount
|
|
44
|
+
onTopVisible={() => setVisible(true)}
|
|
45
|
+
>
|
|
46
|
+
<Loader
|
|
47
|
+
active
|
|
48
|
+
inline='centered'
|
|
49
|
+
size={props.size}
|
|
50
|
+
/>
|
|
51
|
+
</Visibility>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<>
|
|
57
|
+
<Transition
|
|
58
|
+
duration={props.duration}
|
|
59
|
+
visible
|
|
60
|
+
>
|
|
61
|
+
<Dimmer.Dimmable
|
|
62
|
+
as={Segment}
|
|
63
|
+
className='lazy-audio'
|
|
64
|
+
compact
|
|
65
|
+
onBlur={() => setDimmer(false)}
|
|
66
|
+
onMouseEnter={() => setDimmer(true)}
|
|
67
|
+
onMouseLeave={() => setDimmer(false)}
|
|
68
|
+
>
|
|
69
|
+
{ !loaded && (
|
|
70
|
+
<LazyLoader
|
|
71
|
+
active
|
|
72
|
+
size={props.size}
|
|
73
|
+
/>
|
|
74
|
+
)}
|
|
75
|
+
{ !error && props.preview && (
|
|
76
|
+
<Image
|
|
77
|
+
{...props.image}
|
|
78
|
+
onError={() => {
|
|
79
|
+
setError(true);
|
|
80
|
+
setLoaded(true);
|
|
81
|
+
}}
|
|
82
|
+
onLoad={() => {
|
|
83
|
+
setError(false);
|
|
84
|
+
setLoaded(true);
|
|
85
|
+
}}
|
|
86
|
+
size={props.size}
|
|
87
|
+
src={props.preview}
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
{ (error || !props.preview) && (
|
|
91
|
+
<Image
|
|
92
|
+
{...props.image}
|
|
93
|
+
className='placeholder-image'
|
|
94
|
+
size={props.size}
|
|
95
|
+
>
|
|
96
|
+
<Icon
|
|
97
|
+
name='file audio outline'
|
|
98
|
+
size='big'
|
|
99
|
+
/>
|
|
100
|
+
</Image>
|
|
101
|
+
)}
|
|
102
|
+
{ (props.src || props.children) && props.dimmable && (
|
|
103
|
+
<Dimmer
|
|
104
|
+
active={dimmer}
|
|
105
|
+
>
|
|
106
|
+
<div
|
|
107
|
+
className='buttons'
|
|
108
|
+
>
|
|
109
|
+
{ props.src && (
|
|
110
|
+
<Button
|
|
111
|
+
content={i18n.t('LazyAudio.buttons.play')}
|
|
112
|
+
icon='play circle outline'
|
|
113
|
+
onClick={() => setModal(true)}
|
|
114
|
+
primary
|
|
115
|
+
/>
|
|
116
|
+
)}
|
|
117
|
+
{ props.download && (
|
|
118
|
+
<DownloadButton
|
|
119
|
+
color='green'
|
|
120
|
+
filename={props.name}
|
|
121
|
+
url={props.download}
|
|
122
|
+
/>
|
|
123
|
+
)}
|
|
124
|
+
{ props.children }
|
|
125
|
+
</div>
|
|
126
|
+
</Dimmer>
|
|
127
|
+
)}
|
|
128
|
+
</Dimmer.Dimmable>
|
|
129
|
+
</Transition>
|
|
130
|
+
{ props.src && (
|
|
131
|
+
<AudioPlayer
|
|
132
|
+
onClose={() => setModal(false)}
|
|
133
|
+
open={modal}
|
|
134
|
+
size='large'
|
|
135
|
+
src={props.src}
|
|
136
|
+
/>
|
|
137
|
+
)}
|
|
138
|
+
</>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
LazyAudio.defaultProps = {
|
|
143
|
+
dimmable: true,
|
|
144
|
+
duration: 1000,
|
|
145
|
+
preview: undefined,
|
|
146
|
+
size: 'medium',
|
|
147
|
+
src: undefined
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export default LazyAudio;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import React, { useState,
|
|
3
|
+
import React, { useState, type Node } from 'react';
|
|
4
4
|
import { Document, Page } from 'react-pdf/dist/esm/entry.webpack';
|
|
5
5
|
import {
|
|
6
6
|
Dimmer,
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
Transition,
|
|
12
12
|
Visibility
|
|
13
13
|
} from 'semantic-ui-react';
|
|
14
|
-
import i18n from '../i18n/i18n';
|
|
15
14
|
import DownloadButton from './DownloadButton';
|
|
15
|
+
import LazyLoader from './LazyLoader';
|
|
16
16
|
import './LazyDocument.css';
|
|
17
17
|
|
|
18
18
|
type Props = {
|
|
@@ -20,23 +20,17 @@ type Props = {
|
|
|
20
20
|
dimmable?: boolean,
|
|
21
21
|
duration?: number,
|
|
22
22
|
image?: any,
|
|
23
|
+
pdf?: boolean,
|
|
23
24
|
preview?: ?string,
|
|
24
25
|
size?: string,
|
|
25
26
|
src?: string
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
const LazyDocument = (props: Props) => {
|
|
29
|
-
const [visible, setVisible] = useState(false);
|
|
30
30
|
const [dimmer, setDimmer] = useState(false);
|
|
31
|
-
const [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (props.src && !props.preview) {
|
|
35
|
-
fetch(props.src)
|
|
36
|
-
.then((response) => response.blob())
|
|
37
|
-
.then((blob) => setContentType(blob.type));
|
|
38
|
-
}
|
|
39
|
-
}, [props.preview, props.src]);
|
|
31
|
+
const [error, setError] = useState(false);
|
|
32
|
+
const [loaded, setLoaded] = useState(!props.preview);
|
|
33
|
+
const [visible, setVisible] = useState(false);
|
|
40
34
|
|
|
41
35
|
if (!visible) {
|
|
42
36
|
return (
|
|
@@ -68,14 +62,28 @@ const LazyDocument = (props: Props) => {
|
|
|
68
62
|
onMouseEnter={() => setDimmer(true)}
|
|
69
63
|
onMouseLeave={() => setDimmer(false)}
|
|
70
64
|
>
|
|
71
|
-
{
|
|
65
|
+
{ !loaded && (
|
|
66
|
+
<LazyLoader
|
|
67
|
+
active
|
|
68
|
+
size={props.size}
|
|
69
|
+
/>
|
|
70
|
+
)}
|
|
71
|
+
{ !error && props.preview && (
|
|
72
72
|
<Image
|
|
73
73
|
{...props.image}
|
|
74
|
+
onError={() => {
|
|
75
|
+
setError(true);
|
|
76
|
+
setLoaded(true);
|
|
77
|
+
}}
|
|
78
|
+
onLoad={() => {
|
|
79
|
+
setError(false);
|
|
80
|
+
setLoaded(true);
|
|
81
|
+
}}
|
|
74
82
|
src={props.preview}
|
|
75
83
|
size={props.size}
|
|
76
84
|
/>
|
|
77
85
|
)}
|
|
78
|
-
{ !props.preview && props.src &&
|
|
86
|
+
{ !props.preview && props.src && props.pdf && (
|
|
79
87
|
<Image
|
|
80
88
|
{...props.image}
|
|
81
89
|
size={props.size}
|
|
@@ -89,7 +97,7 @@ const LazyDocument = (props: Props) => {
|
|
|
89
97
|
</Document>
|
|
90
98
|
</Image>
|
|
91
99
|
)}
|
|
92
|
-
{ !props.preview && (
|
|
100
|
+
{ (error || (!props.preview && !(props.src && props.pdf))) && (
|
|
93
101
|
<Image
|
|
94
102
|
{...props.image}
|
|
95
103
|
className='placeholder-image'
|
|
@@ -110,10 +118,8 @@ const LazyDocument = (props: Props) => {
|
|
|
110
118
|
>
|
|
111
119
|
{ props.src && (
|
|
112
120
|
<DownloadButton
|
|
113
|
-
content={i18n.t('LazyDocument.buttons.download')}
|
|
114
|
-
icon='cloud download'
|
|
115
121
|
primary
|
|
116
|
-
|
|
122
|
+
src={props.src}
|
|
117
123
|
/>
|
|
118
124
|
)}
|
|
119
125
|
{ props.children }
|
|
@@ -129,6 +135,7 @@ const LazyDocument = (props: Props) => {
|
|
|
129
135
|
LazyDocument.defaultProps = {
|
|
130
136
|
dimmable: true,
|
|
131
137
|
duration: 1000,
|
|
138
|
+
pdf: false,
|
|
132
139
|
preview: undefined,
|
|
133
140
|
size: 'medium',
|
|
134
141
|
src: undefined
|
|
@@ -12,23 +12,29 @@ import {
|
|
|
12
12
|
Visibility
|
|
13
13
|
} from 'semantic-ui-react';
|
|
14
14
|
import i18n from '../i18n/i18n';
|
|
15
|
+
import DownloadButton from './DownloadButton';
|
|
16
|
+
import LazyLoader from './LazyLoader';
|
|
15
17
|
import PhotoViewer from './PhotoViewer';
|
|
16
18
|
import './LazyImage.css';
|
|
17
19
|
|
|
18
20
|
type Props = {
|
|
19
21
|
children?: Node,
|
|
20
22
|
dimmable: boolean,
|
|
23
|
+
download?: string,
|
|
21
24
|
duration?: number,
|
|
22
25
|
image?: any,
|
|
26
|
+
name?: string,
|
|
23
27
|
preview?: string,
|
|
24
28
|
size?: string,
|
|
25
29
|
src?: string
|
|
26
30
|
};
|
|
27
31
|
|
|
28
32
|
const LazyImage = (props: Props) => {
|
|
29
|
-
const [visible, setVisible] = useState(false);
|
|
30
|
-
const [modal, setModal] = useState(false);
|
|
31
33
|
const [dimmer, setDimmer] = useState(false);
|
|
34
|
+
const [error, setError] = useState(false);
|
|
35
|
+
const [loaded, setLoaded] = useState(!(props.src || props.preview));
|
|
36
|
+
const [modal, setModal] = useState(false);
|
|
37
|
+
const [visible, setVisible] = useState(false);
|
|
32
38
|
|
|
33
39
|
if (!visible) {
|
|
34
40
|
return (
|
|
@@ -60,14 +66,28 @@ const LazyImage = (props: Props) => {
|
|
|
60
66
|
onMouseEnter={() => setDimmer(true)}
|
|
61
67
|
onMouseLeave={() => setDimmer(false)}
|
|
62
68
|
>
|
|
63
|
-
{
|
|
69
|
+
{ !loaded && (
|
|
70
|
+
<LazyLoader
|
|
71
|
+
active
|
|
72
|
+
size={props.size}
|
|
73
|
+
/>
|
|
74
|
+
)}
|
|
75
|
+
{ !error && (props.preview || props.src) && (
|
|
64
76
|
<Image
|
|
65
77
|
{...props.image}
|
|
78
|
+
onError={() => {
|
|
79
|
+
setError(true);
|
|
80
|
+
setLoaded(true);
|
|
81
|
+
}}
|
|
82
|
+
onLoad={() => {
|
|
83
|
+
setError(false);
|
|
84
|
+
setLoaded(true);
|
|
85
|
+
}}
|
|
66
86
|
size={props.size}
|
|
67
87
|
src={props.preview || props.src}
|
|
68
88
|
/>
|
|
69
89
|
)}
|
|
70
|
-
{ !props.src && (
|
|
90
|
+
{ (error || !(props.preview || props.src)) && (
|
|
71
91
|
<Image
|
|
72
92
|
{...props.image}
|
|
73
93
|
className='placeholder-image'
|
|
@@ -79,7 +99,7 @@ const LazyImage = (props: Props) => {
|
|
|
79
99
|
/>
|
|
80
100
|
</Image>
|
|
81
101
|
)}
|
|
82
|
-
{ (props.src || props.children) && props.dimmable && (
|
|
102
|
+
{ !error && (props.src || props.children) && props.dimmable && (
|
|
83
103
|
<Dimmer
|
|
84
104
|
active={dimmer}
|
|
85
105
|
>
|
|
@@ -94,18 +114,27 @@ const LazyImage = (props: Props) => {
|
|
|
94
114
|
primary
|
|
95
115
|
/>
|
|
96
116
|
)}
|
|
117
|
+
{ props.download && (
|
|
118
|
+
<DownloadButton
|
|
119
|
+
color='green'
|
|
120
|
+
filename={props.name}
|
|
121
|
+
url={props.download}
|
|
122
|
+
/>
|
|
123
|
+
)}
|
|
97
124
|
{ props.children }
|
|
98
125
|
</div>
|
|
99
126
|
</Dimmer>
|
|
100
127
|
)}
|
|
101
128
|
</Dimmer.Dimmable>
|
|
102
129
|
</Transition>
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
130
|
+
{ props.src && (
|
|
131
|
+
<PhotoViewer
|
|
132
|
+
image={props.src}
|
|
133
|
+
onClose={() => setModal(false)}
|
|
134
|
+
open={modal}
|
|
135
|
+
size='large'
|
|
136
|
+
/>
|
|
137
|
+
)}
|
|
109
138
|
</>
|
|
110
139
|
);
|
|
111
140
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Image, Loader } from 'semantic-ui-react';
|
|
5
|
+
import './LazyLoader.css';
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
active: boolean,
|
|
9
|
+
size: string
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const LazyLoader = (props: Props) => (
|
|
13
|
+
<Image
|
|
14
|
+
className='lazy-loader'
|
|
15
|
+
size={props.size}
|
|
16
|
+
>
|
|
17
|
+
<Loader
|
|
18
|
+
active={props.active}
|
|
19
|
+
/>
|
|
20
|
+
</Image>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
LazyLoader.defaultProps = {
|
|
24
|
+
active: false,
|
|
25
|
+
size: 'small'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default LazyLoader;
|