mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-16 07:30:02 -04:00
193 lines
7.8 KiB
TypeScript
193 lines
7.8 KiB
TypeScript
import { $scramjet } from "../scramjet";
|
|
|
|
export function errorTemplate(trace: string, fetchedURL: string) {
|
|
// turn script into a data URI so we don"t have to escape any HTML values
|
|
const script = `
|
|
errorTrace.value = ${JSON.stringify(trace)};
|
|
fetchedURL.textContent = ${JSON.stringify(fetchedURL)};
|
|
for (const node of document.querySelectorAll("#hostname")) node.textContent = ${JSON.stringify(location.hostname)};
|
|
reload.addEventListener("click", () => location.reload());
|
|
version.textContent = ${JSON.stringify($scramjet.version.version)};
|
|
build.textContent = ${JSON.stringify($scramjet.version.build)};
|
|
|
|
document.getElementById('copy-button').addEventListener('click', async () => {
|
|
const text = document.getElementById('errorTrace').value;
|
|
await navigator.clipboard.writeText(text);
|
|
const btn = document.getElementById('copy-button');
|
|
btn.textContent = 'Copied!';
|
|
setTimeout(() => btn.textContent = 'Copy', 2000);
|
|
});
|
|
`;
|
|
|
|
return `<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<title>Scramjet</title>
|
|
<style>
|
|
:root {
|
|
--deep: #080602;
|
|
--shallow: #181412;
|
|
--beach: #f1e8e1;
|
|
--shore: #b1a8a1;
|
|
--accent: #ffa938;
|
|
--font-sans: -apple-system, system-ui, BlinkMacSystemFont, sans-serif;
|
|
--font-monospace: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
}
|
|
|
|
*:not(div,p,span,ul,li,i,span) {
|
|
background-color: var(--deep);
|
|
color: var(--beach);
|
|
font-family: var(--font-sans);
|
|
}
|
|
|
|
textarea,
|
|
button {
|
|
background-color: var(--shallow);
|
|
border-radius: 0.6em;
|
|
padding: 0.6em;
|
|
border: none;
|
|
appearance: none;
|
|
font-family: var(--font-sans);
|
|
color: var(--beach);
|
|
}
|
|
|
|
button.primary {
|
|
background-color: var(--accent);
|
|
color: var(--deep);
|
|
font-weight: bold;
|
|
}
|
|
|
|
textarea {
|
|
resize: none;
|
|
height: 20em;
|
|
text-align: left;
|
|
color: red;
|
|
font-family: var(--font-monospace);
|
|
}
|
|
|
|
body {
|
|
width: 100vw;
|
|
height: 100vh;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
body,
|
|
html,
|
|
#inner {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-direction: column;
|
|
gap: 0.5em;
|
|
overflow: hidden;
|
|
}
|
|
|
|
#inner {
|
|
z-index: 100;
|
|
}
|
|
|
|
#cover {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color: color-mix(in srgb, var(--deep) 70%, transparent);
|
|
z-index: 99;
|
|
}
|
|
|
|
#info {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: flex-start;
|
|
gap: 1em;
|
|
}
|
|
|
|
#version-wrapper {
|
|
width: auto;
|
|
text-align: right;
|
|
position: absolute;
|
|
top: 0.5rem;
|
|
right: 0.5rem;
|
|
font-size: 0.8rem;
|
|
color: var(--shore)!important;
|
|
i {
|
|
background-color: color-mix(in srgb, var(--deep), transparent 50%);
|
|
border-radius: 9999px;
|
|
padding: 0.2em 0.5em;
|
|
}
|
|
z-index: 101;
|
|
}
|
|
|
|
#errorTrace-wrapper {
|
|
position: relative;
|
|
width: fit-content;
|
|
}
|
|
|
|
#copy-button {
|
|
position: absolute;
|
|
top: 0.5em;
|
|
right: 0.5em;
|
|
padding: 0.23em;
|
|
cursor: pointer;
|
|
opacity: 0;
|
|
transition: opacity 0.4s;
|
|
font-size: 0.9em;
|
|
}
|
|
|
|
#errorTrace-wrapper:hover #copy-button {
|
|
opacity: 1;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="cover"></div>
|
|
<div id="inner">
|
|
<h1 id="errorTitle">Uh oh!</h1>
|
|
<p>There was an error loading <b id="fetchedURL"></b></p>
|
|
<!-- <p id="errorMessage">Internal Server Error</p> -->
|
|
|
|
<div id="info">
|
|
<div id="errorTrace-wrapper">
|
|
<textarea id="errorTrace" cols="40" rows="10" readonly></textarea>
|
|
<button id="copy-button" class="primary">Copy</button>
|
|
</div>
|
|
<div id="troubleshooting">
|
|
<p>Try:</p>
|
|
<ul>
|
|
<li>Checking your internet connection</li>
|
|
<li>Verifying you entered the correct address</li>
|
|
<li>Clearing the site data</li>
|
|
<li>Contacting <b id="hostname"></b>'s administrator</li>
|
|
<li>Verify the server isn't censored</li>
|
|
</ul>
|
|
<p>If you're the administrator of <b id="hostname"></b>, try:</p>
|
|
<ul>
|
|
<li>Restarting your server</li>
|
|
<li>Updating Scramjet</li>
|
|
<li>Troubleshooting the error on the <a href="https://github.com/MercuryWorkshop/scramjet" target="_blank">GitHub repository</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<br>
|
|
<button id="reload" class="primary">Reload</button>
|
|
</div>
|
|
<p id="version-wrapper"><i>Scramjet v<span id="version"></span> (build <span id="build"></span>)</i></p>
|
|
<script src="${"data:application/javascript," + encodeURIComponent(script)}"></script>
|
|
</body>
|
|
</html>
|
|
`;
|
|
}
|
|
|
|
export function renderError(err: unknown, fetchedURL: string) {
|
|
const headers = {
|
|
"content-type": "text/html",
|
|
};
|
|
if (crossOriginIsolated) {
|
|
headers["Cross-Origin-Embedder-Policy"] = "require-corp";
|
|
}
|
|
|
|
return new Response(errorTemplate(String(err), fetchedURL), {
|
|
status: 500,
|
|
headers: headers,
|
|
});
|
|
}
|