optimised templates, broke tracks, improved music gateway UX. we ball

Signed-off-by: ari melody <ari@arimelody.me>
This commit is contained in:
ari melody 2024-03-21 05:19:18 +00:00
parent 6ec813dd58
commit 18c13699af
17 changed files with 593 additions and 496 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
**/.DS_Store **/.DS_Store
.idea/
tmp/ tmp/

View file

@ -619,7 +619,7 @@ var placeholders = []MusicRelease{
}, },
} }
func GetAlbum(id string) (MusicRelease, bool) { func GetRelease(id string) (MusicRelease, bool) {
for _, album := range placeholders { for _, album := range placeholders {
if album.Id == id { if album.Id == id {
return album, true return album, true
@ -628,7 +628,7 @@ func GetAlbum(id string) (MusicRelease, bool) {
return MusicRelease{}, false return MusicRelease{}, false
} }
func QueryAllAlbums() ([]MusicRelease) { func QueryAllMusic() ([]MusicRelease) {
return placeholders return placeholders
} }

63
main.go
View file

@ -30,13 +30,12 @@ var mime_types = map[string]string{
"js": "application/javascript", "js": "application/javascript",
} }
var templates = template.Must(template.ParseFiles( var base_template = template.Must(template.ParseFiles(
"views/base.html",
"views/header.html", "views/header.html",
"views/footer.html", "views/footer.html",
"views/index.html",
"views/music.html",
"views/music-gateway.html",
)) ))
var htmx_template = template.Must(template.New("root").Parse(`<head>{{block "head" .}}{{end}}</head>{{block "content" .}}{{end}}`))
func log_request(req *http.Request, code int, start_time time.Time) { func log_request(req *http.Request, code int, start_time time.Time) {
now := time.Now() now := time.Now()
@ -56,31 +55,41 @@ func log_request(req *http.Request, code int, start_time time.Time) {
) )
} }
func web_handler(writer http.ResponseWriter, req *http.Request) { func handle_request(writer http.ResponseWriter, req *http.Request) {
uri := req.URL.Path uri := req.URL.Path
start_time := time.Now() start_time := time.Now()
hx_boosted := len(req.Header["Hx-Boosted"]) > 0 && req.Header["Hx-Boosted"][0] == "true"
code := func(writer http.ResponseWriter, req *http.Request) int {
var root *template.Template
if hx_boosted {
root = template.Must(htmx_template.Clone())
} else {
root = template.Must(base_template.Clone())
}
if req.URL.Path == "/" { if req.URL.Path == "/" {
code := index_handler(writer, req) return index_handler(writer, root)
log_request(req, code, start_time)
return
} }
if uri == "/music" { if uri == "/music" {
code := music_handler(writer, req) return music_directory_handler(writer, root)
log_request(req, code, start_time)
return
} }
if strings.HasPrefix(uri, "/music/") { if strings.HasPrefix(uri, "/music/") {
code := music_gateway_handler(writer, req) return music_gateway_handler(writer, req, root)
log_request(req, code, start_time)
return
} }
code := static_handler(writer, req)
return static_handler(writer, req)
}(writer, req)
log_request(req, code, start_time) log_request(req, code, start_time)
} }
func index_handler(writer http.ResponseWriter, req *http.Request) int { func index_handler(writer http.ResponseWriter, root *template.Template) int {
err := templates.ExecuteTemplate(writer, "index.html", nil) index_template := template.Must(root.ParseFiles("views/index.html"))
err := index_template.Execute(writer, nil)
if err != nil { if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError) http.Error(writer, err.Error(), http.StatusInternalServerError)
return 500 return 500
@ -88,8 +97,10 @@ func index_handler(writer http.ResponseWriter, req *http.Request) int {
return 200 return 200
} }
func music_handler(writer http.ResponseWriter, req *http.Request) int { func music_directory_handler(writer http.ResponseWriter, root *template.Template) int {
err := templates.ExecuteTemplate(writer, "music.html", music.QueryAllAlbums()) music_template := template.Must(root.ParseFiles("views/music.html"))
music := music.QueryAllMusic()
err := music_template.Execute(writer, music)
if err != nil { if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError) http.Error(writer, err.Error(), http.StatusInternalServerError)
return 500 return 500
@ -97,7 +108,7 @@ func music_handler(writer http.ResponseWriter, req *http.Request) int {
return 200 return 200
} }
func music_gateway_handler(writer http.ResponseWriter, req *http.Request) int { func music_gateway_handler(writer http.ResponseWriter, req *http.Request, root *template.Template) int {
if len(req.URL.Path) <= len("/music/") { if len(req.URL.Path) <= len("/music/") {
http.Error(writer, "400 bad request", http.StatusBadRequest) http.Error(writer, "400 bad request", http.StatusBadRequest)
return 400 return 400
@ -106,12 +117,13 @@ func music_gateway_handler(writer http.ResponseWriter, req *http.Request) int {
id := req.URL.Path[len("/music/"):] id := req.URL.Path[len("/music/"):]
// http.Redirect(writer, req, "https://mellodoot.com/music/"+title, 302) // http.Redirect(writer, req, "https://mellodoot.com/music/"+title, 302)
// return // return
album, ok := music.GetAlbum(id) release, ok := music.GetRelease(id)
if !ok { if !ok {
http.Error(writer, "404 not found", http.StatusNotFound) http.Error(writer, "404 not found", http.StatusNotFound)
return 404 return 404
} }
err := templates.ExecuteTemplate(writer, "music-gateway.html", album) gateway_template := template.Must(root.ParseFiles("views/music-gateway.html"))
err := gateway_template.Execute(writer, release)
if err != nil { if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError) http.Error(writer, err.Error(), http.StatusInternalServerError)
return 500 return 500
@ -180,22 +192,21 @@ func parse_markdown(md []byte) []byte {
func push_to_db_this_is_a_testing_thing_and_will_be_superfluous_later() { func push_to_db_this_is_a_testing_thing_and_will_be_superfluous_later() {
db := InitDatabase() db := InitDatabase()
defer db.Close()
for _, artist := range music.QueryAllArtists() { for _, artist := range music.QueryAllArtists() {
PushArtist(db, artist) PushArtist(db, artist)
} }
for _, album := range music.QueryAllAlbums() { for _, album := range music.QueryAllMusic() {
PushRelease(db, album) PushRelease(db, album)
} }
defer db.Close()
} }
func main() { func main() {
push_to_db_this_is_a_testing_thing_and_will_be_superfluous_later() push_to_db_this_is_a_testing_thing_and_will_be_superfluous_later()
http.HandleFunc("/", web_handler) http.HandleFunc("/", handle_request)
fmt.Printf("now serving at http://127.0.0.1:%d\n", PORT) fmt.Printf("now serving at http://127.0.0.1:%d\n", PORT)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", PORT), nil)) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", PORT), nil))

1
public/script/lib/htmx.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -55,3 +55,11 @@ function fill_list(list) {
fill_list(e); fill_list(e);
}); });
document.addEventListener("htmx:afterSwap", async event => {
const res = await event.detail.xhr.response;
var new_head = res.substring(res.indexOf("<head>")+1, res.indexOf("</head>"));
if (new_head) {
document.head.innerHTML = new_head;
}
window.scrollY = 0;
});

View file

@ -28,6 +28,34 @@ function apply_funny_bob_to_upcoming_tags() {
} }
} }
const extras_pairs = Array.from(document.querySelectorAll("div#info > div").values().map(container => {
return {
container,
button: document.getElementById("extras").querySelector(`ul li a[href="#${container.id}"]`)
};
}));
const info_container = document.getElementById("info")
info_container.addEventListener("scroll", update_extras_buttons);
function update_extras_buttons() {
console.clear();
const info_rect = info_container.getBoundingClientRect();
const info_y = info_rect.y;
const font_size = parseFloat(getComputedStyle(document.documentElement).fontSize);
console.log("info_y: " + info_y);
let current = extras_pairs[0];
extras_pairs.forEach(pair => {
pair.button.classList.remove("active");
const scroll_diff = pair.container.getBoundingClientRect().y -
info_rect.y -
info_rect.height / 2 +
4 * font_size;
if (scroll_diff <= 0) current = pair;
console.log(`${pair.container.id}: ${scroll_diff}`);
})
current.button.classList.add("active");
}
update_extras_buttons();
document.querySelectorAll("div#extras ul li a[href]").forEach(link => { document.querySelectorAll("div#extras ul li a[href]").forEach(link => {
link.addEventListener("click", event => { link.addEventListener("click", event => {
event.preventDefault(); event.preventDefault();

View file

@ -63,4 +63,4 @@ function load_pride_flag_style() {
load_pride_flag_style(); load_pride_flag_style();
pride_flag = create_pride_flag(); pride_flag = create_pride_flag();
document.body.appendChild(pride_flag); document.querySelector("main").appendChild(pride_flag);

View file

@ -3,7 +3,8 @@
main { main {
width: min(calc(100% - 4rem), 720px); width: min(calc(100% - 4rem), 720px);
min-height: calc(100vh - 10.3rem); min-height: calc(100vh - 10.3rem);
margin: 5rem auto 2rem auto; margin: 0 auto 2rem auto;
padding-top: 5rem;
} }
main h1 { main h1 {

View file

@ -21,6 +21,9 @@ body {
scroll-behavior: smooth; scroll-behavior: smooth;
} }
main {
}
a { a {
color: var(--links); color: var(--links);
text-decoration: none; text-decoration: none;

View file

@ -70,7 +70,6 @@ main {
gap: 4rem; gap: 4rem;
font-size: 16px; font-size: 16px;
animation: card-init .5s forwards; animation: card-init .5s forwards;
overflow-y: clip;
padding: 4rem; padding: 4rem;
} }
@ -97,7 +96,6 @@ main {
width: 33.3%; width: 33.3%;
height: 33.3%; height: 33.3%;
z-index: 2; z-index: 2;
/* pointer-events: none; */
} }
#art-container > div.tilt-topleft { #art-container > div.tilt-topleft {
@ -208,10 +206,25 @@ div#vertical-line {
} }
div#info { div#info {
display: flex; margin: -4rem;
flex-direction: column; padding: 4rem;
transition: transform .5s ease; height: 360px;
gap: 6rem; overflow: scroll;
scroll-behavior: smooth;
scrollbar-width: thin;
scrollbar-color: #111;
mask-image: linear-gradient(to bottom, transparent 0%, black 10%, black 90%, transparent 100%);
}
div#info > div {
min-height: 360px;
padding: 4rem 1rem 4rem 4rem;
margin: -4rem -3.5rem -4rem -4rem;
}
div#info p {
max-width: 500px;
white-space: pre-line;
} }
#title-container { #title-container {
@ -279,18 +292,26 @@ div#info {
display: inline-block; display: inline-block;
} }
#links { ul#links {
width: 100%;
margin: 1rem 0; margin: 1rem 0;
padding: 0;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
gap: .5rem gap: .5rem;
list-style: none;
} }
#links a { ul#links li {
padding: .5em .8em;
border-radius: 4px;
flex-grow: 1; flex-grow: 1;
}
ul#links a {
width: calc(100% - 1.6em);
padding: .5em .8em;
display: block;
border-radius: 4px;
font-size: 1em; font-size: 1em;
color: #111; color: #111;
background-color: #fff; background-color: #fff;
@ -299,31 +320,31 @@ div#info {
transition: filter .1s,-webkit-filter .1s transition: filter .1s,-webkit-filter .1s
} }
#links a.buy { ul#links a.buy {
background-color: #ff94e9 background-color: #ff94e9
} }
#links a.presave { ul#links a.presave {
background-color: #ff94e9 background-color: #ff94e9
} }
#links a.spotify { ul#links a.spotify {
background-color: #8cff83 background-color: #8cff83
} }
#links a.applemusic { ul#links a.applemusic {
background-color: #8cd9ff background-color: #8cd9ff
} }
#links a.soundcloud { ul#links a.soundcloud {
background-color: #fdaa6d background-color: #fdaa6d
} }
#links a.youtube { ul#links a.youtube {
background-color: #ff6e6e background-color: #ff6e6e
} }
#links a:hover { ul#links a:hover {
filter: brightness(125%); filter: brightness(125%);
-webkit-filter: brightness(125%) -webkit-filter: brightness(125%)
} }
@ -357,24 +378,11 @@ div#extras ul li a {
transition: color .1s linear; transition: color .1s linear;
} }
div#extras ul li a:hover { div#extras ul li a:hover,
div#extras ul li a.active {
color: #eee; color: #eee;
} }
div#info > div {
max-height: 360px;
min-height: 360px;
overflow-y: scroll;
padding: 2rem 1rem 2rem 4rem;
margin: -2rem -3.5rem -2rem -4rem;
mask-image: linear-gradient(to bottom, transparent 0%, black 10%, black 90%, transparent 100%);
}
div#info p {
max-width: 500px;
white-space: pre-line;
}
a.scrollback { a.scrollback {
color: #888; color: #888;
font-style: italic; font-style: italic;
@ -497,6 +505,7 @@ footer a:hover {
text-decoration: underline text-decoration: underline
} }
/*
@media only screen and (min-width: 1105px) { @media only screen and (min-width: 1105px) {
div#music-container:not(:has(> div#info #credits:target)):not(:has(> div#info #lyrics:target)) { div#music-container:not(:has(> div#info #credits:target)):not(:has(> div#info #lyrics:target)) {
div#extras ul li:first-of-type a { div#extras ul li:first-of-type a {
@ -505,23 +514,18 @@ footer a:hover {
} }
div#music-container:has(> div#info #credits:target) { div#music-container:has(> div#info #credits:target) {
div#info {
transform: translateY(calc(-360px + -6rem));
}
div#extras ul li a[href="#credits"] { div#extras ul li a[href="#credits"] {
color: #eee; color: #eee;
} }
} }
div#music-container:has(> div#info #lyrics:target) { div#music-container:has(> div#info #lyrics:target) {
div#info {
transform: translateY(calc((-360px + -6rem) * 2));
}
div#extras ul li a[href="#lyrics"] { div#extras ul li a[href="#lyrics"] {
color: #eee; color: #eee;
} }
} }
} }
*/
@media only screen and (max-width: 1105px) { @media only screen and (max-width: 1105px) {
main { main {
@ -557,11 +561,12 @@ footer a:hover {
div#info { div#info {
width: 100%; width: 100%;
gap: 2rem; gap: 2rem;
height: auto;
overflow-y: auto;
} }
div#info > div { div#info > div {
max-height: fit-content; min-height: auto;
min-height: fit-content;
padding: 0; padding: 0;
margin: 0; margin: 0;
overflow-y: unset; overflow-y: unset;

50
views/base.html Normal file
View file

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{block "head" .}}
<!-- <title>ari melody 💫</title> -->
<!-- <link rel="shortcut icon" href="img/favicon.png" type="image/x-icon"> -->
<!---->
<!-- <meta name="description" content="home to your local SPACEGIRL 💫"> -->
<!---->
<!-- <meta property="og:title" content="ari melody"> -->
<!-- <meta property="og:type" content="website"> -->
<!-- <meta property="og:url" content="www.arimelody.me"> -->
<!-- <meta property="og:image" content="https://www.arimelody.me/img/favicon.png"> -->
<!-- <meta property="og:site_name" content="ari melody"> -->
<!-- <meta property="og:description" content="home to your local SPACEGIRL 💫"> -->
<!---->
<!-- <link rel="stylesheet" href="style/main.css"> -->
<!---->
<!-- <script type="module" src="/script/main.js" defer></script> -->
{{end}}
<!-- <script type="application/javascript" src="/script/lib/htmx.min.js"></script> -->
</head>
<body>
{{template "header"}}
{{block "content" .}}
<main>
<h1>
# hello, world!
</h1>
<p>
this is a default page!
</p>
</main>
{{end}}
{{template "footer"}}
<div id="overlay"></div>
</body>
</html>

View file

@ -1,6 +1,6 @@
{{define "footer"}} {{define "footer"}}
<footer> <footer hx-preserve="true">
<div id="footer"> <div id="footer">
<small><em>*made with ♥ by ari, 2024*</em></small> <small><em>*made with ♥ by ari, 2024*</em></small>
</div> </div>

View file

@ -1,6 +1,6 @@
{{define "header"}} {{define "header"}}
<header> <header hx-preserve="true">
<nav> <nav>
<div id="header-home"> <div id="header-home">
<img src="/img/favicon.png" id="header-icon" width="100" height="100" alt=""> <img src="/img/favicon.png" id="header-icon" width="100" height="100" alt="">

28
views/htmx-base.html Normal file
View file

@ -0,0 +1,28 @@
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{block "head" .}}
<title>ari melody 💫</title>
<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon">
<meta name="description" content="home to your local SPACEGIRL 💫">
<meta property="og:title" content="ari melody">
<meta property="og:type" content="website">
<meta property="og:url" content="www.arimelody.me">
<meta property="og:image" content="https://www.arimelody.me/img/favicon.png">
<meta property="og:site_name" content="ari melody">
<meta property="og:description" content="home to your local SPACEGIRL 💫">
<link rel="stylesheet" href="style/main.css">
<script type="module" src="/script/main.js" defer></script>
{{end}}
<script type="application/javascript" src="/script/lib/htmx.min.js"></script>
</head>
{{block "content" .}}{{end}}

View file

@ -1,13 +1,6 @@
<!DOCTYPE html> {{define "head"}}
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ari melody 💫</title> <title>ari melody 💫</title>
<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon"> <link rel="shortcut icon" href="/img/favicon.png" type="image/x-icon">
<meta name="description" content="home to your local SPACEGIRL 💫"> <meta name="description" content="home to your local SPACEGIRL 💫">
@ -18,14 +11,13 @@
<meta property="og:site_name" content="ari melody"> <meta property="og:site_name" content="ari melody">
<meta property="og:description" content="home to your local SPACEGIRL 💫"> <meta property="og:description" content="home to your local SPACEGIRL 💫">
<link rel="stylesheet" href="style/index.css"> <link rel="stylesheet" href="/style/index.css">
<script type="module" src="/script/main.js" defer></script> <script type="module" src="/script/main.js" defer></script>
<link rel="me" href="https://wetdry.world/@ari"> <link rel="me" href="https://wetdry.world/@ari">
</head> {{end}}
<body>
{{block "header" .}}{{end}}
{{define "content"}}
<main> <main>
<h1> <h1>
# hello, world! # hello, world!
@ -187,9 +179,4 @@
</a> </a>
</div> </div>
</main> </main>
{{end}}
{{block "footer" .}}{{end}}
<div id="overlay"></div>
</body>
</html>

View file

@ -1,11 +1,4 @@
<!DOCTYPE html> {{define "head"}}
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.PrintPrimaryArtists}} - {{.Title}}</title> <title>{{.PrintPrimaryArtists}} - {{.Title}}</title>
<link rel="icon" href="{{.ResolveArtwork}}"> <link rel="icon" href="{{.ResolveArtwork}}">
@ -32,18 +25,17 @@
<meta name="twitter:image:alt" content="Cover art for &quot;{{.Title}}&quot;"> <meta name="twitter:image:alt" content="Cover art for &quot;{{.Title}}&quot;">
<script type="module" src="/script/music-gateway.js" defer></script> <script type="module" src="/script/music-gateway.js" defer></script>
<script type="text/javascript" src="/script/prideflag.js" defer></script> <script type="application/javascript" src="/script/prideflag.js" defer></script>
<link rel="stylesheet" href="/style/music-gateway.css"> <link rel="stylesheet" href="/style/music-gateway.css">
</head> {{end}}
<body>
{{define "content"}}
<main>
<div id="background" data-url="{{.ResolveArtwork}}"></div> <div id="background" data-url="{{.ResolveArtwork}}"></div>
<div id="overlay"></div> <div id="overlay"></div>
<a id="go-back" title="back to arimelody.me" href="/music">&lt;</a> <a id="go-back" title="back to arimelody.me" href="/music">&lt;</a>
{{block "header" .}}{{end}}
<main>
<div id="music-container"> <div id="music-container">
<div id="art-container"> <div id="art-container">
<div class="tilt-topleft"></div> <div class="tilt-topleft"></div>
@ -58,7 +50,7 @@
</div> </div>
<div id="vertical-line"></div> <div id="vertical-line"></div>
<div id="info"> <div id="info">
<div id="main"> <div id="overview">
<div id="title-container"> <div id="title-container">
<h1 id="title">{{.Title}}</h1> <h1 id="title">{{.Title}}</h1>
<span id="year" title="{{.PrintReleaseDate}}">{{.GetReleaseYear}}</span> <span id="year" title="{{.PrintReleaseDate}}">{{.GetReleaseYear}}</span>
@ -66,19 +58,19 @@
<p id="artist">{{.PrintPrimaryArtists}}</p> <p id="artist">{{.PrintPrimaryArtists}}</p>
<p id="type" class="{{.ResolveType}}">{{.ResolveType}}</p> <p id="type" class="{{.ResolveType}}">{{.ResolveType}}</p>
<div id="links"> <ul id="links">
{{if .Buylink}} {{if .Buylink}}
<a href="{{.Buylink}}" class="buy"> <li>
{{if .Buyname}}{{.Buyname}}{{else}}buy{{end}} <a href="{{.Buylink}}" class="buy">{{or .Buyname "buy"}}</a>
</a> </li>
{{end}} {{end}}
{{range .Links}} {{range .Links}}
<a class="{{.NormaliseName}}" href="{{.Url}}"> <li>
{{.Name}} <a class="{{.NormaliseName}}" href="{{.Url}}">{{.Name}}</a>
</a> </li>
{{end}} {{end}}
</div> </ul>
{{if .Description}} {{if .Description}}
<p id="description"> <p id="description">
@ -105,26 +97,26 @@
</div> </div>
{{end}} {{end}}
{{if .Lyrics}} <!-- {{if .Lyrics}} -->
<div id="lyrics"> <!-- <div id="lyrics"> -->
<h2>lyrics:</h2> <!-- <h2>lyrics:</h2> -->
<p>{{.Lyrics}}</p> <!-- <p>{{.Lyrics}}</p> -->
</div> <!-- </div> -->
{{end}} <!-- {{end}} -->
</div> </div>
{{if or .Credits .Lyrics}} {{if or .Credits .Lyrics}}
<div id="extras"> <div id="extras">
<ul> <ul>
<li><a href="#">overview</a></li> <li><a href="#overview">overview</a></li>
{{if .Credits}} {{if .Credits}}
<li><a href="#credits">credits</a></li> <li><a href="#credits">credits</a></li>
{{end}} {{end}}
{{if .Lyrics}} <!-- {{if .Lyrics}} -->
<li><a href="#lyrics">lyrics</a></li> <!-- <li><a href="#lyrics">lyrics</a></li> -->
{{end}} <!-- {{end}} -->
</ul> </ul>
</div> </div>
{{end}} {{end}}
@ -154,7 +146,4 @@
<!-- </div> --> <!-- </div> -->
</div> </div>
</main> </main>
{{end}}
{{block "footer" .}}{{end}}
</body>
</html>

