broken but cool htmx! also improved templating
Signed-off-by: ari melody <ari@arimelody.me>
This commit is contained in:
parent
5c59348362
commit
c1ff03c4e5
18 changed files with 297 additions and 97 deletions
|
@ -1,4 +1,3 @@
|
|||
const header_home = document.getElementById("header-home");
|
||||
const header_links = document.getElementById("header-links");
|
||||
const hamburger = document.getElementById("header-links-toggle");
|
||||
|
||||
|
@ -7,14 +6,9 @@ function toggle_header_links() {
|
|||
}
|
||||
|
||||
document.addEventListener("click", event => {
|
||||
if (!header_links.contains(event.target) && !hamburger.contains(event.target)) {
|
||||
if (!header_links.contains(event.target) && !hamburger.contains(event.target) && !header_links.href) {
|
||||
header_links.classList.remove("open");
|
||||
}
|
||||
});
|
||||
|
||||
hamburger.addEventListener("click", event => { toggle_header_links(); });
|
||||
|
||||
header_home.addEventListener("click", event => {
|
||||
event.preventDefault();
|
||||
location.href = "/";
|
||||
});
|
||||
|
|
141
public/script/lib/htmx-head-support.js
Normal file
141
public/script/lib/htmx-head-support.js
Normal file
|
@ -0,0 +1,141 @@
|
|||
//==========================================================
|
||||
// head-support.js
|
||||
//
|
||||
// An extension to htmx 1.0 to add head tag merging.
|
||||
//==========================================================
|
||||
(function(){
|
||||
|
||||
var api = null;
|
||||
|
||||
function log() {
|
||||
//console.log(arguments);
|
||||
}
|
||||
|
||||
function mergeHead(newContent, defaultMergeStrategy) {
|
||||
|
||||
if (newContent && newContent.indexOf('<head') > -1) {
|
||||
const htmlDoc = document.createElement("html");
|
||||
// remove svgs to avoid conflicts
|
||||
var contentWithSvgsRemoved = newContent.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, '');
|
||||
// extract head tag
|
||||
var headTag = contentWithSvgsRemoved.match(/(<head(\s[^>]*>|>)([\s\S]*?)<\/head>)/im);
|
||||
|
||||
// if the head tag exists...
|
||||
if (headTag) {
|
||||
|
||||
var added = []
|
||||
var removed = []
|
||||
var preserved = []
|
||||
var nodesToAppend = []
|
||||
|
||||
htmlDoc.innerHTML = headTag;
|
||||
var newHeadTag = htmlDoc.querySelector("head");
|
||||
var currentHead = document.head;
|
||||
|
||||
if (newHeadTag == null) {
|
||||
return;
|
||||
} else {
|
||||
// put all new head elements into a Map, by their outerHTML
|
||||
var srcToNewHeadNodes = new Map();
|
||||
for (const newHeadChild of newHeadTag.children) {
|
||||
srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// determine merge strategy
|
||||
var mergeStrategy = api.getAttributeValue(newHeadTag, "hx-head") || defaultMergeStrategy;
|
||||
|
||||
// get the current head
|
||||
for (const currentHeadElt of currentHead.children) {
|
||||
|
||||
// If the current head element is in the map
|
||||
var inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);
|
||||
var isReAppended = currentHeadElt.getAttribute("hx-head") === "re-eval";
|
||||
var isPreserved = api.getAttributeValue(currentHeadElt, "hx-preserve") === "true";
|
||||
if (inNewContent || isPreserved) {
|
||||
if (isReAppended) {
|
||||
// remove the current version and let the new version replace it and re-execute
|
||||
removed.push(currentHeadElt);
|
||||
} else {
|
||||
// this element already exists and should not be re-appended, so remove it from
|
||||
// the new content map, preserving it in the DOM
|
||||
srcToNewHeadNodes.delete(currentHeadElt.outerHTML);
|
||||
preserved.push(currentHeadElt);
|
||||
}
|
||||
} else {
|
||||
if (mergeStrategy === "append") {
|
||||
// we are appending and this existing element is not new content
|
||||
// so if and only if it is marked for re-append do we do anything
|
||||
if (isReAppended) {
|
||||
removed.push(currentHeadElt);
|
||||
nodesToAppend.push(currentHeadElt);
|
||||
}
|
||||
} else {
|
||||
// if this is a merge, we remove this content since it is not in the new head
|
||||
if (api.triggerEvent(document.body, "htmx:removingHeadElement", {headElement: currentHeadElt}) !== false) {
|
||||
removed.push(currentHeadElt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Push the tremaining new head elements in the Map into the
|
||||
// nodes to append to the head tag
|
||||
nodesToAppend.push(...srcToNewHeadNodes.values());
|
||||
log("to append: ", nodesToAppend);
|
||||
|
||||
for (const newNode of nodesToAppend) {
|
||||
log("adding: ", newNode);
|
||||
var newElt = document.createRange().createContextualFragment(newNode.outerHTML);
|
||||
log(newElt);
|
||||
if (api.triggerEvent(document.body, "htmx:addingHeadElement", {headElement: newElt}) !== false) {
|
||||
currentHead.appendChild(newElt);
|
||||
added.push(newElt);
|
||||
}
|
||||
}
|
||||
|
||||
// remove all removed elements, after we have appended the new elements to avoid
|
||||
// additional network requests for things like style sheets
|
||||
for (const removedElement of removed) {
|
||||
if (api.triggerEvent(document.body, "htmx:removingHeadElement", {headElement: removedElement}) !== false) {
|
||||
currentHead.removeChild(removedElement);
|
||||
}
|
||||
}
|
||||
|
||||
api.triggerEvent(document.body, "htmx:afterHeadMerge", {added: added, kept: preserved, removed: removed});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
htmx.defineExtension("head-support", {
|
||||
init: function(apiRef) {
|
||||
// store a reference to the internal API.
|
||||
api = apiRef;
|
||||
|
||||
htmx.on('htmx:afterSwap', function(evt){
|
||||
var serverResponse = evt.detail.xhr.response;
|
||||
if (api.triggerEvent(document.body, "htmx:beforeHeadMerge", evt.detail)) {
|
||||
mergeHead(serverResponse, evt.detail.boosted ? "merge" : "append");
|
||||
}
|
||||
})
|
||||
|
||||
htmx.on('htmx:historyRestore', function(evt){
|
||||
if (api.triggerEvent(document.body, "htmx:beforeHeadMerge", evt.detail)) {
|
||||
if (evt.detail.cacheMiss) {
|
||||
mergeHead(evt.detail.serverResponse, "merge");
|
||||
} else {
|
||||
mergeHead(evt.detail.item.head, "merge");
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
htmx.on('htmx:historyItemCreated', function(evt){
|
||||
var historyItem = evt.detail.item;
|
||||
historyItem.head = document.head.outerHTML;
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
})()
|
|
@ -63,3 +63,17 @@ document.addEventListener("htmx:afterSwap", async event => {
|
|||
}
|
||||
window.scrollY = 0;
|
||||
});
|
||||
|
||||
const top_button = document.getElementById("backtotop");
|
||||
window.onscroll = () => {
|
||||
if (!top_button) return;
|
||||
const btt_threshold = 100;
|
||||
if (
|
||||
document.body.scrollTop > btt_threshold ||
|
||||
document.documentElement.scrollTop > btt_threshold
|
||||
) {
|
||||
top_button.classList.add("active");
|
||||
} else {
|
||||
top_button.classList.remove("active");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,9 @@ share_btn.onclick = (e) => {
|
|||
share_btn.classList.add('active');
|
||||
}
|
||||
|
||||
document.getElementById("go-back").addEventListener("click", () => {
|
||||
const go_back_btn = document.getElementById("go-back")
|
||||
go_back_btn.innerText = "<";
|
||||
go_back_btn.addEventListener("click", () => {
|
||||
window.history.back();
|
||||
});
|
||||
|
||||
|
|
|
@ -1,15 +1,5 @@
|
|||
document.querySelectorAll("h2.question").forEach(element => {
|
||||
element.onclick = (e) => {
|
||||
const url = `${window.location.protocol}//${window.location.host}${window.location.pathname}#${e.target.id}`;
|
||||
window.location = url;
|
||||
};
|
||||
});
|
||||
import "./main.js";
|
||||
|
||||
document.querySelectorAll("div.music").forEach(element => {
|
||||
console.log(element);
|
||||
element.addEventListener("click", (e) => {
|
||||
const url = `${window.location.protocol}//${window.location.host}/music/${element.id}`;
|
||||
window.location = url;
|
||||
});
|
||||
document.querySelectorAll("h1.music-title").forEach(element => {
|
||||
element.href = "";
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
@import url("/style/colours.css");
|
||||
@import url("/style/header.css");
|
||||
@import url("/style/footer.css");
|
||||
@import url("/style/prideflag.css");
|
||||
|
||||
@font-face {
|
||||
font-family: "Monaspace Argon";
|
||||
|
@ -42,6 +43,32 @@ span.newchar {
|
|||
animation: newchar 0.25s;
|
||||
}
|
||||
|
||||
a#backtotop {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: .5em .8em;
|
||||
display: block;
|
||||
border-radius: 2px;
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
opacity: .5;
|
||||
transition-property: opacity, transform, border-color, background-color, color;
|
||||
transition-duration: .2s;
|
||||
}
|
||||
|
||||
a#backtotop.active {
|
||||
top: 4rem;
|
||||
}
|
||||
|
||||
a#backtotop:hover {
|
||||
color: #eee;
|
||||
border-color: #eee;
|
||||
background-color: var(--links);
|
||||
box-shadow: 0 0 1em var(--links);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@keyframes newchar {
|
||||
from {
|
||||
background: #fff8;
|
||||
|
|
|
@ -241,7 +241,7 @@ div#info p {
|
|||
#title {
|
||||
margin: 0;
|
||||
line-height: 1em;
|
||||
font-size: 3em;
|
||||
font-size: 2.5em;
|
||||
}
|
||||
|
||||
#year {
|
||||
|
@ -571,6 +571,7 @@ footer a:hover {
|
|||
}
|
||||
|
||||
div#info > div {
|
||||
min-width: auto;
|
||||
min-height: auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
@import url("/style/index.css");
|
||||
|
||||
main {
|
||||
width: min(calc(100% - 4rem), 720px);
|
||||
min-height: calc(100vh - 10.3rem);
|
||||
margin: 0 auto 2rem auto;
|
||||
padding-top: 4rem;
|
||||
}
|
||||
|
||||
div.music {
|
||||
margin-bottom: 1rem;
|
||||
padding: 1.5rem;
|
||||
|
@ -114,7 +121,7 @@ h2.question {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collapse {
|
||||
div.answer {
|
||||
margin: -1rem 0 1rem 0;
|
||||
padding: .5em 1.5em;
|
||||
border-radius: 4px;
|
||||
|
|
25
public/style/prideflag.css
Normal file
25
public/style/prideflag.css
Normal file
|
@ -0,0 +1,25 @@
|
|||
#prideflag svg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 120px;
|
||||
transform-origin: 100% 0%;
|
||||
transition: transform .5s cubic-bezier(.32,1.63,.41,1.01);
|
||||
z-index: 8008135;
|
||||
pointer-events: none;
|
||||
}
|
||||
#prideflag svg:hover {
|
||||
transform: scale(110%);
|
||||
}
|
||||
#prideflag svg:active {
|
||||
transform: scale(110%);
|
||||
}
|
||||
#prideflag svg * {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 950px) {
|
||||
#prideflag {
|
||||
display: none;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue