blackout/templates/index.tmpl

245 lines
6.6 KiB
Cheetah

<!DOCTYPE html>
<html>
<head>
<title>blackout engine</title>
<script src="/html2canvas.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<style>
body {
background-color: black;
color: black;
}
.rainbow {
animation-name: rainbow;
animation-duration: 1s;
}
@keyframes rainbow {
20%{color: red;}
40%{color: orange;}
60%{color: yellow;}
80%{color: green;}
100%{color: blue;}
}
.centering {
display: flex;
justify-content: center;
align-items: center;
text-align: left;
margin-left: 25%;
margin-bottom: 4em;
margin-top: 4em;
width: 50%;
}
.black {
background-color: black;
}
.grey {
background-color: grey;
}
.hidden {
display: none;
}
.citation {
font-weight: bold;
font-style: oblique;
font-variant-caps: small-caps;
}
.from {
color: white;
}
#paper {
background-color: white;
padding: 2em;
font-size: 150%;
}
#paper span {
cursor: help;
}
.shifted {
/* hack for the image download. without this, thin white artifacting at span margins */
margin-right:-1px;
}
@media (max-width:400px) {
.centering {
display: block;
width: 100%;
margin: 0px;
}
}
@media (hover: hover) {
#paper span:hover {
background-color: white;
}
#paper span.black:hover {
background-color: grey;
}
}
#aboutToggle {
color: white;
font-weight: bold;
font-style: oblique;
text-decoration: underline;
}
#about {
color: white;
font-family: arial;
}
#about a:visited {
color: white;
}
</style>
<div class="centering">
<div id="paper">
{{- range .Tokens -}}
<span class="black"> {{.}} </span>
{{- end -}}
</div>
</div>
<!--
I have chosen to keep the source hidden behind the ABOUT toggle. I want
people to have the choice of engaging with the text without preconceived
notions.
<p class="from">
&mdash;from <em>{{.Name}}</em> by <em>{{.Author}}</em>
</p>
-->
<center>
<p>
<button id="copyText">copy text to clipboard</button>
<button id="downloadImage">download as image</button>
</p>
<p>
<a id="aboutToggle" href="">ABOUT</a>
</p>
<div id="about" class="hidden">
<p>
THIS WEB SITE ALLOWS YOU TO PERFORM A KIND OF FOUND POETRY CREATION CALLED <a href="https://www.thehistoryofblackoutpoetry.org/">BLACKOUT POETRY</a>.
</p>
<p>
THE TEXT ABOVE IS EXCERPTED FROM <span class="citation">{{.Name}}</span> BY <span class="citation">{{.Author}}</span> AS IT EXISTS ON <a href="https://www.gutenberg.org/">PROJECT GUTENBERG</a>.
</p>
<p>
IT IS <strong>#{{.ID}}</strong> OUT OF <strong>{{.MaxID}}</strong> POSSIBLE TEXT CHUNKS. RELOAD FOR ANOTHER.
</p>
<p>
THIS IS A <a href="https://tilde.town/~vilmibm/blog/#blackout">BLOG POST</a>. THIS IS <a href="https://git.tilde.town/vilmibm/gutchunk">SOURCE</a> <a href="https://git.tilde.town/vilmibm/blackout">CODE</a>.
</p>
<p>
THIS IS A PROJECT BY <a href="https://tilde.town/~vilmibm">~VILMIBM</a>.
</p>
</div>
</center>
<script>
document.querySelectorAll("#paper span").forEach(span => {
span.addEventListener("click", () => span.classList.toggle("black"));
span.addEventListener("touchstart", (e) => {
e.preventDefault();
span.classList.add("grey");
});
span.addEventListener("touchend", (e) => {
e.preventDefault();
span.classList.remove("grey");
span.classList.toggle("black");
});
span.addEventListener("touchcancel", (e) => {
e.preventDefault();
span.classList.remove("grey");
});
});
document.querySelector("#aboutToggle").onclick = (e) => {
e.preventDefault();
document.querySelector("#about").classList.toggle("hidden");
}
const downloadImgButton = document.querySelector("#downloadImage");
downloadImgButton.addEventListener("animationend", () => downloadImgButton.classList.remove("rainbow"), false);
downloadImgButton.addEventListener("click", () => {
document.querySelectorAll("#paper span").forEach(span => {
span.classList.add("shifted");
})
html2canvas(document.querySelector("#paper")).then((canvas) => {
document.querySelectorAll("#paper span").forEach(span => {
span.classList.remove("shifted");
})
canvas.toBlob((blob) => {
/*
// can't use this because ff doesn't have support by default for clipboard.write()
let data = [new ClipboardItem({ [blob.type]: blob })];
navigator.clipboard.write(data).then(() => {
copyImgButton.classList.add("rainbow");
}, console.log);
*/
const downloadUrl = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = "blackout.png";
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(downloadUrl);
});
});
});
const copyTextButton = document.querySelector("#copyText");
copyTextButton.addEventListener("animationend", () => copyTextButton.classList.remove("rainbow"), false);
copyTextButton.addEventListener("click", () => {
let toCopy = "";
document.querySelectorAll("#paper span").forEach(span => {
let guts = span.innerHTML;
if (!span.classList.contains("black")) {
toCopy += guts.trim()+" ";
}
if (guts.includes("\n") && toCopy[toCopy.length-1] != "\n") {
toCopy += "\n"
}
/*
// I think this method of converting to plaintext is interesting but
// it's not very practical--it's way too many characters to
// realistically put in a toot or alt text or similar. I may add a
// "copy wide text" button that re-introduces this behavior.
let out = "";
if (span.classList.contains("black")) {
for (let i = 0; i < guts.length; i++) {
if (guts[i] == "\n") {
out += "\n";
} else {
out += "█";
}
}
} else {
out = guts;
}
toCopy += out
*/
});
navigator.clipboard.writeText(toCopy).then(() => {
copyTextButton.classList.add("rainbow");
}, (err) => {
console.log(err);
});
});
</script>
</body>
</html>