├── .gitignore ├── .idea ├── .gitignore ├── modules.xml ├── vcs.xml └── vue-image-browser.iml ├── LICENSE ├── README.md ├── build └── rollup.config.js ├── dist ├── vue-image-browser.esm.js ├── vue-image-browser.min.js └── vue-image-browser.umd.js ├── images ├── example-image-1.png └── example-image-2.png ├── package-lock.json ├── package.json ├── postcss.config.js └── src ├── vue-image-browser.vue └── wrapper.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/vue-image-browser.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Akash Mitra 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # An Image Browser Component Built with VueJs 2 | 3 | ![](images/example-image-1.png) 4 | 5 | A JavaScript Image Browser written in [VueJS](https://vuejs.org/) and styled with [TailwindCSS](https://tailwindcss.com/docs/installation/). 6 | 7 | ## Features 8 | - Image Upload 9 | - Local or Remote Image Search 10 | - Show larger image (Photo Pane view) 11 | - Delete Image 12 | - Show arbitrary information about the image 13 | - Generate Or Capture Image Caption 14 | - Lazy Load Images on scroll 15 | 16 | ## Usage 17 | 18 | Install as npm package 19 | 20 | ``` 21 | npm install @akashmitra/vue-image-browser 22 | ``` 23 | 24 | `import` this as a component. You may also use this inside another Vue component. 25 | 26 | ```javascript 27 | 38 | 59 | 60 | ``` 61 | 62 | ## Image Object 63 | 64 | The `images` attribute in `VueImageBrowser` accepts an array containing one or more "image objects" with following mandatory fields - `id`, `name` and `url`. The image object can contain other fields as well. You can specify the additional fields in `image-properties` as key-value pairs, where the `key` is the attribute name and the `value` is the attribute title. 65 | 66 | 67 | 68 | ## Image Upload Response 69 | 70 | ![](images/example-image-2.png) 71 | 72 | It is possible to upload an image to a specified API endpoint (`save-url`) via POST. 73 | When an image is uploaded successfully, a 200 HTTP Status code response must be sent back from the server with a response JSON. After the image is uploaded successfully, a `saved` event will be generated and the response JSON will be passed with the event. Please see the example section below. 74 | 75 | 76 | ## Options 77 | 78 | | Parameter | Type | Default Value | Description | 79 | |------------------------|---------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 80 | | `images` | Array | `[]` | An array containing the image objects. Each image object must contain `id`, `name` and `url` of the image | 81 | | `image-properties` | Object | | An object containing all the fields in image object along with the field titles | 82 | | `allow-upload` | Boolean | false | (OPTIONAL) Whether or not to provide provision for image upload. If this is `true`, a `save-url` must be provided. | 83 | | `save-url` | String | /api/photos | Specify the URL endpoint for posting the uploaded images. | 84 | | `save-request-headers` | Object | `{}` | (OPTIONAL) If you need to pass any additional HTTP headers, you may do so by providing the header names and values in this object | 85 | | `allow-photo-pane` | Boolean | false | (OPTIONAL) When this attribute is true, clicking on an image in the gallery will show a larger version of the image in a Photo pane, along with any additional image information. | 86 | | `allow-delete` | Boolean | false | (OPTIONAL) Whether or not to provide a provision for deleting an image in Photo Pane view. If this is true, delete button will be shown and a `deleted` event will be generated | 87 | | `allow-choose` | Boolean | false | (OPTIONAL) Whether or not to provide a provision for chosing the image inside Photo Pane view. If this is true, a "Choose" button will be displayed and a `chosen` event will be generated | 88 | | `allow-copy` | Boolean | true | (OPTIONAL) Whether or not to provide a provision for copying the image URL in the Photo Pane View. If this is true, a `Copy Link` button will be shown and image `url` will be copied to clipboard | 89 | | `captionable` | Boolean | false | (OPTIONAL) Whether or not to provide a provision for specifying the image caption after selecting an image. If this is true, a prompt will be shown for image caption when users select an image | 90 | | `enable-lazy-load` | Boolean | true | (OPTIONAL) Uses IntersectionObserver to ensure the images are only loaded to browser when the image comes near the browser viewport | 91 | | `search-delay` | Number | 500 | (OPTIONAL) A delay in miliseconds after which the search event is fired. | 92 | | `max-images-per-row` | Number | 5 | (OPTIONAL) Maximum number of images to be displayed in each row in image gallery. Must be a value from 1 to 6. Actual number of displayed images will vary based on screen-size | 93 | | `post-key` | String | image | (OPTIONAL) The name of the post request parameter to be used while posting file to the server. | 94 | 95 | 96 | ## Events 97 | 98 | Following events are generated when performing various interactions with the images. 99 | 100 | | Event | Parameter Type | Parameter Value | Description | 101 | |---------------|-----------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 102 | | `searched` | String | seach phrase | This event is generated when users search in the search box. The search phrase is passed to the event handler, which can be used to filter the images array | 103 | | `selected` | Object | image | This event is generated when users click on an image in the Gallery. The image is passed to the event handler. | 104 | | `chosen` | Object | image | This event is generated when users select an image. The image is passed to the event handler. | 105 | | `saved` | Object | image | This event is generated when users successfully upload an image. The image is passed to the event handler. | 106 | | `deleted` | Object | image | This event is generated when users delete an image. The image is passed to the event handler. | 107 | 108 | 109 | ## Example 110 | 111 | ```javascript 112 | 135 | 136 | 197 | 198 | 199 | ``` 200 | 201 | ## Dependency 202 | 203 | [TailwindCSS](https://tailwindcss.com/docs/installation/) must be present for the styling. -------------------------------------------------------------------------------- /build/rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonjs from '@rollup/plugin-commonjs'; // Convert CommonJS modules to ES6 2 | import vue from 'rollup-plugin-vue'; // Handle .vue SFC files 3 | import buble from '@rollup/plugin-buble'; // Transpile/polyfill with reasonable browser support 4 | 5 | export default { 6 | input: 'src/wrapper.js', // Path relative to package.json 7 | output: { 8 | name: 'VueImageBrowser', 9 | exports: 'named', 10 | }, 11 | external: [], 12 | plugins: [ 13 | commonjs(), 14 | vue({ 15 | css: true, // Dynamically inject css as a \n"] 1166 | }, 1167 | media: undefined 1168 | }); 1169 | 1170 | }; 1171 | /* scoped */ 1172 | var __vue_scope_id__ = undefined; 1173 | /* module identifier */ 1174 | var __vue_module_identifier__ = undefined; 1175 | /* functional template */ 1176 | var __vue_is_functional_template__ = false; 1177 | /* style inject SSR */ 1178 | 1179 | /* style inject shadow dom */ 1180 | 1181 | 1182 | 1183 | var __vue_component__ = /*#__PURE__*/normalizeComponent( 1184 | { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, 1185 | __vue_inject_styles__, 1186 | __vue_script__, 1187 | __vue_scope_id__, 1188 | __vue_is_functional_template__, 1189 | __vue_module_identifier__, 1190 | false, 1191 | createInjector, 1192 | undefined, 1193 | undefined 1194 | ); 1195 | 1196 | // Import vue component 1197 | 1198 | // Declare install function executed by Vue.use() 1199 | function install(Vue) { 1200 | if (install.installed) { return; } 1201 | install.installed = true; 1202 | Vue.component('VueImageBrowser', __vue_component__); 1203 | } 1204 | 1205 | // Create module definition for Vue.use() 1206 | var plugin = { 1207 | install: install, 1208 | }; 1209 | 1210 | // Auto-install when vue is found (eg. in browser via \n\n\n"]}, media: undefined }); 1159 | 1160 | }; 1161 | /* scoped */ 1162 | var __vue_scope_id__ = undefined; 1163 | /* module identifier */ 1164 | var __vue_module_identifier__ = undefined; 1165 | /* functional template */ 1166 | var __vue_is_functional_template__ = false; 1167 | /* style inject SSR */ 1168 | 1169 | /* style inject shadow dom */ 1170 | 1171 | 1172 | 1173 | var __vue_component__ = /*#__PURE__*/normalizeComponent( 1174 | { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, 1175 | __vue_inject_styles__, 1176 | __vue_script__, 1177 | __vue_scope_id__, 1178 | __vue_is_functional_template__, 1179 | __vue_module_identifier__, 1180 | false, 1181 | createInjector, 1182 | undefined, 1183 | undefined 1184 | ); 1185 | 1186 | // Import vue component 1187 | 1188 | // Declare install function executed by Vue.use() 1189 | function install(Vue) { 1190 | if (install.installed) { return; } 1191 | install.installed = true; 1192 | Vue.component('VueImageBrowser', __vue_component__); 1193 | } 1194 | 1195 | // Create module definition for Vue.use() 1196 | var plugin = { 1197 | install: install, 1198 | }; 1199 | 1200 | // Auto-install when vue is found (eg. in browser via \n\n\n"] 1172 | }, 1173 | media: undefined 1174 | }); 1175 | 1176 | }; 1177 | /* scoped */ 1178 | var __vue_scope_id__ = undefined; 1179 | /* module identifier */ 1180 | var __vue_module_identifier__ = undefined; 1181 | /* functional template */ 1182 | var __vue_is_functional_template__ = false; 1183 | /* style inject SSR */ 1184 | 1185 | /* style inject shadow dom */ 1186 | 1187 | 1188 | 1189 | var __vue_component__ = /*#__PURE__*/normalizeComponent( 1190 | { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, 1191 | __vue_inject_styles__, 1192 | __vue_script__, 1193 | __vue_scope_id__, 1194 | __vue_is_functional_template__, 1195 | __vue_module_identifier__, 1196 | false, 1197 | createInjector, 1198 | undefined, 1199 | undefined 1200 | ); 1201 | 1202 | // Import vue component 1203 | 1204 | // Declare install function executed by Vue.use() 1205 | function install(Vue) { 1206 | if (install.installed) { return; } 1207 | install.installed = true; 1208 | Vue.component('VueImageBrowser', __vue_component__); 1209 | } 1210 | 1211 | // Create module definition for Vue.use() 1212 | var plugin = { 1213 | install: install, 1214 | }; 1215 | 1216 | // Auto-install when vue is found (eg. in browser via 516 | 517 | 549 | -------------------------------------------------------------------------------- /src/wrapper.js: -------------------------------------------------------------------------------- 1 | // Import vue component 2 | import component from './vue-image-browser.vue'; 3 | 4 | // Declare install function executed by Vue.use() 5 | export function install(Vue) { 6 | if (install.installed) return; 7 | install.installed = true; 8 | Vue.component('VueImageBrowser', component); 9 | } 10 | 11 | // Create module definition for Vue.use() 12 | const plugin = { 13 | install, 14 | }; 15 | 16 | // Auto-install when vue is found (eg. in browser via