initial commit
authorAndrew Lorimer <andrew@lorimer.id.au>
Wed, 15 Jun 2022 11:01:32 +0000 (21:01 +1000)
committerAndrew Lorimer <andrew@lorimer.id.au>
Wed, 15 Jun 2022 11:01:32 +0000 (21:01 +1000)
slideshow.css [new file with mode: 0644]
slideshow.html [new file with mode: 0644]
slideshow.js [new file with mode: 0644]
test-img/1.jpg [new file with mode: 0644]
test-img/2.jpg [new file with mode: 0644]
test-img/3.jpg [new file with mode: 0644]
diff --git a/slideshow.css b/slideshow.css
new file mode 100644 (file)
index 0000000..552d5fb
--- /dev/null
@@ -0,0 +1,135 @@
+:root {
+  --sl-cap: 20px;
+  --sl-dots: 10px;
+  --sl-transition: 0.5s;
+}
+
+div.slideshow {
+  max-width: 1000px;
+  position: relative;
+  margin: auto;
+}
+
+
+/* 
+ * Slides
+ */
+
+figure.slide:first-child {
+  /* Position the first slide relatively to set the height (others are 
+   * positioned absolutely to allow overlapping) */
+  position: relative;
+}
+
+figure.slide {
+  /* Position slides absolutely to allow overlapping */
+  position: absolute;
+  top: 0;
+  left: 0;
+  margin: 0;
+  /* Slides start at 0 opacity */
+  opacity: 0;
+  /* Fade out duration is double the fade in duration (approximates a cross 
+   * dissolve) */
+  transition: opacity calc(2 * var(--sl-transition)) ease;
+  -webkit-transition: opacity calc(2 * var(--sl-transition)) ease;
+  -moz-transition: opacity calc(2 * var(--sl-transition))  ease;
+  z-index: -1;
+}
+
+figure.slide.active {
+  opacity: 1;
+  z-index: 0;
+  /*display: block;*/
+  transition: opacity 1s ease;
+  -webkit-transition: opacity 1s ease;
+  -moz-transition: opacity 1s ease;
+}
+
+figure.slide *,
+div.slideshow div#controls {
+  width: 100%;
+}
+
+figure.slide figcaption {
+  height: var(--sl-cap);
+  text-align: center;
+}
+
+
+/* 
+ * Buttons
+ */
+
+#prev, #next, #state {
+  cursor: pointer;
+  font-weight: bold;
+  font-size: 1.5em;
+  user-select: none;
+  opacity: 0;
+  transition: 0.2s ease;
+  position: absolute;
+  color: white;
+}
+
+#prev, #next {
+  top: calc(50% - calc(var(--sl-cap) + var(--sl-dots) + 50px) / 2);
+  width: auto;
+  padding: 16px;
+  border-radius: 0 3px 3px 0;
+}
+
+#state {
+  width: 1.5em;
+  height: 1.5em;
+  text-align: center;
+  font-family: monospace;
+  top: 15px;
+  right: 15px;
+  padding: 4px;
+  border-radius: 3px;
+}
+
+#next {
+  /* Position next button on right */
+  right: 0;
+  border-radius: 3px 0 0 3px;
+}
+
+div.slideshow:hover #prev,
+div.slideshow:hover #next,
+div.slideshow:hover #state {
+  /* Show buttons on slideshow hover */
+  opacity: 100;
+  background-color: rgba(0,0,0,0.3);
+}
+
+#prev:hover, #next:hover, #state:hover {
+  /* Button hover */
+  background-color: rgba(0,0,0,0.8) !important;
+}
+
+
+/* 
+ * Dot controls/indicators
+ */
+
+div.slideshow div#controls {
+  text-align: center;
+}
+
+div.slideshow div#controls span {
+  cursor: pointer;
+  height: var(--sl-dots);
+  width: var(--sl-dots);
+  margin: 0 2px;
+  background-color: #bbb;
+  border-radius: 50%;
+  display: inline-block;
+  transition: background-color 0.6s ease;
+}
+
+div#controls span.active,
+div#controls span:hover {
+  background-color: #717171 !important;
+}
diff --git a/slideshow.html b/slideshow.html
new file mode 100644 (file)
index 0000000..a581b1f
--- /dev/null
@@ -0,0 +1,41 @@
+<html>
+
+  <head>
+    <link href="slideshow.css" rel="stylesheet" type="text/css" media="all" />
+  </head>
+
+  <body>
+
+    <div class="slideshow" onmouseenter="mouseEnter()" onmouseleave="mouseLeave()">
+
+      <figure class="slide">
+        <img src="test-img/1.jpg">
+        <figcaption><span>This is a long caption yeah yeah yeah</figcaption>
+      </figure>
+
+      <figure class="slide">
+        <img src="test-img/2.jpg">
+        <figcaption><span>Shorter caption</figcaption>
+      </figure>
+
+      <figure class="slide">
+        <img src="test-img/3.jpg">
+        <figcaption><span>Caption 3</figcaption>
+      </figure>
+
+      <a id="prev" onclick="prevSlide()">&#10094;</a>
+      <a id="next" onclick="nextSlide()">&#10095;</a>
+      <a id="state" onclick="changeState()">&#x23f8;&#xFE0E;</a>
+
+      <div id="controls">
+        <span class="dot" onclick="setSlide(0)"></span>
+        <span class="dot" onclick="setSlide(1)"></span>
+        <span class="dot" onclick="setSlide(2)"></span>
+      </div>
+
+    </div>
+
+    <script src="slideshow.js" type="text/javascript"></script>
+
+  </body>
+</html>
diff --git a/slideshow.js b/slideshow.js
new file mode 100644 (file)
index 0000000..f73a888
--- /dev/null
@@ -0,0 +1,96 @@
+const INTERVAL = 2000;
+const STATE_PAUSE = "&#x23f8;&#xFE0E;";
+const STATE_PLAY = "&#x23f5;&#xFE0E;";
+
+// Start at -1 - the recursive function playSlideshow() increases this to 0
+// on page load
+let currentSlide = -1;
+
+// Elements
+let slides = document.getElementsByClassName("slide");
+let dots = document.getElementsByClassName("dot");
+let stateBtn = document.getElementById("state");
+
+// Global state
+let maxIndex = slides.length - 1;
+var timeout;
+var paused = false;
+
+// Start the slideshow
+playSlideshow();
+
+// Recursive function that advances the slide and then calls itself with a 
+// delay
+function playSlideshow() {
+  nextSlide();
+  timeout = setTimeout(playSlideshow, INTERVAL);
+}
+
+// Change the slide to a given index
+function setSlide(slide) {
+
+  if (slide < 0 || slide > maxIndex) {
+    console.log("Attempted to change to slide outside range");
+    return;
+  }
+
+  // Remove active class from figure and dot
+  for (i = 0; i <= maxIndex; i++) {
+    slides[i].className = slides[i].className.replace(" active", "");
+    dots[i].className = dots[i].className.replace(" active", "");
+  }
+
+  // Add active class to figure and dot
+  slides[slide].className += " active";
+  dots[slide].className += " active";
+
+  currentSlide = slide;
+}
+
+function nextSlide() {
+  // Go to the next slide
+  if (currentSlide == maxIndex) {
+    setSlide(0);
+  }
+  else {
+    setSlide(currentSlide + 1);
+  }
+}
+
+function prevSlide() {
+  // Go to the previous slide
+  if (currentSlide == 0) {
+    setSlide(maxIndex);
+  }
+  else {
+    setSlide(currentSlide - 1);
+  }
+}
+
+function mouseEnter() {
+  // Pause the slideshow
+  clearTimeout(timeout);
+  timeout = null;
+}
+
+function mouseLeave() {
+  // Start the slideshow if not manually paused
+  if (!paused && timeout == null) {
+    timeout = setTimeout(playSlideshow, INTERVAL);
+  }
+}
+
+function changeState() {
+  if (paused) {
+    // Play immediately despite mouseover
+    stateBtn.innerHTML = STATE_PAUSE;
+    timeout = setTimeout(playSlideshow, INTERVAL);
+  }
+  else {
+    // Pause until user presses play again
+    clearTimeout(timeout); // make sure timer is stopped
+    timeout = null;
+    stateBtn.innerHTML = STATE_PLAY;
+  }
+  paused = !paused;
+}
diff --git a/test-img/1.jpg b/test-img/1.jpg
new file mode 100644 (file)
index 0000000..bab2280
Binary files /dev/null and b/test-img/1.jpg differ
diff --git a/test-img/2.jpg b/test-img/2.jpg
new file mode 100644 (file)
index 0000000..b3f3d4c
Binary files /dev/null and b/test-img/2.jpg differ
diff --git a/test-img/3.jpg b/test-img/3.jpg
new file mode 100644 (file)
index 0000000..f93f45c
Binary files /dev/null and b/test-img/3.jpg differ