]> littlesong.place Git - littlesongplace.git/commitdiff
Add custom profile colors
authorChris Fulljames <christianfulljames@gmail.com>
Fri, 7 Feb 2025 02:47:26 +0000 (21:47 -0500)
committerChris Fulljames <christianfulljames@gmail.com>
Fri, 7 Feb 2025 02:47:53 +0000 (21:47 -0500)
main.py
schema.sql
schema_update.sql
static/coloris.min.css [new file with mode: 0644]
static/coloris.min.js [new file with mode: 0644]
static/styles.css
templates/base.html
templates/profile.html
todo.txt

diff --git a/main.py b/main.py
index b89d5f9615f0200704cc7a46277c1224e56367ee..92c2a1ee2092d2b6070218b603487d909a167daf 100644 (file)
--- a/main.py
+++ b/main.py
@@ -23,7 +23,7 @@ from PIL import Image, UnidentifiedImageError
 from werkzeug.utils import secure_filename
 from werkzeug.middleware.proxy_fix import ProxyFix
 
-DB_VERSION = 1
+DB_VERSION = 2
 DATA_DIR = Path(os.environ["DATA_DIR"]) if "DATA_DIR" in os.environ else Path(".")
 SCRIPT_DIR = Path(__file__).parent
 
@@ -164,6 +164,9 @@ def users_profile(profile_username):
             name=profile_username,
             userid=profile_userid,
             bio=profile_bio,
+            user_fgcolor=profile_data["fgcolor"],
+            user_bgcolor=profile_data["bgcolor"],
+            user_accolor=profile_data["accolor"],
             song_list=render_template("song-list.html", songs=songs))
 
 @app.post("/edit-profile")
@@ -172,8 +175,8 @@ def edit_profile():
         abort(401)
 
     query_db(
-            "update users set bio = ? where userid = ?",
-            [request.form["bio"], session["userid"]])
+            "update users set bio = ?, bgcolor = ?, fgcolor = ?, accolor = ? where userid = ?",
+            [request.form["bio"], request.form["bgcolor"], request.form["fgcolor"], request.form["accolor"], session["userid"]])
     get_db().commit()
 
     if request.files["pfp"]:
index 9cbab0334ec9af64a31bceae8990f05209bfb787..f70f7dfcf8819a13a6f2d35d3f2b6c6092f66c5a 100644 (file)
@@ -4,7 +4,8 @@ CREATE TABLE users (
     created TEXT NOT NULL,
     username TEXT UNIQUE NOT NULL,
     password BLOB NOT NULL,
-    bio TEXT
+    bio TEXT,
+    activitytime TEXT
 );
 CREATE INDEX users_by_name ON users(username);
 
@@ -17,6 +18,7 @@ CREATE TABLE songs (
     description TEXT,
     FOREIGN KEY(userid) REFERENCES users(userid)
 );
+CREATE INDEX idx_songs_by_user ON songs(userid);
 
 DROP TABLE IF EXISTS song_collaborators;
 CREATE TABLE song_collaborators (
@@ -36,4 +38,30 @@ CREATE TABLE song_tags (
 CREATE INDEX idx_song_tags_tag ON song_tags(tag);
 
 DROP TABLE IF EXISTS song_comments;
+CREATE TABLE song_comments (
+    commentid INTEGER PRIMARY KEY,
+    songid INTEGER NOT NULL,
+    userid INTEGER NOT NULL,
+    replytoid INTEGER,
+    created TEXT NOT NULL,
+    content TEXT NOT NULL,
+    FOREIGN KEY(songid) REFERENCES songs(songid) ON DELETE CASCADE,
+    FOREIGN KEY(userid) REFERENCES users(userid) ON DELETE CASCADE
+);
+CREATE INDEX idx_comments_by_song ON song_comments(songid);
+CREATE INDEX idx_comments_by_user ON song_comments(userid);
+CREATE INDEX idx_comments_by_replyto ON song_comments(replytoid);
+CREATE INDEX idx_comments_by_time ON song_comments(created);
+
 DROP TABLE IF EXISTS song_comment_notifications;
+CREATE TABLE song_comment_notifications (
+    notificationid INTEGER PRIMARY KEY,
+    commentid INTEGER NOT NULL,
+    targetuserid INTEGER NOT NULL,
+    FOREIGN KEY(commentid) REFERENCES song_comments(commentid) ON DELETE CASCADE,
+    FOREIGN KEY(targetuserid) REFERENCES users(userid) ON DELETE CASCADE
+);
+CREATE INDEX idx_song_comment_notifications_by_target ON song_comment_notifications(targetuserid);
+
+PRAGMA user_version = 1;
+
index 1fbf6b93afd97f7ad7901aebcbf8c9317ff540e6..598e8baaa6f8a57023302db545794e9bc0c39f96 100644 (file)
@@ -1,30 +1,6 @@
-ALTER TABLE users ADD COLUMN activitytime TEXT;
+ALTER TABLE users ADD COLUMN bgcolor TEXT;
+ALTER TABLE users ADD COLUMN fgcolor TEXT;
+ALTER TABLE users ADD COLUMN accolor TEXT;
 
-CREATE INDEX idx_songs_by_user ON songs(userid);
-
-CREATE TABLE song_comments (
-    commentid INTEGER PRIMARY KEY,
-    songid INTEGER NOT NULL,
-    userid INTEGER NOT NULL,
-    replytoid INTEGER,
-    created TEXT NOT NULL,
-    content TEXT NOT NULL,
-    FOREIGN KEY(songid) REFERENCES songs(songid) ON DELETE CASCADE,
-    FOREIGN KEY(userid) REFERENCES users(userid) ON DELETE CASCADE
-);
-CREATE INDEX idx_comments_by_song ON song_comments(songid);
-CREATE INDEX idx_comments_by_user ON song_comments(userid);
-CREATE INDEX idx_comments_by_replyto ON song_comments(replytoid);
-CREATE INDEX idx_comments_by_time ON song_comments(created);
-
-CREATE TABLE song_comment_notifications (
-    notificationid INTEGER PRIMARY KEY,
-    commentid INTEGER NOT NULL,
-    targetuserid INTEGER NOT NULL,
-    FOREIGN KEY(commentid) REFERENCES song_comments(commentid) ON DELETE CASCADE,
-    FOREIGN KEY(targetuserid) REFERENCES users(userid) ON DELETE CASCADE
-);
-CREATE INDEX idx_song_comment_notifications_by_target ON song_comment_notifications(targetuserid);
-
-PRAGMA user_version = 1;
+PRAGMA user_version = 2;
 
diff --git a/static/coloris.min.css b/static/coloris.min.css
new file mode 100644 (file)
index 0000000..885df05
--- /dev/null
@@ -0,0 +1 @@
+.clr-picker{display:none;flex-wrap:wrap;position:absolute;width:200px;z-index:1000;border-radius:10px;background-color:#fff;justify-content:flex-end;direction:ltr;box-shadow:0 0 5px rgba(0,0,0,.05),0 5px 20px rgba(0,0,0,.1);-moz-user-select:none;-webkit-user-select:none;user-select:none}.clr-picker.clr-open,.clr-picker[data-inline=true]{display:flex}.clr-picker[data-inline=true]{position:relative}.clr-gradient{position:relative;width:100%;height:100px;margin-bottom:15px;border-radius:3px 3px 0 0;background-image:linear-gradient(rgba(0,0,0,0),#000),linear-gradient(90deg,#fff,currentColor);cursor:pointer}.clr-marker{position:absolute;width:12px;height:12px;margin:-6px 0 0 -6px;border:1px solid #fff;border-radius:50%;background-color:currentColor;cursor:pointer}.clr-picker input[type=range]::-webkit-slider-runnable-track{width:100%;height:16px}.clr-picker input[type=range]::-webkit-slider-thumb{width:16px;height:16px;-webkit-appearance:none}.clr-picker input[type=range]::-moz-range-track{width:100%;height:16px;border:0}.clr-picker input[type=range]::-moz-range-thumb{width:16px;height:16px;border:0}.clr-hue{background-image:linear-gradient(to right,red 0,#ff0 16.66%,#0f0 33.33%,#0ff 50%,#00f 66.66%,#f0f 83.33%,red 100%)}.clr-alpha,.clr-hue{position:relative;width:calc(100% - 40px);height:8px;margin:5px 20px;border-radius:4px}.clr-alpha span{display:block;height:100%;width:100%;border-radius:inherit;background-image:linear-gradient(90deg,rgba(0,0,0,0),currentColor)}.clr-alpha input[type=range],.clr-hue input[type=range]{position:absolute;width:calc(100% + 32px);height:16px;left:-16px;top:-4px;margin:0;background-color:transparent;opacity:0;cursor:pointer;appearance:none;-webkit-appearance:none}.clr-alpha div,.clr-hue div{position:absolute;width:16px;height:16px;left:0;top:50%;margin-left:-8px;transform:translateY(-50%);border:2px solid #fff;border-radius:50%;background-color:currentColor;box-shadow:0 0 1px #888;pointer-events:none}.clr-alpha div:before{content:'';position:absolute;height:100%;width:100%;left:0;top:0;border-radius:50%;background-color:currentColor}.clr-format{display:none;order:1;width:calc(100% - 40px);margin:0 20px 20px}.clr-segmented{display:flex;position:relative;width:100%;margin:0;padding:0;border:1px solid #ddd;border-radius:15px;box-sizing:border-box;color:#999;font-size:12px}.clr-segmented input,.clr-segmented legend{position:absolute;width:100%;height:100%;margin:0;padding:0;border:0;left:0;top:0;opacity:0;pointer-events:none}.clr-segmented label{flex-grow:1;margin:0;padding:4px 0;font-size:inherit;font-weight:400;line-height:initial;text-align:center;cursor:pointer}.clr-segmented label:first-of-type{border-radius:10px 0 0 10px}.clr-segmented label:last-of-type{border-radius:0 10px 10px 0}.clr-segmented input:checked+label{color:#fff;background-color:#666}.clr-swatches{order:2;width:calc(100% - 32px);margin:0 16px}.clr-swatches div{display:flex;flex-wrap:wrap;padding-bottom:12px;justify-content:center}.clr-swatches button{position:relative;width:20px;height:20px;margin:0 4px 6px 4px;padding:0;border:0;border-radius:50%;color:inherit;text-indent:-1000px;white-space:nowrap;overflow:hidden;cursor:pointer}.clr-swatches button:after{content:'';display:block;position:absolute;width:100%;height:100%;left:0;top:0;border-radius:inherit;background-color:currentColor;box-shadow:inset 0 0 0 1px rgba(0,0,0,.1)}input.clr-color{order:1;width:calc(100% - 80px);height:32px;margin:15px 20px 20px auto;padding:0 10px;border:1px solid #ddd;border-radius:16px;color:#444;background-color:#fff;font-family:sans-serif;font-size:14px;text-align:center;box-shadow:none}input.clr-color:focus{outline:0;border:1px solid #1e90ff}.clr-clear,.clr-close{display:none;order:2;height:24px;margin:0 20px 20px;padding:0 20px;border:0;border-radius:12px;color:#fff;background-color:#666;font-family:inherit;font-size:12px;font-weight:400;cursor:pointer}.clr-close{display:block;margin:0 20px 20px auto}.clr-preview{position:relative;width:32px;height:32px;margin:15px 0 20px 20px;border-radius:50%;overflow:hidden}.clr-preview:after,.clr-preview:before{content:'';position:absolute;height:100%;width:100%;left:0;top:0;border:1px solid #fff;border-radius:50%}.clr-preview:after{border:0;background-color:currentColor;box-shadow:inset 0 0 0 1px rgba(0,0,0,.1)}.clr-preview button{position:absolute;width:100%;height:100%;z-index:1;margin:0;padding:0;border:0;border-radius:50%;outline-offset:-2px;background-color:transparent;text-indent:-9999px;cursor:pointer;overflow:hidden}.clr-alpha div,.clr-color,.clr-hue div,.clr-marker{box-sizing:border-box}.clr-field{display:inline-block;position:relative;color:transparent}.clr-field input{margin:0;direction:ltr}.clr-field.clr-rtl input{text-align:right}.clr-field button{position:absolute;width:30px;height:100%;right:0;top:50%;transform:translateY(-50%);margin:0;padding:0;border:0;color:inherit;text-indent:-1000px;white-space:nowrap;overflow:hidden;pointer-events:none}.clr-field.clr-rtl button{right:auto;left:0}.clr-field button:after{content:'';display:block;position:absolute;width:100%;height:100%;left:0;top:0;border-radius:inherit;background-color:currentColor;box-shadow:inset 0 0 1px rgba(0,0,0,.5)}.clr-alpha,.clr-alpha div,.clr-field button,.clr-preview:before,.clr-swatches button{background-image:repeating-linear-gradient(45deg,#aaa 25%,transparent 25%,transparent 75%,#aaa 75%,#aaa),repeating-linear-gradient(45deg,#aaa 25%,#fff 25%,#fff 75%,#aaa 75%,#aaa);background-position:0 0,4px 4px;background-size:8px 8px}.clr-marker:focus{outline:0}.clr-keyboard-nav .clr-alpha input:focus+div,.clr-keyboard-nav .clr-hue input:focus+div,.clr-keyboard-nav .clr-marker:focus,.clr-keyboard-nav .clr-segmented input:focus+label{outline:0;box-shadow:0 0 0 2px #1e90ff,0 0 2px 2px #fff}.clr-picker[data-alpha=false] .clr-alpha{display:none}.clr-picker[data-minimal=true]{padding-top:16px}.clr-picker[data-minimal=true] .clr-alpha,.clr-picker[data-minimal=true] .clr-color,.clr-picker[data-minimal=true] .clr-gradient,.clr-picker[data-minimal=true] .clr-hue,.clr-picker[data-minimal=true] .clr-preview{display:none}.clr-dark{background-color:#444}.clr-dark .clr-segmented{border-color:#777}.clr-dark .clr-swatches button:after{box-shadow:inset 0 0 0 1px rgba(255,255,255,.3)}.clr-dark input.clr-color{color:#fff;border-color:#777;background-color:#555}.clr-dark input.clr-color:focus{border-color:#1e90ff}.clr-dark .clr-preview:after{box-shadow:inset 0 0 0 1px rgba(255,255,255,.5)}.clr-dark .clr-alpha,.clr-dark .clr-alpha div,.clr-dark .clr-preview:before,.clr-dark .clr-swatches button{background-image:repeating-linear-gradient(45deg,#666 25%,transparent 25%,transparent 75%,#888 75%,#888),repeating-linear-gradient(45deg,#888 25%,#444 25%,#444 75%,#888 75%,#888)}.clr-picker.clr-polaroid{border-radius:6px;box-shadow:0 0 5px rgba(0,0,0,.1),0 5px 30px rgba(0,0,0,.2)}.clr-picker.clr-polaroid:before{content:'';display:block;position:absolute;width:16px;height:10px;left:20px;top:-10px;border:solid transparent;border-width:0 8px 10px 8px;border-bottom-color:currentColor;box-sizing:border-box;color:#fff;filter:drop-shadow(0 -4px 3px rgba(0,0,0,.1));pointer-events:none}.clr-picker.clr-polaroid.clr-dark:before{color:#444}.clr-picker.clr-polaroid.clr-left:before{left:auto;right:20px}.clr-picker.clr-polaroid.clr-top:before{top:auto;bottom:-10px;transform:rotateZ(180deg)}.clr-polaroid .clr-gradient{width:calc(100% - 20px);height:120px;margin:10px;border-radius:3px}.clr-polaroid .clr-alpha,.clr-polaroid .clr-hue{width:calc(100% - 30px);height:10px;margin:6px 15px;border-radius:5px}.clr-polaroid .clr-alpha div,.clr-polaroid .clr-hue div{box-shadow:0 0 5px rgba(0,0,0,.2)}.clr-polaroid .clr-format{width:calc(100% - 20px);margin:0 10px 15px}.clr-polaroid .clr-swatches{width:calc(100% - 12px);margin:0 6px}.clr-polaroid .clr-swatches div{padding-bottom:10px}.clr-polaroid .clr-swatches button{width:22px;height:22px}.clr-polaroid input.clr-color{width:calc(100% - 60px);margin:10px 10px 15px auto}.clr-polaroid .clr-clear{margin:0 10px 15px 10px}.clr-polaroid .clr-close{margin:0 10px 15px auto}.clr-polaroid .clr-preview{margin:10px 0 15px 10px}.clr-picker.clr-large{width:275px}.clr-large .clr-gradient{height:150px}.clr-large .clr-swatches button{width:22px;height:22px}.clr-picker.clr-pill{width:380px;padding-left:180px;box-sizing:border-box}.clr-pill .clr-gradient{position:absolute;width:180px;height:100%;left:0;top:0;margin-bottom:0;border-radius:3px 0 0 3px}.clr-pill .clr-hue{margin-top:20px}
\ No newline at end of file
diff --git a/static/coloris.min.js b/static/coloris.min.js
new file mode 100644 (file)
index 0000000..ec59a98
--- /dev/null
@@ -0,0 +1,6 @@
+/*!
+ * Copyright (c) 2021 Momo Bassit.
+ * Licensed under the MIT License (MIT)
+ * https://github.com/mdbassit/Coloris
+ */
+!function(u,p,s,c){var d,f,h,i,b,y,v,m,g,l,w,k,L,E,a,n,r=p.createElement("canvas").getContext("2d"),x={r:0,g:0,b:0,h:0,s:0,v:0,a:1},A={},C={el:"[data-coloris]",parent:"body",theme:"default",themeMode:"light",rtl:!1,wrap:!0,margin:2,format:"hex",formatToggle:!1,swatches:[],swatchesOnly:!1,alpha:!0,forceAlpha:!1,focusInput:!0,selectInput:!1,inline:!1,defaultColor:"#000000",clearButton:!1,clearLabel:"Clear",closeButton:!1,closeLabel:"Close",onChange:function(){return c},a11y:{open:"Open color picker",close:"Close color picker",clear:"Clear the selected color",marker:"Saturation: {s}. Brightness: {v}.",hueSlider:"Hue slider",alphaSlider:"Opacity slider",input:"Color value field",format:"Color format",swatch:"Color swatch",instruction:"Saturation and brightness selector. Use up, down, left and right arrow keys to select."}},o={},S="",T={},B=!1;function M(t){if("object"==typeof t)for(var e in t)switch(e){case"el":D(t.el),!1!==t.wrap&&R(t.el);break;case"parent":(d=t.parent instanceof HTMLElement?t.parent:p.querySelector(t.parent))&&(d.appendChild(f),C.parent=t.parent,d===p.body&&(d=c));break;case"themeMode":C.themeMode=t.themeMode,"auto"===t.themeMode&&u.matchMedia&&u.matchMedia("(prefers-color-scheme: dark)").matches&&(C.themeMode="dark");case"theme":t.theme&&(C.theme=t.theme),f.className="clr-picker clr-"+C.theme+" clr-"+C.themeMode,C.inline&&j();break;case"rtl":C.rtl=!!t.rtl,Array.from(p.getElementsByClassName("clr-field")).forEach(function(e){return e.classList.toggle("clr-rtl",C.rtl)});break;case"margin":t.margin*=1,C.margin=(isNaN(t.margin)?C:t).margin;break;case"wrap":t.el&&t.wrap&&R(t.el);break;case"formatToggle":C.formatToggle=!!t.formatToggle,V("clr-format").style.display=C.formatToggle?"block":"none",C.formatToggle&&(C.format="auto");break;case"swatches":Array.isArray(t.swatches)&&function(){var e=V("clr-swatches"),l=p.createElement("div");e.textContent="",t.swatches.forEach(function(e,t){var a=p.createElement("button");a.setAttribute("type","button"),a.setAttribute("id","clr-swatch-"+t),a.setAttribute("aria-labelledby","clr-swatch-label clr-swatch-"+t),a.style.color=e,a.textContent=e,l.appendChild(a)}),t.swatches.length&&e.appendChild(l),C.swatches=t.swatches.slice()}();break;case"swatchesOnly":C.swatchesOnly=!!t.swatchesOnly,f.setAttribute("data-minimal",C.swatchesOnly);break;case"alpha":C.alpha=!!t.alpha,f.setAttribute("data-alpha",C.alpha);break;case"inline":C.inline=!!t.inline,f.setAttribute("data-inline",C.inline),C.inline&&(l=t.defaultColor||C.defaultColor,E=P(l),j(),Y(l));break;case"clearButton":"object"==typeof t.clearButton&&(t.clearButton.label&&(C.clearLabel=t.clearButton.label,v.innerHTML=C.clearLabel),t.clearButton=t.clearButton.show),C.clearButton=!!t.clearButton,v.style.display=C.clearButton?"block":"none";break;case"clearLabel":C.clearLabel=t.clearLabel,v.innerHTML=C.clearLabel;break;case"closeButton":C.closeButton=!!t.closeButton,C.closeButton?f.insertBefore(m,b):b.appendChild(m);break;case"closeLabel":C.closeLabel=t.closeLabel,m.innerHTML=C.closeLabel;break;case"a11y":var a,l,r=t.a11y,n=!1;if("object"==typeof r)for(var o in r)r[o]&&C.a11y[o]&&(C.a11y[o]=r[o],n=!0);n&&(a=V("clr-open-label"),l=V("clr-swatch-label"),a.innerHTML=C.a11y.open,l.innerHTML=C.a11y.swatch,m.setAttribute("aria-label",C.a11y.close),v.setAttribute("aria-label",C.a11y.clear),g.setAttribute("aria-label",C.a11y.hueSlider),w.setAttribute("aria-label",C.a11y.alphaSlider),y.setAttribute("aria-label",C.a11y.input),h.setAttribute("aria-label",C.a11y.instruction));break;default:C[e]=t[e]}}function H(e,t){"string"==typeof e&&"object"==typeof t&&(o[e]=t,B=!0)}function N(e){delete o[e],0===Object.keys(o).length&&(B=!1,e===S&&O())}function t(l){if(B){var e,r=["el","wrap","rtl","inline","defaultColor","a11y"];for(e in o)if("break"===function(e){var t=o[e];if(l.matches(e)){for(var a in S=e,T={},r.forEach(function(e){return delete t[e]}),t)T[a]=Array.isArray(C[a])?C[a].slice():C[a];return M(t),"break"}}(e))break}}function O(){0<Object.keys(T).length&&(M(T),S="",T={})}function D(e){e instanceof HTMLElement&&(e=[e]),Array.isArray(e)?e.forEach(function(e){Z(e,"click",I),Z(e,"input",q)}):(Z(p,"click",e,I),Z(p,"input",e,q))}function I(e){C.inline||(t(e.target),L=e.target,a=L.value,E=P(a),f.classList.add("clr-open"),j(),Y(a),(C.focusInput||C.selectInput)&&(y.focus({preventScroll:!0}),y.setSelectionRange(L.selectionStart,L.selectionEnd)),C.selectInput&&y.select(),(n||C.swatchesOnly)&&Q().shift().focus(),L.dispatchEvent(new Event("open",{bubbles:!0})))}function j(){var e,t,a,l,r=d,n=u.scrollY,o=f.offsetWidth,c=f.offsetHeight,i={left:!1,top:!1},s={x:0,y:0};r&&(a=u.getComputedStyle(r),e=parseFloat(a.marginTop),l=parseFloat(a.borderTopWidth),(s=r.getBoundingClientRect()).y+=l+n),C.inline||(a=(t=L.getBoundingClientRect()).x,l=n+t.y+t.height+C.margin,r?(a-=s.x,l-=s.y,a+o>r.clientWidth&&(a+=t.width-o,i.left=!0),l+c>r.clientHeight-e&&c+C.margin<=t.top-(s.y-n)&&(l-=t.height+c+2*C.margin,i.top=!0),l+=r.scrollTop):(a+o>p.documentElement.clientWidth&&(a+=t.width-o,i.left=!0),l+c-n>p.documentElement.clientHeight&&c+C.margin<=t.top&&(l=n+t.y-c-C.margin,i.top=!0)),f.classList.toggle("clr-left",i.left),f.classList.toggle("clr-top",i.top),f.style.left=a+"px",f.style.top=l+"px",s.x+=f.offsetLeft,s.y+=f.offsetTop),A={width:h.offsetWidth,height:h.offsetHeight,x:h.offsetLeft+s.x,y:h.offsetTop+s.y}}function R(e){e instanceof HTMLElement?W(e):(Array.isArray(e)?e:p.querySelectorAll(e)).forEach(W)}function W(e){var t,a,l=e.parentNode;l.classList.contains("clr-field")||(t=p.createElement("div"),a="clr-field",(C.rtl||e.classList.contains("clr-rtl"))&&(a+=" clr-rtl"),t.innerHTML='<button type="button" aria-labelledby="clr-open-label"></button>',l.insertBefore(t,e),t.className=a,t.style.color=e.value,t.appendChild(e))}function q(e){var t=e.target.parentNode;t.classList.contains("clr-field")&&(t.style.color=e.target.value)}function F(e){var t;L&&!C.inline&&(t=L,e&&(L=c,a!==t.value&&(t.value=a,t.dispatchEvent(new Event("input",{bubbles:!0})))),setTimeout(function(){a!==t.value&&t.dispatchEvent(new Event("change",{bubbles:!0}))}),f.classList.remove("clr-open"),B&&O(),t.dispatchEvent(new Event("close",{bubbles:!0})),C.focusInput&&t.focus({preventScroll:!0}),L=c)}function Y(e){var t=function(e){r.fillStyle="#000",r.fillStyle=e,e=(e=/^((rgba)|rgb)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i.exec(r.fillStyle))?{r:+e[3],g:+e[4],b:+e[5],a:+e[6]}:(e=r.fillStyle.replace("#","").match(/.{2}/g).map(function(e){return parseInt(e,16)}),{r:e[0],g:e[1],b:e[2],a:1});return e}(e),e=function(e){var t=e.r/255,a=e.g/255,l=e.b/255,r=s.max(t,a,l),n=s.min(t,a,l),o=r-n,c=r,i=0,n=0;o&&(r===t&&(i=(a-l)/o),r===a&&(i=2+(l-t)/o),r===l&&(i=4+(t-a)/o),r&&(n=o/r));return{h:(i=s.floor(60*i))<0?i+360:i,s:s.round(100*n),v:s.round(100*c),a:e.a}}(t);G(e.s,e.v),z(t,e),g.value=e.h,f.style.color="hsl("+e.h+", 100%, 50%)",l.style.left=e.h/360*100+"%",i.style.left=A.width*e.s/100+"px",i.style.top=A.height-A.height*e.v/100+"px",w.value=100*e.a,k.style.left=100*e.a+"%"}function P(e){e=e.substring(0,3).toLowerCase();return"rgb"===e||"hsl"===e?e:"hex"}function U(e){e=e!==c?e:y.value,L&&(L.value=e,L.dispatchEvent(new Event("input",{bubbles:!0}))),C.onChange&&C.onChange.call(u,e,L),p.dispatchEvent(new CustomEvent("coloris:pick",{detail:{color:e,currentEl:L}}))}function X(e,t){e={h:+g.value,s:e/A.width*100,v:100-t/A.height*100,a:w.value/100},t=function(e){var t=e.s/100,a=e.v/100,l=t*a,r=e.h/60,n=l*(1-s.abs(r%2-1)),o=a-l;l+=o,n+=o;t=s.floor(r)%6,a=[l,n,o,o,n,l][t],r=[n,l,l,n,o,o][t],t=[o,o,n,l,l,n][t];return{r:s.round(255*a),g:s.round(255*r),b:s.round(255*t),a:e.a}}(e);G(e.s,e.v),z(t,e),U()}function G(e,t){var a=C.a11y.marker;e=+e.toFixed(1),t=+t.toFixed(1),a=(a=a.replace("{s}",e)).replace("{v}",t),i.setAttribute("aria-label",a)}function K(e){var t={pageX:((a=e).changedTouches?a.changedTouches[0]:a).pageX,pageY:(a.changedTouches?a.changedTouches[0]:a).pageY},a=t.pageX-A.x,t=t.pageY-A.y;d&&(t+=d.scrollTop),$(a,t),e.preventDefault(),e.stopPropagation()}function $(e,t){e=e<0?0:e>A.width?A.width:e,t=t<0?0:t>A.height?A.height:t,i.style.left=e+"px",i.style.top=t+"px",X(e,t),i.focus()}function z(e,t){void 0===t&&(t={});var a,l,r=C.format;for(a in e=void 0===e?{}:e)x[a]=e[a];for(l in t)x[l]=t[l];var n,o=function(e){var t=e.r.toString(16),a=e.g.toString(16),l=e.b.toString(16),r="";e.r<16&&(t="0"+t);e.g<16&&(a="0"+a);e.b<16&&(l="0"+l);C.alpha&&(e.a<1||C.forceAlpha)&&(e=255*e.a|0,r=e.toString(16),e<16&&(r="0"+r));return"#"+t+a+l+r}(x),c=o.substring(0,7);switch(i.style.color=c,k.parentNode.style.color=c,k.style.color=o,b.style.color=o,h.style.display="none",h.offsetHeight,h.style.display="",k.nextElementSibling.style.display="none",k.nextElementSibling.offsetHeight,k.nextElementSibling.style.display="","mixed"===r?r=1===x.a?"hex":"rgb":"auto"===r&&(r=E),r){case"hex":y.value=o;break;case"rgb":y.value=(n=x,!C.alpha||1===n.a&&!C.forceAlpha?"rgb("+n.r+", "+n.g+", "+n.b+")":"rgba("+n.r+", "+n.g+", "+n.b+", "+n.a+")");break;case"hsl":y.value=(n=function(e){var t,a=e.v/100,l=a*(1-e.s/100/2);0<l&&l<1&&(t=s.round((a-l)/s.min(l,1-l)*100));return{h:e.h,s:t||0,l:s.round(100*l),a:e.a}}(x),!C.alpha||1===n.a&&!C.forceAlpha?"hsl("+n.h+", "+n.s+"%, "+n.l+"%)":"hsla("+n.h+", "+n.s+"%, "+n.l+"%, "+n.a+")")}p.querySelector('.clr-format [value="'+r+'"]').checked=!0}function e(){var e=+g.value,t=+i.style.left.replace("px",""),a=+i.style.top.replace("px","");f.style.color="hsl("+e+", 100%, 50%)",l.style.left=e/360*100+"%",X(t,a)}function J(){var e=w.value/100;k.style.left=100*e+"%",z({a:e}),U()}function Q(){return Array.from(f.querySelectorAll("input, button")).filter(function(e){return!!e.offsetWidth})}function V(e){return p.getElementById(e)}function Z(e,t,a,l){var r=Element.prototype.matches||Element.prototype.msMatchesSelector;"string"==typeof a?e.addEventListener(t,function(e){r.call(e.target,a)&&l.call(e.target,e)}):(l=a,e.addEventListener(t,l))}function _(e,t){t=t!==c?t:[],"loading"!==p.readyState?e.apply(void 0,t):p.addEventListener("DOMContentLoaded",function(){e.apply(void 0,t)})}NodeList!==c&&NodeList.prototype&&!NodeList.prototype.forEach&&(NodeList.prototype.forEach=Array.prototype.forEach),u.Coloris=function(){var r={set:M,wrap:R,close:F,setInstance:H,removeInstance:N,updatePosition:j,ready:_};function e(e){_(function(){e&&("string"==typeof e?D:M)(e)})}for(var t in r)!function(l){e[l]=function(){for(var e=arguments.length,t=new Array(e),a=0;a<e;a++)t[a]=arguments[a];_(r[l],t)}}(t);return e}(),_(function(){d=c,(f=p.createElement("div")).setAttribute("id","clr-picker"),f.className="clr-picker",f.innerHTML='<input id="clr-color-value" name="clr-color-value" class="clr-color" type="text" value="" spellcheck="false" aria-label="'+C.a11y.input+'"><div id="clr-color-area" class="clr-gradient" role="application" aria-label="'+C.a11y.instruction+'"><div id="clr-color-marker" class="clr-marker" tabindex="0"></div></div><div class="clr-hue"><input id="clr-hue-slider" name="clr-hue-slider" type="range" min="0" max="360" step="1" aria-label="'+C.a11y.hueSlider+'"><div id="clr-hue-marker"></div></div><div class="clr-alpha"><input id="clr-alpha-slider" name="clr-alpha-slider" type="range" min="0" max="100" step="1" aria-label="'+C.a11y.alphaSlider+'"><div id="clr-alpha-marker"></div><span></span></div><div id="clr-format" class="clr-format"><fieldset class="clr-segmented"><legend>'+C.a11y.format+'</legend><input id="clr-f1" type="radio" name="clr-format" value="hex"><label for="clr-f1">Hex</label><input id="clr-f2" type="radio" name="clr-format" value="rgb"><label for="clr-f2">RGB</label><input id="clr-f3" type="radio" name="clr-format" value="hsl"><label for="clr-f3">HSL</label><span></span></fieldset></div><div id="clr-swatches" class="clr-swatches"></div><button type="button" id="clr-clear" class="clr-clear" aria-label="'+C.a11y.clear+'">'+C.clearLabel+'</button><div id="clr-color-preview" class="clr-preview"><button type="button" id="clr-close" class="clr-close" aria-label="'+C.a11y.close+'">'+C.closeLabel+'</button></div><span id="clr-open-label" hidden>'+C.a11y.open+'</span><span id="clr-swatch-label" hidden>'+C.a11y.swatch+"</span>",p.body.appendChild(f),h=V("clr-color-area"),i=V("clr-color-marker"),v=V("clr-clear"),m=V("clr-close"),b=V("clr-color-preview"),y=V("clr-color-value"),g=V("clr-hue-slider"),l=V("clr-hue-marker"),w=V("clr-alpha-slider"),k=V("clr-alpha-marker"),D(C.el),R(C.el),Z(f,"mousedown",function(e){f.classList.remove("clr-keyboard-nav"),e.stopPropagation()}),Z(h,"mousedown",function(e){Z(p,"mousemove",K)}),Z(h,"contextmenu",function(e){e.preventDefault()}),Z(h,"touchstart",function(e){p.addEventListener("touchmove",K,{passive:!1})}),Z(i,"mousedown",function(e){Z(p,"mousemove",K)}),Z(i,"touchstart",function(e){p.addEventListener("touchmove",K,{passive:!1})}),Z(y,"change",function(e){var t=y.value;(L||C.inline)&&U(""===t?t:Y(t))}),Z(v,"click",function(e){U(""),F()}),Z(m,"click",function(e){U(),F()}),Z(V("clr-format"),"click",".clr-format input",function(e){E=e.target.value,z(),U()}),Z(f,"click",".clr-swatches button",function(e){Y(e.target.textContent),U(),C.swatchesOnly&&F()}),Z(p,"mouseup",function(e){p.removeEventListener("mousemove",K)}),Z(p,"touchend",function(e){p.removeEventListener("touchmove",K)}),Z(p,"mousedown",function(e){n=!1,f.classList.remove("clr-keyboard-nav"),F()}),Z(p,"keydown",function(e){var t,a=e.key,l=e.target,r=e.shiftKey;"Escape"===a?F(!0):["Tab","ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(a)&&(n=!0,f.classList.add("clr-keyboard-nav")),"Tab"===a&&l.matches(".clr-picker *")&&(a=(t=Q()).shift(),t=t.pop(),r&&l===a?(t.focus(),e.preventDefault()):r||l!==t||(a.focus(),e.preventDefault()))}),Z(p,"click",".clr-field button",function(e){B&&O(),e.target.nextElementSibling.dispatchEvent(new Event("click",{bubbles:!0}))}),Z(i,"keydown",function(e){var t={ArrowUp:[0,-1],ArrowDown:[0,1],ArrowLeft:[-1,0],ArrowRight:[1,0]};Object.keys(t).includes(e.key)&&(!function(e,t){$(+i.style.left.replace("px","")+e,+i.style.top.replace("px","")+t)}.apply(void 0,t[e.key]),e.preventDefault())}),Z(h,"click",K),Z(g,"input",e),Z(w,"input",J)})}(window,document,Math);
\ No newline at end of file
index aa3df318faa9f9aa713391d7b5b54933255b50da..934fb565ec990b8a04078ec9b1041b45af98f1ba 100644 (file)
@@ -203,6 +203,22 @@ input[type=file] {
     margin: 10px;
 }
 
+/* Coloris Color Picker */
+
+.clr-field button {
+    width: 22px !important;
+    height: 22px !important;
+    left: 7px;
+    right: auto;
+    border-radius: 5px;
+}
+
+.clr-field input {
+    padding-left: 36px;
+    width: 100px;
+    cursor: pointer;
+}
+
 /* Filters on /songs page */
 .filter {
     margin: 5px;
index dfb6be5a364a8d7831de6088f48a98b6c32994d7..b1d4639a50fe8c87d73316aa400f06fb082a14d0 100644 (file)
@@ -2,8 +2,8 @@
 <html>
     <head>
         <title>{% block title %}{% endblock %}</title>
-        <link rel="stylesheet" href="/static/styles.css">
-        <link rel="icon" type="image/x-icon" href="/static/lsp_notes.png">
+        <link rel="stylesheet" href="/static/styles.css"/>
+        <link rel="icon" type="image/x-icon" href="/static/lsp_notes.png"/>
         <script src="/static/player.js"></script>
         <meta name="viewport" content="width=device-width, initial-scale=1">
         <!-- Page-specific head fields -->
index 308cb69a734b5fda5dea02a5541cfcf719772e7c..8709499896b8014eb4a666ecb7231ea606f93f08 100644 (file)
@@ -2,6 +2,21 @@
 
 {% block title %}{{ name }}'s profile{% endblock %}
 
+{% block head %}
+<!-- Include coloris library for color picker -->
+<link rel="stylesheet" href="/static/coloris.min.css"/>
+<script src="/static/coloris.min.js"></script>
+
+<style>
+:root {
+    {% if user_bgcolor %} --yellow: {{ user_bgcolor }} !important; {% endif %}
+    {% if user_fgcolor %} --black:  {{ user_fgcolor }} !important; {% endif %}
+    {% if user_accolor %} --purple: {{ user_accolor }} !important; {% endif %}
+}
+</style>
+
+{% endblock %}
+
 {% block body %}
 
 <!-- Username -->
     <h2> Profile Picture </h2>
     <input type="file" name="pfp" accept="image/png, image/jpg, image/gif, image/svg" />
 
+    <h2> Profile Colors </h2>
+    <table>
+        <tr>
+            <td> <label for="bgcolor">Background</label> </td>
+            <td> <input name="bgcolor" type="text" value="{{ user_bgcolor }}" data-coloris oninput="document.documentElement.style.setProperty('--yellow', this.value)"/> </td>
+        </tr>
+        <tr>
+            <td> <label for="fgcolor">Text</label> </td>
+            <td> <input name="fgcolor" type="text" value="{{ user_fgcolor }}" data-coloris oninput="document.documentElement.style.setProperty('--black', this.value)"/> </td>
+        </tr>
+        <tr>
+            <td> <label for="accolor">Accent</label> </td>
+            <td> <input name="accolor" type="text" value="{{ user_accolor }}" data-coloris oninput="document.documentElement.style.setProperty('--purple', this.value)"/> </td>
+        </tr>
+    </table>
+    <script>
+        Coloris({
+          alpha: false
+        });
+    </script>
+
     <h2> Edit Bio </h2>
     <p>Common HTML tags (&lt;a&gt;, &lt;b&gt;, &lt;i&gt;, &lt;img&gt;, etc.) are allowed.</p>
     <p>Examples:</p>
index 5b52ddda4e6c91073b60cd442e1248498122f286..d9cfa9dc8893ca26b067650fefefca30df344eee 100644 (file)
--- a/todo.txt
+++ b/todo.txt
@@ -1,5 +1,5 @@
 NOW
-- Site color customization
+- Site color customization: apply custom colors to images
 - YouTube importer
 
 SOON