add remaining settings and navigation pages

This commit is contained in:
2026-02-13 23:15:09 -08:00
parent 78bc1a9974
commit 90121b4fd1
6 changed files with 196 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
<!--
version: "2.0"
unicode: "f69e"
-->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M14.647 4.081a.724 .724 0 0 0 1.08 .448c2.439 -1.485 5.23 1.305 3.745 3.744a.724 .724 0 0 0 .447 1.08c2.775 .673 2.775 4.62 0 5.294a.724 .724 0 0 0 -.448 1.08c1.485 2.439 -1.305 5.23 -3.744 3.745a.724 .724 0 0 0 -1.08 .447c-.673 2.775 -4.62 2.775 -5.294 0a.724 .724 0 0 0 -1.08 -.448c-2.439 1.485 -5.23 -1.305 -3.745 -3.744a.724 .724 0 0 0 -.447 -1.08c-2.775 -.673 -2.775 -4.62 0 -5.294a.724 .724 0 0 0 .448 -1.08c-1.485 -2.439 1.305 -5.23 3.744 -3.745a.722 .722 0 0 0 1.08 -.447c.673 -2.775 4.62 -2.775 5.294 0zm-2.647 4.919a3 3 0 1 0 0 6a3 3 0 0 0 0 -6" />
</svg>

After

Width:  |  Height:  |  Size: 732 B

View File

@@ -0,0 +1,14 @@
<!--
version: "2.39"
unicode: "fd19"
-->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M12 2a5 5 0 1 1 -5 5l.005 -.217a5 5 0 0 1 4.995 -4.783z" />
<path d="M14 14a5 5 0 0 1 5 5v1a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-1a5 5 0 0 1 5 -5h4z" />
</svg>

After

Width:  |  Height:  |  Size: 328 B

32
static/menu.js Normal file
View File

@@ -0,0 +1,32 @@
document.addEventListener('DOMContentLoaded', function() {
const menuButton = document.getElementById('menuButton');
const sideMenu = document.getElementById('sideMenu');
const menuOverlay = document.getElementById('menuOverlay');
function toggleMenu() {
menuButton.classList.toggle('active');
sideMenu.classList.toggle('active');
menuOverlay.classList.toggle('active');
}
function closeMenu() {
menuButton.classList.remove('active');
sideMenu.classList.remove('active');
menuOverlay.classList.remove('active');
}
if (menuButton) {
menuButton.addEventListener('click', toggleMenu);
}
if (menuOverlay) {
menuOverlay.addEventListener('click', closeMenu);
}
// Close menu on escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeMenu();
}
});
});

51
templates/base.gohtml Normal file
View File

@@ -0,0 +1,51 @@
{{define "base"}}
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="/files/style.css" type="text/css">
<title>{{.Title}}</title>
{{block "head" .}}{{end}}
</head>
<body>
<!-- Hamburger Menu Button -->
<div class="menu-button" id="menuButton">
<span></span>
<span></span>
<span></span>
</div>
<!-- Slide-out Menu -->
<div class="side-menu" id="sideMenu">
<div class="menu-header">
<h3>muzi</h3>
</div>
<nav class="menu-nav">
{{if .LoggedInUsername}}
<a href="/profile/{{.LoggedInUsername}}" class="menu-item">
<img src="/files/assets/icons/user.svg" class="menu-icon" alt="Profile">
<span>My Profile</span>
</a>
{{else}}
<a href="/login" class="menu-item">
<img src="/files/assets/icons/user.svg" class="menu-icon" alt="Login">
<span>Login</span>
</a>
{{end}}
<a href="/settings" class="menu-item">
<img src="/files/assets/icons/settings.svg" class="menu-icon" alt="Settings">
<span>Settings</span>
</a>
</nav>
</div>
<!-- Overlay for closing menu -->
<div class="menu-overlay" id="menuOverlay"></div>
<!-- Main Content -->
{{ if eq .TemplateName "profile"}}{{block "profile" .}}{{end}}{{end}}
{{ if eq .TemplateName "settings"}}{{block "settings" .}}{{end}}{{end}}
<script src="/files/menu.js"></script>
</body>
</html>
{{end}}

59
templates/settings.gohtml Normal file
View File

@@ -0,0 +1,59 @@
{{define "settings"}}
<div class="settings-container">
<h1>Settings</h1>
<!-- Tab Navigation -->
<div class="settings-tabs">
<button class="tab-button active" data-tab="import">Import Data</button>
</div>
<!-- Tab Content -->
<div class="tab-content">
<!-- Import Data Tab -->
<div class="tab-panel active" id="import">
<div class="import-section">
<h2>Spotify</h2>
<p>Import your Spotify listening history from your data export.</p>
<form id="spotify-form" method="POST" action="/settings/import/spotify" enctype="multipart/form-data">
<input type="file" name="json_files" accept=".json,application/json" multiple required>
<button type="submit">Upload Spotify Data</button>
</form>
<div id="spotify-progress" class="progress-container" style="display: none;">
<div class="progress-status" id="spotify-progress-status">Initializing...</div>
<div class="progress-bar-wrapper">
<div class="progress-bar-fill" id="spotify-progress-fill"></div>
<div class="progress-text" id="spotify-progress-text">0%</div>
</div>
<div class="progress-tracks" id="spotify-progress-tracks"></div>
<div class="progress-error" id="spotify-progress-error"></div>
<div class="progress-success" id="spotify-progress-success"></div>
</div>
</div>
<div class="import-section">
<h2>Last.fm</h2>
<p>Import your Last.fm scrobbles.</p>
<form id="lastfm-form" method="POST" action="/settings/import/lastfm">
<input type="text" name="lastfm_username" placeholder="Last.FM Username" required>
<input type="text" name="lastfm_api_key" placeholder="Last.FM API Key" required>
<button type="submit">Import from Last.fm</button>
</form>
<div id="lastfm-progress" class="progress-container" style="display: none;">
<div class="progress-status" id="lastfm-progress-status">Initializing...</div>
<div class="progress-bar-wrapper">
<div class="progress-bar-fill" id="lastfm-progress-fill"></div>
<div class="progress-text" id="lastfm-progress-text">0%</div>
</div>
<div class="progress-tracks" id="lastfm-progress-tracks"></div>
<div class="progress-error" id="lastfm-progress-error"></div>
<div class="progress-success" id="lastfm-progress-success"></div>
</div>
</div>
</div>
</div>
</div>
<script src="/files/import.js"></script>
{{end}}

27
web/settings.go Normal file
View File

@@ -0,0 +1,27 @@
package web
import "net/http"
func settingsPageHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
username := getLoggedInUsername(r)
if username == "" {
http.Redirect(w, r, "/login", http.StatusSeeOther)
return
}
type data struct {
Title string
LoggedInUsername string
TemplateName string
}
d := data{
Title: "muzi | Settings",
LoggedInUsername: username,
TemplateName: "settings",
}
err := templates.ExecuteTemplate(w, "base", d)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
}