tickle-godot-frontend/server_files/index.html
2022-06-21 17:07:23 +03:00

249 lines
6.7 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>Tickle</title>
<meta charset="UTF-8" />
<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=Lobster&family=Nunito+Sans:ital,wght@0,400;0,700;1,400&display=swap"
rel="stylesheet"
/>
<style>
:root {
--accent: hotpink;
--background: #fdfdfd;
font-family: "Nunito Sans", sans-serif;
}
body,
html {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.trigger {
display: none;
}
.left-nav > * {
position: fixed;
top: 0;
left: 0;
}
.left-nav > .menu {
padding: 1em;
transform: translateX(-100%);
display: flex;
flex-direction: column;
top: 0;
bottom: 0;
transition: all 0.3s ease-out;
gap: 1em;
}
.left-nav > .menu a {
text-decoration: none;
background: var(--background);
color: var(--accent);
box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
padding: 0.2em 0.4em;
}
.left-nav > .menu a:hover {
background: var(--accent);
color: var(--background);
}
.left-nav > .trigger:checked ~ .menu {
transform: translateX(0);
transition-duration: 0.1s;
}
.burger {
width: 2em;
height: 2em;
display: flex;
justify-content: center;
align-content: center;
text-align: center;
vertical-align: middle;
line-height: 2em;
border-radius: 0.2em;
box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
transition: background 0.5s ease;
}
.left-nav > .trigger:checked ~ .burger {
color: transparent;
}
.left-nav > .trigger:checked ~ .burger,
#Loading {
top: 0;
right: 0;
width: 100%;
height: 100%;
border-radius: 0;
background: rgba(17, 17, 17, 0.2);
}
#Loading {
position: absolute;
text-align: center;
align-items: center;
justify-content: center;
font-size: 8rem;
color: var(--accent);
opacity: 0;
transition: opacity 0.3s ease-in, height 0s linear 0.3s;
height: 0;
display: flex;
overflow: hidden;
}
.is-loading #Loading {
opacity: 1;
height: 100%;
transition: opacity 1s ease-in, height 0 linear;
}
#Loading::after {
content: "❤";
animation: beat 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
}
@keyframes beat {
0% {
transform: scale(0.95);
}
5% {
transform: scale(1.1);
}
39% {
transform: scale(0.85);
}
45% {
transform: scale(1);
}
60% {
transform: scale(0.95);
}
100% {
transform: scale(0.9);
}
}
#Body {
padding: 3em;
max-width: 52em;
margin: 0 auto;
}
#Body h1,
#Body h2,
#Body h3,
#Body h4 {
color: var(--accent);
font-family: "Lobster", serif;
}
#Body a {
color: var(--background);
background-color: var(--accent);
text-decoration: none;
padding: 0.1em 0.4em;
}
</style>
</head>
<body>
<nav class="left-nav">
<input id="main-nav" type="checkbox" class="trigger" />
<label for="main-nav" class="burger">&#8801;</label>
<div id="Menu" class="menu"></div>
</nav>
<header id="Menu"></header>
<main id="Body"></main>
<div id="Loading"></div>
<script type="module">
/**
* markdown parser. Remove if you don't use markdown
*/
// @ts-ignore
import { micromark } from "https://esm.sh/micromark@3?bundle";
/**
* useful to check for transitions while developing styles, if the loading screen disappears too fast
*
*/
const wait = (val) => new Promise((ok) => setTimeout(ok, 1, val));
/**
* The elements we will need
*/
const [Menu, Body, Loading] = ["Menu", "Body", "Loading"].map((id) =>
document.getElementById(id)
);
/**
* cache the original title to append it to the page title
*/
const mainTitle = document.title;
const startLoading = () => document.body.classList.add("is-loading");
const stopLoading = () => document.body.classList.remove("is-loading");
const getCurrentPage = () =>
window.location.hash[1] === "/" ? window.location.hash.slice(2) : "";
const onHashChange = (evt) => {
const path = getCurrentPage();
if (!path) {
return false;
}
startLoading();
return fetch(`./${path}`)
.then((response) => response.text())
.then(wait)
.then((text) => {
const [, title] = text.match(/^(#\s\w+)/) ||
text.match(/(.*?)\n===+/m) || [, path];
document.title = `${title} | ${mainTitle}`;
Body.innerHTML = micromark(text);
stopLoading();
});
};
window.addEventListener("hashchange", onHashChange);
/**
* Loads the article list, parses it, creates the menu items
*/
const start = () => {
startLoading();
fetch("./files.txt")
.then((response) => response.text())
.then((lines) => {
Menu.innerHTML = lines
.split(`\n`)
.map((line, index) => {
const today = new Date().toISOString().split("T")[0];
const result = line.match(
/(?<name>.+)\.(?<ext>\w{2,3})(?:\s(?<date>[\d-]+)?(?<title>.+))?/
);
if (!result) {
console.log(`could not parse line ${index}: [${line}]`);
return null;
}
const {
groups: { name, ext, date = today, title = name },
} = result;
const href = `/${name}.${ext}`;
if (!getCurrentPage()) {
window.location.hash = `#${href}`;
}
return { name, href, date, title };
})
.filter(Boolean)
.sort(({ date: a }, { date: b }) => a - b)
.map(
({ href, title }) => `<a data-link href="#${href}">${title}</a>`
)
.join(`\n`);
onHashChange();
});
};
start();
</script>
</body>
</html>