diff --git a/README.md b/README.md index 7a61b11f..4b1545f5 100644 --- a/README.md +++ b/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) diff --git a/server/index.gohtml b/server/index.gohtml index 422f250d..71cd374b 100644 --- a/server/index.gohtml +++ b/server/index.gohtml @@ -41,10 +41,21 @@ It allows you to send notifications to your phone or desktop via scripts from any computer, entirely without signup or cost. It's also open source if you want to run your own.

+ +
+ + + + + + + +
+

- 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 example on GitHub!

Publishing messages

@@ -239,6 +250,7 @@
+ diff --git a/server/static/css/app.css b/server/static/css/app.css index 79a35264..75800e02 100644 --- a/server/static/css/app.css +++ b/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 { diff --git a/server/static/img/screenshot-curl.png b/server/static/img/screenshot-curl.png new file mode 100644 index 00000000..aeb5a31a Binary files /dev/null and b/server/static/img/screenshot-curl.png differ diff --git a/server/static/img/screenshot-phone-add.jpg b/server/static/img/screenshot-phone-add.jpg new file mode 100644 index 00000000..f728ec99 Binary files /dev/null and b/server/static/img/screenshot-phone-add.jpg differ diff --git a/server/static/img/screenshot-phone-detail.jpg b/server/static/img/screenshot-phone-detail.jpg new file mode 100644 index 00000000..2cd3b2fe Binary files /dev/null and b/server/static/img/screenshot-phone-detail.jpg differ diff --git a/server/static/img/screenshot-phone-main.jpg b/server/static/img/screenshot-phone-main.jpg new file mode 100644 index 00000000..5caeee14 Binary files /dev/null and b/server/static/img/screenshot-phone-main.jpg differ diff --git a/server/static/img/screenshot-phone-notification.jpg b/server/static/img/screenshot-phone-notification.jpg new file mode 100644 index 00000000..7924c6fd Binary files /dev/null and b/server/static/img/screenshot-phone-notification.jpg differ diff --git a/server/static/img/screenshot-web-detail.png b/server/static/img/screenshot-web-detail.png new file mode 100644 index 00000000..46c33231 Binary files /dev/null and b/server/static/img/screenshot-web-detail.png differ diff --git a/server/static/js/app.js b/server/static/js/app.js index 928c1493..385f02d9 100644 --- a/server/static/js/app.js +++ b/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 = '
' + 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();