add a crappy image viewer that "90% works" without js

This commit is contained in:
Benjamin Wiegand 2024-09-07 18:17:57 -07:00
parent e470c4b6eb
commit 09134e8c36
4 changed files with 381 additions and 10 deletions

62
www/image-modal.js Normal file
View File

@ -0,0 +1,62 @@
const images = document.getElementsByClassName('project-image');
for (const image of images) {
const modal = image.querySelector('.modal')
const close = image.querySelector('.close')
const lazy_image = image.querySelector('.lazy-image')
const zoom = modal.querySelector('input')
// for pan
let grabbed = false;
let startX = 0;
let startY = 0;
// for zoom
let clickX = 0;
let clickY = 0;
let initW = lazy_image.clientWidth;
let initH = lazy_image.clientHeight;
// pan the image
lazy_image.addEventListener('mouseleave', () => {grabbed = false;});
lazy_image.addEventListener('mouseup', () => {
grabbed = false;
});
lazy_image.addEventListener('mousedown', (e) => {
grabbed = true;
startX = modal.scrollLeft + e.pageX;
startY = modal.scrollTop + e.pageY;
// set stuff for zoom
clickX = e.clientX - lazy_image.offsetLeft;
clickY = e.clientY - lazy_image.offsetTop;
initW = lazy_image.clientWidth;
initH = lazy_image.clientHeight;
});
lazy_image.addEventListener('mousemove', (e) => {
if(!grabbed) return;
modal.scrollLeft = startX - e.pageX;
modal.scrollTop = startY - e.pageY;
});
// unzoom on close
close.addEventListener('click', () => {
zoom.checked = false;
});
// zoom to click target
zoom.addEventListener('change', e => {
if (zoom.checked) {
zoom_factor = Math.max(
lazy_image.clientWidth / initW,
lazy_image.clientHeight / initH
);
console.log(zoom_factor);
x = clickX * zoom_factor - (window.innerWidth / 2);
y = clickY * zoom_factor - (window.innerHeight / 2);
console.log('zoom 2 ' + x + ', ' + y);
modal.scrollLeft = x;
modal.scrollTop = y;
}
})
}

