diff options
-rw-r--r-- | Caddyfile | 6 | ||||
-rw-r--r-- | README.md | 21 | ||||
-rw-r--r-- | content/landing.html | 1 | ||||
-rw-r--r-- | content/posts/1-hello-new-blog.html | 2 | ||||
-rw-r--r-- | content/posts/2-second-post.html | 1 | ||||
-rw-r--r-- | index.html | 87 | ||||
-rw-r--r-- | routes.json | 14 |
7 files changed, 132 insertions, 0 deletions
diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..02ba6af --- /dev/null +++ b/Caddyfile @@ -0,0 +1,6 @@ +localhost { + encode gzip + root * . + try_files {path} /index.html + file_server +}
\ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..be7aeaf --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# spa + +Example SPA approach to a simple blog website. + +## prerequisites +- [caddy web server](https://caddywebserver.com) + +## run +launch with `caddy run` and open the browser to http://localhost + +## how it works + +caddy tries to load from files, and falls back to index.html by default if no file matches. + +[index.html](./index.html) has a plain page template and uses javascript to dynamically create navigation and load the content. + +[routes.json](./routes.json) file contains the metadata for website pages (currently just title and content location) + +content/* files are HTML content to be embedded in the page template. + +assets/* files are just plain files to be served direct.
\ No newline at end of file diff --git a/content/landing.html b/content/landing.html new file mode 100644 index 0000000..95688d5 --- /dev/null +++ b/content/landing.html @@ -0,0 +1 @@ +Welcome to Martin's Blog!
\ No newline at end of file diff --git a/content/posts/1-hello-new-blog.html b/content/posts/1-hello-new-blog.html new file mode 100644 index 0000000..8776c33 --- /dev/null +++ b/content/posts/1-hello-new-blog.html @@ -0,0 +1,2 @@ +Hello there, here's the content of the first post of my new blog +<b> here's something blahh</b>
\ No newline at end of file diff --git a/content/posts/2-second-post.html b/content/posts/2-second-post.html new file mode 100644 index 0000000..8f83954 --- /dev/null +++ b/content/posts/2-second-post.html @@ -0,0 +1 @@ +And here's the second
\ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..eba968c --- /dev/null +++ b/index.html @@ -0,0 +1,87 @@ +<!doctype HTML> +<html> +<head> + <style> + /* CSS taken from https://perfectmotherfuckingwebsite.com/ */ + body{ + max-width:650px; + margin:40px auto; + padding:0 10px; + font:18px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + color:#444 + } + h1,h2,h3{ + line-height:1.2 + } + @media (prefers-color-scheme: dark){ + body{ + color:#c9d1d9; + background:#0d1117 + } + a:link{ + color:#58a6ff + } + a:visited{ + color:#8e96f0 + } + } + </style> + <script type="text/javascript"> + let routes = {}; + async function loadNav() { + let resp = await fetch("/routes.json"); + routes = await resp.json(); + let lis = Object.entries(routes).map(([key,route]) => { + let li = document.createElement("li"); + let a = document.createElement("a"); + let tn = document.createTextNode(route.title); + a.replaceChildren(tn); + a.href = "/"+key; + a.onclick = function(e) { + goto(key).then(() => {}); + e.preventDefault(); + }; + li.replaceChildren(a); + return li; + }) + let nav = document.getElementsByTagName("nav")[0]; + nav.children[0].replaceChildren(...lis); + } + async function goto(key) { + let nextURL = new URL(window.location); + nextURL.pathname = "/"+key; + const nextTitle = routes[key].title; + const nextState = { additionalInformation: 'Updated the URL with JS' }; + window.history.pushState(nextState, nextTitle, nextURL); + // Manually fire popstate :shrug: + // https://stackoverflow.com/questions/10940837/history-pushstate-does-not-trigger-popstate-event + let popStateEvent = new PopStateEvent('popstate', { state: nextState, title: nextTitle, location: nextURL }); + dispatchEvent(popStateEvent); + } + async function loadContent() { + let key = window.location.pathname.substring(1); + let contentElem = document.getElementsByTagName("content")[0]; + let head = document.getElementsByTagName("h1")[0]; + let route = routes[key] ?? routes[""]; + let contentFile = route.content; + head.innerHTML = route.title; + let resp = await fetch(contentFile); + let content = await resp.text(); + contentElem.innerHTML = content; + } + window.addEventListener('popstate', async (event) => { + await loadContent(); + }); + window.addEventListener('load', async (event) => { + await loadNav(); + await loadContent(); + }); + </script> + <title>Martin's Blog!</title> +</head> +<body> + <h1></h1> + <nav><ol></ol></nav> + <content></content> +</body> +</html>
\ No newline at end of file diff --git a/routes.json b/routes.json new file mode 100644 index 0000000..9b02008 --- /dev/null +++ b/routes.json @@ -0,0 +1,14 @@ +{ + "": { + "title": "Home", + "content": "/content/landing.html" + }, + "1-hello-new-blog": { + "title": "Hello New Blog", + "content": "/content/posts/1-hello-new-blog.html" + }, + "2-second-blog": { + "title": "Second Blog Post", + "content": "/content/posts/2-second-post.html" + } +}
\ No newline at end of file |