From c7d028ba596b233afe681c11281781b129c5a645 Mon Sep 17 00:00:00 2001 From: Denis Stebunov Date: Sun, 7 Jul 2024 16:53:50 +0200 Subject: [PATCH] add a lightbox --- content/on-estimates/index.md | 8 +- content/router-or-moderator/index.md | 4 +- content/three-steps/index.md | 4 +- layouts/partials/footer.html | 2 + static/lightbox.css | 94 ++++++++++++++++++ static/lightbox.js | 141 +++++++++++++++++++++++++++ 6 files changed, 245 insertions(+), 8 deletions(-) create mode 100644 static/lightbox.css create mode 100644 static/lightbox.js diff --git a/content/on-estimates/index.md b/content/on-estimates/index.md index 3384450..1644d5f 100644 --- a/content/on-estimates/index.md +++ b/content/on-estimates/index.md @@ -47,7 +47,7 @@ thing happens, just later. As a rule of thumb, you may think of deadlines as "the earliest dates when something can be delivered." So no matter whether they over- or underestimated, nothing ships until the deadline. -![Productivity by Estimation Approach](peopleware-estimates.png) +[![Productivity by Estimation Approach](peopleware-estimates.png)](peopleware-estimates.png) *Source: [Peopleware by Tom DeMarko and Timothy Lister](https://www.amazon.com/Peopleware-Productive-Projects-Tom-DeMarco/dp/0932633439)* @@ -76,7 +76,7 @@ out-of-the-box product, or exist as a library or framework. Therefore, in most cases, developers have to provide estimates for tasks that have a high degree of uncertainty. -![Figuring out what to do – Getting it done](hill-concept.png) +[![Figuring out what to do – Getting it done](hill-concept.png)](hill-concept.png) *Source: [Show Progress | Shape Up by BaseCamp](https://basecamp.com/shapeup/3.4-chapter-12)* @@ -104,7 +104,7 @@ how many women are assigned." However, when people hear that a project will take nine man-months, they sometimes assume that it probably can be three months for three random developers. -![Mythical Man-Month](man-month.png) +[![Mythical Man-Month](man-month.png)](man-month.png) *Source: [The Mythical Man-Month by Frederick P. Brooks](https://www.amazon.com/Mythical-Man-Month-Anniversary-Software-Engineering-ebook/dp/B00B8USS14/)* @@ -117,7 +117,7 @@ deadline, but fail the task altogether. ## Initial development is a minor cost -![Maintenance vs. initial development](dev-maintenance.png) +[![Maintenance vs. initial development](dev-maintenance.png)](dev-maintenance.png) Arguably the biggest problem with estimates is that people routinely ask for initial development estimates, but rarely ask for estimates about the diff --git a/content/router-or-moderator/index.md b/content/router-or-moderator/index.md index 3525e77..80f6689 100644 --- a/content/router-or-moderator/index.md +++ b/content/router-or-moderator/index.md @@ -27,7 +27,7 @@ Each strategy has pros and cons. ## Router -![Manager as a router](manager-router.png) +[![Manager as a router](manager-router.png)](manager-router.png) In *router* mode, the manager is responsible for all communication between the engineering team and the stakeholders. Centralizing communication this way @@ -68,7 +68,7 @@ Cons: ## Moderator -![Manager as a moderator](manager-moderator.png) +[![Manager as a moderator](manager-moderator.png)](manager-moderator.png) An alternative approach is *moderator* mode, where the manager supervises while stakeholders communicate directly with engineering team members. Everyone is diff --git a/content/three-steps/index.md b/content/three-steps/index.md index 7b58a71..e9db101 100644 --- a/content/three-steps/index.md +++ b/content/three-steps/index.md @@ -75,7 +75,7 @@ designer. For example, you can use a rapid wireframing tool like quickly without spending time on minor visual details. Or, use a whiteboard or good old pencil and paper. Any sketch is better than nothing. -![Low-fidelity Balsamiq wireframes](balsamiq.png) +[![Low-fidelity Balsamiq wireframes](balsamiq.png)](balsamiq.png) *Low-fidelity [Balsamiq](https://balsamiq.com) wireframes* @@ -113,7 +113,7 @@ diagram. ER diagrams are arguably the most useful part of the UML specification. You may skip everything else in UML, but if you're working with relational databases - don't skip ER diagrams :) -![ER diagram example](dbdiagram.png) +[![ER diagram example](dbdiagram.png)](dbdiagram.png) *Credit: [dbdiagram.io](https://dbdiagram.io)* ## Summary diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html index 46b364d..c1e2db3 100644 --- a/layouts/partials/footer.html +++ b/layouts/partials/footer.html @@ -8,3 +8,5 @@ + + diff --git a/static/lightbox.css b/static/lightbox.css new file mode 100644 index 0000000..e81a309 --- /dev/null +++ b/static/lightbox.css @@ -0,0 +1,94 @@ +#lightbox {width: 100%; height: 100%; position: fixed; top: 0; left: 0; background: rgba(0,0,0,0.85); z-index: 9999999; line-height: 0; cursor: pointer; display: none;} +#lightbox .img { + position: relative; + top: 50%; + left: 50%; + -ms-transform: translateX(-50%) translateY(-50%); + -webkit-transform: translate(-50%,-50%); + transform: translate(-50%,-50%); + max-width: 100%; + max-height: 100%; +} +#lightbox .img img {opacity: 0; pointer-events: none; width: auto;} +@media screen and (min-width: 1200px) { + #lightbox .img { + max-width: 1200px; + } +} +@media screen and (min-height: 1200px) { + #lightbox .img { + max-height: 1200px; + } +} +#lightbox span {display: block; position: fixed; bottom: 13px; height: 1.5em; line-height: 1.4em; width: 100%; text-align: center; color: white; text-shadow: + -1px -1px 0 #000, + 1px -1px 0 #000, + -1px 1px 0 #000, + 1px 1px 0 #000; +} + +#lightbox span {display: none;} + +#lightbox .videoWrapperContainer { + position: relative; + top: 50%; + left: 50%; + -ms-transform: translateX(-50%) translateY(-50%); + -webkit-transform: translate(-50%,-50%); + transform: translate(-50%,-50%); + max-width: 900px; + max-height: 100%; +} +#lightbox .videoWrapperContainer .videoWrapper { + height: 0; + line-height: 0; + margin: 0; + padding: 0; + position: relative; + padding-bottom: 56.333%; /* custom */ + background: black; +} +#lightbox .videoWrapper iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; + display: block; +} +#lightbox #prev, #lightbox #next {height: 50px; line-height: 36px; display: none; margin-top: -25px; position: fixed; top: 50%; padding: 0 15px; cursor: pointer; text-decoration: none; z-index: 99; color: white; font-size: 60px;} +#lightbox.gallery #prev, #lightbox.gallery #next {display: block;} +#lightbox #prev {left: 0;} +#lightbox #next {right: 0;} +#lightbox #close {height: 50px; width: 50px; position: fixed; cursor: pointer; text-decoration: none; z-index: 99; right: 0; top: 0;} +#lightbox #close:after, #lightbox #close:before {position: absolute; margin-top: 22px; margin-left: 14px; content: ""; height: 3px; background: white; width: 23px; +-webkit-transform-origin: 50% 50%; +-moz-transform-origin: 50% 50%; +-o-transform-origin: 50% 50%; +transform-origin: 50% 50%; +/* Safari */ +-webkit-transform: rotate(-45deg); +/* Firefox */ +-moz-transform: rotate(-45deg); +/* IE */ +-ms-transform: rotate(-45deg); +/* Opera */ +-o-transform: rotate(-45deg); +} +#lightbox #close:after { +/* Safari */ +-webkit-transform: rotate(45deg); +/* Firefox */ +-moz-transform: rotate(45deg); +/* IE */ +-ms-transform: rotate(45deg); +/* Opera */ +-o-transform: rotate(45deg); +} +#lightbox, #lightbox * { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} \ No newline at end of file diff --git a/static/lightbox.js b/static/lightbox.js new file mode 100644 index 0000000..c42a289 --- /dev/null +++ b/static/lightbox.js @@ -0,0 +1,141 @@ +function is_youtubelink(url) { + var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/; + return (url.match(p)) ? RegExp.$1 : false; +} +function is_imagelink(url) { + var p = /([a-z\-_0-9\/\:\.]*\.(jpg|jpeg|png|gif))/i; + return (url.match(p)) ? true : false; +} +function is_vimeolink(url,el) { + var id = false; + var xmlhttp = new XMLHttpRequest(); + xmlhttp.onreadystatechange = function() { + if (xmlhttp.readyState == XMLHttpRequest.DONE) { // XMLHttpRequest.DONE == 4 + if (xmlhttp.status == 200) { + var response = JSON.parse(xmlhttp.responseText); + id = response.video_id; + console.log(id); + el.classList.add('lightbox-vimeo'); + el.setAttribute('data-id',id); + + el.addEventListener("click", function(event) { + event.preventDefault(); + document.getElementById('lightbox').innerHTML = '
'; + document.getElementById('lightbox').style.display = 'block'; + + setGallery(this); + }); + } + else if (xmlhttp.status == 400) { + alert('There was an error 400'); + } + else { + alert('something else other than 200 was returned'); + } + } + }; + xmlhttp.open("GET", 'https://vimeo.com/api/oembed.json?url='+url, true); + xmlhttp.send(); +} +function setGallery(el) { + var elements = document.body.querySelectorAll(".gallery"); + elements.forEach(element => { + element.classList.remove('gallery'); + }); + if(el.closest('ul, p')) { + var link_elements = el.closest('ul, p').querySelectorAll("a[class*='lightbox-']"); + link_elements.forEach(link_element => { + link_element.classList.remove('current'); + }); + link_elements.forEach(link_element => { + if(el.getAttribute('href') == link_element.getAttribute('href')) { + link_element.classList.add('current'); + } + }); + if(link_elements.length>1) { + document.getElementById('lightbox').classList.add('gallery'); + link_elements.forEach(link_element => { + link_element.classList.add('gallery'); + }); + } + var currentkey; + var gallery_elements = document.querySelectorAll('a.gallery'); + Object.keys(gallery_elements).forEach(function (k) { + if(gallery_elements[k].classList.contains('current')) currentkey = k; + }); + if(currentkey==(gallery_elements.length-1)) var nextkey = 0; + else var nextkey = parseInt(currentkey)+1; + if(currentkey==0) var prevkey = parseInt(gallery_elements.length-1); + else var prevkey = parseInt(currentkey)-1; + document.getElementById('next').addEventListener("click", function() { + gallery_elements[nextkey].click(); + }); + document.getElementById('prev').addEventListener("click", function() { + gallery_elements[prevkey].click(); + }); + } +} + +document.addEventListener("DOMContentLoaded", function() { + + //create lightbox div in the footer + var newdiv = document.createElement("div"); + newdiv.setAttribute('id',"lightbox"); + document.body.appendChild(newdiv); + + //add classes to links to be able to initiate lightboxes + var elements = document.querySelectorAll('a'); + elements.forEach(element => { + var url = element.getAttribute('href'); + if(url) { + if(url.indexOf('vimeo') !== -1 && !element.classList.contains('no-lightbox')) { + is_vimeolink(url,element); + } + if(is_youtubelink(url) && !element.classList.contains('no-lightbox')) { + element.classList.add('lightbox-youtube'); + element.setAttribute('data-id',is_youtubelink(url)); + } + if(is_imagelink(url) && !element.classList.contains('no-lightbox')) { + element.classList.add('lightbox-image'); + var href = element.getAttribute('href'); + var filename = href.split('/').pop(); + var split = filename.split("."); + var name = split[0]; + element.setAttribute('title',name); + } + } + }); + + //remove the clicked lightbox + document.getElementById('lightbox').addEventListener("click", function(event) { + if(event.target.id != 'next' && event.target.id != 'prev'){ + this.innerHTML = ''; + document.getElementById('lightbox').style.display = 'none'; + } + }); + + //add the youtube lightbox on click + var elements = document.querySelectorAll('a.lightbox-youtube'); + elements.forEach(element => { + element.addEventListener("click", function(event) { + event.preventDefault(); + document.getElementById('lightbox').innerHTML = '
'; + document.getElementById('lightbox').style.display = 'block'; + + setGallery(this); + }); + }); + + //add the image lightbox on click + var elements = document.querySelectorAll('a.lightbox-image'); + elements.forEach(element => { + element.addEventListener("click", function(event) { + event.preventDefault(); + document.getElementById('lightbox').innerHTML = '
'+this.getAttribute('title')+'
'+this.getAttribute('title')+''; + document.getElementById('lightbox').style.display = 'block'; + + setGallery(this); + }); + }); + +}); \ No newline at end of file