Make web ui prettier

pull/12/head
Philipp Heckel 2021-11-04 22:32:17 -04:00
parent 644ffa1420
commit c9124cb5eb
5 changed files with 81 additions and 23 deletions

View File

@ -21,7 +21,7 @@ const (
var ( var (
defaultGlobalTopicLimit = 5000 defaultGlobalTopicLimit = 5000
defaultVisitorRequestLimit = rate.Every(10 * time.Second) defaultVisitorRequestLimit = rate.Every(10 * time.Second)
defaultVisitorRequestLimitBurst = 50 defaultVisitorRequestLimitBurst = 60
defaultVisitorSubscriptionLimit = 30 defaultVisitorSubscriptionLimit = 30
) )

View File

@ -65,25 +65,25 @@
</p> </p>
<div id="subscribeBox"> <div id="subscribeBox">
<form id="subscribeForm"> <h3>Subscribe in this Web UI</h3>
<h3>Subscribe via web</h3>
<p id="error"></p> <p id="error"></p>
<p> <p>
Messages published to topics subscribed here will show up as <b>desktop notification</b>. Subscribe to topics here and receive messages as <b>desktop notification</b>. Topics are not password-protected,
Topics are not password-protected, so choose a name that's not easy to guess. Once subscribed, you can so choose a name that's not easy to guess. Once subscribed, you can publish messages via PUT/POST.
publish messages via PUT/POST.
</p> </p>
<form id="subscribeForm">
<p> <p>
<b>Topic:</b><br/>
<input type="text" id="topicField" autocomplete="off" placeholder="Topic name, e.g. phil_alerts" pattern="[-_A-Za-z]{1,64}" /> <input type="text" id="topicField" autocomplete="off" placeholder="Topic name, e.g. phil_alerts" pattern="[-_A-Za-z]{1,64}" />
<button id="subscribeButton">Subscribe</button> <button id="subscribeButton">Subscribe</button>
</p> </p>
</form>
<p id="topicsHeader"><b>Subscribed topics:</b></p> <p id="topicsHeader"><b>Subscribed topics:</b></p>
<ul id="topicsList"></ul> <ul id="topicsList"></ul>
</form>
<audio id="notifySound" src="static/sound/mixkit-message-pop-alert-2354.mp3"></audio> <audio id="notifySound" src="static/sound/mixkit-message-pop-alert-2354.mp3"></audio>
</div> </div>
<h3>Subscribe via phone</h3> <h3>Subscribe via Android App</h3>
<p> <p>
You can use the <a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy">Ntfy Android App</a> You can use the <a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy">Ntfy Android App</a>
to receive notifications directly on your phone. Just like the server, this app is also <a href="https://github.com/binwiederhier/ntfy-android">open source</a>. to receive notifications directly on your phone. Just like the server, this app is also <a href="https://github.com/binwiederhier/ntfy-android">open source</a>.
@ -190,7 +190,6 @@
is the Firebase Cloud Messaging (FCM) service, which is required to provide instant Android notifications (see is the Firebase Cloud Messaging (FCM) service, which is required to provide instant Android notifications (see
FAQ for details). FAQ for details).
</p> </p>
<p> <p>
The web server does not log or otherwise store request paths, remote IP addresses or even topics or messages, The web server does not log or otherwise store request paths, remote IP addresses or even topics or messages,
aside from a short on-disk cache (up to a day) to support service restarts. aside from a short on-disk cache (up to a day) to support service restarts.

View File

@ -58,9 +58,9 @@ code {
border-radius: 3px; border-radius: 3px;
margin-top: 10px; margin-top: 10px;
margin-bottom: 20px; margin-bottom: 20px;
overflow-x: scroll;
} }
/* Lato font (OFL), https://fonts.google.com/specimen/Lato#about, /* Lato font (OFL), https://fonts.google.com/specimen/Lato#about,
embedded with the help of https://google-webfonts-helper.herokuapp.com/fonts/lato?subsets=latin */ embedded with the help of https://google-webfonts-helper.herokuapp.com/fonts/lato?subsets=latin */
@ -118,6 +118,69 @@ li {
font-size: 0.9em; font-size: 0.9em;
} }
/* Subscribe box SMALL SCREEN */
@media only screen and (max-width: 1599px) {
#subscribeBox #subscribeForm {
border-left: 4px solid #3a9784;
padding: 10px;
}
#subscribeBox h3 {
margin-top: 0;
margin-bottom: 0;
font-size: 1.1em;
}
#subscribeBox #topicsHeader {
margin-bottom: 0;
}
#subscribeBox input {
height: 24px;
min-width: 200px;
max-width: 300px;
border-radius: 3px;
border: none;
border-bottom: 1px solid #aaa;
font-size: 0.8em;
}
#subscribeBox input:focus {
border-bottom: 2px solid #3a9784;
outline: none;
}
#subscribeBox ul {
margin: 0;
padding: 0;
}
#subscribeBox li {
margin: 3px 0;
padding: 0;
}
#subscribeBox li img {
width: 15px;
height: 15px;
vertical-align: bottom;
}
#subscribeBox button {
font-size: 0.8em;
background: #3a9784;
border-radius: 3px;
padding: 5px;
color: white;
cursor: pointer;
}
#subscribeBox button:hover {
background: #317f6f;
}
}
/* Subscribe box BIG SCREEN */
@media only screen and (min-width: 1600px) { @media only screen and (min-width: 1600px) {
#subscribeBox { #subscribeBox {
position: fixed; position: fixed;
@ -175,11 +238,9 @@ li {
font-size: 0.7em; font-size: 0.7em;
background: #3a9784; background: #3a9784;
border-radius: 3px; border-radius: 3px;
padding: 3px 5px; padding: 5px;
color: white; color: white;
cursor: pointer; cursor: pointer;
border-top: solid transparent 2px;
border-bottom: solid transparent 2px;
} }
#subscribeBox button:hover { #subscribeBox button:hover {

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#FFFFFF"><path d="M0 0h24v24H0z" fill="none"/><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>

Before

Width:  |  Height:  |  Size: 235 B

View File

@ -16,7 +16,6 @@ const topicsList = document.getElementById("topicsList");
const topicField = document.getElementById("topicField"); const topicField = document.getElementById("topicField");
const notifySound = document.getElementById("notifySound"); const notifySound = document.getElementById("notifySound");
const subscribeButton = document.getElementById("subscribeButton"); const subscribeButton = document.getElementById("subscribeButton");
const subscribeForm = document.getElementById("subscribeForm");
const errorField = document.getElementById("error"); const errorField = document.getElementById("error");
const subscribe = (topic) => { const subscribe = (topic) => {
@ -40,7 +39,7 @@ const subscribeInternal = (topic, delaySec) => {
if (!topicEntry) { if (!topicEntry) {
topicEntry = document.createElement('li'); topicEntry = document.createElement('li');
topicEntry.id = `topic-${topic}`; topicEntry.id = `topic-${topic}`;
topicEntry.innerHTML = `${topic} <button onclick="test('${topic}')"> <img src="static/img/send_black_24dp.svg"> Test</button> <button onclick="unsubscribe('${topic}')"> <img src="static/img/clear_black_24dp.svg"> Unsubscribe</button>`; topicEntry.innerHTML = `${topic} <button onclick="test('${topic}'); return false;"> <img src="static/img/send_black_24dp.svg"> Test</button> <button onclick="unsubscribe('${topic}'); return false;"> <img src="static/img/clear_black_24dp.svg"> Unsubscribe</button>`;
topicsList.appendChild(topicEntry); topicsList.appendChild(topicEntry);
} }
topicsHeader.style.display = ''; topicsHeader.style.display = '';
@ -48,13 +47,13 @@ const subscribeInternal = (topic, delaySec) => {
// Open event source // Open event source
let eventSource = new EventSource(`${topic}/sse`); let eventSource = new EventSource(`${topic}/sse`);
eventSource.onopen = () => { eventSource.onopen = () => {
topicEntry.innerHTML = `${topic} <button onclick="test('${topic}')"> <img src="static/img/send_black_24dp.svg"> Test</button> <button onclick="unsubscribe('${topic}')"> <img src="static/img/clear_black_24dp.svg"> Unsubscribe</button>`; topicEntry.innerHTML = `${topic} <button onclick="test('${topic}'); return false;"> <img src="static/img/send_black_24dp.svg"> Test</button> <button onclick="unsubscribe('${topic}'); return false;"> <img src="static/img/clear_black_24dp.svg"> Unsubscribe</button>`;
delaySec = 0; // Reset on successful connection delaySec = 0; // Reset on successful connection
}; };
eventSource.onerror = (e) => { eventSource.onerror = (e) => {
topicEntry.innerHTML = `${topic} <i>(Reconnecting)</i> <button disabled="disabled">Test</button> <button onclick="unsubscribe('${topic}'); return false;">Unsubscribe</button>`;
eventSource.close();
const newDelaySec = (delaySec + 5 <= 15) ? delaySec + 5 : 15; const newDelaySec = (delaySec + 5 <= 15) ? delaySec + 5 : 15;
topicEntry.innerHTML = `${topic} <i>(Reconnecting in ${newDelaySec}s ...)</i> <button disabled="disabled">Test</button> <button onclick="unsubscribe('${topic}')">Unsubscribe</button>`;
eventSource.close()
subscribeInternal(topic, newDelaySec); subscribeInternal(topic, newDelaySec);
}; };
eventSource.onmessage = (e) => { eventSource.onmessage = (e) => {
@ -83,7 +82,7 @@ const unsubscribe = (topic) => {
const test = (topic) => { const test = (topic) => {
fetch(`/${topic}`, { fetch(`/${topic}`, {
method: 'PUT', method: 'PUT',
body: `This is a test notification sent from the Ntfy Web UI. It was sent at ${new Date().toString()}.` body: `This is a test notification sent by the ntfy.sh Web UI at ${new Date().toString()}.`
}) })
}; };