63
www/img/modal-close.svg Normal file
View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="120"
height="120"
viewBox="0 0 120 120"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
sodipodi:docname="modal-close.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="4.8790368"
inkscape:cx="48.165245"
inkscape:cy="57.183418"
inkscape:window-width="1920"
inkscape:window-height="1010"
inkscape:window-x="0"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#000000;stroke-width:34.7;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1"
d="M 24.536613,95.463387 95.463387,24.536613"
id="path1" />
<path
style="fill:none;stroke:#000000;stroke-width:34.7;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1"
d="M 24.536613,24.536613 95.463387,95.463387"
id="path2" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer 2">
<path
style="fill:none;stroke:#ffffff;stroke-width:13;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:5.4;stroke-dasharray:none;stroke-opacity:1"
d="M 24.536606,95.463385 95.463385,24.536606"
id="path1-5" />
<path
style="fill:none;stroke:#ffffff;stroke-width:13;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:5.4;stroke-dasharray:none;stroke-opacity:1"
d="M 24.536606,24.536606 95.463385,95.463385"
id="path2-3" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -55,7 +55,7 @@
<div class="projects-section text-section">
<h2>Projects</h2>
<div class="project sub-section">
<h3>PeerCord <small>(2023)</small></h3>
<p>An end-to-end encrypted client/server messaging application.</p>
@ -66,7 +66,30 @@
</p>
</details>
<div class="double-screenshot">
<a target="_blank" href="/img/peercord-login.png"><img src="/img/peercord-login-thumb.webp" alt="PeerCord login screen"></a><a target="_blank" href="/img/peercord-chat.png"><img src="/img/peercord-chat-thumb.webp" alt="PeerCord chat screen"></a>
<div class="project-image">
<label for="lpcl"><img src="/img/peercord-login-thumb.webp" alt="PeerCord login screen"></label>
<input type="checkbox" id="lpcl">
<div class="modal"><label for="lpcl" class="modal-bg"></label><label for="lpcl" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/peercord-login.png')"></div>
</label>
</div>
</div>
<div class="project-image">
<label for="lpcc">
<img src="/img/peercord-chat-thumb.webp" alt="PeerCord login screen">
</label>
<input type="checkbox" id="lpcc">
<div class="modal">
<label for="lpcc" class="modal-bg"></label>
<label for="lpcc" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/peercord-chat.png')"></div>
</label>
</div>
</div>
</div>
<small>click image to view in full resolution</small>
</div>
@ -87,10 +110,62 @@
</p>
</details>
<div class="double-screenshot">
<a target="_blank" href="/img/ilo-overview.jpg"><img src="/img/ilo-overview-thumb.webp" alt="overview of my ILO dashboard in grafana"></a>
<a target="_blank" href="/img/ilo-temperatures.jpg"><img src="/img/ilo-temperatures-thumb.webp" alt="temperature sensor data shown in my ILO dashboard in grafana"></a>
<a target="_blank" href="/img/ilo-drives.jpg"><img src="/img/ilo-drives-thumb.webp" alt="drive health, status, and temperature shown in my ILO dashboard in grafana"></a>
<a target="_blank" href="/img/ilo-fan-and-cpu-info.jpg"><img src="/img/ilo-fan-and-cpu-info-thumb.webp" alt="fan speed, fan health, fan status, and cpu status shown in my ILO dashboard in grafana"></a>
<div class="project-image">
<label for="lio">
<img src="/img/ilo-overview-thumb.webp" alt="overview of my ILO dashboard in grafana">
</label>
<input type="checkbox" id="lio">
<div class="modal">
<label for="lio" class="modal-bg"></label>
<label for="lio" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/ilo-overview.jpg');"></div>
</label>
</div>
</div>
<div class="project-image">
<label for="lit">
<img src="/img/ilo-temperatures-thumb.webp" alt="temperature sensor data shown in my ILO dashboard in grafana">
</label>
<input type="checkbox" id="lit">
<div class="modal">
<label for="lit" class="modal-bg"></label>
<label for="lit" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/ilo-temperatures.jpg');"></div>
</label>
</div>
</div>
<div class="project-image">
<label for="lid">
<img src="/img/ilo-drives-thumb.webp" alt="drive health, status, and temperature shown in my ILO dashboard in grafana">
</label>
<input type="checkbox" id="lid">
<div class="modal">
<label for="lid" class="modal-bg"></label>
<label for="lid" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/ilo-drives.jpg');"></div>
</label>
</div>
</div>
<div class="project-image">
<label for="lifci">
<img src="/img/ilo-fan-and-cpu-info-thumb.webp" alt="fan speed, fan health, fan status, and cpu status shown in my ILO dashboard in grafana">
</label>
<input type="checkbox" id="lifci">
<div class="modal">
<label for="lifci" class="modal-bg"></label>
<label for="lifci" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/ilo-fan-and-cpu-info.jpg');"></div>
</label>
</div>
</div>
</div>
<small>click image to view in full resolution</small>
</div>
@ -111,7 +186,34 @@
</p>
</details>
<div class="double-screenshot">
<a target="_blank" href="/img/smbus-mitm-arduino.jpg"><img src="/img/smbus-mitm-arduino-thumb.webp" alt="the arduino leonardo that's attached to my battery, complete with small OLED display"></a><a target="_blank" href="/img/smbus-mitm-wiring.jpg"><img src="/img/smbus-mitm-wiring-thumb.webp" alt="wiring to intercept communications between the BMS and the laptop"></a>
<div class="project-image">
<label for="sma">
<img src="/img/smbus-mitm-arduino-thumb.webp" alt="the arduino leonardo that's attached to my battery, complete with small OLED display">
</label>
<input type="checkbox" id="sma">
<div class="modal">
<label for="sma" class="modal-bg"></label>
<label for="sma" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/smbus-mitm-arduino.jpg');"></div>
</label>
</div>
</div>
<div class="project-image">
<label for="smw">
<img src="/img/smbus-mitm-wiring-thumb.webp" alt="wiring to intercept communications between the BMS and the laptop">
</label>
<input type="checkbox" id="smw">
<div class="modal">
<label for="smw" class="modal-bg"></label>
<label for="smw" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/smbus-mitm-wiring.jpg');"></div>
</label>
</div>
</div>
</div>
<small>click image to view in full resolution</small>
</div>
@ -126,7 +228,34 @@
</p>
</details>
<div class="double-screenshot">
<a target="_blank" href="/img/security-camera-stream.jpg"><img src="/img/security-camera-stream-thumb.webp" alt="two phones, one streaming video to another over the network"></a><a target="_blank" href="/img/security-camera-screenshot.png"><img src="/img/security-camera-screenshot-thumb.webp" alt="screenshot of the app while it's recording video"></a>
<div class="project-image">
<label for="scst">
<img src="/img/security-camera-stream-thumb.webp" alt="two phones, one streaming video to another over the network">
</label>
<input type="checkbox" id="scst">
<div class="modal">
<label for="scst" class="modal-bg"></label>
<label for="scst" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/security-camera-stream.jpg');"></div>
</label>
</div>
</div>
<div class="project-image">
<label for="scsc">
<img src="/img/security-camera-screenshot-thumb.webp" alt="screenshot of the app while it's recording video">
</label>
<input type="checkbox" id="scsc">
<div class="modal">
<label for="scsc" class="modal-bg"></label>
<label for="scsc" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/security-camera-screenshot.png');"></div>
</label>
</div>
</div>
</div>
<small>click image to view in full resolution</small>
</div>
@ -142,11 +271,39 @@
</details>
<div class="double-screenshot">
<a target="_blank" href="/img/roomba.jpg"><img src="/img/roomba-thumb.webp" alt="a normal Roomba with a webcam, Raspberry pi, Arduino, and a voltage regulator mounted on it"></a><a target="_blank" href="/img/roomba-control.jpg"><img src="/img/roomba-control-thumb.webp" alt="webpage for controlling the Roomba and viewing the live feed"></a>
<div class="project-image">
<label for="r">
<img src="/img/roomba-thumb.webp" alt="a normal Roomba with a webcam, Raspberry pi, Arduino, and a voltage regulator mounted on it">
</label>
<input type="checkbox" id="r">
<div class="modal">
<label for="r" class="modal-bg"></label>
<label for="r" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/roomba.jpg');"></div>
</label>
</div>
</div>
<div class="project-image">
<label for="rc">
<img src="/img/roomba-control-thumb.webp" alt="webpage for controlling the Roomba and viewing the live feed">
</label>
<input type="checkbox" id="rc">
<div class="modal">
<label for="rc" class="modal-bg"></label>
<label for="rc" class="close"></label>
<label>
<input type="checkbox">
<div class="lazy-image" style="background-image: url('/img/roomba-control.jpg');"></div>
</label>
</div>
</div>
</div>
<small>click image to view in full resolution</small>
</div>
<script src="/image-modal.js"></script>
</div>
</div>

