mirror of
https://github.com/tarampampam/error-pages.git
synced 2024-08-30 18:22:40 +00:00
274 lines
14 KiB
HTML
274 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
Error {{ code }}: {{ message }}
|
|
Description: {{ description }}
|
|
-->
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
<meta name="robots" content="noindex, nofollow"/>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
|
<title>{{ code }} | {{ message }}</title>
|
|
<link rel="preconnect" href="https://fonts.bunny.net" crossorigin>
|
|
<link rel="dns-prefetch" href="https://fonts.bunny.net">
|
|
<link href="https://fonts.bunny.net/css2?family=Red+Hat+Display:wght@500&family=Fira+Mono&family=Ubuntu&display=swap" rel="stylesheet"/>
|
|
<style>
|
|
/** Idea author: https://github.com/186526/CloudflareCustomErrorPage */
|
|
:root{--color-bg-primary:#fff;--color-text-primary:#000;--color-text-secondary:#575958;--font-size-primary:56px;--font-size-secondary:20px;--ui-card-color-bg:#f2f2f2;--color-text-ok:#137333;--color-bg-ok:#e6f4ea;--color-text-error:#c5221f;--color-bg-error:#fce8e6;--color-text-warning:#b05a00;--color-bg-warning:#fef7e0;--icon-size:48px}
|
|
@media (prefers-color-scheme:dark){
|
|
:root{--color-bg-primary:#111;--color-text-primary:rgba(255, 255, 255, 0.86);--color-text-secondary:rgba(255, 255, 255, 0.4);--ui-card-color-bg:rgba(40, 40, 40, 0.73);--color-bg-ok:#07220f;--color-bg-error:#270501;--color-bg-warning:#392605}
|
|
}
|
|
body{margin:2rem 2rem;font-family:'Red Hat Display',Ubuntu,Roboto,'Noto Sans SC',sans-serif;color:var(--color-text-primary);background-color:var(--color-bg-primary)}
|
|
header{margin-left:1rem}
|
|
header .error-code{font-size:var(--font-size-primary);line-height:var(--font-size-primary);font-family:'Fira Mono',Ubuntu,monospace;font-weight:400;margin:0 0 0 10px}
|
|
header .error-description{font-family:Ubuntu,Roboto,'Noto Sans SC',sans-serif;font-size:var(--font-size-secondary);color:var(--color-text-secondary);margin:0 0 0 10px}
|
|
code{font-family:'Fira Mono',monospace}
|
|
.status{margin-top:2.5rem;display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;align-items:center}
|
|
.card{background-color:var(--ui-card-color-bg);padding:2rem;margin:1rem 1rem;min-height:3rem;border-radius:9px;flex-grow:1}
|
|
.arrows svg{fill:var(--color-text-secondary)}
|
|
.icon svg{width:var(--icon-size);height:auto;fill:var(--color-text-primary)}
|
|
.card.ok{background-color:var(--color-bg-ok)}.card.ok .status-text{color:var(--color-text-ok)}.card.ok svg{fill:var(--color-text-ok)}
|
|
.card.error{background-color:var(--color-bg-error)}.card.error .status-text{color:var(--color-text-error)}.card.error svg{fill:var(--color-text-error)}
|
|
.card.warning{background-color:var(--color-bg-warning)}.card.warning .status-text{color:var(--color-text-warning)}.card.warning svg{fill:var(--color-text-warning)}
|
|
.card main{font-size:calc(var(--font-size-secondary) + .1rem)}
|
|
.card .status-text,.reason p{margin:0;font-family:Ubuntu,Roboto,Noto Sans SC,sans-serif}
|
|
.reason p{line-height:125%}
|
|
a{text-decoration:none;color:#1967d2}
|
|
.reason{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:baseline}
|
|
.reason>*{display:block;margin:1rem;flex-grow:1;max-width:40%}
|
|
.reason h2{font-size:calc(var(--font-size-secondary) + .2rem);margin:0 0 .6em 0;font-weight:550}
|
|
footer{margin:1rem;color:var(--color-text-secondary);font-size:0}
|
|
/* {{ if show_details }} */
|
|
footer .details{margin-top:20px}
|
|
footer .details ul{padding:0}
|
|
footer .details code,footer .details span{font-size:calc(var(--font-size-secondary) - .6rem)}
|
|
footer .details code{padding-left:7px}
|
|
/* {{ end }} */
|
|
@media screen and (max-width:820px){
|
|
.arrows{display:none}
|
|
}
|
|
@media screen and (max-width:480px){
|
|
.reason>*{max-width:100%}
|
|
/* {{ if show_details }} */
|
|
footer .details code,footer .details span{font-size:calc(var(--font-size-secondary) - .3rem)}
|
|
/* {{ end }} */
|
|
}
|
|
@media screen and (min-width:768px){
|
|
body{margin:8% 10%}
|
|
header>*{display:inline-block;margin-left:1%}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<h1 class="error-code">{{ code }}</h1>
|
|
<p class="error-description">{{ message }}</p>
|
|
</header>
|
|
<div class="status">
|
|
<div class="card warning" id="client-status-card">
|
|
<i class="icon">
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
|
<path d="M0 0h24v24H0V0z" fill="none"/>
|
|
<path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm0 14H5V8h14v10z"/>
|
|
</svg>
|
|
</i>
|
|
<main data-l10n>Your Client</main>
|
|
<p class="status-text" data-l10n>Unknown</p>
|
|
</div>
|
|
|
|
<div class="arrows">
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" width="24px" fill="#000000">
|
|
<defs>
|
|
<symbol id="arrows-horizontal" viewBox="0 0 24 24">
|
|
<rect fill="none" height="24" width="24" x="0"/>
|
|
<polygon points="7.41,13.41 6,12 2,16 6,20 7.41,18.59 5.83,17 21,17 21,15 5.83,15"/>
|
|
<polygon points="16.59,10.59 18,12 22,8 18,4 16.59,5.41 18.17,7 3,7 3,9 18.17,9"/>
|
|
</symbol>
|
|
</defs>
|
|
<use href="#arrows-horizontal"/>
|
|
</svg>
|
|
</div>
|
|
|
|
<div class="card ok" id="network-status-card">
|
|
<i class="icon">
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
|
<path d="M0 0h24v24H0V0z" fill="none"/>
|
|
<path d="M12 6c2.62 0 4.88 1.86 5.39 4.43l.3 1.5 1.53.11c1.56.1 2.78 1.41 2.78 2.96 0 1.65-1.35 3-3 3H6c-2.21 0-4-1.79-4-4 0-2.05 1.53-3.76 3.56-3.97l1.07-.11.5-.95C8.08 7.14 9.94 6 12 6m0-2C9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96C18.67 6.59 15.64 4 12 4z"/>
|
|
</svg>
|
|
</i>
|
|
<main data-l10n>Network</main>
|
|
<p class="status-text" data-l10n>Working</p>
|
|
</div>
|
|
|
|
<div class="arrows">
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" width="24px" fill="#000000">
|
|
<use href="#arrows-horizontal" />
|
|
</svg>
|
|
</div>
|
|
|
|
<div class="card warning" id="server-status-card">
|
|
<i class="icon">
|
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
|
<path d="M0 0h24v24H0V0z" fill="none"/>
|
|
<path d="M19 15v4H5v-4h14m1-2H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zM7 18.5c-.82 0-1.5-.67-1.5-1.5s.68-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM19 5v4H5V5h14m1-2H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zM7 8.5c-.82 0-1.5-.67-1.5-1.5S6.18 5.5 7 5.5s1.5.68 1.5 1.5S7.83 8.5 7 8.5z"/>
|
|
</svg>
|
|
</i>
|
|
<main data-l10n>Web Server</main>
|
|
<p class="status-text" data-l10n>Unknown</p>
|
|
</div>
|
|
</div>
|
|
<div class="reason">
|
|
<div class="what-happened">
|
|
<h2 data-l10n>What happened?</h2>
|
|
<p class="description" data-l10n>{{ description }}</p>
|
|
</div>
|
|
<div class="what-can-i-do">
|
|
<h2 data-l10n>What can I do?</h2>
|
|
<p class="description" data-l10n>Please try again in a few minutes</p>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
<footer>
|
|
{{ if show_details }}
|
|
<div class="details">
|
|
<ul>
|
|
{{- if host }}<li><span><span data-l10n>Host</span>:</span> <code>{{ host }}</code></li>{{ end -}}
|
|
{{- if original_uri }}<li><span><span data-l10n>Original URI</span>:</span> <code>{{ original_uri }}</code></li>{{ end -}}
|
|
{{- if forwarded_for }}<li><span><span data-l10n>Forwarded for</span>:</span> <code>{{ forwarded_for }}</code></li>{{ end -}}
|
|
{{- if namespace }}<li><span><span data-l10n>Namespace</span>:</span> <code>{{ namespace }}</code></li>{{ end -}}
|
|
{{- if ingress_name }}<li><span><span data-l10n>Ingress name</span>:</span> <code>{{ ingress_name }}</code></li>{{ end -}}
|
|
{{- if service_name }}<li><span><span data-l10n>Service name</span>:</span> <code>{{ service_name }}</code></li>{{ end -}}
|
|
{{- if service_port }}<li><span><span data-l10n>Service port</span>:</span> <code>{{ service_port }}</code></li>{{ end -}}
|
|
{{- if request_id }}<li><span><span data-l10n>Request ID</span>:</span> <code>{{ request_id }}</code></li>{{ end -}}
|
|
<li><span><span data-l10n>Timestamp</span>:</span> <code>{{ now.Unix }}</code></li>
|
|
</ul>
|
|
</div>
|
|
{{ end }}
|
|
</footer>
|
|
<script>
|
|
const errorCode = parseInt(`{{ code }}`, 10);
|
|
|
|
if (typeof errorCode !== 'undefined' && !isNaN(errorCode)) {
|
|
/**
|
|
* @param {HTMLElement} $card
|
|
* @param { {isOk?: boolean, isWarning?: boolean, isError?: boolean} } state
|
|
* @param {string} statusText
|
|
*/
|
|
const setCardState = function ($card, state, statusText) {
|
|
const okClass = 'ok', warnClass = 'warning', errClass = 'error',
|
|
$statusText = $card.querySelectorAll('.status-text');
|
|
|
|
switch (true) {
|
|
case state.isOk === true:
|
|
$card.classList.remove(errClass, warnClass);
|
|
$card.classList.add(okClass);
|
|
$statusText.forEach(($statusText) => $statusText.innerText = statusText);
|
|
break;
|
|
|
|
case state.isWarning === true:
|
|
$card.classList.remove(okClass, errClass);
|
|
$card.classList.add(warnClass);
|
|
$statusText.forEach(($statusText) => $statusText.innerText = statusText);
|
|
break;
|
|
|
|
case state.isError === true:
|
|
$card.classList.remove(okClass, warnClass);
|
|
$card.classList.add(errClass);
|
|
$statusText.forEach(($statusText) => $statusText.innerText = statusText);
|
|
break;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @param { {whatHappened?: string, whatToDo?: string} } reasons
|
|
*/
|
|
const setReasons = function (reasons) {
|
|
const descSelector = '.description';
|
|
|
|
Array.prototype.forEach.call(document.getElementsByClassName('what-happened'), ($el) => {
|
|
if (typeof reasons.whatHappened === 'string' && reasons.whatHappened.length > 0) {
|
|
Array.prototype.forEach.call($el.querySelectorAll(descSelector), ($desc) => $desc.innerText = reasons.whatHappened);
|
|
} else {
|
|
$el.remove();
|
|
}
|
|
});
|
|
|
|
Array.prototype.forEach.call(document.getElementsByClassName('what-can-i-do'), ($el) => {
|
|
if (typeof reasons.whatToDo === 'string' && reasons.whatToDo.length > 0) {
|
|
Array.prototype.forEach.call($el.querySelectorAll(descSelector), ($desc) => $desc.innerText = reasons.whatToDo);
|
|
} else {
|
|
$el.remove();
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* @param {string} text
|
|
*/
|
|
const setErrorDescription = function (text) {
|
|
Array.prototype.forEach.call(document.getElementsByClassName('error-description'), function ($el) {
|
|
$el.innerHTML = text;
|
|
});
|
|
};
|
|
|
|
const message = `{{ message }}`.trim(), cards = {
|
|
$client: document.getElementById('client-status-card'),
|
|
$network: document.getElementById('network-status-card'),
|
|
$server: document.getElementById('server-status-card'),
|
|
};
|
|
|
|
let whatToDo = 'Please try again in a few minutes';
|
|
|
|
switch (true) {
|
|
case errorCode >= 400 && errorCode <= 499:
|
|
switch (errorCode) {
|
|
case 400: case 405: case 411: case 413: whatToDo = 'Please try to change the request method, headers, payload, or URL'; break;
|
|
case 401: case 403: case 407: whatToDo = 'Please check your authorization data'; break;
|
|
case 404: whatToDo = 'Please double-check the URL and try again'; break;
|
|
case 409: case 410: case 418: whatToDo = '¯\\_(ツ)_/¯'; break;
|
|
}
|
|
|
|
setErrorDescription(`<span data-l10n>${message}</span> (<span data-l10n>client-side error</span>)`);
|
|
setCardState(cards.$client, {isError: true}, message)
|
|
setCardState(cards.$network, {isOk: true}, 'Working')
|
|
setCardState(cards.$server, {isOk: true}, 'Working')
|
|
break;
|
|
|
|
case errorCode >= 500 && errorCode <= 599:
|
|
setErrorDescription(`<span data-l10n>${message}</span> (<span data-l10n>server-side error</span>)`);
|
|
setCardState(cards.$client, {isOk: true}, 'Working')
|
|
setCardState(cards.$network, {isOk: true}, 'Working')
|
|
setCardState(cards.$server, {isError: true}, message)
|
|
break;
|
|
|
|
default:
|
|
setErrorDescription(message);
|
|
setCardState(cards.$client, {isWarning: true}, 'Unknown')
|
|
setCardState(cards.$network, {isOk: true}, 'Working')
|
|
setCardState(cards.$server, {isWarning: true}, 'Unknown')
|
|
break;
|
|
}
|
|
|
|
setReasons({whatHappened: `{{ description }}`.trim(), whatToDo: whatToDo.trim()});
|
|
} else {
|
|
console.warn('Cannot parse the error code:', errorCode);
|
|
}
|
|
|
|
// {{ if l10n_enabled }}
|
|
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
|
|
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
|
|
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
|
|
s.async = s.defer = true;
|
|
s.addEventListener('load', () => p.removeChild(s));
|
|
p.appendChild(s);
|
|
})(document.createElement('script'), document.body);
|
|
}
|
|
// {{ end }}
|
|
</script>
|
|
<!--
|
|
Error {{ code }}: {{ message }}
|
|
Description: {{ description }}
|
|
-->
|
|
</html>
|