Compare commits
17 Commits
master
...
error-page
Author | SHA1 | Date |
---|---|---|
Karol Wypchlo | ab317b428a | |
Karol Wypchlo | d6bfb50516 | |
Karol Wypchlo | dc602054f2 | |
Karol Wypchlo | 3fe46e3ef6 | |
Karol Wypchlo | b838979b94 | |
Karol Wypchlo | 18fddcd8a4 | |
Karol Wypchlo | f5d7973eab | |
Karol Wypchlo | 83521f141f | |
Karol Wypchlo | 7c52fe77e1 | |
Karol Wypchlo | 35bf172d28 | |
Karol Wypchlo | 185daf6a08 | |
Karol Wypchlo | 2f60d02131 | |
Karol Wypchlo | 9d8b34af43 | |
Karol Wypchlo | 5ac6d34e00 | |
Karol Wypchlo | d858b8b33e | |
Karol Wypchlo | 1678b17e9a | |
Karol Wypchlo | 69c6f9e42a |
|
@ -74,7 +74,7 @@ services:
|
||||||
- ./docker/data/certbot:/etc/letsencrypt
|
- ./docker/data/certbot:/etc/letsencrypt
|
||||||
- ./docker/nginx/libs:/etc/nginx/libs
|
- ./docker/nginx/libs:/etc/nginx/libs
|
||||||
- ./docker/nginx/conf.d:/etc/nginx/conf.d
|
- ./docker/nginx/conf.d:/etc/nginx/conf.d
|
||||||
- ./docker/nginx/conf.d.templates:/etc/nginx/templates
|
- ./docker/nginx/templates:/etc/nginx/templates
|
||||||
- ./docker/nginx/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf
|
- ./docker/nginx/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf
|
||||||
networks:
|
networks:
|
||||||
shared:
|
shared:
|
||||||
|
@ -99,7 +99,7 @@ services:
|
||||||
logging: *default-logging
|
logging: *default-logging
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker/data/website/.cache:/usr/app/.cache
|
- ./docker/data/website/.cache:/usr/app/.cache
|
||||||
- ./docker/data/website/.public:/usr/app/public
|
- ./docker/data/website/public:/usr/app/public
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
networks:
|
networks:
|
||||||
|
|
|
@ -15,10 +15,10 @@ rewrite_by_lua_block {
|
||||||
|
|
||||||
-- print error and exit with 500 or exit with response if status is not 200
|
-- print error and exit with 500 or exit with response if status is not 200
|
||||||
if hnsres_err or (hnsres_res and hnsres_res.status ~= ngx.HTTP_OK) then
|
if hnsres_err or (hnsres_res and hnsres_res.status ~= ngx.HTTP_OK) then
|
||||||
ngx.status = (hnsres_err and ngx.HTTP_INTERNAL_SERVER_ERROR) or hnsres_res.status
|
-- ngx.status = (hnsres_err and ngx.HTTP_INTERNAL_SERVER_ERROR) or hnsres_res.status
|
||||||
ngx.header["content-type"] = "text/plain"
|
-- ngx.header["content-type"] = "text/plain"
|
||||||
ngx.say(hnsres_err or hnsres_res.body)
|
-- ngx.say(hnsres_err or hnsres_res.body)
|
||||||
return ngx.exit(ngx.status)
|
return ngx.exit((hnsres_err and ngx.HTTP_INTERNAL_SERVER_ERROR) or hnsres_res.status)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- since /hnsres endpoint response is a json, we need to decode it before we access it
|
-- since /hnsres endpoint response is a json, we need to decode it before we access it
|
||||||
|
@ -48,10 +48,10 @@ rewrite_by_lua_block {
|
||||||
|
|
||||||
-- print error and exit with 500 or exit with response if status is not 200
|
-- print error and exit with 500 or exit with response if status is not 200
|
||||||
if registry_err or (registry_res and registry_res.status ~= ngx.HTTP_OK) then
|
if registry_err or (registry_res and registry_res.status ~= ngx.HTTP_OK) then
|
||||||
ngx.status = (registry_err and ngx.HTTP_INTERNAL_SERVER_ERROR) or registry_res.status
|
-- ngx.status = (registry_err and ngx.HTTP_INTERNAL_SERVER_ERROR) or registry_res.status
|
||||||
ngx.header["content-type"] = "text/plain"
|
-- ngx.header["content-type"] = "text/plain"
|
||||||
ngx.say(registry_err or registry_res.body)
|
-- ngx.say(registry_err or registry_res.body)
|
||||||
return ngx.exit(ngx.status)
|
return ngx.exit((registry_err and ngx.HTTP_INTERNAL_SERVER_ERROR) or registry_res.status)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- since /skynet/registry endpoint response is a json, we need to decode it before we access it
|
-- since /skynet/registry endpoint response is a json, we need to decode it before we access it
|
||||||
|
|
|
@ -36,6 +36,7 @@ proxy_read_timeout 600;
|
||||||
proxy_set_header User-Agent: Sia-Agent;
|
proxy_set_header User-Agent: Sia-Agent;
|
||||||
|
|
||||||
proxy_pass http://sia:9980/skynet/skylink/$skylink$path$is_args$args;
|
proxy_pass http://sia:9980/skynet/skylink/$skylink$path$is_args$args;
|
||||||
|
proxy_intercept_errors on;
|
||||||
|
|
||||||
log_by_lua_block {
|
log_by_lua_block {
|
||||||
local skynet_account = require("skynet.account")
|
local skynet_account = require("skynet.account")
|
||||||
|
|
|
@ -23,12 +23,19 @@ rewrite ^/stats /skynet/stats permanent;
|
||||||
rewrite ^/skynet/blacklist /skynet/blocklist permanent;
|
rewrite ^/skynet/blacklist /skynet/blocklist permanent;
|
||||||
rewrite ^/docs(?:/(.*))?$ https://sdk.skynetlabs.com/$1 permanent;
|
rewrite ^/docs(?:/(.*))?$ https://sdk.skynetlabs.com/$1 permanent;
|
||||||
|
|
||||||
location / {
|
error_page 401 /401.html;
|
||||||
include /etc/nginx/conf.d/include/cors;
|
location = /401.html {
|
||||||
|
root /etc/nginx/conf.d/pages;
|
||||||
proxy_pass http://website:9000;
|
allow all;
|
||||||
|
internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#location / {
|
||||||
|
# include /etc/nginx/conf.d/include/cors;
|
||||||
|
#
|
||||||
|
# proxy_pass http://website:9000;
|
||||||
|
#}
|
||||||
|
|
||||||
location /skynet/blocklist {
|
location /skynet/blocklist {
|
||||||
include /etc/nginx/conf.d/include/cors;
|
include /etc/nginx/conf.d/include/cors;
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,10 @@ location / {
|
||||||
ngx.var.skylink = match_skylink[1]
|
ngx.var.skylink = match_skylink[1]
|
||||||
ngx.var.path = match_skylink[2] or "/"
|
ngx.var.path = match_skylink[2] or "/"
|
||||||
else
|
else
|
||||||
ngx.status = (err and ngx.HTTP_INTERNAL_SERVER_ERROR) or res.status
|
-- ngx.status = (err and ngx.HTTP_INTERNAL_SERVER_ERROR) or res.status
|
||||||
ngx.header["content-type"] = "text/plain"
|
-- ngx.header["content-type"] = "text/plain"
|
||||||
ngx.say(err or res.body)
|
-- ngx.say(err or res.body)
|
||||||
ngx.exit(ngx.status)
|
ngx.exit((err and ngx.HTTP_INTERNAL_SERVER_ERROR) or res.status)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local resolved = cjson.decode(res.body)
|
local resolved = cjson.decode(res.body)
|
||||||
|
|
|
@ -44,18 +44,18 @@ end
|
||||||
|
|
||||||
-- handle request exit when access to portal should be restricted to authenticated users only
|
-- handle request exit when access to portal should be restricted to authenticated users only
|
||||||
function _M.exit_access_unauthorized(message)
|
function _M.exit_access_unauthorized(message)
|
||||||
ngx.status = ngx.HTTP_UNAUTHORIZED
|
-- ngx.status = ngx.HTTP_UNAUTHORIZED
|
||||||
ngx.header["content-type"] = "text/plain"
|
-- ngx.header["content-type"] = "text/plain"
|
||||||
ngx.say(message or "Portal operator restricted access to authenticated users only")
|
-- ngx.say(message or "Portal operator restricted access to authenticated users only")
|
||||||
return ngx.exit(ngx.status)
|
return ngx.exit(ngx.HTTP_UNAUTHORIZED)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- handle request exit when access to portal should be restricted to subscription users only
|
-- handle request exit when access to portal should be restricted to subscription users only
|
||||||
function _M.exit_access_forbidden(message)
|
function _M.exit_access_forbidden(message)
|
||||||
ngx.status = ngx.HTTP_FORBIDDEN
|
-- ngx.status = ngx.HTTP_FORBIDDEN
|
||||||
ngx.header["content-type"] = "text/plain"
|
-- ngx.header["content-type"] = "text/plain"
|
||||||
ngx.say(message or "Portal operator restricted access to users with active subscription only")
|
-- ngx.say(message or "Portal operator restricted access to users with active subscription only")
|
||||||
return ngx.exit(ngx.status)
|
return ngx.exit(ngx.HTTP_FORBIDDEN)
|
||||||
end
|
end
|
||||||
|
|
||||||
function _M.accounts_enabled()
|
function _M.accounts_enabled()
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="h-full">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<!-- meta tags generated with https://metatags.io/ -->
|
||||||
|
<title>401: Unauthorized</title>
|
||||||
|
<meta name="title" content="401: Unauthorized" />
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="You must be authenticated to access this content"
|
||||||
|
/>
|
||||||
|
<!-- svg favicon encoded with https://yoksel.github.io/url-encoder/ -->
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
href="data:image/svg+xml, %3Csvg role='img' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' fill='%2300C65E' %3E%3Ctitle%3ESkynet%3C/title%3E%3Cpath d='m-.0004 6.4602 21.3893 11.297c.561.2935.6633 1.0532.1999 1.4846h-.011a10.0399 10.0399 0 0 1-2.2335 1.5307c-6.912 3.4734-14.9917-1.838-14.5438-9.5605l2.8601 1.9752c.856 4.508 5.6187 7.1094 9.8742 5.3932zm8.6477 3.1509 14.3661 5.6785a.8704.8704 0 0 1 .5197 1.0466v.0182c-.1537.5377-.7668.7938-1.2575.5252zm5.2896-7.4375c2.7093-.2325 6.0946.7869 8.1116 3.3871 1.699 2.1951 2.0497 4.8772 1.9298 7.6465v-.007c-.0478.5874-.6494.9616-1.1975.745l-9.7652-3.8596 9.0656 2.4313a7.296 7.296 0 0 0-1.0677-4.5631c-2.9683-4.7678-9.9847-4.5344-12.6297.4201a7.5048 7.5048 0 0 0-.398.8831L5.5546 7.9614c.069-.1017.1417-.198.2144-.2962.1163-.2416.2417-.487.3798-.7268 1.6118-2.7911 4.3102-4.4338 7.1558-4.6973.2108-.0182.4215-.049.6323-.0672z' /%3E%3C/svg%3E"
|
||||||
|
type="image/svg+xml"
|
||||||
|
/>
|
||||||
|
<!-- https://fonts.google.com/specimen/Sora -->
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Sora:wght@400;800&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<!-- https://tailwindcss.com/docs/installation/play-cdn -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<script>
|
||||||
|
tailwind.config = {
|
||||||
|
theme: { extend: { fontFamily: { sans: ["Sora", "sans-serif"] } } },
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body class="h-full">
|
||||||
|
<div
|
||||||
|
class="bg-white min-h-full px-4 py-16 sm:px-6 sm:py-24 md:grid md:place-items-center lg:px-8"
|
||||||
|
>
|
||||||
|
<div class="max-w-max mx-auto">
|
||||||
|
<main class="sm:flex">
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
height="88"
|
||||||
|
fill="#00C65E"
|
||||||
|
>
|
||||||
|
<title>Skynet</title>
|
||||||
|
<path
|
||||||
|
d="m-.0004 6.4602 21.3893 11.297c.561.2935.6633 1.0532.1999 1.4846h-.011a10.0399 10.0399 0 0 1-2.2335 1.5307c-6.912 3.4734-14.9917-1.838-14.5438-9.5605l2.8601 1.9752c.856 4.508 5.6187 7.1094 9.8742 5.3932zm8.6477 3.1509 14.3661 5.6785a.8704.8704 0 0 1 .5197 1.0466v.0182c-.1537.5377-.7668.7938-1.2575.5252zm5.2896-7.4375c2.7093-.2325 6.0946.7869 8.1116 3.3871 1.699 2.1951 2.0497 4.8772 1.9298 7.6465v-.007c-.0478.5874-.6494.9616-1.1975.745l-9.7652-3.8596 9.0656 2.4313a7.296 7.296 0 0 0-1.0677-4.5631c-2.9683-4.7678-9.9847-4.5344-12.6297.4201a7.5048 7.5048 0 0 0-.398.8831L5.5546 7.9614c.069-.1017.1417-.198.2144-.2962.1163-.2416.2417-.487.3798-.7268 1.6118-2.7911 4.3102-4.4338 7.1558-4.6973.2108-.0182.4215-.049.6323-.0672z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<div class="sm:ml-6">
|
||||||
|
<div class="sm:border-l sm:border-gray-200 sm:pl-6">
|
||||||
|
<h1
|
||||||
|
class="text-xl font-extrabold text-gray-900 tracking-tight sm:text-2xl"
|
||||||
|
>
|
||||||
|
You must be authenticated to access this content
|
||||||
|
</h1>
|
||||||
|
<p class="mt-1 text-base text-gray-500">
|
||||||
|
You're being redirected to the Log In page of this Skynet Portal
|
||||||
|
</p>
|
||||||
|
<p class="mt-2 text-sm text-gray-300">HTTP 401: Unauthorized</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mt-10 flex space-x-3 sm:border-l sm:border-transparent sm:pl-6"
|
||||||
|
>
|
||||||
|
<p class="mt-1 text-sm text-gray-500">
|
||||||
|
If you're not redirected automatically,
|
||||||
|
<a
|
||||||
|
href="https://account.${PORTAL_DOMAIN}/auth/login"
|
||||||
|
class="text-[#00C65E]"
|
||||||
|
>click here</a
|
||||||
|
>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
// prevent auto redirect if not on portal domain to allow local development
|
||||||
|
if (window.location.hostname.endsWith("${PORTAL_DOMAIN}")) {
|
||||||
|
setTimeout(function redirect() {
|
||||||
|
const encodedReturnTo = encodeURIComponent(window.location.href);
|
||||||
|
window.location.href = `https://account.${PORTAL_DOMAIN}/auth/login?return_to=${encodedReturnTo}`;
|
||||||
|
}, 5000); // redirect after 5 secons
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -17,6 +17,7 @@ import * as React from "react";
|
||||||
import Layout from "./src/components/Layout";
|
import Layout from "./src/components/Layout";
|
||||||
|
|
||||||
export const wrapPageElement = ({ element, props }) => {
|
export const wrapPageElement = ({ element, props }) => {
|
||||||
|
if (props.uri.startsWith("/errors")) return element;
|
||||||
// props provide same data to Layout as Page element will get
|
// props provide same data to Layout as Page element will get
|
||||||
// including location, data, etc - you don't need to pass it
|
// including location, data, etc - you don't need to pass it
|
||||||
return <Layout {...props}>{element}</Layout>;
|
return <Layout {...props}>{element}</Layout>;
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { LogoBlackText } from "./Icons";
|
||||||
|
import Seo from "./seo";
|
||||||
|
|
||||||
|
export default function ErrorPage({ statusCode, statusReason, header, subheader, redirect, more }) {
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (redirect && typeof window !== "undefined") {
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = redirect;
|
||||||
|
}, 3000); // 3s
|
||||||
|
}
|
||||||
|
}, [redirect]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Seo title={`${statusCode}: ${statusReason}`} />
|
||||||
|
|
||||||
|
<div className="bg-white min-h-full px-4 py-16 sm:px-6 sm:py-24 md:grid md:place-items-center lg:px-8">
|
||||||
|
<div className="max-w-max mx-auto">
|
||||||
|
<main className="sm:flex-col sm:max-w-3xl space-y-4 sm:space-y-6">
|
||||||
|
<LogoBlackText className="h-10 ml-[-10px]" />
|
||||||
|
|
||||||
|
<div className="flex-col space-y-1 sm:space-y-2">
|
||||||
|
<h1 className="text-lg sm:text-2xl">{header}</h1>
|
||||||
|
|
||||||
|
<p className="text-sm sm:text-md text-palette-400">{subheader}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{more && <p className="text-sm text-palette-300">{more}</p>}
|
||||||
|
|
||||||
|
{redirect && (
|
||||||
|
<p className="text-xs text-palette-300">
|
||||||
|
If you're not redirected automatically,{" "}
|
||||||
|
<a href={redirect} className="text-primary hover:text-primary-light transition-colors duration-200">
|
||||||
|
click here
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import ErrorPage from "../../components/ErrorPage";
|
||||||
|
|
||||||
|
const statusCode = 400;
|
||||||
|
const statusReason = "Bad Request";
|
||||||
|
|
||||||
|
const header = "Bad Request";
|
||||||
|
const subheader = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor";
|
||||||
|
const redirect = null;
|
||||||
|
|
||||||
|
export default function BadRequest() {
|
||||||
|
return (
|
||||||
|
<ErrorPage
|
||||||
|
statusCode={statusCode}
|
||||||
|
statusReason={statusReason}
|
||||||
|
header={header}
|
||||||
|
subheader={subheader}
|
||||||
|
redirect={redirect}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import ErrorPage from "../../components/ErrorPage";
|
||||||
|
|
||||||
|
const statusCode = 401;
|
||||||
|
const statusReason = "Unauthorized";
|
||||||
|
|
||||||
|
const header = "You must be authenticated to access this content";
|
||||||
|
const subheader = "You're being redirected to the Log In page of this Skynet Portal";
|
||||||
|
const redirect = `https://account.${process.env.PORTAL_DOMAIN}/auth/login`;
|
||||||
|
|
||||||
|
export default function Unauthorized() {
|
||||||
|
return (
|
||||||
|
<ErrorPage
|
||||||
|
statusCode={statusCode}
|
||||||
|
statusReason={statusReason}
|
||||||
|
header={header}
|
||||||
|
subheader={subheader}
|
||||||
|
redirect={redirect}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import ErrorPage from "../../components/ErrorPage";
|
||||||
|
|
||||||
|
const statusCode = 403;
|
||||||
|
const statusReason = "Forbidden";
|
||||||
|
|
||||||
|
const header = "You are not authorized to access this content";
|
||||||
|
const subheader = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor";
|
||||||
|
const redirect = null;
|
||||||
|
|
||||||
|
export default function Forbidden() {
|
||||||
|
return (
|
||||||
|
<ErrorPage
|
||||||
|
statusCode={statusCode}
|
||||||
|
statusReason={statusReason}
|
||||||
|
header={header}
|
||||||
|
subheader={subheader}
|
||||||
|
redirect={redirect}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import ErrorPage from "../../components/ErrorPage";
|
||||||
|
|
||||||
|
const statusCode = 404;
|
||||||
|
const statusReason = "Not Found";
|
||||||
|
|
||||||
|
const header = "We could not load this content";
|
||||||
|
const subheader = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor";
|
||||||
|
const redirect = null;
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<ErrorPage
|
||||||
|
statusCode={statusCode}
|
||||||
|
statusReason={statusReason}
|
||||||
|
header={header}
|
||||||
|
subheader={subheader}
|
||||||
|
redirect={redirect}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import Link from "../../components/Link";
|
||||||
|
import ErrorPage from "../../components/ErrorPage";
|
||||||
|
|
||||||
|
const statusCode = 451;
|
||||||
|
const statusReason = "Unavailable For Legal Reasons";
|
||||||
|
|
||||||
|
const header = "This file is unavailable for legal reasons";
|
||||||
|
const subheader = "This Skynet Portal has blocked access to this file, likely for legal reasons";
|
||||||
|
const redirect = null;
|
||||||
|
const more = (
|
||||||
|
<>
|
||||||
|
To learn more, see the{" "}
|
||||||
|
<Link
|
||||||
|
href="https://support.skynetlabs.com/key-concepts/faqs#is-skynet-censorship-free"
|
||||||
|
className="text-primary hover:text-primary-light transition-colors duration-200"
|
||||||
|
>
|
||||||
|
Skynet FAQ
|
||||||
|
</Link>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function UnavailableForLegalReasons() {
|
||||||
|
return (
|
||||||
|
<ErrorPage
|
||||||
|
statusCode={statusCode}
|
||||||
|
statusReason={statusReason}
|
||||||
|
header={header}
|
||||||
|
subheader={subheader}
|
||||||
|
more={more}
|
||||||
|
redirect={redirect}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import ErrorPage from "../../components/ErrorPage";
|
||||||
|
|
||||||
|
const statusCode = 500;
|
||||||
|
const statusReason = "Internal Server Error";
|
||||||
|
|
||||||
|
const header = "Internal Server Error";
|
||||||
|
const subheader = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor";
|
||||||
|
const redirect = null;
|
||||||
|
|
||||||
|
export default function InternalServerError() {
|
||||||
|
return (
|
||||||
|
<ErrorPage
|
||||||
|
statusCode={statusCode}
|
||||||
|
statusReason={statusReason}
|
||||||
|
header={header}
|
||||||
|
subheader={subheader}
|
||||||
|
redirect={redirect}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -2,6 +2,13 @@
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
#___gatsby,
|
||||||
|
#gatsby-focus-wrapper {
|
||||||
|
@apply h-full;
|
||||||
|
}
|
||||||
|
|
||||||
.newsletter-message a {
|
.newsletter-message a {
|
||||||
@apply text-primary;
|
@apply text-primary;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,15 +58,5 @@ module.exports = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [require("@tailwindcss/typography")],
|
||||||
require("@tailwindcss/typography"),
|
|
||||||
plugin(function ({ addBase, theme }) {
|
|
||||||
addBase({
|
|
||||||
body: {
|
|
||||||
color: theme("textColor.palette.600"),
|
|
||||||
backgroundColor: theme("backgroundColor.palette.500"),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
Reference in New Issue