releasable
parent
458f87066f
commit
5b8567edcb
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
18
main.go
18
main.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"log"
|
||||
"math/big"
|
||||
"net/http"
|
||||
|
@ -29,7 +30,9 @@ func connectDB() (*sql.DB, error) {
|
|||
return db, nil
|
||||
}
|
||||
|
||||
type chunk struct {
|
||||
type payload struct {
|
||||
ID int64
|
||||
MaxID int
|
||||
Chunk string
|
||||
Tokens []string
|
||||
Name string
|
||||
|
@ -38,7 +41,11 @@ type chunk struct {
|
|||
|
||||
func main() {
|
||||
r := gin.Default()
|
||||
r.SetFuncMap(template.FuncMap{
|
||||
"upper": strings.ToUpper,
|
||||
})
|
||||
r.LoadHTMLFiles("templates/index.tmpl")
|
||||
r.StaticFile("/favicon.ico", "./assets/favicon.ico")
|
||||
|
||||
randMax := big.NewInt(maxID)
|
||||
|
||||
|
@ -67,13 +74,20 @@ func main() {
|
|||
}
|
||||
|
||||
row := stmt.QueryRow(id.Int64())
|
||||
var dest chunk
|
||||
var dest payload
|
||||
err = row.Scan(&dest.Chunk, &dest.Name, &dest.Author)
|
||||
if err != nil {
|
||||
log.Println(err.Error())
|
||||
c.String(http.StatusInternalServerError, "oh no.")
|
||||
}
|
||||
|
||||
if dest.Author == "" {
|
||||
dest.Author = "Unknown"
|
||||
}
|
||||
|
||||
dest.MaxID = maxID
|
||||
dest.ID = id.Int64()
|
||||
|
||||
dest.Tokens = []string{}
|
||||
for _, t := range spaceRE.Split(dest.Chunk, -1) {
|
||||
if t == "" {
|
||||
|
|
|
@ -8,34 +8,76 @@
|
|||
body {
|
||||
background-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;
|
||||
min-height: 95vh;
|
||||
margin-left: 25%;
|
||||
margin-bottom: 4em;
|
||||
margin-top: 4em;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.black {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.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%;
|
||||
}
|
||||
|
||||
.data {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.black {
|
||||
background-color: black;
|
||||
#paper span {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
#paper span:hover {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#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">
|
||||
|
@ -43,14 +85,73 @@
|
|||
<span class="black"> {{.}} </span>
|
||||
{{- end -}}
|
||||
</div>
|
||||
<script>
|
||||
document.querySelectorAll("#paper span").forEach(span =>
|
||||
span.onclick = () => span.classList.toggle("black")
|
||||
);
|
||||
</script>
|
||||
</div>
|
||||
<div class="data" id="chunk">{{.Chunk}}</div>
|
||||
<div class="data" id="bookTitle">{{.Name}}</div>
|
||||
<div class="data" id="bookAuthor">{{.Author}}</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">
|
||||
—from <em>{{.Name}}</em> by <em>{{.Author}}</em>
|
||||
</p>
|
||||
-->
|
||||
<center>
|
||||
<p>
|
||||
<button id="copy">copy to clipboard</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 PROJECT BY <a href="https://tilde.town/~vilmibm">~VILMIBM</a>.
|
||||
</p>
|
||||
</div>
|
||||
</center>
|
||||
<script>
|
||||
document.querySelectorAll("#paper span").forEach(span =>
|
||||
span.onclick = () => span.classList.toggle("black"));
|
||||
document.querySelector("#aboutToggle").onclick = (e) => {
|
||||
e.preventDefault();
|
||||
document.querySelector("#about").classList.toggle("hidden");
|
||||
}
|
||||
const copyButton = document.querySelector("#copy");
|
||||
copyButton.addEventListener("animationend", () => copyButton.classList.remove("rainbow"), false);
|
||||
copyButton.onclick = (e) => {
|
||||
let toCopy = "";
|
||||
document.querySelectorAll("#paper span").forEach(span => {
|
||||
let guts = span.innerHTML;
|
||||
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(() => {
|
||||
copyButton.classList.add("rainbow");
|
||||
}, (err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue