diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..5ca234d
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "liveServer.settings.file": "index.html"
+}
\ No newline at end of file
diff --git a/assets/app.js b/assets/app.js
index c6c3ff9..646f20d 100644
--- a/assets/app.js
+++ b/assets/app.js
@@ -455,7 +455,12 @@ function resolveRoute(pathname) {
}
}
}
- return { tab: SITE_TREE[0], group: SITE_TREE[0].groups[0], item: SITE_TREE[0].groups[0].items[0] };
+ return {
+ is404: true,
+ tab: SITE_TREE[0],
+ group: { title: "Error" },
+ item: { title: "404 Not Found", path: path }
+ };
}
function renderNavTabs(currentTab) {
@@ -837,6 +842,47 @@ function loadPage() {
document.title = route.item.title + " — Vyla";
var contentEl = document.getElementById("main-content");
+
+ document.body.classList.remove("is-404");
+
+ var route = resolveRoute(window.location.pathname);
+ renderNavTabs(route.tab);
+ renderSidebar(route.tab, route.item);
+
+ document.title = route.item.title + " — Vyla";
+
+ var contentEl = document.getElementById("main-content");
+
+ if (route.is404) {
+ document.body.classList.add("is-404");
+ document.title = "404 - Page Not Found — Vyla";
+
+ if (contentEl) {
+ contentEl.classList.remove("content-animate");
+ contentEl.innerHTML =
+ '
' +
+ '
404
' +
+ '
PAGE NOT FOUND
' +
+ '
But if you don\'t change your direction, and if you keep looking, you may end up where you are heading.
' +
+ '
Take me home' +
+ '
';
+
+ var tocList = document.getElementById("toc-list");
+ if (tocList) tocList.innerHTML = "";
+ var prevBtn = document.getElementById("footer-prev");
+ var nextBtn = document.getElementById("footer-next");
+ if (prevBtn) prevBtn.classList.add("hidden");
+ if (nextBtn) nextBtn.classList.add("hidden");
+ window.scrollTo(0, 0);
+ }
+ var sidebar = document.getElementById("sidebar");
+ if (sidebar && sidebar.classList.contains("open")) {
+ sidebar.classList.remove("open");
+ document.body.classList.remove("nav-open");
+ }
+ return;
+ }
+
if (contentEl) {
contentEl.classList.remove("content-animate");
contentEl.innerHTML =
@@ -854,7 +900,8 @@ function loadPage() {
fetch(route.item.file)
.then(function (res) {
- if (!res.ok) throw new Error("Not found");
+ var ctype = res.headers.get("content-type") || "";
+ if (!res.ok || ctype.indexOf("text/html") !== -1) throw new Error("Not found");
return res.text();
})
.then(function (md) {
diff --git a/assets/styling/404.css b/assets/styling/404.css
new file mode 100644
index 0000000..c938933
--- /dev/null
+++ b/assets/styling/404.css
@@ -0,0 +1,81 @@
+body.is-404 #sidebar,
+body.is-404 #toc,
+body.is-404 #mobile-bar,
+body.is-404 .footer-nav {
+ display: none !important;
+}
+
+body.is-404 #content-wrapper {
+ padding: 0 !important;
+ margin: 0 auto !important;
+ max-width: 100% !important;
+ width: 100% !important;
+}
+
+body.is-404 #content-col,
+body.is-404 #main-wrap,
+body.is-404 #main-content {
+ max-width: 100% !important;
+ width: 100% !important;
+ margin: 0 !important;
+}
+
+body.is-404 .error-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: calc(80vh - 120px);
+ padding: 40px 20px;
+ box-sizing: border-box;
+ text-align: center;
+}
+
+body.is-404 .error-code {
+ margin: 0 0 16px;
+ color: var(--color-text-primary);
+ font-size: clamp(74px, 14vw, 112px);
+ font-weight: 700;
+ line-height: 1;
+ letter-spacing: -2px;
+}
+
+body.is-404 .error-title {
+ margin: 0 0 24px;
+ color: var(--color-text-primary);
+ font-size: 18px;
+ font-weight: 800;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+}
+
+body.is-404 .error-desc {
+ max-width: 440px;
+ margin: 0 0 32px;
+ color: var(--muted-light);
+ font-size: 15.5px;
+ line-height: 1.6;
+}
+
+html.dark body.is-404 .error-desc {
+ color: var(--muted-dark);
+}
+
+body.is-404 .btn-home {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 10px 28px;
+ border-radius: 9999px;
+ background: var(--bg-dark);
+ color: var(--bg-light) !important;
+ font-size: 14.5px;
+ font-weight: 500;
+ text-decoration: none !important;
+ transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
+}
+
+html.dark body.is-404 .btn-home {
+ background: var(--bg-light);
+ color: var(--bg-dark) !important;
+}
\ No newline at end of file
diff --git a/assets/styling/layout.css b/assets/styling/layout.css
index d8b8af8..8c335bf 100644
--- a/assets/styling/layout.css
+++ b/assets/styling/layout.css
@@ -204,6 +204,7 @@ html.dark #sidebar li a:hover {
gap: 92px;
max-width: 100%;
box-sizing: border-box;
+ width: 80vw;
}
#main-wrap {
diff --git a/assets/styling/prose.css b/assets/styling/prose.css
index 3316ca2..7e83520 100644
--- a/assets/styling/prose.css
+++ b/assets/styling/prose.css
@@ -138,6 +138,7 @@ main.prose pre {
background: rgba(250, 250, 250);
--fade-l: 0px;
--fade-r: 0px;
+ scrollbar-width: none;
-webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent 100%);
mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent 100%);
}
diff --git a/home.txt b/home.txt
index d3dc3e6..c09aef2 100644
--- a/home.txt
+++ b/home.txt
@@ -257,15 +257,15 @@
+ src="https://www.pexels.com/download/video/14517238/">
-