]> littlesong.place Git - littlesongplace.git/commitdiff
Use icons in more places, revamp song page
authorChris Fulljames <christianfulljames@gmail.com>
Sun, 23 Feb 2025 13:33:05 +0000 (08:33 -0500)
committerChris Fulljames <christianfulljames@gmail.com>
Sun, 23 Feb 2025 13:33:35 +0000 (08:33 -0500)
main.py
static/lsp_btn_add02.gif [new file with mode: 0644]
static/styles.css
templates/playlist.html
templates/profile.html
templates/song-list.html
templates/song-macros.html [new file with mode: 0644]
templates/song.html
test/test_offline.py
todo.txt

diff --git a/main.py b/main.py
index 5e81a87ed29259fe51ad009f72e63a9b348b6984..521065811ff00d4f74bb320ff7586410e0bd58b1 100644 (file)
--- a/main.py
+++ b/main.py
@@ -287,10 +287,11 @@ def upload_song():
     if not "userid" in session:
         return redirect("/login")  # Must be logged in to edit
 
+    userid = session["userid"]
+
     error = validate_song_form()
 
     if not error:
-        userid = session["userid"]
         if "songid" in request.args:
             error = update_song()
         else:
@@ -299,7 +300,12 @@ def upload_song():
     if not error:
         username = session["username"]
         app.logger.info(f"{username} uploaded/modified a song")
-        return redirect(f"/users/{username}")
+        if "songid" in request.args:
+            # After editing an existing song, go back to song page
+            return redirect(f"/song/{userid}/{request.args['songid']}?action=view")
+        else:
+            # After creating a new song, go back to profile
+            return redirect(f"/users/{username}")
 
     else:
         username = session["username"]
@@ -525,7 +531,7 @@ def delete_song(songid):
     app.logger.info(f"{session['username']} deleted song: {song_data['title']}")
     flash_and_log(f"Deleted '{song_data['title']}'", "success")
 
-    return redirect(request.referrer)
+    return redirect(f"/users/{session['username']}")
 
 @app.get("/song/<int:userid>/<int:songid>")
 def song(userid, songid):
diff --git a/static/lsp_btn_add02.gif b/static/lsp_btn_add02.gif
new file mode 100644 (file)
index 0000000..38ec190
Binary files /dev/null and b/static/lsp_btn_add02.gif differ
index c79f8c6b91af3b982c6bc8abc8fe894f319dc156..f539dbb0060967ef9b97f8cc0eb39075f824fc78 100644 (file)
@@ -304,7 +304,7 @@ div.song-list {
     gap: 10px;
 }
 
-div.song {
+.song-list .song {
     box-shadow: 0px 0px 5px 0px;
     border-radius: 10px;
 }
@@ -372,6 +372,9 @@ div.song-details {
     flex-direction: column;
     gap: 15px;
     align-items: left;
+}
+
+.song .song-details {
     margin: 10px;
 }
 
index e0aed6396acb66df2644f3d9160d487bb0ad3f0a..20ec14311df4784047cc870310ec8587e2133bbb 100644 (file)
@@ -22,8 +22,8 @@ Playlist by <a href="/users/{{ username }}" class="profile-link">{{ username }}<
 
 {% if session["userid"] == userid -%}
 <p class="playlist-actions">
-<button class="button" onclick="showPlaylistEditor()">Edit</button>
-<a href="/delete-playlist/{{ playlistid }}" class="button" onclick="return confirm('Are you sure you want to delete this playlist?')">Delete</a>
+<button class="song-list-button" onclick="showPlaylistEditor()" title="Edit"><img class="lsp_btn_edit02" /></button>
+<a href="/delete-playlist/{{ playlistid }}" class="song-list-button" onclick="return confirm('Are you sure you want to delete this playlist?')" title="Delete"><img class="lsp_btn_delete02" /></a>
 </p>
 
 <script>
index 9a9c8eff4367b635361cd99618c0005ee7b19912..1ee5697a32816d401c119f23fc0e0322c1eaf0d5 100644 (file)
@@ -27,7 +27,7 @@
 {% if session["userid"] == userid %}
 
 <div class="profile-action">
-    <button class="button" onclick="showEditForm()" id="profile-bio-edit-btn">Edit Profile</button>
+    <button class="song-list-button" onclick="showEditForm()" id="profile-bio-edit-btn" title="Edit Profile"><img class="lsp_btn_edit02" /></button>
 </div>
 
 <form id="profile-edit-form" action="/edit-profile" method="post" enctype="multipart/form-data" hidden>
 <!-- Add Playlist button/form -->
 {% if session["userid"] == userid -%}
 <div class="profile-action">
-    <button type="button" class="button" id="add-playlist-button" onclick="showAddPlaylist()">Add Playlist</button>
+    <button type="button" class="song-list-button" id="add-playlist-button" onclick="showAddPlaylist()" title="Add Playlist"><img class="lsp_btn_add02" /></button>
     <form action="/create-playlist" method="post" id="create-playlist-form" hidden>
         <label for="name">Playlist Name</label><br>
         <input name="name" type="text" maxlength="100" /><br>
 <!-- Add Song button -->
 {% if session["userid"] == userid %}
 <div class="profile-action">
-    <a class="button" href="/edit-song">Add Song</a>
+    <a class="song-list-button" href="/edit-song" title="Add Song"><img class="lsp_btn_add02" /></a>
 </div>
 {% endif %}
 
index f641ed0e79f7e5e86cfbcffee1561de2f6f6ea3f..0b5ac2eaed5608a696a2cae255e61d2b443a8188 100644 (file)
@@ -1,3 +1,5 @@
+{% from "song-macros.html" import song_info, song_details %}
+
 <div class="song-list">
 {% for song in songs %}
     <div class="song" data-song="{{ song.json() }}">
                 {%- endif %}
             </div>
 
-            <div class="song-info">
-                <!-- Song Title -->
-                <div class="song-title"><a href="/song/{{ song.userid }}/{{ song.songid }}?action=view">{{ song.title }}</a></div>
-
-                <!-- Separator -->
-                <div class="song-info-sep">
-                    -
-                </div>
+            {{ song_info(song) | indent(12) }}
 
-                <!-- Song Artist(s) -->
-                <div class="song-artist">
-                    <a href="/users/{{ song.username }}" class="profile-link">{{ song.username }}</a>
-
-                    <!-- Song Collaborators -->
-                    {% for collab in song.collaborators %}
-                    {% if collab.startswith("@") -%}
-                    <a href="/users/{{ collab[1:] }}" class="profile-link">{{ collab[1:] }}</a>
-                    {%- else -%}
-                    <span class="collab-name">{{ collab }}</span>
-                    {%- endif %}
-                    {% endfor %}
-                </div>
-            </div>
             <div class="song-buttons">
-
-                {% if session["userid"] == song.userid and is_profile_song_list -%}
-                <!-- Owner-Specific Buttons (Edit/Delete) -->
-                <a href="/edit-song?songid={{ song.songid }}" class="song-list-button">
-                    <img class="lsp_btn_edit02" alt="Edit">
-                </a>
-                <a href="/delete-song/{{ song.songid }}" onclick="return confirm(&#34;Are you sure you want to delete this song?&#34;)" class="song-list-button">
-                    <img class="lsp_btn_delete02" alt="Delete">
-                </a>
-                {%- endif %}
-
                 <!-- Details Button -->
-                <button onclick="return showDetails(event)" class="song-list-button details-toggle">
+                <button onclick="return showDetails(event)" class="song-list-button details-toggle" title="Toggle Details">
                     <img class="lsp_btn_show02" alt="Show Details">
                 </button>
 
                 <!-- Play Button -->
-                <button onclick="return play(event)" class="song-list-button">
+                <button onclick="return play(event)" class="song-list-button" title="Play">
                     <img class="lsp_btn_play02" alt="Play">
                 </button>
             </div>
         </div>
-
-        <div class="song-details" {% if request.endpoint != 'song' %}hidden{% endif %}>
-            {% if current_user_playlists -%}
-            <!-- Add to Playlist Buttons -->
-            <div class="song-playlist-controls">
-                <form action="/append-to-playlist" method="post">
-                    <input type="hidden" name="songid" value="{{ song.songid }}" id="playlist-selector-songid"/>
-                    <select name="playlistid" onchange="this.closest('form').requestSubmit()">
-                        <option value="-1">Add to Playlist...</option>
-                        {% for plist in current_user_playlists -%}
-                        <option value="{{ plist.playlistid }}">{{ plist['name'] }}</option>
-                        {%- endfor %}
-                    </select>
-                </form>
-            </div>
-            {%- endif %}
-
-            {% if song.description -%}
-            <!-- Song Description -->
-            <div class="song-description">{{ (song.description.replace("\n", "<br>"))|safe  }}</div>
-            {%- endif %}
-
-            {% if song.tags -%}
-            <!-- Song Tags -->
-            <div class="song-tags">
-                Tags:
-                {% for tag in song.tags %}
-                <a href="/songs?user={{ song.username }}&tag={{ tag }}">{{ tag }}</a>
-                {% endfor %}
-            </div>
-            {%- endif %}
-
-            <div class="song-date">
-                Uploaded {{ song.created }}
-            </div>
-
-            <!-- Song Comments -->
-            <div class="song-comments">
-                Comments:<br>
-                {% if session['userid'] %}
-                <a href="/comment?songid={{ song.songid }}">Add a Comment</a>
-                {% endif %}
-
-                {% for comment in song.get_comments() %}
-                <div class="top-level-comment">
-
-                    <a href="/users/{{ comment['username'] }}" class="profile-link">{{ comment['username'] }}</a>:
-                    {{ (comment['content'].replace("\n", "<br>"))|safe }}
-
-                    {% if session['userid'] == comment['userid'] or session['userid'] == song.userid %}
-                    <div class="comment-button-container">
-                    {% endif %}
-
-                        <!-- Only commenter can edit comment -->
-                        {% if session['userid'] == comment['userid'] %}
-                        <a href="/comment?commentid={{ comment['commentid'] }}&songid={{ song.songid }}" class="comment-button">
-                            Edit
-                        </a>
-                        {% endif %}
-
-                        <!-- Commenter and song owner can delete comment -->
-                        {% if session['userid'] == comment['userid'] or session['userid'] == song.userid %}
-                        <a href="/delete-comment/{{ comment['commentid'] }}" onclick="return confirm(&#34;Are you sure you want to delete this comment?&#34;)" class="comment-button">
-                            Delete
-                        </a>
-                        {% endif %}
-
-                    {% if session['userid'] == comment['userid'] or session['userid'] == song.userid %}
-                    </div>
-                    {% endif %}
-
-                    {% for reply in comment['replies'] %}
-                    <div class="reply-comment">
-
-                        <a href="/users/{{ reply['username'] }}" class="profile-link">{{ reply['username'] }}</a>:
-                        {{ reply['content'] }}
-
-                        {% if session['userid'] == reply['userid'] or session['userid'] == song.userid %}
-                        <div class="comment-button-container">
-                        {% endif %}
-
-                            <!-- Only commenter can edit comment -->
-                            {% if session['userid'] == reply['userid'] %}
-                            <a href="/comment?commentid={{ reply['commentid'] }}&songid={{ song.songid }}&replytoid={{ comment['commentid'] }}" class="comment-button">
-                                Edit
-                            </a>
-                            {% endif %}
-
-                            <!-- Commenter and song owner can delete comment -->
-                            {% if session['userid'] == reply['userid'] or session['userid'] == song.userid %}
-                            <a href="/delete-comment/{{ reply['commentid'] }}" onclick="return confirm(&#34;Are you sure you want to delete this comment?&#34;)" class="comment-button">
-                                Delete
-                            </a>
-                            {% endif %}
-
-                        {% if session['userid'] == reply['userid'] or session['userid'] == song.userid %}
-                        </div>
-                        {% endif %}
-                    </div>
-                    {% endfor %}
-
-                    <div class="comment-button-container">
-                        <a href="/comment?songid={{ song.songid }}&replytoid={{ comment['commentid'] }}">Reply</a>
-                    </div>
-                </div>
-                {% endfor %}
-            </div>
-        </div>
+        {{ song_details(song, current_user_playlists) | indent(8) }}
     </div>
 {% endfor %}
 </div>
diff --git a/templates/song-macros.html b/templates/song-macros.html
new file mode 100644 (file)
index 0000000..3e954b4
--- /dev/null
@@ -0,0 +1,139 @@
+{% macro song_artist(song) %}
+<span class="song-artist">
+    <a href="/users/{{ song.username }}" class="profile-link">{{ song.username }}</a>
+
+    <!-- Song Collaborators -->
+    {% for collab in song.collaborators %}
+    {% if collab.startswith("@") -%}
+    <a href="/users/{{ collab[1:] }}" class="profile-link">{{ collab[1:] }}</a>
+    {%- else -%}
+    <span class="collab-name">{{ collab }}</span>
+    {%- endif %}
+    {% endfor %}
+</span>
+{% endmacro %}
+
+{% macro song_info(song) %}
+<div class="song-info">
+    <!-- Song Title -->
+    <div class="song-title"><a href="/song/{{ song.userid }}/{{ song.songid }}?action=view">{{ song.title }}</a></div>
+
+    <!-- Separator -->
+    <div class="song-info-sep">
+        -
+    </div>
+
+    <!-- Song Artist(s) -->
+    {{ song_artist(song) | indent(4) }}
+</div>
+{% endmacro %}
+
+{% macro song_details(song, current_user_playlists, hidden=True) %}
+<div class="song-details" {% if hidden %}hidden{% endif %}>
+    {% if current_user_playlists -%}
+    <!-- Add to Playlist Buttons -->
+    <div class="song-playlist-controls">
+        <form action="/append-to-playlist" method="post">
+            <input type="hidden" name="songid" value="{{ song.songid }}" id="playlist-selector-songid"/>
+            <select name="playlistid" onchange="this.closest('form').requestSubmit()">
+                <option value="-1">Add to Playlist...</option>
+                {% for plist in current_user_playlists -%}
+                <option value="{{ plist.playlistid }}">{{ plist['name'] }}</option>
+                {%- endfor %}
+            </select>
+        </form>
+    </div>
+    {%- endif %}
+
+    {% if song.description -%}
+    <!-- Song Description -->
+    <div class="song-description">{{ (song.description.replace("\n", "<br>"))|safe  }}</div>
+    {%- endif %}
+
+    {% if song.tags -%}
+    <!-- Song Tags -->
+    <div class="song-tags">
+        Tags:
+        {% for tag in song.tags %}
+        <a href="/songs?user={{ song.username }}&tag={{ tag }}">{{ tag }}</a>
+        {% endfor %}
+    </div>
+    {%- endif %}
+
+    <div class="song-date">
+        Uploaded {{ song.created }}
+    </div>
+
+    <!-- Song Comments -->
+    <div class="song-comments">
+        Comments:<br>
+        {% if session['userid'] %}
+        <a href="/comment?songid={{ song.songid }}" class="song-list-button" title="Add a Comment"><img class="lsp_btn_add02" /></a>
+        {% endif %}
+
+        {% for comment in song.get_comments() %}
+        <div class="top-level-comment">
+
+            <a href="/users/{{ comment['username'] }}" class="profile-link">{{ comment['username'] }}</a>:
+            {{ (comment['content'].replace("\n", "<br>"))|safe }}
+
+            {% if session['userid'] == comment['userid'] or session['userid'] == song.userid %}
+            <div class="comment-button-container">
+            {% endif %}
+
+                <!-- Only commenter can edit comment -->
+                {% if session['userid'] == comment['userid'] %}
+                <a href="/comment?commentid={{ comment['commentid'] }}&songid={{ song.songid }}" class="comment-button">
+                    Edit
+                </a>
+                {% endif %}
+
+                <!-- Commenter and song owner can delete comment -->
+                {% if session['userid'] == comment['userid'] or session['userid'] == song.userid %}
+                <a href="/delete-comment/{{ comment['commentid'] }}" onclick="return confirm(&#34;Are you sure you want to delete this comment?&#34;)" class="comment-button">
+                    Delete
+                </a>
+                {% endif %}
+
+            {% if session['userid'] == comment['userid'] or session['userid'] == song.userid %}
+            </div>
+            {% endif %}
+
+            {% for reply in comment['replies'] %}
+            <div class="reply-comment">
+
+                <a href="/users/{{ reply['username'] }}" class="profile-link">{{ reply['username'] }}</a>:
+                {{ reply['content'] }}
+
+                {% if session['userid'] == reply['userid'] or session['userid'] == song.userid %}
+                <div class="comment-button-container">
+                {% endif %}
+
+                    <!-- Only commenter can edit comment -->
+                    {% if session['userid'] == reply['userid'] %}
+                    <a href="/comment?commentid={{ reply['commentid'] }}&songid={{ song.songid }}&replytoid={{ comment['commentid'] }}" class="comment-button">
+                        Edit
+                    </a>
+                    {% endif %}
+
+                    <!-- Commenter and song owner can delete comment -->
+                    {% if session['userid'] == reply['userid'] or session['userid'] == song.userid %}
+                    <a href="/delete-comment/{{ reply['commentid'] }}" onclick="return confirm(&#34;Are you sure you want to delete this comment?&#34;)" class="comment-button">
+                        Delete
+                    </a>
+                    {% endif %}
+
+                {% if session['userid'] == reply['userid'] or session['userid'] == song.userid %}
+                </div>
+                {% endif %}
+            </div>
+            {% endfor %}
+
+            <div class="comment-button-container">
+                <a href="/comment?songid={{ song.songid }}&replytoid={{ comment['commentid'] }}">Reply</a>
+            </div>
+        </div>
+        {% endfor %}
+    </div>
+</div>
+{% endmacro %}
index 032421addf405c529d03f6449d7fa7058c3bdab6..6e1e49f6c08d63144179b9598616d8d0a0ea2c35 100644 (file)
@@ -1,4 +1,5 @@
 {% extends "base.html" %}
+{% from "song-macros.html" import song_artist, song_details %}
 
 {% block head %}
 <meta property="og:title" content="{{ song.title }}" />
@@ -9,6 +10,23 @@
 
 {% block body %}
 
-{% include "song-list.html" %}
+<h1>{{ song.title }}</h1>
+
+<p>Song by {{ song_artist(song) }}</p>
+
+<p class="song-actions">
+<!-- Play Button -->
+<span class="song" data-song="{{ song.json() }}">
+    <button onclick="return play(event)" class="song-list-button" title="Play">
+        <img class="lsp_btn_play02" alt="Play">
+    </button>
+</span>
+{% if session["userid"] == song.userid -%}
+<a href="/edit-song?songid={{ song.songid }}" class="song-list-button" title="Edit"><img class="lsp_btn_edit02" /></a>
+<a href="/delete-song/{{ song.songid }}" class="song-list-button" onclick="return confirm('Are you sure you want to delete this song?')" title="Delete"><img class="lsp_btn_delete02" /></a>
+{%- endif %}
+</p>
+
+{{ song_details(song, current_user_playlists, hidden=False) }}
 
 {% endblock %}
index 822e286943269dbc2f235ebf6039ab39cdcd3bdb..9d9389b664442364c02c69391a2bc90e47419f32 100644 (file)
@@ -474,7 +474,7 @@ def test_delete_song_success(client):
     _create_user_and_song(client)
     response = client.get("/delete-song/1")
     assert response.status_code == 302
-    assert response.headers["Location"] == "None"
+    assert response.headers["Location"] == "/users/user"
 
     response = client.get("/")
     assert b"Deleted &#39;song title&#39;" in response.data
@@ -691,7 +691,7 @@ def test_delete_song_with_comments(client):
     _create_user_song_and_comment(client, "comment text here")
     response = client.get("/delete-song/1")
     assert response.status_code == 302
-    assert response.headers["Location"] == "None" # No previous page, use homepage
+    assert response.headers["Location"] == "/users/user"
 
     response = client.get("/song/1/1?action=view")
     assert response.status_code == 404  # Song deleted
index 40011227a644c3078c779d523555b00ce3a2b412..aba571b4e776eb4dbd0d8f59ee1b400fafa074ad 100644 (file)
--- a/todo.txt
+++ b/todo.txt
@@ -1,6 +1,8 @@
 NOW
 
 SOON
+- Hide playlists & songs while editing profile
+- Use edit/delete icons in comments
 - Break up main.py, test_offline.py
 - Pinned profile playlists
 - Image support in comments, descriptions, bios, etc.