Philipp Heckel 4 лет назад
Родитель
Сommit
cc752cf797

+ 1 - 0
README.md

@@ -183,3 +183,4 @@ Third party libraries and resources:
 * [GoReleaser](https://goreleaser.com/) (MIT) is used to create releases
 * [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) (MIT) is used to provide the persistent message cache
 * [Firebase Admin SDK](https://github.com/firebase/firebase-admin-go) (Apache 2.0) is used to send FCM messages
+* [Lightbox with vanilla JS](https://yossiabramov.com/blog/vanilla-js-lightbox) 

+ 14 - 2
server/index.gohtml

@@ -41,10 +41,21 @@
         It allows you to send notifications <a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy">to your phone</a> or desktop via scripts from any computer,
         entirely <b>without signup or cost</b>. It's also <a href="https://github.com/binwiederhier/ntfy">open source</a> if you want to run your own.
     </p>
+
+    <div id="screenshots">
+        <a href="static/img/screenshot-curl.png"><img src="static/img/screenshot-curl.png"/></a>
+        <a href="static/img/screenshot-web-detail.png"><img src="static/img/screenshot-web-detail.png"/></a>
+        <span class="nowrap">
+            <a href="static/img/screenshot-phone-main.jpg"><img src="static/img/screenshot-phone-main.jpg"/></a>
+            <a href="static/img/screenshot-phone-detail.jpg"><img src="static/img/screenshot-phone-detail.jpg"/></a>
+            <a href="static/img/screenshot-phone-notification.jpg"><img src="static/img/screenshot-phone-notification.jpg"/></a>
+        </span>
+    </div>
+
     <p>
-        There are many ways to use ntfy. You can send yourself messages for all sorts of things: When a long process finishes or fails (a backup, a long rsync job, ...),
+        There are many ways to use Ntfy. You can send yourself messages for all sorts of things: When a long process finishes or fails (a backup, a long rsync job, ...),
         or to notify yourself when somebody logs into your server(s). Or you may want to use it in your own app to distribute messages to subscribed clients.
-        Endless possibilities 😀.
+        Endless possibilities 😀. Be sure to check out the  <a href="https://github.com/binwiederhier/ntfy/tree/main/examples">example on GitHub</a>!
     </p>
 
     <h2>Publishing messages</h2>
@@ -239,6 +250,7 @@
         <div id="detailEventsList"></div>
     </div>
 </div>
+<div id="lightbox" class="lightbox"></div>
 <script src="static/js/app.js"></script>
 </body>
 </html>

+ 77 - 0
server/static/css/app.css

@@ -95,6 +95,83 @@ code {
     color: #666;
 }
 
+/* Screenshots */
+
+#screenshots {
+    text-align: center;
+}
+
+#screenshots img {
+    height: 190px;
+    margin: 3px;
+    border-radius: 5px;
+    filter: drop-shadow(2px 2px 2px #ddd);
+}
+
+#screenshots .nowrap {
+    white-space: nowrap;
+}
+
+/* Lightbox; thanks to https://yossiabramov.com/blog/vanilla-js-lightbox */
+
+.lightbox {
+    opacity: 0;
+    visibility: hidden;
+    position: fixed;
+    left:0;
+    right: 0;
+    top: 0;
+    bottom: 0;
+    z-index: -1;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    transition: all 0.15s ease-in;
+}
+
+.lightbox.show {
+    background-color: rgba(0,0,0, 0.75);
+    opacity: 1;
+    visibility: visible;
+    z-index: 1000;
+}
+
+.lightbox img {
+    max-width: 90%;
+    max-height: 90%;
+    filter: drop-shadow(5px 5px 10px #222);
+    border-radius: 5px;
+}
+
+.lightbox .close-lightbox {
+    cursor: pointer;
+    position: absolute;
+    top: 30px;
+    right: 30px;
+    width: 20px;
+    height: 20px;
+}
+
+.lightbox .close-lightbox::after,
+.lightbox .close-lightbox::before {
+    content: '';
+    width: 3px;
+    height: 20px;
+    background-color: #ddd;
+    position: absolute;
+    border-radius: 5px;
+    transform: rotate(45deg);
+}
+
+.lightbox .close-lightbox::before {
+    transform: rotate(-45deg);
+}
+
+.lightbox .close-lightbox:hover::after,
+.lightbox .close-lightbox:hover::before {
+    background-color: #fff;
+}
+
 /* Subscribe box */
 
 button {

BIN
server/static/img/screenshot-curl.png


BIN
server/static/img/screenshot-phone-add.jpg


BIN
server/static/img/screenshot-phone-detail.jpg


BIN
server/static/img/screenshot-phone-main.jpg


BIN
server/static/img/screenshot-phone-notification.jpg


BIN
server/static/img/screenshot-web-detail.png


+ 59 - 0
server/static/js/app.js

@@ -32,6 +32,9 @@ const detailNoNotifications = document.getElementById("detailNoNotifications");
 const detailCloseButton = document.getElementById("detailCloseButton");
 const detailNotificationsDisallowed = document.getElementById("detailNotificationsDisallowed");
 
+/* Screenshots */
+const lightbox = document.getElementById("lightbox");
+
 const subscribe = (topic) => {
     if (Notification.permission !== "granted") {
         Notification.requestPermission().then((permission) => {
@@ -203,6 +206,54 @@ const showNotificationDeniedError = () => {
     showError("You have blocked desktop notifications for this website. Please unblock them and refresh to use the web-based desktop notifications.");
 };
 
+const showScreenshotOverlay = (e, el, index) => {
+    lightbox.classList.add('show');
+    document.addEventListener('keydown', nextScreenshotKeyboardListener);
+    return showScreenshot(e, index);
+};
+
+const showScreenshot = (e, index) => {
+    const actualIndex = resolveScreenshotIndex(index);
+    lightbox.innerHTML = '<div class="close-lightbox"></div>' + screenshots[actualIndex].innerHTML;
+    lightbox.querySelector('img').onclick = (e) => { return showScreenshot(e,actualIndex+1); };
+    currentScreenshotIndex = actualIndex;
+    e.stopPropagation();
+    return false;
+};
+
+const nextScreenshot = (e) => {
+    return showScreenshot(e, currentScreenshotIndex+1);
+};
+
+const previousScreenshot = (e) => {
+    return showScreenshot(e, currentScreenshotIndex-1);
+};
+
+const resolveScreenshotIndex = (index) => {
+    if (index < 0) {
+        return screenshots.length - 1;
+    } else if (index > screenshots.length - 1) {
+        return 0;
+    }
+    return index;
+};
+
+const hideScreenshotOverlay = (e) => {
+    lightbox.classList.remove('show');
+    document.removeEventListener('keydown', nextScreenshotKeyboardListener);
+};
+
+const nextScreenshotKeyboardListener = (e) => {
+    switch (e.keyCode) {
+        case 37:
+            previousScreenshot(e);
+            break;
+        case 39:
+            nextScreenshot(e);
+            break;
+    }
+};
+
 // From: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
 async function* makeTextFileLineIterator(fileURL) {
     const utf8Decoder = new TextDecoder('utf-8');
@@ -248,6 +299,14 @@ detailCloseButton.onclick = () => {
     hideDetailView();
 };
 
+let currentScreenshotIndex = 0;
+const screenshots = [...document.querySelectorAll("#screenshots a")];
+screenshots.forEach((el, index) => {
+    el.onclick = (e) => { return showScreenshotOverlay(e, el, index); };
+});
+
+lightbox.onclick = hideScreenshotOverlay;
+
 // Disable Web UI if notifications of EventSource are not available
 if (!window["Notification"] || !window["EventSource"]) {
     showBrowserIncompatibleError();