Compare commits

..

5 commits

Author SHA1 Message Date
8aa281e1f4 Improve responsiveness 2023-08-04 16:45:20 +02:00
c020aacdce Add simple button to try again for now 2023-08-04 15:46:53 +02:00
48641bdef1 Add documentation 2023-08-04 15:44:52 +02:00
69e78963d7 Add package.json 2023-08-04 15:43:19 +02:00
5368b1815f Move some things around 2023-08-04 15:12:24 +02:00
6 changed files with 2475 additions and 16 deletions

View file

@ -3,3 +3,31 @@
[![Netlify Status](https://api.netlify.com/api/v1/badges/7821f152-5b28-4dec-9d98-035a18e8a57a/deploy-status)](https://app.netlify.com/sites/tdpeuter-down/deploys) [![Netlify Status](https://api.netlify.com/api/v1/badges/7821f152-5b28-4dec-9d98-035a18e8a57a/deploy-status)](https://app.netlify.com/sites/tdpeuter-down/deploys)
Ultra simple website to tell people a service is down Ultra simple website to tell people a service is down
## Starting the website
```shell
npm run start
```
## Setup networking
### Using [Cloudflare](https://dash.cloudflare.com)
If you want to use Cloudflare to handle redirection to the website, you can use [Page Rules](https://developers.cloudflare.com/support/page-rules/).
First, make sure the DNS records for the (sub-) domains you want to redirect are [being proxied through Cloudflare](https://developers.cloudflare.com/dns/manage-dns-records/reference/proxied-dns-records). Then, head over to [Redirect Rules](https://developers.cloudflare.com/rules/url-forwarding/) (Page Rules are harder to configure, and it seems like [Cloudflare itself is more keen of Redirect Rules too](https://developers.cloudflare.com/support/page-rules/recommended-page-rules-to-consider/)).
Create a Single Redirect rule that looks similar to:
```
# When incoming requests match...
(http.host in {"example.com" "another.example.com"})
# Then URL redirect
Dynamic
concat("https://your.host.tdl/?destination=", http.request.full_uri)
302
```
Enable the rule and everything should be set!

View file

@ -1,22 +1,33 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title>Service unavailable</title> <meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="robots" content="noindex">
<title>Service unavailable</title>
<link rel="stylesheet" type="text/css" href="style.css"> <link rel="stylesheet" type="text/css" href="style.css">
<link rel="shortcut icon" type="image/png" href="assets/icon.jpg"> <link rel="shortcut icon" type="image/png" href="assets/icon.jpg">
<meta name="color-scheme" content="light dark">
<meta name="robots" content="noindex">
</head> </head>
<body> <body>
<main>
<h1>Oh, no!</h1> <h1>Oh, no!</h1>
<p>The website you are trying to reach is currently down. Your URL works, but the system is in maintenance and powered off temporarily.</p> <p>The website you are trying to reach is currently down. Your URL works, but the system is in maintenance and/or powered off temporarily.</p>
<p>Please come back later!</p> <p>Please come back later!</p>
<p>Kind regards, <a href="https://tibo.depeuter.dev">Tibo De Peuter</a></p> <p>Kind regards, <a href="https://tibo.depeuter.dev">Tibo De Peuter</a></p>
<div id="checkContainer"></div> <div id="checkContainer"></div>
<img src="/assets/oh-no-kitten.jpg" alt="kitten holding paw to forehead"/> <img src="/assets/oh-no-kitten.jpg" alt="kitten holding paw to forehead"/>
</main>
<script src="script.js"></script> <footer>
<p>
Made with <span class="heart">&hearts;</span>.
<a href="https://git.depeuter.dev/tdpeuter/down-website" about="source code of this webpage" class="hidden">Source code</a>
</p>
</footer>
<script src="script.js"></script>
</body> </body>
</html> </html>

2332
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

19
package.json Normal file
View file

@ -0,0 +1,19 @@
{
"name": "down-message",
"version": "1.1.0",
"description": "Ultra simple website to tell people a service is down",
"main": "index.html",
"scripts": {
"start": "live-server --port=3000 .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://git.depeuter.dev/tdpeuter/down-message.git"
},
"author": "Tibo De Peuter <tibo@depeuter.dev>",
"license": "GPL-3.0-only",
"devDependencies": {
"live-server": "^1.2.2"
}
}

View file

@ -1,15 +1,18 @@
async function websiteUp(url) { async function websiteUp(url) {
// TODO Fix CORS // TODO Fix CORS
try { try {
const response = await fetch(url, { method: 'head' }); const response = await fetch(url, { method: 'options' });
console.log(response); return response.ok;
return false;
} catch (error) { } catch (error) {
console.error(`An error occurred while checking the URL '${url}': ${error.message}`); console.error(`An error occurred while checking the URL '${url}': ${error.message}`);
} }
} }
async function check(destination, container, dot, message, button) { async function check(destination, container, dot, message, button) {
dot.className = 'dot orange';
message.textContent = 'Checking availability...';
button.style.visibility = 'hidden';
const destinationUp = await websiteUp(destination); const destinationUp = await websiteUp(destination);
if (destinationUp) { if (destinationUp) {
@ -34,14 +37,8 @@ async function check(destination, container, dot, message, button) {
function createCheckButton(destination) { function createCheckButton(destination) {
const dot = document.createElement('span'); const dot = document.createElement('span');
dot.className = 'dot orange';
dot.id = 'checkDot';
const message = document.createElement('span'); const message = document.createElement('span');
message.textContent = 'Checking availability...';
const button = document.createElement('button'); const button = document.createElement('button');
button.style.visibility = 'hidden';
const container = document.getElementById('checkContainer'); const container = document.getElementById('checkContainer');
container.appendChild(dot); container.appendChild(dot);
@ -51,13 +48,23 @@ function createCheckButton(destination) {
check(destination, container, dot, message, button); check(destination, container, dot, message, button);
} }
function createTryAgainButton(destination) {
const button = document.createElement('button');
button.textContent = 'Try Again';
button.onclick = function () {
window.location.href = destination;
}
document.getElementById('checkContainer').appendChild(button);
}
function checkDestination() { function checkDestination() {
const url = window.location.search; const url = window.location.search;
const searchParams = new URLSearchParams(url); const searchParams = new URLSearchParams(url);
const destination = searchParams.get('destination'); const destination = searchParams.get('destination');
if (destination) { if (destination) {
createCheckButton(destination); createTryAgainButton(destination);
} }
} }

View file

@ -1,3 +1,22 @@
:root {
/* Support dark mode */
color-scheme: light dark;
}
body {
margin: 20px;
padding: 10px;
}
footer {
opacity: 0.6;
font-size: small;
display: flex;
width: 100%;
justify-content: center;
}
.dot { .dot {
width: 15px; width: 15px;
height: 15px; height: 15px;
@ -17,3 +36,46 @@
.dot.red { .dot.red {
background-color: red; background-color: red;
} }
.heart {
color: #CD001A; /* Cherry red */
}
/* Don't let media go offscreen */
img,
picture,
video {
max-width: 100%;
padding: 2% 0;
}
/* Display the button in the center of small screens such as phones */
@media screen and (max-device-width: 1000px) {
#checkContainer {
display: flex;
justify-content: center;
}
}
/* Hover animation for URLs */
a {
text-decoration: none;
color: inherit; /* Reset to default text color */
position: relative;
}
a::before {
content: '';
position: absolute;
/* Height of the line */
bottom: -2px;
height: 2px;
left: 0;
width: 0;
background-color: orange;
transition: width 0.3s ease;
}
a:hover::before {
width: 100%;
}