@selkirk-systems/attachments 1.0.4
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 +0 -0
- package/dist/actions/AttachmentActions.js +11 -0
- package/dist/actions/FileActions.js +37 -0
- package/dist/actions/ImageUploadActions.js +99 -0
- package/dist/actions/PhotoActions.js +53 -0
- package/dist/components/FileDeleteIcon.js +30 -0
- package/dist/components/FileDownloadIcon.js +34 -0
- package/dist/components/FileList.js +111 -0
- package/dist/components/Icons/ExcelFileTypeImage.js +8 -0
- package/dist/components/Icons/HTMLFileTypeImage.js +7 -0
- package/dist/components/Icons/JSONFileTypeImage.js +7 -0
- package/dist/components/Icons/PDFFileTypeImage.js +7 -0
- package/dist/components/Icons/PhotoFileTypeImage.js +6 -0
- package/dist/components/Icons/PowerPointTypeImage.js +7 -0
- package/dist/components/Icons/TextFileTypeImage.js +7 -0
- package/dist/components/Icons/UnknownFileTypeImage.js +7 -0
- package/dist/components/Icons/WordFileTypeImage.js +7 -0
- package/dist/components/Icons/ZipFileTypeImage.js +7 -0
- package/dist/components/ImageViewerDialog.js +78 -0
- package/dist/components/MimeTypeIcons.js +28 -0
- package/dist/components/PhotoGallery.js +130 -0
- package/dist/components/ResponsiveImageUploadList.js +57 -0
- package/dist/components/UploadImageDialog.js +85 -0
- package/dist/constants/MessageConstants.js +5 -0
- package/dist/constants/PhotosConstants.js +18 -0
- package/dist/css/attachments.css +143 -0
- package/dist/css/image-viewer.css +45 -0
- package/dist/img/PowerPoint-filetype.png +0 -0
- package/dist/img/blue-pattern-bg.jpg +0 -0
- package/dist/img/excel-filetype.png +0 -0
- package/dist/img/html-filetype.png +0 -0
- package/dist/img/json-filetype.png +0 -0
- package/dist/img/pdf-filetype.png +0 -0
- package/dist/img/photo-filetype.png +0 -0
- package/dist/img/txt-filetype.png +0 -0
- package/dist/img/unknown-filetype.png +0 -0
- package/dist/img/word-filetype.png +0 -0
- package/dist/img/zip-filetype.png +0 -0
- package/dist/index.js +19 -0
- package/dist/stores/DownloadStore.js +16 -0
- package/dist/stores/ImageUploadStore.js +24 -0
- package/dist/stores/PhotosStore.js +59 -0
- package/lib/actions/AttachmentActions.js +14 -0
- package/lib/actions/FileActions.js +34 -0
- package/lib/actions/ImageUploadActions.js +134 -0
- package/lib/actions/PhotoActions.js +65 -0
- package/lib/components/FileDeleteIcon.jsx +42 -0
- package/lib/components/FileDownloadIcon.jsx +42 -0
- package/lib/components/FileList.jsx +111 -0
- package/lib/components/Icons/ExcelFileTypeImage.jsx +6 -0
- package/lib/components/Icons/HTMLFileTypeImage.jsx +5 -0
- package/lib/components/Icons/JSONFileTypeImage.jsx +5 -0
- package/lib/components/Icons/PDFFileTypeImage.jsx +5 -0
- package/lib/components/Icons/PhotoFileTypeImage.jsx +5 -0
- package/lib/components/Icons/PowerPointTypeImage.jsx +5 -0
- package/lib/components/Icons/TextFileTypeImage.jsx +5 -0
- package/lib/components/Icons/UnknownFileTypeImage.jsx +5 -0
- package/lib/components/Icons/WordFileTypeImage.jsx +5 -0
- package/lib/components/Icons/ZipFileTypeImage.jsx +5 -0
- package/lib/components/ImageViewerDialog.jsx +72 -0
- package/lib/components/MimeTypeIcons.jsx +30 -0
- package/lib/components/PhotoGallery.jsx +160 -0
- package/lib/components/ResponsiveImageUploadList.jsx +61 -0
- package/lib/components/UploadImageDialog.jsx +93 -0
- package/lib/constants/MessageConstants.js +5 -0
- package/lib/constants/PhotosConstants.js +21 -0
- package/lib/css/attachments.css +143 -0
- package/lib/css/image-viewer.css +45 -0
- package/lib/img/PowerPoint-filetype.png +0 -0
- package/lib/img/blue-pattern-bg.jpg +0 -0
- package/lib/img/excel-filetype.png +0 -0
- package/lib/img/html-filetype.png +0 -0
- package/lib/img/json-filetype.png +0 -0
- package/lib/img/pdf-filetype.png +0 -0
- package/lib/img/photo-filetype.png +0 -0
- package/lib/img/txt-filetype.png +0 -0
- package/lib/img/unknown-filetype.png +0 -0
- package/lib/img/word-filetype.png +0 -0
- package/lib/img/zip-filetype.png +0 -0
- package/lib/index.js +19 -0
- package/lib/stores/DownloadStore.js +23 -0
- package/lib/stores/ImageUploadStore.js +31 -0
- package/lib/stores/PhotosStore.js +81 -0
- package/package.json +50 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React, { Component } from "react";
|
|
3
|
+
import { Connect } from '@selkirk-systems/state-management';
|
|
4
|
+
import PhotoStore from "../stores/PhotosStore";
|
|
5
|
+
import { ImageIcon } from "lucide-react";
|
|
6
|
+
import { Column } from "@selkirk-systems/layout";
|
|
7
|
+
import { Skeleton } from "primereact/skeleton";
|
|
8
|
+
import memoizee from "memoizee";
|
|
9
|
+
import { showImageViewerDialog } from "../actions/AttachmentActions";
|
|
10
|
+
import { createProxiedURL } from "@selkirk-systems/selkirk-utils";
|
|
11
|
+
import { Typography } from "@selkirk-systems/selkirk-components";
|
|
12
|
+
import '../css/attachments.css';
|
|
13
|
+
class PhotoGallery extends React.Component {
|
|
14
|
+
static subscribe = [PhotoStore];
|
|
15
|
+
static defaultProps = {
|
|
16
|
+
baseURL: "",
|
|
17
|
+
items: [],
|
|
18
|
+
fetching: false
|
|
19
|
+
};
|
|
20
|
+
static storeStateToProps = {
|
|
21
|
+
items: (props, state) => sortAndSplitImages(state.photos),
|
|
22
|
+
fetching: (props, state) => state.fetching
|
|
23
|
+
};
|
|
24
|
+
render() {
|
|
25
|
+
const {
|
|
26
|
+
baseURL,
|
|
27
|
+
items,
|
|
28
|
+
fetching,
|
|
29
|
+
...other
|
|
30
|
+
} = this.props;
|
|
31
|
+
const count = items[0].length + items[1].length + items[2].length + items[3].length;
|
|
32
|
+
return /*#__PURE__*/React.createElement("div", _extends({
|
|
33
|
+
className: "photo-gallery paralax-content"
|
|
34
|
+
}, other), count < 1 && !fetching && /*#__PURE__*/React.createElement(Column, {
|
|
35
|
+
center: true,
|
|
36
|
+
className: "text-secondary"
|
|
37
|
+
}, /*#__PURE__*/React.createElement(ImageIcon, {
|
|
38
|
+
mt: "-xxxl",
|
|
39
|
+
mb: "sm",
|
|
40
|
+
style: {
|
|
41
|
+
width: '75px',
|
|
42
|
+
height: '75px',
|
|
43
|
+
strokeWidth: 1
|
|
44
|
+
}
|
|
45
|
+
}), /*#__PURE__*/React.createElement(Typography, {
|
|
46
|
+
style: {
|
|
47
|
+
fontWeight: 500
|
|
48
|
+
},
|
|
49
|
+
variant: "subtitle2"
|
|
50
|
+
}, "NO PHOTOS FOUND.")), fetching && /*#__PURE__*/React.createElement(Skeleton, {
|
|
51
|
+
width: "100%",
|
|
52
|
+
height: window.innerHeight - 300
|
|
53
|
+
}), !fetching && getImagesByColumn(items, 0, fetching), !fetching && getImagesByColumn(items, 1, fetching), !fetching && getImagesByColumn(items, 2, fetching), !fetching && getImagesByColumn(items, 3, fetching));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
class Image extends Component {
|
|
57
|
+
state = {
|
|
58
|
+
loaded: false
|
|
59
|
+
};
|
|
60
|
+
handleImageLoaded = e => {
|
|
61
|
+
this.setState({
|
|
62
|
+
loaded: true
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
render() {
|
|
66
|
+
const {
|
|
67
|
+
loaded
|
|
68
|
+
} = this.state;
|
|
69
|
+
const styles = this.props.styles || {};
|
|
70
|
+
if (!loaded) {
|
|
71
|
+
styles.height = 0;
|
|
72
|
+
}
|
|
73
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, !loaded && /*#__PURE__*/React.createElement("div", {
|
|
74
|
+
style: {
|
|
75
|
+
position: 'absolute',
|
|
76
|
+
top: "2px",
|
|
77
|
+
left: "2px",
|
|
78
|
+
right: "2px",
|
|
79
|
+
bottom: "2px"
|
|
80
|
+
}
|
|
81
|
+
}, /*#__PURE__*/React.createElement(Skeleton, {
|
|
82
|
+
width: "100%",
|
|
83
|
+
height: "100%"
|
|
84
|
+
})), /*#__PURE__*/React.createElement("img", _extends({
|
|
85
|
+
alt: this.props.alt
|
|
86
|
+
}, this.props, {
|
|
87
|
+
styles: styles,
|
|
88
|
+
onLoad: this.handleImageLoaded
|
|
89
|
+
})));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function getImagesByColumn(items, col) {
|
|
93
|
+
if (!items || !items[col].length) return null;
|
|
94
|
+
let columnStyle = {};
|
|
95
|
+
if (items[1].length === 0) {
|
|
96
|
+
columnStyle = {
|
|
97
|
+
flex: '100%,1',
|
|
98
|
+
maxWidth: '100%'
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
102
|
+
className: "photo-column",
|
|
103
|
+
style: columnStyle
|
|
104
|
+
}, items[col].map(p => {
|
|
105
|
+
const finalUrl = createProxiedURL(p.links ? p.links[0].href : p._links.self.href);
|
|
106
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
107
|
+
className: "photo",
|
|
108
|
+
key: p.id,
|
|
109
|
+
onClick: () => showImageViewerDialog(p.name, finalUrl)
|
|
110
|
+
}, /*#__PURE__*/React.createElement(Image, {
|
|
111
|
+
alt: p.name,
|
|
112
|
+
src: finalUrl
|
|
113
|
+
}));
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
const sortAndSplitImages = memoizee(arrayOfPhotos => {
|
|
117
|
+
if (!arrayOfPhotos) return [];
|
|
118
|
+
const ret = {
|
|
119
|
+
0: [],
|
|
120
|
+
1: [],
|
|
121
|
+
2: [],
|
|
122
|
+
3: []
|
|
123
|
+
};
|
|
124
|
+
const sortedByCreationTimestamp = arrayOfPhotos.filter(p => p.mimeType.indexOf("image") >= 0).sort((a, b) => a.creationTimestamp - b.creationTimestamp).reverse();
|
|
125
|
+
Object.values(sortedByCreationTimestamp).forEach((photo, i) => {
|
|
126
|
+
ret[i % 4].push(photo);
|
|
127
|
+
});
|
|
128
|
+
return ret;
|
|
129
|
+
});
|
|
130
|
+
export default Connect(PhotoGallery);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import ImageUploadStore from '../stores/ImageUploadStore';
|
|
4
|
+
import { Connect } from '@selkirk-systems/state-management';
|
|
5
|
+
import { Column, Row } from '@selkirk-systems/layout';
|
|
6
|
+
import { AlertTriangle, CheckCircle2 } from 'lucide-react';
|
|
7
|
+
import { Typography, Paper } from '@selkirk-systems/selkirk-components';
|
|
8
|
+
import { ProgressBar } from 'primereact/progressbar';
|
|
9
|
+
import clsx from 'clsx';
|
|
10
|
+
import MIME_TYPE_ICONS from './MimeTypeIcons';
|
|
11
|
+
import UnknownFileTypeImage from './Icons/UnknownFileTypeImage';
|
|
12
|
+
import PhotoFileTypeImage from './Icons/PhotoFileTypeImage';
|
|
13
|
+
class ResponsiveImageUploadList extends React.Component {
|
|
14
|
+
static subscribe = [ImageUploadStore];
|
|
15
|
+
static defaultProps = {
|
|
16
|
+
files: []
|
|
17
|
+
};
|
|
18
|
+
static storeStateToProps = {
|
|
19
|
+
files: (props, state) => state.uploads
|
|
20
|
+
};
|
|
21
|
+
render() {
|
|
22
|
+
const {
|
|
23
|
+
files,
|
|
24
|
+
...other
|
|
25
|
+
} = this.props;
|
|
26
|
+
return Object.keys(files).map((key, i) => {
|
|
27
|
+
const file = files[key];
|
|
28
|
+
const FileType = file.mimeType.indexOf("image") >= 0 ? /*#__PURE__*/React.createElement(PhotoFileTypeImage, null) : MIME_TYPE_ICONS[file.mimeType] || /*#__PURE__*/React.createElement(UnknownFileTypeImage, null);
|
|
29
|
+
return /*#__PURE__*/React.createElement(Paper, _extends({
|
|
30
|
+
key: file.id,
|
|
31
|
+
elevation: 0,
|
|
32
|
+
onClick: e => e.stopPropagation()
|
|
33
|
+
}, other), /*#__PURE__*/React.createElement(Column, {
|
|
34
|
+
gap: "sm"
|
|
35
|
+
}, /*#__PURE__*/React.createElement(Row, {
|
|
36
|
+
gap: "md",
|
|
37
|
+
align: "center",
|
|
38
|
+
xs: "auto 1fr auto"
|
|
39
|
+
}, FileType, /*#__PURE__*/React.createElement(Typography, {
|
|
40
|
+
variant: "body1"
|
|
41
|
+
}, file.title), !file.error && file.progress >= 100 && /*#__PURE__*/React.createElement(CheckCircle2, {
|
|
42
|
+
mr: "sm",
|
|
43
|
+
className: "success-color"
|
|
44
|
+
}), file.error && /*#__PURE__*/React.createElement(AlertTriangle, {
|
|
45
|
+
style: {
|
|
46
|
+
color: 'red'
|
|
47
|
+
}
|
|
48
|
+
})), /*#__PURE__*/React.createElement(ProgressBar, {
|
|
49
|
+
className: clsx("uploading-progress", {
|
|
50
|
+
'error': file.error
|
|
51
|
+
}),
|
|
52
|
+
value: file.progress
|
|
53
|
+
})));
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export default Connect(ResponsiveImageUploadList);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { closeImageUploadDialog, uploadFiles, invokeUploadInput } from '../actions/ImageUploadActions';
|
|
4
|
+
import ResponsiveImageUploadList from './ResponsiveImageUploadList';
|
|
5
|
+
import { Connect } from '@selkirk-systems/state-management';
|
|
6
|
+
import { Dialog } from 'primereact/dialog';
|
|
7
|
+
import { Button } from 'primereact/button';
|
|
8
|
+
import { UploadCloud, UploadIcon } from 'lucide-react';
|
|
9
|
+
import { Column } from '@selkirk-systems/layout';
|
|
10
|
+
import { Typography } from '@selkirk-systems/selkirk-components';
|
|
11
|
+
import ImageUploadStore from '../stores/ImageUploadStore';
|
|
12
|
+
import { FILE_ACCEPT } from '../constants/PhotosConstants';
|
|
13
|
+
import { ConfirmDialog } from 'primereact/confirmdialog';
|
|
14
|
+
class UploadImageDialog extends React.Component {
|
|
15
|
+
static subscribe = [ImageUploadStore];
|
|
16
|
+
static defaultProps = {
|
|
17
|
+
url: null,
|
|
18
|
+
show: false
|
|
19
|
+
};
|
|
20
|
+
static storeStateToProps = {
|
|
21
|
+
show: (props, state) => state.showImageUploadDialog
|
|
22
|
+
};
|
|
23
|
+
render() {
|
|
24
|
+
const {
|
|
25
|
+
show,
|
|
26
|
+
url,
|
|
27
|
+
...other
|
|
28
|
+
} = this.props;
|
|
29
|
+
return /*#__PURE__*/React.createElement(Dialog, _extends({
|
|
30
|
+
header: "Upload",
|
|
31
|
+
visible: show,
|
|
32
|
+
icons: /*#__PURE__*/React.createElement(Button, {
|
|
33
|
+
text: true,
|
|
34
|
+
type: "button",
|
|
35
|
+
style: {
|
|
36
|
+
color: 'inherit'
|
|
37
|
+
},
|
|
38
|
+
onClick: invokeUploadInput
|
|
39
|
+
}, /*#__PURE__*/React.createElement(UploadIcon, null)),
|
|
40
|
+
onHide: closeImageUploadDialog,
|
|
41
|
+
position: "bottom",
|
|
42
|
+
maximized: true,
|
|
43
|
+
transitionOptions: {
|
|
44
|
+
onExited: this.handledExited
|
|
45
|
+
}
|
|
46
|
+
}, other), /*#__PURE__*/React.createElement("form", null, /*#__PURE__*/React.createElement("input", {
|
|
47
|
+
type: "file",
|
|
48
|
+
id: "fileupload",
|
|
49
|
+
accept: FILE_ACCEPT,
|
|
50
|
+
multiple: "multiple",
|
|
51
|
+
ref: fileInputEl => this.fileInputEl = fileInputEl,
|
|
52
|
+
onChange: () => uploadFiles(url, this.fileInputEl.files)
|
|
53
|
+
})), /*#__PURE__*/React.createElement(Column, {
|
|
54
|
+
fill: true,
|
|
55
|
+
xs: "200px 1fr",
|
|
56
|
+
gap: "md",
|
|
57
|
+
onClick: invokeUploadInput
|
|
58
|
+
}, /*#__PURE__*/React.createElement(Column, {
|
|
59
|
+
gap: "sm",
|
|
60
|
+
center: true,
|
|
61
|
+
pt: "xl"
|
|
62
|
+
}, /*#__PURE__*/React.createElement(UploadCloud, {
|
|
63
|
+
style: {
|
|
64
|
+
width: 85,
|
|
65
|
+
height: 85,
|
|
66
|
+
strokeWidth: 2
|
|
67
|
+
}
|
|
68
|
+
}), /*#__PURE__*/React.createElement(Typography, {
|
|
69
|
+
variant: "h6",
|
|
70
|
+
style: {
|
|
71
|
+
fontWeight: 600
|
|
72
|
+
}
|
|
73
|
+
}, "Upload your files"), /*#__PURE__*/React.createElement(Typography, {
|
|
74
|
+
variant: "subtitle1"
|
|
75
|
+
}, "Tap here to choose a file from your device")), /*#__PURE__*/React.createElement(Column, {
|
|
76
|
+
gap: "sm",
|
|
77
|
+
justify: "top",
|
|
78
|
+
pl: "md",
|
|
79
|
+
pr: "md"
|
|
80
|
+
}, /*#__PURE__*/React.createElement(ResponsiveImageUploadList, {
|
|
81
|
+
p: "sm"
|
|
82
|
+
}))), /*#__PURE__*/React.createElement(ConfirmDialog, null));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export default Connect(UploadImageDialog);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// this is a bit funky as attachments was referencing the messages package locally - once messages is added to npm this should be removed
|
|
2
|
+
export const SHOW_MESSAGES = "SHOW_MESSAGES";
|
|
3
|
+
export const CLEAR_ALL_MESSAGES = "CLEAR_ALL_MESSAGES";
|
|
4
|
+
export const ADD_IGNORE_ERROR = "ADD_IGNORE_ERROR";
|
|
5
|
+
export const REMOVE_IGNORE_ERROR_BY_ID = "REMOVE_IGNORE_ERROR_BY_ID";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const SHOW_IMAGE_VIEWER_DIALOG = "SHOW_IMAGE_VIEWER_DIALOG";
|
|
2
|
+
export const HIDE_IMAGE_VIEWER_DIALOG = "HIDE_IMAGE_VIEWER_DIALOG";
|
|
3
|
+
export const FETCH_PHOTOS = "FETCH_PHOTOS";
|
|
4
|
+
export const FETCHED_PHOTOS = "FETCHED_PHOTOS";
|
|
5
|
+
export const CLEAR_PHOTOS = "CLEAR_PHOTOS";
|
|
6
|
+
export const SHOW_IMAGE_UPLOAD_DIALOG = "SHOW_IMAGE_UPLOAD_DIALOG";
|
|
7
|
+
export const HIDE_IMAGE_UPLOAD_DIALOG = "HIDE_IMAGE_UPLOAD_DIALOG";
|
|
8
|
+
export const SET_UPLOAD_PROGRESS = "SET_UPLOAD_PROGRESS";
|
|
9
|
+
export const DELETE_IMAGE = "DELETE_IMAGE";
|
|
10
|
+
export const DELETED_IMAGE = "DELETED_IMAGE";
|
|
11
|
+
export const IMAGE_UPLOAD_COMPLETE = "IMAGE_UPLOAD_COMPLETE";
|
|
12
|
+
export const CLEAR_UPLOADS = "CLEAR_UPLOADS";
|
|
13
|
+
export const CANCEL_UPLOAD = "CANCEL_UPLOAD";
|
|
14
|
+
export const FILE_DOWNLOAD = "FILE_DOWNLOAD";
|
|
15
|
+
export const FILE_DOWNLOADED = "FILE_DOWNLOADED";
|
|
16
|
+
export const FILE_DELETE = "FILE_DELETE";
|
|
17
|
+
export const FILE_DELETED = "FILE_DELETED";
|
|
18
|
+
export const FILE_ACCEPT = "image/*,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/pdf,application/msword,application/vnd.ms-excel,text/plain,application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#root .attachments {
|
|
2
|
+
overflow-x: hidden;
|
|
3
|
+
overflow-y: auto;
|
|
4
|
+
perspective: 2px;
|
|
5
|
+
}
|
|
6
|
+
.attachments .bg img {
|
|
7
|
+
width: 56px;
|
|
8
|
+
opacity: 0.7;
|
|
9
|
+
}
|
|
10
|
+
.attachments .paralax-content {
|
|
11
|
+
position: relative;
|
|
12
|
+
z-index: 2;
|
|
13
|
+
background: #ffffff;
|
|
14
|
+
transform-style: preserve-3d;
|
|
15
|
+
position: relative;
|
|
16
|
+
min-height: 40px;
|
|
17
|
+
display: flex;
|
|
18
|
+
}
|
|
19
|
+
.attachments .file-gallery>*,
|
|
20
|
+
.attachments .photo-gallery{
|
|
21
|
+
background-color: whitesmoke;
|
|
22
|
+
}
|
|
23
|
+
.attachments .paralax-spacer {
|
|
24
|
+
background: transparent;
|
|
25
|
+
height: 175px;
|
|
26
|
+
transform-style: preserve-3d;
|
|
27
|
+
position: relative;
|
|
28
|
+
}
|
|
29
|
+
.attachments .p-tabview-nav-container{
|
|
30
|
+
width:100%;
|
|
31
|
+
}
|
|
32
|
+
.attachments .p-tabview .p-tabview-nav li.p-tabview-selected{
|
|
33
|
+
color:var(--icon);
|
|
34
|
+
}
|
|
35
|
+
.attachments .p-tabview .p-tabview-nav li.p-highlight .p-tabview-nav-link {
|
|
36
|
+
background: white;
|
|
37
|
+
border-top: none;
|
|
38
|
+
border-right: none;
|
|
39
|
+
border-left: none;
|
|
40
|
+
border-bottom-width: 5px;
|
|
41
|
+
}
|
|
42
|
+
.attachments .p-tabview-nav a{
|
|
43
|
+
border-bottom-width:0;
|
|
44
|
+
}
|
|
45
|
+
.file-gallery {
|
|
46
|
+
}
|
|
47
|
+
.photo-gallery {
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-wrap: wrap;
|
|
50
|
+
padding: 2px;
|
|
51
|
+
}
|
|
52
|
+
.photo-column {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex: 33.333%;
|
|
55
|
+
max-width: 33.333%;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
}
|
|
58
|
+
.photo-column > * {
|
|
59
|
+
flex: 1 1 auto;
|
|
60
|
+
}
|
|
61
|
+
.photo {
|
|
62
|
+
overflow: hidden;
|
|
63
|
+
border-radius: 10px;
|
|
64
|
+
padding: 2px;
|
|
65
|
+
min-width: 50%;
|
|
66
|
+
min-height: 150px;
|
|
67
|
+
position: relative;
|
|
68
|
+
background: white;
|
|
69
|
+
border: 2px solid white;
|
|
70
|
+
}
|
|
71
|
+
.photo img {
|
|
72
|
+
width: 100%;
|
|
73
|
+
height: 100%;
|
|
74
|
+
object-fit: cover;
|
|
75
|
+
vertical-align: middle;
|
|
76
|
+
border-radius: 5px;
|
|
77
|
+
}
|
|
78
|
+
input[type="file"] {
|
|
79
|
+
display: none;
|
|
80
|
+
}
|
|
81
|
+
.attachments .parallax {
|
|
82
|
+
content: " ";
|
|
83
|
+
position: absolute;
|
|
84
|
+
top: 0;
|
|
85
|
+
right: 0;
|
|
86
|
+
bottom: 0;
|
|
87
|
+
left: 0;
|
|
88
|
+
transform: translateZ(-1px) scale(1.5);
|
|
89
|
+
background-size: 100%;
|
|
90
|
+
z-index: -1;
|
|
91
|
+
}
|
|
92
|
+
.attachments .bg {
|
|
93
|
+
margin: 0 -1px;
|
|
94
|
+
background-position: -60px -6px;
|
|
95
|
+
color: rgba(255, 255, 255, 0.9);
|
|
96
|
+
}
|
|
97
|
+
.attachments .bg > * {
|
|
98
|
+
backdrop-filter: blur(3px); /* blur effect to the backdrop */
|
|
99
|
+
-webkit-backdrop-filter: blur(3px);
|
|
100
|
+
height: 180px;
|
|
101
|
+
}
|
|
102
|
+
@media (min-width: 600px) {
|
|
103
|
+
.photo-gallery > *:last-child {
|
|
104
|
+
display: grid;
|
|
105
|
+
grid-auto-flow: column;
|
|
106
|
+
grid-auto-columns: minmax(33.333%, 1fr);
|
|
107
|
+
max-width: 100%;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.photo-gallery > *:last-child > * {
|
|
111
|
+
max-height: 250px;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.photo-gallery > *:last-child > *:only-child {
|
|
115
|
+
max-height: 250px;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@media (max-width: 600px) {
|
|
120
|
+
.photo-column {
|
|
121
|
+
flex: 50%;
|
|
122
|
+
max-width: 50%;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* .photo-gallery>*:last-child{
|
|
126
|
+
display:flex;
|
|
127
|
+
flex-wrap: wrap;
|
|
128
|
+
flex:100%;
|
|
129
|
+
max-width:100%;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.photo-gallery>*:last-child>*{
|
|
133
|
+
flex:50%;
|
|
134
|
+
max-width:50%;
|
|
135
|
+
} */
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@media (max-width: 300px) {
|
|
139
|
+
.photo-column {
|
|
140
|
+
flex: 100%;
|
|
141
|
+
max-width: 100%;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
.image-viewer {
|
|
2
|
+
position: fixed;
|
|
3
|
+
top: 0;
|
|
4
|
+
left: 0;
|
|
5
|
+
right: 0;
|
|
6
|
+
bottom: 0;
|
|
7
|
+
z-index: 9999;
|
|
8
|
+
background: black;
|
|
9
|
+
color: white;
|
|
10
|
+
}
|
|
11
|
+
.image-viewer .title {
|
|
12
|
+
white-space: nowrap;
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
text-overflow: ellipsis;
|
|
15
|
+
}
|
|
16
|
+
.image-viewer .icon {
|
|
17
|
+
color: white;
|
|
18
|
+
z-index: 1;
|
|
19
|
+
}
|
|
20
|
+
.image-viewer .top.actions {
|
|
21
|
+
top: 0;
|
|
22
|
+
left: 0;
|
|
23
|
+
right: 0;
|
|
24
|
+
}
|
|
25
|
+
.image-viewer .bottom.actions {
|
|
26
|
+
bottom: 0;
|
|
27
|
+
left: 0;
|
|
28
|
+
right: 0;
|
|
29
|
+
}
|
|
30
|
+
.image-viewer .actions {
|
|
31
|
+
position: absolute;
|
|
32
|
+
padding: 10px 15px;
|
|
33
|
+
width: 100%;
|
|
34
|
+
z-index: 1;
|
|
35
|
+
background-color: rgba(0, 0, 0, 0.88);
|
|
36
|
+
}
|
|
37
|
+
.image-viewer img {
|
|
38
|
+
position: absolute;
|
|
39
|
+
top: 0;
|
|
40
|
+
left: 0;
|
|
41
|
+
width: 100%;
|
|
42
|
+
height: 100%;
|
|
43
|
+
object-fit: contain;
|
|
44
|
+
z-index: 0;
|
|
45
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Components
|
|
2
|
+
export { default as PhotoGallery } from './components/PhotoGallery';
|
|
3
|
+
export { default as FileList } from './components/FileList';
|
|
4
|
+
export { default as UploadImageDialog } from './components/UploadImageDialog';
|
|
5
|
+
export { default as ImageViewerDialog } from './components/ImageViewerDialog';
|
|
6
|
+
export { default as FileDownloadIcon } from './components/FileDownloadIcon';
|
|
7
|
+
export { default as FileDeleteIcon } from './components/FileDeleteIcon';
|
|
8
|
+
export { default as MimeTypeIcons } from './components/MimeTypeIcons';
|
|
9
|
+
|
|
10
|
+
// Actions
|
|
11
|
+
export { showImageViewerDialog, hideImageViewerDialog } from './actions/AttachmentActions';
|
|
12
|
+
export { fetchPhotos, deleteImage, clearPhotos } from './actions/PhotoActions';
|
|
13
|
+
export { showImageUploadDialog, closeImageUploadDialog, invokeUploadInput, uploadFiles, deleteImageById } from './actions/ImageUploadActions';
|
|
14
|
+
export { downloadFile, deleteFile } from './actions/FileActions';
|
|
15
|
+
|
|
16
|
+
// Stores
|
|
17
|
+
export { default as PhotosStore } from './stores/PhotosStore';
|
|
18
|
+
export { default as ImageUploadStore } from './stores/ImageUploadStore';
|
|
19
|
+
export { default as DownloadStore } from './stores/DownloadStore';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FILE_DELETE, FILE_DELETED, FILE_DOWNLOAD, FILE_DOWNLOADED } from "../constants/PhotosConstants";
|
|
2
|
+
import { CreateStore, setValues, withPayload } from "@selkirk-systems/state-management";
|
|
3
|
+
const DownloadStore = CreateStore({
|
|
4
|
+
name: "DownloadStore",
|
|
5
|
+
events: {
|
|
6
|
+
[FILE_DOWNLOAD]: withPayload().setValues("downloading"),
|
|
7
|
+
[FILE_DOWNLOADED]: setValues("downloading", null),
|
|
8
|
+
[FILE_DELETE]: withPayload().setValues("deleting"),
|
|
9
|
+
[FILE_DELETED]: setValues("deleting", null)
|
|
10
|
+
},
|
|
11
|
+
state: {
|
|
12
|
+
downloading: null,
|
|
13
|
+
deleting: null
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
export default DownloadStore;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CLEAR_UPLOADS, HIDE_IMAGE_UPLOAD_DIALOG, SET_UPLOAD_PROGRESS, SHOW_IMAGE_UPLOAD_DIALOG } from "../constants/PhotosConstants";
|
|
2
|
+
import update from "@mbernal/simple-immutable";
|
|
3
|
+
import { CreateStore, setFalse, setValues, withPayload } from "@selkirk-systems/state-management";
|
|
4
|
+
const ImageUploadStore = CreateStore({
|
|
5
|
+
name: "ImageUploadStore",
|
|
6
|
+
events: {
|
|
7
|
+
[SET_UPLOAD_PROGRESS]: (action, state) => {
|
|
8
|
+
return update(state, {
|
|
9
|
+
'merge uploads': {
|
|
10
|
+
[action.payload.id]: action.payload
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
},
|
|
14
|
+
[CLEAR_UPLOADS]: setValues("uploads", {}),
|
|
15
|
+
[SHOW_IMAGE_UPLOAD_DIALOG]: withPayload().setValues("imageUploadTag").setTrue("showImageUploadDialog"),
|
|
16
|
+
[HIDE_IMAGE_UPLOAD_DIALOG]: setFalse("showImageUploadDialog")
|
|
17
|
+
},
|
|
18
|
+
state: {
|
|
19
|
+
showImageUploadDialog: false,
|
|
20
|
+
imageUploadTag: null,
|
|
21
|
+
uploads: {}
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
export default ImageUploadStore;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import update from "@mbernal/simple-immutable";
|
|
2
|
+
import { CreateStore, setFalse, setStore, setTrue, setValues, withPayload } from "@selkirk-systems/state-management";
|
|
3
|
+
import { CLEAR_PHOTOS, DELETED_IMAGE, DELETE_IMAGE, FETCHED_PHOTOS, FETCH_PHOTOS, FILE_DELETED, FILE_DOWNLOAD, FILE_DOWNLOADED, HIDE_IMAGE_VIEWER_DIALOG, IMAGE_UPLOAD_COMPLETE, SET_UPLOAD_PROGRESS, SHOW_IMAGE_VIEWER_DIALOG } from "../constants/PhotosConstants";
|
|
4
|
+
const PhotoStore = CreateStore({
|
|
5
|
+
name: "PhotoStore",
|
|
6
|
+
events: {
|
|
7
|
+
[IMAGE_UPLOAD_COMPLETE]: setTrue("reload"),
|
|
8
|
+
[FETCH_PHOTOS]: setFalse("reload").setTrue("fetching"),
|
|
9
|
+
[FETCHED_PHOTOS]: withPayload().setValues("photos").setFalse("fetching"),
|
|
10
|
+
[CLEAR_PHOTOS]: setStore(() => init()),
|
|
11
|
+
[DELETE_IMAGE]: setTrue("deleting"),
|
|
12
|
+
[SHOW_IMAGE_VIEWER_DIALOG]: withPayload().setValues("imageViewer"),
|
|
13
|
+
[HIDE_IMAGE_VIEWER_DIALOG]: setValues("imageViewer", {}),
|
|
14
|
+
[SET_UPLOAD_PROGRESS]: (action, state) => {
|
|
15
|
+
const payload = action.payload;
|
|
16
|
+
if (payload.error || payload.progress !== 100) return state;
|
|
17
|
+
const matchIndex = state.photos.findIndex(p => p.name.toLowerCase() === payload.id.toLowerCase());
|
|
18
|
+
if (matchIndex >= 0) {
|
|
19
|
+
return update(state, {
|
|
20
|
+
[`set photos.${matchIndex}`]: payload.response.data[0]
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return update(state, {
|
|
24
|
+
'unshift photos': Array.isArray(payload.response.data) ? payload.response.data : [payload.response.data]
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
[FILE_DELETED]: (action, state) => {
|
|
28
|
+
const {
|
|
29
|
+
fileName
|
|
30
|
+
} = action.payload;
|
|
31
|
+
const index = state.photos.findIndex(p => p.name === fileName);
|
|
32
|
+
if (index < 0) return state;
|
|
33
|
+
return update(state, {
|
|
34
|
+
'splice photos': [[index, 1]],
|
|
35
|
+
'set deleting': false
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
[DELETED_IMAGE]: (action, state) => {
|
|
39
|
+
const name = action.payload;
|
|
40
|
+
const index = state.photos.findIndex(p => p.name === name);
|
|
41
|
+
if (index < 0) return state;
|
|
42
|
+
return update(state, {
|
|
43
|
+
'splice photos': [[index, 1]],
|
|
44
|
+
'set deleting': false
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
state: init()
|
|
49
|
+
});
|
|
50
|
+
function init() {
|
|
51
|
+
return {
|
|
52
|
+
imageViewer: {},
|
|
53
|
+
fetching: true,
|
|
54
|
+
deleting: false,
|
|
55
|
+
reload: false,
|
|
56
|
+
photos: []
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export default PhotoStore;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { HIDE_IMAGE_VIEWER_DIALOG, SHOW_IMAGE_VIEWER_DIALOG } from "../constants/PhotosConstants"
|
|
2
|
+
import { dispatch } from "@selkirk-systems/state-management"
|
|
3
|
+
|
|
4
|
+
export const showImageViewerDialog = ( name, url ) => {
|
|
5
|
+
|
|
6
|
+
dispatch( SHOW_IMAGE_VIEWER_DIALOG, { name: name, url: url } )
|
|
7
|
+
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const hideImageViewerDialog = () => {
|
|
11
|
+
|
|
12
|
+
dispatch( HIDE_IMAGE_VIEWER_DIALOG );
|
|
13
|
+
|
|
14
|
+
}
|