@visns-studio/visns-components 5.13.7 → 5.13.9
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/package.json
CHANGED
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
89
89
|
},
|
|
90
90
|
"name": "@visns-studio/visns-components",
|
|
91
|
-
"version": "5.13.
|
|
91
|
+
"version": "5.13.9",
|
|
92
92
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
93
93
|
"main": "src/index.js",
|
|
94
94
|
"files": [
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
SortableContainer,
|
|
4
4
|
SortableElement,
|
|
5
5
|
sortableHandle,
|
|
6
6
|
} from 'react-sortable-hoc';
|
|
7
7
|
import { GripVertical as ChevronVertical, Edit as Pencil, Trash2 as TrashCan } from 'lucide-react';
|
|
8
|
+
import ImageModal from './ImageModal';
|
|
8
9
|
import styles from './styles/Gallery.module.css';
|
|
9
10
|
|
|
10
11
|
// Drag handle component
|
|
@@ -24,7 +25,7 @@ const truncateText = (text, maxLength) => {
|
|
|
24
25
|
|
|
25
26
|
// Sortable gallery item
|
|
26
27
|
const SortableGalleryItem = SortableElement(
|
|
27
|
-
({ value, handleEdit, handleDelete, showDescription = true }) => {
|
|
28
|
+
({ value, handleEdit, handleDelete, showDescription = true, onImageClick }) => {
|
|
28
29
|
const imageUrl = value.image_url || value.file_url;
|
|
29
30
|
const title =
|
|
30
31
|
value.file_title || value.label || value.file_name || 'Untitled';
|
|
@@ -34,7 +35,11 @@ const SortableGalleryItem = SortableElement(
|
|
|
34
35
|
<div className={styles.galleryItem}>
|
|
35
36
|
<DragHandle />
|
|
36
37
|
|
|
37
|
-
<div
|
|
38
|
+
<div
|
|
39
|
+
className={styles.galleryImage}
|
|
40
|
+
onClick={() => onImageClick && onImageClick(value)}
|
|
41
|
+
style={{ cursor: onImageClick ? 'pointer' : 'default' }}
|
|
42
|
+
>
|
|
38
43
|
{imageUrl ? (
|
|
39
44
|
<img src={imageUrl} alt={title} />
|
|
40
45
|
) : (
|
|
@@ -95,6 +100,30 @@ const SortableGalleryItem = SortableElement(
|
|
|
95
100
|
|
|
96
101
|
// Sortable gallery container
|
|
97
102
|
const Gallery = SortableContainer(({ items, handleEdit, handleDelete, showDescription = true }) => {
|
|
103
|
+
const [modalOpen, setModalOpen] = React.useState(false);
|
|
104
|
+
const [currentImageIndex, setCurrentImageIndex] = React.useState(0);
|
|
105
|
+
|
|
106
|
+
const handleImageClick = (clickedImage) => {
|
|
107
|
+
const imageIndex = items.findIndex(item => item.id === clickedImage.id);
|
|
108
|
+
setCurrentImageIndex(imageIndex);
|
|
109
|
+
setModalOpen(true);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const handleNextImage = () => {
|
|
113
|
+
setCurrentImageIndex((prevIndex) =>
|
|
114
|
+
prevIndex < items.length - 1 ? prevIndex + 1 : 0
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const handlePrevImage = () => {
|
|
119
|
+
setCurrentImageIndex((prevIndex) =>
|
|
120
|
+
prevIndex > 0 ? prevIndex - 1 : items.length - 1
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const handleCloseModal = () => {
|
|
125
|
+
setModalOpen(false);
|
|
126
|
+
};
|
|
98
127
|
if (!items || items.length === 0) {
|
|
99
128
|
return (
|
|
100
129
|
<div className={styles.galleryEmpty}>
|
|
@@ -130,18 +159,29 @@ const Gallery = SortableContainer(({ items, handleEdit, handleDelete, showDescri
|
|
|
130
159
|
}
|
|
131
160
|
|
|
132
161
|
return (
|
|
133
|
-
|
|
134
|
-
{
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
162
|
+
<>
|
|
163
|
+
<div className={styles.galleryGrid}>
|
|
164
|
+
{items.map((value, index) => (
|
|
165
|
+
<SortableGalleryItem
|
|
166
|
+
key={`item-${index}`}
|
|
167
|
+
index={index}
|
|
168
|
+
value={value}
|
|
169
|
+
handleEdit={handleEdit}
|
|
170
|
+
handleDelete={handleDelete}
|
|
171
|
+
showDescription={showDescription}
|
|
172
|
+
onImageClick={handleImageClick}
|
|
173
|
+
/>
|
|
174
|
+
))}
|
|
175
|
+
</div>
|
|
176
|
+
<ImageModal
|
|
177
|
+
isOpen={modalOpen}
|
|
178
|
+
onClose={handleCloseModal}
|
|
179
|
+
images={items}
|
|
180
|
+
currentIndex={currentImageIndex}
|
|
181
|
+
onNext={handleNextImage}
|
|
182
|
+
onPrevious={handlePrevImage}
|
|
183
|
+
/>
|
|
184
|
+
</>
|
|
145
185
|
);
|
|
146
186
|
});
|
|
147
187
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React, { useEffect, useCallback } from 'react';
|
|
2
|
+
import { X as CloseIcon, ChevronLeft, ChevronRight } from 'lucide-react';
|
|
3
|
+
import styles from './styles/ImageModal.module.css';
|
|
4
|
+
|
|
5
|
+
const ImageModal = ({
|
|
6
|
+
isOpen,
|
|
7
|
+
onClose,
|
|
8
|
+
images,
|
|
9
|
+
currentIndex,
|
|
10
|
+
onNext,
|
|
11
|
+
onPrevious,
|
|
12
|
+
showNavigation = true
|
|
13
|
+
}) => {
|
|
14
|
+
const handleKeyDown = useCallback((e) => {
|
|
15
|
+
if (!isOpen) return;
|
|
16
|
+
|
|
17
|
+
switch (e.key) {
|
|
18
|
+
case 'Escape':
|
|
19
|
+
onClose();
|
|
20
|
+
break;
|
|
21
|
+
case 'ArrowLeft':
|
|
22
|
+
e.preventDefault();
|
|
23
|
+
onPrevious();
|
|
24
|
+
break;
|
|
25
|
+
case 'ArrowRight':
|
|
26
|
+
e.preventDefault();
|
|
27
|
+
onNext();
|
|
28
|
+
break;
|
|
29
|
+
default:
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}, [isOpen, onClose, onNext, onPrevious]);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (isOpen) {
|
|
36
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
37
|
+
document.body.style.overflow = 'hidden';
|
|
38
|
+
} else {
|
|
39
|
+
document.body.style.overflow = 'unset';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return () => {
|
|
43
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
44
|
+
document.body.style.overflow = 'unset';
|
|
45
|
+
};
|
|
46
|
+
}, [isOpen, handleKeyDown]);
|
|
47
|
+
|
|
48
|
+
if (!isOpen || !images || images.length === 0) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const currentImage = images[currentIndex];
|
|
53
|
+
const imageUrl = currentImage?.image_url || currentImage?.file_url;
|
|
54
|
+
const title = currentImage?.file_title || currentImage?.label || currentImage?.file_name || 'Untitled';
|
|
55
|
+
const description = currentImage?.file_description || '';
|
|
56
|
+
|
|
57
|
+
const handleBackdropClick = (e) => {
|
|
58
|
+
if (e.target === e.currentTarget) {
|
|
59
|
+
onClose();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className={styles.modalOverlay} onClick={handleBackdropClick}>
|
|
65
|
+
<div className={styles.modalContent}>
|
|
66
|
+
<button
|
|
67
|
+
className={styles.closeButton}
|
|
68
|
+
onClick={onClose}
|
|
69
|
+
aria-label="Close modal"
|
|
70
|
+
>
|
|
71
|
+
<CloseIcon size={24} />
|
|
72
|
+
</button>
|
|
73
|
+
|
|
74
|
+
{showNavigation && images.length > 1 && (
|
|
75
|
+
<>
|
|
76
|
+
<button
|
|
77
|
+
className={`${styles.navButton} ${styles.prevButton}`}
|
|
78
|
+
onClick={onPrevious}
|
|
79
|
+
aria-label="Previous image"
|
|
80
|
+
disabled={currentIndex === 0}
|
|
81
|
+
>
|
|
82
|
+
<ChevronLeft size={32} />
|
|
83
|
+
</button>
|
|
84
|
+
<button
|
|
85
|
+
className={`${styles.navButton} ${styles.nextButton}`}
|
|
86
|
+
onClick={onNext}
|
|
87
|
+
aria-label="Next image"
|
|
88
|
+
disabled={currentIndex === images.length - 1}
|
|
89
|
+
>
|
|
90
|
+
<ChevronRight size={32} />
|
|
91
|
+
</button>
|
|
92
|
+
</>
|
|
93
|
+
)}
|
|
94
|
+
|
|
95
|
+
<div className={styles.imageContainer}>
|
|
96
|
+
<img
|
|
97
|
+
src={imageUrl}
|
|
98
|
+
alt={title}
|
|
99
|
+
className={styles.modalImage}
|
|
100
|
+
loading="lazy"
|
|
101
|
+
/>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<div className={styles.imageInfo}>
|
|
105
|
+
<h3 className={styles.imageTitle}>{title}</h3>
|
|
106
|
+
{description && (
|
|
107
|
+
<p className={styles.imageDescription}>{description}</p>
|
|
108
|
+
)}
|
|
109
|
+
{images.length > 1 && (
|
|
110
|
+
<div className={styles.imageCounter}>
|
|
111
|
+
{currentIndex + 1} of {images.length}
|
|
112
|
+
</div>
|
|
113
|
+
)}
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export default ImageModal;
|
|
@@ -370,7 +370,7 @@ const GenericEditableTable = ({
|
|
|
370
370
|
if (coloursValue) {
|
|
371
371
|
return `${coloursValue}40`; // Add 40% opacity
|
|
372
372
|
}
|
|
373
|
-
|
|
373
|
+
|
|
374
374
|
// Check for status color if no manual color is set
|
|
375
375
|
const statusColor = getStatusColor(entry);
|
|
376
376
|
return statusColor ? `${statusColor}40` : undefined; // Add 40% opacity
|
|
@@ -396,11 +396,10 @@ const GenericEditableTable = ({
|
|
|
396
396
|
return statusOption?.colour || undefined;
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
|
-
|
|
399
|
+
|
|
400
400
|
return undefined;
|
|
401
401
|
};
|
|
402
402
|
|
|
403
|
-
|
|
404
403
|
// Calculate total project cost (sum of all entries excluding margin row)
|
|
405
404
|
const calculateTotalProjectCost = (dataEntries) => {
|
|
406
405
|
const totalColIndex = columns.findIndex((c) => c.type === 'total');
|
|
@@ -425,8 +424,8 @@ const GenericEditableTable = ({
|
|
|
425
424
|
if (!whereConditions || !Array.isArray(whereConditions)) {
|
|
426
425
|
return true;
|
|
427
426
|
}
|
|
428
|
-
|
|
429
|
-
return whereConditions.every(condition => {
|
|
427
|
+
|
|
428
|
+
return whereConditions.every((condition) => {
|
|
430
429
|
const { id, value } = condition;
|
|
431
430
|
return row[id] === value;
|
|
432
431
|
});
|
|
@@ -472,9 +471,11 @@ const GenericEditableTable = ({
|
|
|
472
471
|
if (!data || !Array.isArray(data)) {
|
|
473
472
|
return 0;
|
|
474
473
|
}
|
|
475
|
-
|
|
476
|
-
const filteredData = data.filter(row =>
|
|
477
|
-
|
|
474
|
+
|
|
475
|
+
const filteredData = data.filter((row) =>
|
|
476
|
+
matchesWhereConditions(row, whereConditions)
|
|
477
|
+
);
|
|
478
|
+
|
|
478
479
|
return filteredData.reduce((sum, entry) => {
|
|
479
480
|
return sum + calculateTotal(entry, keys);
|
|
480
481
|
}, 0);
|
|
@@ -1294,7 +1295,7 @@ const GenericEditableTable = ({
|
|
|
1294
1295
|
textAlign: 'left',
|
|
1295
1296
|
width: '20%',
|
|
1296
1297
|
}}
|
|
1297
|
-
colSpan={
|
|
1298
|
+
colSpan={2}
|
|
1298
1299
|
>
|
|
1299
1300
|
Margin %
|
|
1300
1301
|
</th>
|
|
@@ -1307,6 +1308,7 @@ const GenericEditableTable = ({
|
|
|
1307
1308
|
textAlign: 'right',
|
|
1308
1309
|
width: '20%',
|
|
1309
1310
|
}}
|
|
1311
|
+
colSpan={2}
|
|
1310
1312
|
>
|
|
1311
1313
|
Total
|
|
1312
1314
|
</th>
|
|
@@ -1325,7 +1327,7 @@ const GenericEditableTable = ({
|
|
|
1325
1327
|
{/* Margin % input */}
|
|
1326
1328
|
<td
|
|
1327
1329
|
style={{ textAlign: 'center', padding: '8px' }}
|
|
1328
|
-
colSpan={
|
|
1330
|
+
colSpan={2}
|
|
1329
1331
|
>
|
|
1330
1332
|
<input
|
|
1331
1333
|
type="number"
|
|
@@ -1351,6 +1353,7 @@ const GenericEditableTable = ({
|
|
|
1351
1353
|
fontWeight: 'bold',
|
|
1352
1354
|
padding: '8px',
|
|
1353
1355
|
}}
|
|
1356
|
+
colSpan={2}
|
|
1354
1357
|
>
|
|
1355
1358
|
{totalWithMargin.toLocaleString('en-AU', {
|
|
1356
1359
|
style: 'currency',
|
|
@@ -1661,10 +1664,16 @@ const GenericEditableTable = ({
|
|
|
1661
1664
|
);
|
|
1662
1665
|
}
|
|
1663
1666
|
if (index === totalColIndex) {
|
|
1664
|
-
const totalColumn =
|
|
1667
|
+
const totalColumn =
|
|
1668
|
+
columns[totalColIndex];
|
|
1665
1669
|
const groupTotal =
|
|
1666
1670
|
group.entries
|
|
1667
|
-
.filter(entry =>
|
|
1671
|
+
.filter((entry) =>
|
|
1672
|
+
matchesWhereConditions(
|
|
1673
|
+
entry,
|
|
1674
|
+
totalColumn.where
|
|
1675
|
+
)
|
|
1676
|
+
)
|
|
1668
1677
|
.reduce(
|
|
1669
1678
|
(sum, entry) =>
|
|
1670
1679
|
sum +
|
|
@@ -1728,11 +1737,9 @@ const GenericEditableTable = ({
|
|
|
1728
1737
|
<td
|
|
1729
1738
|
key={column.id}
|
|
1730
1739
|
style={{
|
|
1731
|
-
width:
|
|
1732
|
-
column.width || 'auto',
|
|
1740
|
+
width: column.width || 'auto',
|
|
1733
1741
|
textAlign:
|
|
1734
|
-
column.type ===
|
|
1735
|
-
'currency'
|
|
1742
|
+
column.type === 'currency'
|
|
1736
1743
|
? 'right'
|
|
1737
1744
|
: 'left',
|
|
1738
1745
|
}}
|
|
@@ -1817,21 +1824,25 @@ const GenericEditableTable = ({
|
|
|
1817
1824
|
);
|
|
1818
1825
|
}
|
|
1819
1826
|
if (index === totalColIndex) {
|
|
1820
|
-
const totalColumn =
|
|
1827
|
+
const totalColumn =
|
|
1828
|
+
columns[totalColIndex];
|
|
1821
1829
|
const overallTotal =
|
|
1822
|
-
sortBySortOrder(
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
.filter(entry => matchesWhereConditions(entry, totalColumn.where))
|
|
1826
|
-
.reduce(
|
|
1827
|
-
(sum, entry) =>
|
|
1828
|
-
sum +
|
|
1829
|
-
calculateTotal(
|
|
1830
|
+
sortBySortOrder(localData)
|
|
1831
|
+
.filter((entry) =>
|
|
1832
|
+
matchesWhereConditions(
|
|
1830
1833
|
entry,
|
|
1831
|
-
totalColumn.
|
|
1832
|
-
)
|
|
1833
|
-
|
|
1834
|
-
|
|
1834
|
+
totalColumn.where
|
|
1835
|
+
)
|
|
1836
|
+
)
|
|
1837
|
+
.reduce(
|
|
1838
|
+
(sum, entry) =>
|
|
1839
|
+
sum +
|
|
1840
|
+
calculateTotal(
|
|
1841
|
+
entry,
|
|
1842
|
+
totalColumn.keys
|
|
1843
|
+
),
|
|
1844
|
+
0
|
|
1845
|
+
);
|
|
1835
1846
|
return (
|
|
1836
1847
|
<td key={col.id}>
|
|
1837
1848
|
{overallTotal.toLocaleString(
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
.modalOverlay {
|
|
2
|
+
position: fixed;
|
|
3
|
+
top: 0;
|
|
4
|
+
left: 0;
|
|
5
|
+
right: 0;
|
|
6
|
+
bottom: 0;
|
|
7
|
+
background-color: rgba(0, 0, 0, 0.9);
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
z-index: 1000;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.modalContent {
|
|
16
|
+
position: relative;
|
|
17
|
+
max-width: 95vw;
|
|
18
|
+
max-height: 95vh;
|
|
19
|
+
width: 100%;
|
|
20
|
+
height: 100%;
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
align-items: center;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.closeButton {
|
|
28
|
+
position: absolute;
|
|
29
|
+
top: 20px;
|
|
30
|
+
right: 20px;
|
|
31
|
+
background: rgba(255, 255, 255, 0.9);
|
|
32
|
+
border: none;
|
|
33
|
+
border-radius: 50%;
|
|
34
|
+
width: 44px;
|
|
35
|
+
height: 44px;
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
z-index: 1001;
|
|
41
|
+
transition: all 0.2s ease;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.closeButton:hover {
|
|
45
|
+
background: rgba(255, 255, 255, 1);
|
|
46
|
+
transform: scale(1.1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.navButton {
|
|
50
|
+
position: absolute;
|
|
51
|
+
top: 50%;
|
|
52
|
+
transform: translateY(-50%);
|
|
53
|
+
background: rgba(255, 255, 255, 0.9);
|
|
54
|
+
border: none;
|
|
55
|
+
border-radius: 50%;
|
|
56
|
+
width: 56px;
|
|
57
|
+
height: 56px;
|
|
58
|
+
display: flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
justify-content: center;
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
z-index: 1001;
|
|
63
|
+
transition: all 0.2s ease;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.navButton:hover {
|
|
67
|
+
background: rgba(255, 255, 255, 1);
|
|
68
|
+
transform: translateY(-50%) scale(1.1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.navButton:disabled {
|
|
72
|
+
opacity: 0.5;
|
|
73
|
+
cursor: not-allowed;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.navButton:disabled:hover {
|
|
77
|
+
background: rgba(255, 255, 255, 0.9);
|
|
78
|
+
transform: translateY(-50%) scale(1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.prevButton {
|
|
82
|
+
left: 20px;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.nextButton {
|
|
86
|
+
right: 20px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.imageContainer {
|
|
90
|
+
flex: 1;
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
justify-content: center;
|
|
94
|
+
max-width: 100%;
|
|
95
|
+
max-height: 100%;
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.modalImage {
|
|
100
|
+
max-width: 100%;
|
|
101
|
+
max-height: 100%;
|
|
102
|
+
object-fit: contain;
|
|
103
|
+
border-radius: 8px;
|
|
104
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.imageInfo {
|
|
108
|
+
position: absolute;
|
|
109
|
+
bottom: 20px;
|
|
110
|
+
left: 20px;
|
|
111
|
+
right: 20px;
|
|
112
|
+
background: rgba(0, 0, 0, 0.7);
|
|
113
|
+
color: white;
|
|
114
|
+
padding: 16px;
|
|
115
|
+
border-radius: 8px;
|
|
116
|
+
text-align: center;
|
|
117
|
+
max-width: 500px;
|
|
118
|
+
margin: 0 auto;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.imageTitle {
|
|
122
|
+
margin: 0 0 8px 0;
|
|
123
|
+
font-size: 18px;
|
|
124
|
+
font-weight: 600;
|
|
125
|
+
color: white;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.imageDescription {
|
|
129
|
+
margin: 0 0 8px 0;
|
|
130
|
+
font-size: 14px;
|
|
131
|
+
color: rgba(255, 255, 255, 0.9);
|
|
132
|
+
line-height: 1.4;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.imageCounter {
|
|
136
|
+
font-size: 12px;
|
|
137
|
+
color: rgba(255, 255, 255, 0.7);
|
|
138
|
+
margin: 0;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* Mobile responsive styles */
|
|
142
|
+
@media (max-width: 768px) {
|
|
143
|
+
.modalOverlay {
|
|
144
|
+
padding: 10px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.closeButton {
|
|
148
|
+
top: 10px;
|
|
149
|
+
right: 10px;
|
|
150
|
+
width: 40px;
|
|
151
|
+
height: 40px;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.navButton {
|
|
155
|
+
width: 48px;
|
|
156
|
+
height: 48px;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.prevButton {
|
|
160
|
+
left: 10px;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.nextButton {
|
|
164
|
+
right: 10px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.imageInfo {
|
|
168
|
+
bottom: 10px;
|
|
169
|
+
left: 10px;
|
|
170
|
+
right: 10px;
|
|
171
|
+
padding: 12px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.imageTitle {
|
|
175
|
+
font-size: 16px;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.imageDescription {
|
|
179
|
+
font-size: 13px;
|
|
180
|
+
}
|
|
181
|
+
}
|
package/src/index.js
CHANGED
|
@@ -34,6 +34,7 @@ import DataGridSearch from './components/controls/DataGridSearch';
|
|
|
34
34
|
import AutoRefreshControls from './components/controls/AutoRefreshControls';
|
|
35
35
|
import AudioPlayer from './components/controls/AudioPlayer';
|
|
36
36
|
import GalleryModal from './components/modals/GalleryModal';
|
|
37
|
+
import ImageModal from './components/ImageModal';
|
|
37
38
|
import DatePickerPortal from './components/utils/DatePickerPortal';
|
|
38
39
|
export * from './components/columns/ColumnRenderers.jsx';
|
|
39
40
|
|
|
@@ -110,6 +111,7 @@ export {
|
|
|
110
111
|
Field,
|
|
111
112
|
Form,
|
|
112
113
|
GalleryModal,
|
|
114
|
+
ImageModal,
|
|
113
115
|
GenericAuth,
|
|
114
116
|
GenericClientPortal,
|
|
115
117
|
GenericDashboard,
|