View File

@ -190,9 +190,81 @@ h3 {
.double-screenshot img {
width: 450px;
max-width: 100%;
vertical-align: middle;
}
.text-section * {
.project-image input {
display: none;
}
.project-image img {
cursor: pointer;
}
.modal {
display: none;
}
input:checked + .modal {
animation: fly-forward .5s ease-out 0s 1 normal none;
display: flex;
justify-content: safe center;
align-items: safe center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #00000066;
overflow: auto;
}
.lazy-image {
width: 500px;
height: 500px;
min-width: 90vw;
min-height: 90vh;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
cursor: zoom-in;
}
input:checked + .lazy-image {
cursor: zoom-out;
min-width: 200vw;
min-height: 200vh;
scroll-snap-align: center;
}
body:has(.project-image > input:checked) {
overflow: hidden;
}
.modal .close {
cursor: pointer;
position: fixed;
top: 0;
right: 0;
margin: 20px;
width: 60px;
height: 60px;
background-image: url('/img/modal-close.svg');
background-size: 30px 30px;
background-position: center;
background-repeat: no-repeat;
}
.modal-bg {
position: fixed;
z-index: -1;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.text-section > * {
animation: fly-up .5s ease-out 0s 1 normal none;
}
@ -230,6 +302,23 @@ h3 {
}
@keyframes fly-forward {
0% {
transform: scale(0);
opacity: 0%;
}
20% {
transform: scale(1);
opacity: 70%;
}
100% {
opacity: 100%;
}
}
@keyframes color-change-1 {
0% {
background-color: #29BDBD;