├── README.md
├── package.json
└── src
├── index.html
├── css
└── style.css
└── js
└── main.js
/README.md:
--------------------------------------------------------------------------------
1 | # [box-img](http://tscanlin.github.io/box-img/src/index.html)
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "box-img",
3 | "version": "0.0.1",
4 | "description": "lightbox-like script for image galleries",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/tscanlin/box-img"
12 | },
13 | "keywords": [
14 | "lightbox",
15 | "script",
16 | "image",
17 | "gallery",
18 | "preview",
19 | "full",
20 | "screen"
21 | ],
22 | "author": "Tim Scanlin",
23 | "license": "MIT"
24 | }
25 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Box Img
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
×
17 |
18 |
![]()
19 |
20 | «
21 | test
22 | »
23 |
24 |
25 |
26 |
27 |
28 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/css/style.css:
--------------------------------------------------------------------------------
1 | /* BASE */
2 | * {
3 | box-sizing: border-box;
4 | }
5 | html {
6 | height: 100%;
7 | }
8 | body {
9 | min-height: 100%;
10 | margin: 0;
11 | line-height: 1.4;
12 | font-family: sans-serif;
13 | position: relative;
14 | }
15 |
16 | .block {
17 | display: block;
18 | }
19 | .inline {
20 | display: inline;
21 | }
22 | .inline-block {
23 | display: inline-block;
24 | }
25 | .hidden {
26 | display: none;
27 | }
28 |
29 |
30 | /* CLEARFIX (from: https://css-tricks.com/snippets/css/clear-fix/) */
31 | .clearfix::after {
32 | visibility: hidden;
33 | display: block;
34 | font-size: 0;
35 | content: " ";
36 | clear: both;
37 | height: 0;
38 | }
39 | .clearfix { display: inline-block; }
40 | /* start commented backslash hack \*/
41 | * html .clearfix { height: 1%; }
42 | .clearfix { display: block; }
43 | /* close commented backslash hack */
44 |
45 | /* HELPERS */
46 | .max-height--100 {
47 | max-height: 100%;
48 | }
49 |
50 | .font-size--2 {
51 | font-size: 2em;
52 | }
53 |
54 | .max--100 {
55 | max-width: 100%;
56 | max-height: 100%;
57 | }
58 |
59 | .center {
60 | text-align: center;
61 | }
62 |
63 | .margin--auto {
64 | margin: auto;
65 | }
66 |
67 | .cursor--pointer {
68 | cursor: pointer;
69 | }
70 |
71 | .left {
72 | float: left;
73 | }
74 | .right {
75 | float: right;
76 | }
77 |
78 | .bg--dark {
79 | background-color: rgba(10, 10, 10, 0.5);
80 | }
81 | .bg--darker {
82 | background-color: rgba(10, 10, 10, 0.9);
83 | }
84 | .transition {
85 | transition: all 300ms ease-in-out;
86 | }
87 |
88 |
89 | /* GALLERY COMPONENTS */
90 | .gallery {
91 | padding: 20px;
92 | }
93 |
94 | .image-container {
95 | margin-right: 5px;
96 | margin-bottom: 5px;
97 | position: relative;
98 | overflow: hidden;
99 | height: 240px;
100 | }
101 |
102 | .image-meta {
103 | color: white;
104 | position: relative;
105 | top: -1.5em;
106 | padding: 2px 4px;
107 | width: 100%;
108 | }
109 |
110 |
111 | /* PREVIEW COMPONENTS */
112 | .preview-container {
113 | position: absolute;
114 | min-height: inherit;
115 | top: 0;
116 | left: 0;
117 | right: 0;
118 | }
119 |
120 | .preview-image-container {
121 | display: block;
122 | max-width: 90%;
123 | max-height: 90%;
124 | margin: 5% auto;
125 | overflow: hidden;
126 | }
127 |
128 | .preview-controls {
129 | padding: 0 20px;
130 | text-align: center;
131 | width: auto;
132 | }
133 |
134 | .preview-arrow {
135 | position: relative;
136 | top: -2px;
137 | }
138 |
139 | .preview-title {
140 | margin: 0 40px;
141 | }
142 |
143 | .btn--close {
144 | color: white;
145 | position: absolute;
146 | top: 0;
147 | right: 0;
148 | padding-top: 0.1em;
149 | padding-right: 0.4em;
150 | font-size: 3em;
151 | }
152 |
153 |
154 | /* CSS TRANSITIONS */
155 | .preview-container {
156 | opacity: 1;
157 | z-index: 300;
158 | }
159 |
160 | .preview-image-container {
161 | transform: scale(1);
162 | }
163 |
164 | .preview-container.hidden {
165 | display: block;
166 | opacity: 0;
167 | z-index: -1;
168 | }
169 |
170 | .preview-container.hidden > .preview-image-container {
171 | transform: scale(0.9);
172 | }
173 |
174 |
175 | /* GRID VIEW TOGGLE */
176 | #is-grid-view:checked ~ .gallery .image-container {
177 | text-align: center;
178 | width: 200px;
179 | }
180 | #is-grid-view:checked ~ .gallery .image-meta {
181 | width: auto;
182 | top: -1.4em;
183 | }
184 |
--------------------------------------------------------------------------------
/src/js/main.js:
--------------------------------------------------------------------------------
1 | (function(window) {
2 |
3 | var each = [].forEach;
4 | var indexOf = [].indexOf;
5 |
6 | function initializePreview(document, photos) {
7 | var previewContainer = document.querySelector('[data-preview-container]');
8 | var previewHides = document.querySelectorAll('[data-preview-hide]');
9 | var previewImage = document.querySelector('[data-preview-image]');
10 | var previewTitle = document.querySelector('[data-preview-title]');
11 | var previewControls = document.querySelectorAll('[data-preview-control]');
12 | var activators = document.querySelectorAll('[data-preview-show]');
13 | var hiddenClass = 'hidden';
14 |
15 | function contains(arr, item) {
16 | return indexOf.call(arr, item) !== -1;
17 | }
18 |
19 | function findPhoto(photos, url) {
20 | return photos.filter(function(photo) {
21 | return photo.largeImg === url;
22 | })[0] || {};
23 | }
24 |
25 | function showPhoto(photo, event) {
26 | if (!photo) {
27 | return;
28 | }
29 | previewImage.src = photo.largeImg;
30 | previewTitle.textContent = photo.title;
31 |
32 | // Hide or show the arrows.
33 | var index = indexOf.call(photos, findPhoto(photos, previewImage.src));
34 | if (index === 0) {
35 | previewControls.item(0).classList.add(hiddenClass);
36 | } else {
37 | previewControls.item(0).classList.remove(hiddenClass);
38 | }
39 |
40 | if (index === photos.length - 1) {
41 | previewControls.item(1).classList.add(hiddenClass);
42 | } else {
43 | previewControls.item(1).classList.remove(hiddenClass);
44 | }
45 |
46 | previewImage.onload = function() {
47 | previewContainer.classList.remove(hiddenClass);
48 | }
49 |
50 | if (event) {
51 | event.preventDefault();
52 | }
53 | }
54 |
55 | function clickListener(event) {
56 | var el = event.target;
57 |
58 | // Clicking thumbnail images should actually trigger the parent link.
59 | if (el.getAttribute('data-click-parent')) {
60 | el = el.parentNode;
61 | }
62 |
63 | if (contains(previewHides, el)) {
64 | previewContainer.classList.add(hiddenClass)
65 | }
66 |
67 | if (contains(activators, el)) {
68 | var url = el.getAttribute('data-preview-show');
69 | var photo = findPhoto(photos, url);
70 | showPhoto(photo, event);
71 | }
72 |
73 | // Listen for clicks on previous button.
74 | if (contains(previewControls, el)) {
75 | var val = el.getAttribute('data-preview-control');
76 |
77 | var index = indexOf.call(photos, findPhoto(photos, previewImage.src));
78 | var photo = photos[index + 1]; // Default to next.
79 | if (val === 'prev') {
80 | photo = photos[index - 1];
81 | }
82 | showPhoto(photo);
83 | }
84 | }
85 |
86 | function keyupListener(event) {
87 | // Escape.
88 | if (event.keyCode === 27) {
89 | previewContainer.classList.add(hiddenClass);
90 | return;
91 | }
92 |
93 | // Left / Right arrows.
94 | var index = indexOf.call(photos, findPhoto(photos, previewImage.src));
95 | var photo = false; // Default to false.
96 | if (event.keyCode === 37) { // Left.
97 | photo = photos[index - 1];
98 | } else if (event.keyCode === 39) { // Right.
99 | photo = photos[index + 1];
100 | }
101 | showPhoto(photo);
102 | }
103 |
104 | document.body.addEventListener('click', clickListener);
105 | document.body.addEventListener('keyup', keyupListener);
106 |
107 | return function() {
108 | document.body.removeEventListener('click', clickListener);
109 | document.body.removeEventListener('keyup', keyupListener);
110 | }
111 | }
112 |
113 | // Tranform Data.
114 | function buildURL(photoObj, size) {
115 | var ext = '_n.jpg';
116 | if (size === 'large') {
117 | ext = '_b.jpg';
118 | }
119 | return 'https://c' + photoObj.farm + '.staticflickr.com/' + photoObj.farm
120 | + '/' + photoObj.server + '/' + photoObj.id + '_' + photoObj.secret + ext; // "+ _h"
121 | }
122 |
123 | // Build HTML.
124 | function buildPhoto(photo, templateHtml) {
125 | var container = document.createElement('DIV');
126 | container.className = 'left hidden';
127 | container.innerHTML = templateHtml;
128 | for (var prop in photo) {
129 | var el = container.querySelector('[data-prop*="' + prop + '"]')
130 | if (!el) {
131 | continue;
132 | }
133 | var keyVal = el.getAttribute('data-prop').split(':');
134 | var key = keyVal[0].trim();
135 | var val = keyVal[1].trim();
136 | if (key.split('-')[0] === 'data') {
137 | el.setAttribute(key, photo[val]);
138 | } else {
139 | el[key] = photo[val];
140 | }
141 |
142 | // Show el once image loads.
143 | if (key === 'src') {
144 | el.onload = function() {
145 | el.parentNode.parentNode.classList.remove('hidden');
146 | }
147 | }
148 | }
149 |
150 | return container;
151 | }
152 |
153 | function buildHTML(photos) {
154 | var gallery = document.querySelector('.js-gallery');
155 | var templateHtml = document.querySelector('#image-template').innerHTML;
156 |
157 | var arr = [];
158 | each.call(photos, function(photo, i) {
159 | var data = {
160 | thumbnailImg: buildURL(photo),
161 | largeImg: buildURL(photo, 'large'),
162 | title: photo.title
163 | };
164 | arr.push(data);
165 | var el = buildPhoto(data, templateHtml);
166 |
167 | gallery.appendChild(el);
168 |
169 | // At the end.
170 | if (i === photos.length - 1) {
171 | initializePreview(document, arr);
172 | }
173 | });
174 | }
175 |
176 | // Get Data (Ajax).
177 | var xhr = new XMLHttpRequest();
178 | var userId = '141551706@N07';
179 | xhr.open('GET', encodeURI('https://api.flickr.com/services/rest/?&method=flickr.people.getPublicPhotos&format=json&nojsoncallback=1&api_key=5c1f1af33b907a0e7e1bb79b5b0a5fee&user_id=' + userId));
180 | xhr.onload = function() {
181 | var response = {};
182 |
183 | if (xhr.status !== 200) {
184 | console.error('Failed with status of ' + xhr.status);
185 | }
186 |
187 | try {
188 | response = JSON.parse(xhr.responseText);
189 | } catch (e) {
190 | console.error(e);
191 | }
192 |
193 | if (response.photos && response.photos.photo.length) {
194 | buildHTML(response.photos.photo);
195 | } else {
196 | console.error('You don\'t have any public photos');
197 | }
198 | };
199 | xhr.send();
200 |
201 | }(window));
202 |
--------------------------------------------------------------------------------