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"> | ||||||
|         <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. | ||||||
|  |  | ||||||
|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue