import bcrypt
from flask import Blueprint, render_template, redirect, flash, g, request, current_app, session
-from . import comments, db
+from . import comments, db, users
from .logutils import flash_and_log
bp = Blueprint("auth", __name__)
if not "userid" in session:
return redirect("/login")
- g.userid = session["userid"]
- g.username = session["username"]
-
return f(*args, **kwargs)
return _wrapper
+@bp.before_app_request
+def load_user():
+ if "userid" in session:
+ g.userid = session["userid"]
+ g.username = session["username"]
+ g.user = users.by_id(g.userid)
+
var loggedIn = username ? true : false;
document.querySelectorAll(".nav-logged-in").forEach((e) => {e.hidden = !loggedIn;});
document.querySelectorAll(".nav-logged-out").forEach((e) => {e.hidden = loggedIn;});
- if (loggedIn) {
- document.getElementById("logged-in-status").innerText = `Signed in as ${username}`;
- document.getElementById("my-profile").href = `/users/${username}`;
- }
+ // if (loggedIn) {
+ // document.getElementById("logged-in-status").innerText = `signed in as ${username}`;
+ // document.getElementById("my-profile").href = `/users/${username}`;
+ // }
// Add event handler to navbar links to hide menu on mobile
document.querySelectorAll("#navbar a, #page-header div a").forEach((link) => {
data = parser.parseFromString(data, "text/html");
// Update main body content
- var newMainDiv = data.getElementById("main");
- var oldMainDiv = document.getElementById("main");
- document.body.replaceChild(newMainDiv, oldMainDiv);
+ var newOuterDiv = data.getElementById("outer");
+ var oldOuterDiv = document.getElementById("outer");
+ document.body.replaceChild(newOuterDiv, oldOuterDiv);
// Update flashed messages
var newFlashes = data.getElementById("flashes-container");
document.title = data.title;
// Load inline scripts (DOMParser disables these by default)
- var scripts = document.getElementById("main").getElementsByTagName("script");
+ var scripts = document.getElementById("outer").getElementsByTagName("script");
for (const script of scripts) {
var newScript = document.createElement("script");
newScript.type = script.type;
color: var(--black);
font-family: "Unageo", sans-serif;
border-color: var(--purple);
- max-width: 700px;
+ max-width: 1200px;
margin: auto;
}
padding: 8px;
}
-div.main {
- max-width: 700px;
- margin: auto;
+#outer {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+ gap: 20px;
+ margin-top: 20px;
+}
+
+#left {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+#main {
+ flex-grow: 2;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+#right {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.page-section {
+ border: 1px solid var(--black);
+ box-shadow: 4px 4px 0px 0px var(--black);
+ border-radius: var(--radius);
padding: 10px;
}
+.page-section-header {
+ font-size: 26px;
+ font-family: "Mat Saleh", sans-serif;
+ /*border: 2px solid var(--purple);*/
+ background: var(--purple);
+ color: var(--yellow);
+ border-radius: var(--radius) var(--radius) 0px 0px;
+ text-align: center;
+ position: relative;
+ left: -10px;
+ top: -10px;
+ padding: 5px 0px;
+ width: calc(100% + 20px);
+}
+
+#user-actions {
+ display: flex;
+ gap: 10px;
+ justify-content: space-evenly;
+ margin: 10px 0px 0px 0px;
+}
+
.flashes {
border: 3px solid var(--blue);
border-radius: var(--radius);
background-color: var(--yellow);
margin: 0px;
padding: 5px;
- box-sizing: border-box;
width: 100%;
height: 100%;
top: 0px;
justify-content: center;
align-items: center;
gap: 10px;
- padding-bottom: 10px;
+ margin: 10px;
+}
+
+#site-title {
+ padding: 10px 20px;
+}
+
+#site-title a {
+ font-family: "Mat Saleh", sans-serif;
+ color: var(--purple);
+ font-size: 2em;
}
@media screen and (min-width: 480px) {
#page-header {
width: auto;
- display: block;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
position: static;
- margin: 10px;
+ margin: 10px 0px;
box-shadow: 5px 5px 0px 0px var(--black);
border: 1px solid var(--black);
border-radius: var(--radius);
div.song-info {
font-family: "Unageo", sans-serif;
display: flex;
- flex-wrap: wrap;
- flex-direction: row;
+ flex-direction: column;
+ align-items: flex-start;
row-gap: 0px;
- column-gap: 10px;
- align-items: center;
flex-grow: 1;
margin: 5px 0px;
min-width: 0;
overflow: hidden;
}
-/* Artist on separate line for mobile */
-@media screen and (max-width: 480px) {
- div.song-info {
- flex-direction: column;
- align-items: flex-start;
- }
-
- div.song-info-sep {
- display: none;
- }
-}
-
.song-title a {
text-decoration: none;
}
div.player-container {
position: fixed;
- max-width: 700px;
+ max-width: 1200px;
margin: auto;
bottom: 0;
left: 0;
<button id="mobile-hide-header-btn" onclick="hideNavMenu()">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><g fill="none" fill-rule="evenodd"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="m12 14.122l5.303 5.303a1.5 1.5 0 0 0 2.122-2.122L14.12 12l5.304-5.303a1.5 1.5 0 1 0-2.122-2.121L12 9.879L6.697 4.576a1.5 1.5 0 1 0-2.122 2.12L9.88 12l-5.304 5.304a1.5 1.5 0 1 0 2.122 2.12z"/></g></svg>
</button>
- <div style="text-align: center;">
- <!--<img class="title-image littlesongplace02">-->
- <a href="/" style="text-decoration: none;"><h1>little song place</h1></a>
+
+ <div id="site-title">
+ <a href="/" style="text-decoration: none;">little song place</a>
</div>
+
<!-- Navbar/Menu -->
<div id="navbar">
- <a href="/jams/1">Jam</a>
- <a href="/about">About</a>
- <a href="/site-news">News</a>
- <a href="/songs">Random</a>
+ <a href="/site-news">site news</a>
+ <a href="/about">about the site</a>
+
+ <!-- <a href="/songs">tunes</a> -->
+ <!-- <a href="/jams/1">jams</a> -->
- <a href="/users/{{ session["username"] }}" class="nav-logged-in" id="my-profile" hidden>My Profile</a>
- <a href="/activity" class="nav-logged-in" hidden><span id="activity-indicator" hidden></span>Activity</a>
- <a href="/logout" class="nav-logged-in" hidden>Sign Out</a>
+ <!-- <a href="/users/{{ session["username"] }}" class="nav-logged-in" id="my-profile" hidden>profile</a> -->
+ <!-- <a href="/activity" class="nav-logged-in" hidden><span id="activity-indicator" hidden></span>activity</a> -->
+ <!-- <a href="/logout" class="nav-logged-in" hidden>sign out</a> -->
- <a href="/signup" class="nav-logged-out">Create Account</a>
- <a href="/login" class="nav-logged-out">Sign In</a>
+ <!-- <a href="/signup" class="nav-logged-out">create account</a> -->
+ <!-- <a href="/login" class="nav-logged-out">sign in</a> -->
- <span class="nav-logged-in" id="logged-in-status" hidden></span>
+ <!-- <span class="nav-logged-in" id="logged-in-status" hidden></span> -->
</div>
</div>
<!-- Flashed Status Messages -->
<div id="flashes-container">
{% with messages = get_flashed_messages(with_categories=True) -%}
- {% if messages -%}
+ {% if messages -%}
<div class="flashes">
<ul>
{% for category, message in messages %}
{%- endwith %}
</div>
- <!-- Page-Specific Content -->
- <div class="main" id="main" data-bgcolor="{{ bgcolor }}" data-fgcolor="{{ fgcolor }}" data-accolor="{{ accolor }}" data-username="{{ session['username'] }}">{% block body %}{% endblock %}</div>
+ <div id="outer">
+ <div id="left">
+ <div class="page-section">
+ <div class="page-section-header">me</div>
+ <div class="user-list-entry-container">
+ <a href="/users/{{ g.user.username }}" class="user-list-entry" style="--yellow:{{ g.user.bgcolor }};--black:{{ g.user.fgcolor }};--purple:{{ g.user.accolor }};">
+ {% if g.user.has_pfp -%}
+ <img class="small-pfp" src="/pfp/{{ g.user['userid'] }}" width="32" height="32" />
+ {%- endif %}
+ <span>{{ g.user.username }}</span>
+ </a>
+ </div>
+ <div id="user-actions">
+ <a href="/activity" class="nav-logged-in" hidden><span id="activity-indicator" hidden></span>activity</a>
+ <a href="/logout" class="nav-logged-in" hidden>sign out</a>
+ </div>
+ </div>
+ {% block left %}{% endblock %}
+ </div>
+
+ <!-- Page-Specific Content -->
+ <div id="main" data-bgcolor="{{ bgcolor }}" data-fgcolor="{{ fgcolor }}" data-accolor="{{ accolor }}" data-username="{{ session['username'] }}">{% block body %}{% endblock %}</div>
+
+ <div id="right">
+ {% block right %}{% endblock %}
+ </div>
+
+ </div> <!-- outer -->
<!-- Padding to prevent player from obscuring content -->
<div id="scroll-padding"></div>
{% block title %}Little Song Place{% endblock %}
+{% block left %}
+{% if ongoing_events or upcoming_events %}
+<div class="page-section">
+ <div class="page-section-header">jams</div>
+ {% from "jam-event-list.html" import jam_event_list %}
+ {{ jam_event_list("ongoing events", ongoing_events, "ends", "end") }}
+ {{ jam_event_list("upcoming events", upcoming_events, "starts", "start") }}
+</div>
+{% endif %}
+{% endblock %}
+
{% block body %}
-<h2>hello!</h2>
-<div style="display: flex; flex-direction: row; justify-content: center; gap: 10px; align-items: center;">
-<div>🎶</div>
-<div style="text-align: center;">Welcome to littlesong.place.<br/>Make music, and share it with friends!</div>
-<div>🎵</div>
+<div class="page-section">
+ <div class="page-section-header">tunes</div>
+ {% include "song-list.html" %}
</div>
-{% if ongoing_events or upcoming_events %}
-<h2>happenings</h2>
-{% from "jam-event-list.html" import jam_event_list %}
-{{ jam_event_list("ongoing events", ongoing_events, "ends", "end") }}
-{{ jam_event_list("upcoming events", upcoming_events, "starts", "start") }}
-{% endif %}
+{% endblock %}
-<h2>humans</h2>
-<div class="user-list">
- {% for user in users %}
- <div class="user-list-entry-container">
- <a href="/users/{{ user['username'] }}" class="user-list-entry" style="--yellow:{{ user['bgcolor'] }};--black:{{ user['fgcolor'] }};--purple:{{ user['accolor'] }};">
- {% if user['has_pfp'] -%}
- <img class="small-pfp" src="/pfp/{{ user['userid'] }}" width="32" height="32" />
- {%- endif %}
- <span>{{ user['username'] }}</span>
- </a>
+{% block right %}
+
+<div class="page-section">
+ <div class="page-section-header">folks</div>
+ <div class="user-list">
+ {% for user in users %}
+ <div class="user-list-entry-container">
+ <a href="/users/{{ user['username'] }}" class="user-list-entry" style="--yellow:{{ user['bgcolor'] }};--black:{{ user['fgcolor'] }};--purple:{{ user['accolor'] }};">
+ {% if user['has_pfp'] -%}
+ <img class="small-pfp" src="/pfp/{{ user['userid'] }}" width="32" height="32" />
+ {%- endif %}
+ <span>{{ user['username'] }}</span>
+ </a>
+ </div>
+ {% endfor %}
</div>
- {% endfor %}
</div>
-<h2>hot new tunes</h2>
-{% include "song-list.html" %}
-
{% endblock %}
<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>
bgcolor: str
accolor: str
+ @property
+ def has_pfp(self):
+ return user_has_pfp(self.userid)
+
@property
def colors(self):
return {