@mgonza02/goal-image-gallery 1.0.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.
@@ -0,0 +1,173 @@
1
+ import { Box } from '@mui/material';
2
+ import { alpha, styled } from '@mui/material/styles';
3
+
4
+ /**
5
+ * Styled component for image containers with enhanced hover effects
6
+ */
7
+ export const StyledImageContainer = styled(Box)(_ref => {
8
+ let {
9
+ theme
10
+ } = _ref;
11
+ return {
12
+ position: 'relative',
13
+ borderRadius: theme.spacing(1.5),
14
+ overflow: 'hidden',
15
+ backgroundColor: theme.palette.background.paper,
16
+ border: `1px solid ${theme.palette.divider}`,
17
+ cursor: 'pointer',
18
+ transition: theme.transitions.create(['border-color', 'box-shadow', 'transform'], {
19
+ duration: theme.transitions.duration.short
20
+ }),
21
+ '&:hover': {
22
+ borderColor: theme.palette.primary.main,
23
+ boxShadow: theme.shadows[4],
24
+ transform: 'translateY(-2px)',
25
+ '& .image-overlay': {
26
+ opacity: 1
27
+ }
28
+ }
29
+ };
30
+ });
31
+
32
+ /**
33
+ * Styled component for image overlay with action buttons
34
+ */
35
+ export const ImageOverlay = styled(Box)(_ref2 => {
36
+ let {
37
+ theme
38
+ } = _ref2;
39
+ return {
40
+ position: 'absolute',
41
+ top: 0,
42
+ left: 0,
43
+ right: 0,
44
+ bottom: 0,
45
+ background: alpha(theme.palette.common.black, 0.5),
46
+ display: 'flex',
47
+ alignItems: 'center',
48
+ justifyContent: 'center',
49
+ opacity: 0,
50
+ transition: theme.transitions.create('opacity', {
51
+ duration: theme.transitions.duration.short
52
+ }),
53
+ '& .MuiIconButton-root': {
54
+ color: theme.palette.common.white,
55
+ backgroundColor: alpha(theme.palette.common.black, 0.7),
56
+ margin: theme.spacing(0.5),
57
+ '&:hover': {
58
+ backgroundColor: alpha(theme.palette.common.black, 0.9)
59
+ }
60
+ }
61
+ };
62
+ });
63
+
64
+ /**
65
+ * Styled component for modal container
66
+ */
67
+ export const StyledModalContainer = styled(Box)(_ref3 => {
68
+ let {
69
+ theme,
70
+ isMobile
71
+ } = _ref3;
72
+ return {
73
+ position: 'absolute',
74
+ top: '50%',
75
+ left: '50%',
76
+ transform: 'translate(-50%, -50%)',
77
+ width: isMobile ? '95vw' : '90vw',
78
+ maxWidth: 1200,
79
+ height: isMobile ? '95vh' : '90vh',
80
+ backgroundColor: theme.palette.background.paper,
81
+ borderRadius: theme.spacing(2),
82
+ overflow: 'hidden',
83
+ display: 'flex',
84
+ flexDirection: 'column',
85
+ boxShadow: 24
86
+ };
87
+ });
88
+
89
+ /**
90
+ * Styled component for modal header
91
+ */
92
+ export const StyledModalHeader = styled(Box)(_ref4 => {
93
+ let {
94
+ theme
95
+ } = _ref4;
96
+ return {
97
+ display: 'flex',
98
+ justifyContent: 'space-between',
99
+ alignItems: 'center',
100
+ padding: theme.spacing(2),
101
+ borderBottom: `1px solid ${theme.palette.divider}`,
102
+ backgroundColor: alpha(theme.palette.background.paper, 0.95)
103
+ };
104
+ });
105
+
106
+ /**
107
+ * Styled component for modal body
108
+ */
109
+ export const StyledModalBody = styled(Box)(_ref5 => {
110
+ let {
111
+ theme
112
+ } = _ref5;
113
+ return {
114
+ flex: 1,
115
+ display: 'flex',
116
+ alignItems: 'center',
117
+ justifyContent: 'center',
118
+ overflow: 'hidden',
119
+ position: 'relative',
120
+ backgroundColor: theme.palette.grey[50]
121
+ };
122
+ });
123
+
124
+ /**
125
+ * Styled component for modal footer
126
+ */
127
+ export const StyledModalFooter = styled(Box)(_ref6 => {
128
+ let {
129
+ theme
130
+ } = _ref6;
131
+ return {
132
+ display: 'flex',
133
+ justifyContent: 'space-between',
134
+ alignItems: 'center',
135
+ padding: theme.spacing(2),
136
+ borderTop: `1px solid ${theme.palette.divider}`,
137
+ backgroundColor: alpha(theme.palette.background.paper, 0.95)
138
+ };
139
+ });
140
+
141
+ /**
142
+ * Styled component for empty state container
143
+ */
144
+ export const StyledEmptyStateContainer = styled(Box)(_ref7 => {
145
+ let {
146
+ theme
147
+ } = _ref7;
148
+ return {
149
+ display: 'flex',
150
+ flexDirection: 'column',
151
+ justifyContent: 'center',
152
+ alignItems: 'center',
153
+ padding: theme.spacing(2),
154
+ minHeight: 300
155
+ };
156
+ });
157
+
158
+ /**
159
+ * Styled component for image grid container
160
+ */
161
+ export const StyledImageGridContainer = styled(Box)(_ref8 => {
162
+ let {
163
+ theme
164
+ } = _ref8;
165
+ return {
166
+ display: 'flex',
167
+ flexDirection: 'column',
168
+ justifyContent: 'center',
169
+ alignItems: 'center',
170
+ padding: theme.spacing(2),
171
+ minHeight: 200
172
+ };
173
+ });
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Image gallery utility functions
3
+ */
4
+
5
+ /**
6
+ * Handle image errors with fallback logic
7
+ */
8
+ export const handleImageError = (e, noImageUrl) => {
9
+ if (e.target.src.includes(noImageUrl)) {
10
+ e.target.src = '/static/images/pic-share-logo.png';
11
+ } else {
12
+ e.target.onerror = null;
13
+ e.target.src = noImageUrl;
14
+ }
15
+ };
16
+
17
+ /**
18
+ * Download image from URL
19
+ */
20
+ export const downloadImage = (imageUrl, imageCode) => {
21
+ const link = document.createElement('a');
22
+ link.href = imageUrl;
23
+ link.download = `image-${imageCode}.jpg`;
24
+ link.click();
25
+ };
26
+
27
+ /**
28
+ * Process image codes into standardized format
29
+ */
30
+ export const processImageCodes = imageCodes => {
31
+ if (!imageCodes) return [];
32
+ const splitedImages = Array.isArray(imageCodes) ? imageCodes : imageCodes.split(/[\s,]+/);
33
+ return splitedImages.map((image_code, index) => ({
34
+ id: index,
35
+ width: 1,
36
+ height: 1,
37
+ title: 'Goal Image',
38
+ image_code
39
+ }));
40
+ };
41
+
42
+ /**
43
+ * Get responsive grid columns based on screen size and multiple flag
44
+ */
45
+ export const getGridColumns = (isMobile, isTablet, multiple) => {
46
+ if (isMobile) return 6; // 2 columns on mobile
47
+ if (isTablet) return multiple ? 4 : 6; // 3 or 2 columns on tablet
48
+ return multiple ? 3 : 4; // 4 or 3 columns on desktop
49
+ };
50
+
51
+ /**
52
+ * Validate image file type
53
+ */
54
+ export const isValidImageFile = file => {
55
+ const validTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];
56
+ return validTypes.includes(file.type);
57
+ };
58
+
59
+ /**
60
+ * Format file size for display
61
+ */
62
+ export const formatFileSize = bytes => {
63
+ if (bytes === 0) return '0 Bytes';
64
+ const k = 1024;
65
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
66
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
67
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
68
+ };
69
+
70
+ /**
71
+ * Generate unique ID for components
72
+ */
73
+ export const generateId = () => {
74
+ return Math.random().toString(36).substr(2, 9);
75
+ };
76
+
77
+ /**
78
+ * Debounce function for performance optimization
79
+ */
80
+ export const debounce = (func, wait) => {
81
+ let timeout;
82
+ return function executedFunction() {
83
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
84
+ args[_key] = arguments[_key];
85
+ }
86
+ const later = () => {
87
+ clearTimeout(timeout);
88
+ func(...args);
89
+ };
90
+ clearTimeout(timeout);
91
+ timeout = setTimeout(later, wait);
92
+ };
93
+ };
94
+
95
+ /**
96
+ * Check if device supports touch
97
+ */
98
+ export const isTouchDevice = () => {
99
+ return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
100
+ };
101
+
102
+ /**
103
+ * Get image dimensions from URL
104
+ */
105
+ export const getImageDimensions = url => {
106
+ return new Promise((resolve, reject) => {
107
+ const img = new Image();
108
+ img.onload = () => {
109
+ resolve({
110
+ width: img.width,
111
+ height: img.height
112
+ });
113
+ };
114
+ img.onerror = reject;
115
+ img.src = url;
116
+ });
117
+ };
118
+
119
+ /**
120
+ * Create image preview from file
121
+ */
122
+ export const createImagePreview = file => {
123
+ return new Promise((resolve, reject) => {
124
+ const reader = new FileReader();
125
+ reader.onload = e => resolve(e.target.result);
126
+ reader.onerror = reject;
127
+ reader.readAsDataURL(file);
128
+ });
129
+ };
package/package.json ADDED
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "@mgonza02/goal-image-gallery",
3
+ "version": "1.0.0",
4
+ "description": "Enhanced, modular image gallery component for React applications",
5
+ "main": "lib/index.js",
6
+ "module": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
+ "keywords": [
9
+ "react",
10
+ "image-gallery",
11
+ "material-ui",
12
+ "component",
13
+ "upload",
14
+ "drag-drop",
15
+ "clipboard",
16
+ "modal",
17
+ "zoom",
18
+ "responsive"
19
+ ],
20
+ "author": "Goal Team",
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/goal-systems/goal-image-gallery"
25
+ },
26
+ "homepage": "https://github.com/goal-systems/goal-image-gallery#readme",
27
+ "bugs": {
28
+ "url": "https://github.com/goal-systems/goal-image-gallery/issues"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "files": [
34
+ "lib/",
35
+ "README.md",
36
+ "QUICK_REFERENCE.md",
37
+ "MIGRATION.md",
38
+ "IMPLEMENTATION_SUMMARY.md",
39
+ "LICENSE"
40
+ ],
41
+ "peerDependencies": {
42
+ "react": "^18.0.0",
43
+ "react-dom": "^18.0.0",
44
+ "@mui/material": "^5.0.0",
45
+ "@mui/icons-material": "^5.0.0",
46
+ "@emotion/react": "^11.0.0",
47
+ "@emotion/styled": "^11.0.0"
48
+ },
49
+ "dependencies": {
50
+ "prop-types": "^15.8.0"
51
+ },
52
+ "scripts": {
53
+ "build": "npm run clean && npm run build:js && npm run build:types",
54
+ "build:js": "babel src --out-dir lib --copy-files --ignore '**/*.test.js'",
55
+ "build:types": "cp src/index.d.ts lib/index.d.ts",
56
+ "prepublishOnly": "npm run build",
57
+ "test": "jest",
58
+ "lint": "eslint src/**/*.js --fix",
59
+ "lint:check": "eslint src/**/*.js",
60
+ "format": "prettier --write src/**/*.js",
61
+ "format:check": "prettier --check src/**/*.js",
62
+ "clean": "rm -rf lib",
63
+ "validate": "npm run lint:check && npm run format:check",
64
+ "dev": "npm run build -- --watch",
65
+ "prepack": "npm run validate && npm run build"
66
+ },
67
+ "devDependencies": {
68
+ "@babel/cli": "^7.20.0",
69
+ "@babel/core": "^7.20.0",
70
+ "@babel/preset-env": "^7.20.0",
71
+ "@babel/preset-react": "^7.18.0",
72
+ "eslint": "^8.30.0",
73
+ "eslint-plugin-react": "^7.31.0",
74
+ "eslint-plugin-react-hooks": "^4.6.0",
75
+ "jest": "^29.0.0",
76
+ "prettier": "^2.8.0"
77
+ },
78
+ "browserslist": {
79
+ "production": [
80
+ ">0.2%",
81
+ "not dead",
82
+ "not op_mini all"
83
+ ],
84
+ "development": [
85
+ "last 1 chrome version",
86
+ "last 1 firefox version",
87
+ "last 1 safari version"
88
+ ]
89
+ },
90
+ "engines": {
91
+ "node": ">=16.0.0"
92
+ }
93
+ }