View file

@ -1,11 +1,4 @@
<!DOCTYPE html> {{define "head"}}
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>music - ari melody 💫</title> <title>music - ari melody 💫</title>
<link rel="shortcut icon" href="/img/favicon.png" type="image/x-icon"> <link rel="shortcut icon" href="/img/favicon.png" type="image/x-icon">
@ -18,16 +11,13 @@
<meta property="og:site_name" content="ari melody"> <meta property="og:site_name" content="ari melody">
<meta property="og:description" content="music from your local SPACEGIRL 💫"> <meta property="og:description" content="music from your local SPACEGIRL 💫">
<link rel="stylesheet" href="/style/main.css">
<link rel="stylesheet" href="/style/music.css"> <link rel="stylesheet" href="/style/music.css">
<script type="module" src="/script/main.js" defer></script> <script type="module" src="/script/main.js" defer></script>
<script type="application/javascript" src="/script/accessibility.js" defer></script>
<script type="application/javascript" src="/script/music.js" defer></script> <script type="application/javascript" src="/script/music.js" defer></script>
</head> {{end}}
<body>
{{block "header" .}}{{end}}
{{define "content"}}
<main> <main>
<h1> <h1>
# my music # my music
@ -96,9 +86,4 @@
</p> </p>
</div> </div>
</main> </main>
{{end}}
{{block "footer" .}}{{end}}
<div id="overlay"></div>
</body>
</html>