forked from mirrors/ntfy
Make web ui prettier
This commit is contained in:
parent
644ffa1420
commit
c9124cb5eb
5 changed files with 81 additions and 23 deletions
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -65,25 +65,25 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div id="subscribeBox">
|
<div id="subscribeBox">
|
||||||
|
<h3>Subscribe in this Web UI</h3>
|
||||||
|
<p id="error"></p>
|
||||||
|
<p>
|
||||||
|
Subscribe to topics here and receive messages as <b>desktop notification</b>. Topics are not password-protected,
|
||||||
|
so choose a name that's not easy to guess. Once subscribed, you can publish messages via PUT/POST.
|
||||||
|
</p>
|
||||||
<form id="subscribeForm">
|
<form id="subscribeForm">
|
||||||
<h3>Subscribe via web</h3>
|
|
||||||
<p id="error"></p>
|
|
||||||
<p>
|
|
||||||
Messages published to topics subscribed here will show up as <b>desktop notification</b>.
|
|
||||||
Topics are not password-protected, so choose a name that's not easy to guess. Once subscribed, you can
|
|
||||||
publish messages via PUT/POST.
|
|
||||||
</p>
|
|
||||||
<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>
|
||||||
|
<p id="topicsHeader"><b>Subscribed topics:</b></p>
|
||||||
|
<ul id="topicsList"></ul>
|
||||||
</form>
|
</form>
|
||||||
<p id="topicsHeader"><b>Subscribed topics:</b></p>
|
|
||||||
<ul id="topicsList"></ul>
|
|
||||||
<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.
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 |
|
@ -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()}.`
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue