<% }); %>
diff --git a/src/views/profile.ejs b/src/views/profile.ejs
index 73f5440..09cdbeb 100644
--- a/src/views/profile.ejs
+++ b/src/views/profile.ejs
@@ -29,18 +29,25 @@ along with this program. If not, see
. %>
<%- include('partial/navbar', {user}); %>
<% if(profile){ %>
-
-
<%- profile.user %>
- <%- include('partial/profile/image', {profile, selfProfile}); %>
- <%- include('partial/profile/tokeCount', {profile, selfProfile}); %>
- <%- include('partial/profile/signature', {profile, selfProfile}); %>
- <%- include('partial/profile/bio', {profile, selfProfile}); %>
- <%- include('partial/profile/date', {profile, selfProfile}); %>
- <%- include('partial/profile/badges', {profile, selfProfile}); %>
+
+
+
+ <%- profile.user %>
+ <%- include('partial/profile/image', {profile, selfProfile}); %>
+ <%- include('partial/profile/pronouns', {profile, selfProfile}); %>
+ <%- include('partial/profile/signature', {profile, selfProfile}); %>
+ <%- include('partial/profile/tokeCount', {profile, selfProfile}); %>
+ <%- include('partial/profile/date', {profile, selfProfile}); %>
+
+
+ <%- include('partial/profile/bio', {profile, selfProfile}); %>
+ <%- include('partial/profile/badges', {profile, selfProfile}); %>
+
+
+ <% if(selfProfile){ %>
+ <%- include('partial/profile/settings', {profile, selfProfile}); %>
+ <% } %>
- <% if(selfProfile){ %>
- <%- include('partial/profile/settings', {profile, selfProfile}); %>
- <% } %>
<% }else if(user){ %>
Profile not found!
<% } else {%>
diff --git a/www/css/global.css b/www/css/global.css
index 23ee9f9..41771d6 100644
--- a/www/css/global.css
+++ b/www/css/global.css
@@ -65,7 +65,7 @@ input.control-prompt{
flex: 1;
}
-div.dynamic-container{
+div.dynamic-container, div.nested-dynamic-container{
overflow: auto;
}
diff --git a/www/css/profile.css b/www/css/profile.css
index ee74276..0976aeb 100644
--- a/www/css/profile.css
+++ b/www/css/profile.css
@@ -13,53 +13,96 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see
.*/
+#account{
+ display: flex;
+ margin-top: 2em;
+ justify-content: space-evenly;
+}
-p.profile-item-edit{
- display: inline;
+#profile-div{
+ display: flex;
+ padding: 1em;
+ flex-direction: row;
+ overflow-y: hidden;
+}
+
+#profile-info{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ flex: 1;
+}
+
+#profile-info-aux{
+ flex: 2;
+ margin: 0 1em;
+}
+
+#account-settings-div{
+ display: flex;
+ flex-direction: column;
+ padding: 1em;
+}
+
+#account-settings-buttons{
+ display: flex;
+ flex-direction: column;
+ justify-content: space-around;
+ flex: 1;
+}
+
+#profile-username{
+ margin: 0;
+}
+
+#profile-img{
+ position: relative;
+}
+
+#profile-img-content{
+ margin: 1em 0;
+}
+
+#profile-img-prompt{
+ position: absolute;
+ left: -2em;
+ right: -2em;
+ top: calc(50% - 1.3em);
+}
+
+.profile-toke-count{
+ margin: 0;
}
span.profile-item{
- display: block;
- margin-top: 1em;
- margin-bottom: 1em;
-}
-
-p.profile-item-label{
- display: inline;
-}
-
-span.account-settings{
- display: block;
- margin-top: 1em;
- margin-bottom: 1em;
-}
-
-input.account-settings-password-reset{
- display: block;
-}
-
-a#account-settings-delete-button{
- font-weight: bold;
-}
-
-span.profile-toke-count{
display: flex;
flex-direction: row;
width: fit-content;
+ margin: 0.2em;
}
-p.profile-toke-count{
+p.profile-item{
margin: 0;
}
+span.profile-item-oneliner{
+ text-wrap: nowrap
+}
+
+.profile-item-prompt{
+ display: none;
+}
+
#profile-tokes{
resize: vertical;
- max-width: fit-content;
+ width: fit-content;
height: fit-content;
min-height: 1.5em;
max-height: 5.8em;
- display: none;
+ padding: 0.5em 0;
border-bottom-right-radius: 0;
+ text-wrap: nowrap;
+ visibility: collapse;
}
/*Little hacky but this keeps initial max-height from fucking up resizing*/
@@ -69,4 +112,23 @@ p.profile-toke-count{
.profile-toke{
margin: 0.2em 1em;
+}
+
+#profile-bio-label{
+ margin-bottom: 0.2em;
+}
+
+#profile-bio-content{
+ width: 30VW;
+}
+
+#profile-bio-prompt{
+ width: 30VW;
+ height: 11em;
+ resize: vertical;
+}
+
+/* temp */
+input:not([type="checkbox"]):not(.navbar-item):not(.profile-item-prompt){
+ display: block;
}
\ No newline at end of file
diff --git a/www/css/theme/movie-night.css b/www/css/theme/movie-night.css
index 3ae49ae..ed0e0cc 100644
--- a/www/css/theme/movie-night.css
+++ b/www/css/theme/movie-night.css
@@ -187,10 +187,23 @@ textarea{
.dynamic-container{
background-color: var(--bg1);
color: var(--accent1);
+}
+
+.nested-dynamic-container{
+ border: 1px var(--accent1) solid;
+ background-color: var(--bg0);
+ color: var(--accent0);
+}
+
+.dynamic-container, .nested-dynamic-container{
box-shadow: 3px 3px 1px var(--bg1-alt0) inset;
border-radius: 1em;
}
+.dynamic-container a{
+ color: var(--accent1);
+}
+
tr{
box-shadow: var(--accent1) 0px 1em 1px -2em, var(--accent1) 0px -1em 1px -1em;
diff --git a/www/js/profile.js b/www/js/profile.js
index b34bea2..050053b 100644
--- a/www/js/profile.js
+++ b/www/js/profile.js
@@ -14,104 +14,125 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see
.*/
-//Base Class
-class profileEditPrompt{
- constructor(field, content, useTextArea = false){
+class profileUpdatePrompt{
+ constructor(field){
this.field = field;
- this.useTextArea = useTextArea;
- this.content = content;
- this.link = document.querySelector(`#profile-${field}-edit`);
+ this.contentNode = document.querySelector(`#profile-${field}-content`);
+ this.promptNode = document.querySelector(`#profile-${field}-prompt`);
- //Bail out if something ain't right
- if(!this.link || !this.content){
- return;
- }
-
- this.setupPrompt();
- }
-
- setupPrompt(){
- if(this.link != null){
- this.link.addEventListener("click", this.prompt.bind(this));
+ if(this.promptNode != null){
+ this.setupInput();
}
}
+
+ setupInput(){
+ this.contentNode.addEventListener('click', this.popPrompt.bind(this));
+ this.promptNode.addEventListener('keydown', this.closePrompt.bind(this));
+ }
- prompt(){
- //Create input element
- if(this.useTextArea){
- this.prompt = document.createElement("textArea");
+ popPrompt(){
+ this.promptNode.style.display = 'inline';
+ this.promptNode.focus();
+ }
+
+ closePrompt(event){
+ //Check if we're finished
+ const fin = event.key == "Escape" || event.key == "Enter";
+
+ //IF we are
+ if(fin){
+ //Display the prompt
+ this.promptNode.style.display = 'none';
+ }
+
+ //Return whether or not we're done
+ return fin;
+ }
+}
+
+class profileUpdateTextPrompt extends profileUpdatePrompt{
+ constructor(field, fillPrompt = false){
+ //call derived constructor
+ super(field);
+
+ //Set fill prompt
+ this.fillPrompt = fillPrompt;
+ }
+
+ popPrompt(){
+ //Call derived method
+ super.popPrompt();
+
+ //If we're filling the prompt
+ if(this.fillPrompt){
+ //Fill the prompt content and placeholder
+ this.promptNode.value = this.contentNode.textContent;
+ this.promptNode.placeholder = this.field;
+ //otherwise
}else{
- this.prompt = document.createElement("input");
+ //Just fill the placeholder
+ this.promptNode.placeholder = this.contentNode.textContent;
}
- //Setup properties
- this.prompt.id = `profile-${this.field}-prompt`;
- this.prompt.classList.add("profile-edit-prompt");
- if(this.field == "img"){
- this.prompt.placeholder = this.content.src;
- }else{
- this.prompt.placeholder = this.content.innerHTML;
- }
-
- //Setup event listener
- this.prompt.addEventListener("keydown", this.update.bind(this));
-
- //replace label
- this.content.replaceWith(this.prompt);
+ //Hide content
+ this.contentNode.style.display = 'none';
}
- async update(event){
- if((!event || event.key == "Enter") && this.prompt.value){
- //setup object
- var updateObj = {};
- updateObj[this.field] = this.prompt.value;
+ async closePrompt(event){
+ //Call derived constructor and check if we're finished, assuming we're finished...
+ if(super.closePrompt(event)){
+ //Display
+ this.contentNode.style.display = 'inline-block';
- //contact server, and collect response
- var updated_content = (await utils.ajax.updateProfile(updateObj))[this.field];
+ //If we're not cancelling
+ if(event.key == "Enter"){
+ //Create empty update object
+ let updateObj = {};
- //Update label
- if(updated_content != null){
- if(this.field == "img"){
- this.content.src = updated_content;
- }else{
- this.content.innerHTML = updated_content;
- }
+ //Fill field
+ updateObj[this.field] = this.promptNode.value;
+
+ //Send er' off
+ const update = await utils.ajax.updateProfile(updateObj);
+
+ //Fill content from update
+ this.contentNode.innerHTML = update[this.field];
}
- this.finish();
- }else if(event.key == "Escape" || event.key == "Enter"){
- this.finish();
}
}
-
- finish(){
- this.prompt.replaceWith(this.content);
- }
}
-class profileTextEditPrompt extends profileEditPrompt{
- constructor(field, useTextArea = false){
- //Get content based on field name
- var content = document.querySelector(`#profile-${field}-content`);
- //Derived Constructor
- super(field, content, useTextArea);
- }
-
- prompt(){
- super.prompt();
- }
-
- async update(event){
- await super.update(event)
- }
-}
-
-//Child Classes
-class profileImgEditPrompt extends profileEditPrompt{
+class profileUpdateImagePrompt extends profileUpdatePrompt{
constructor(){
- //Get content based on field name
- var content = document.querySelector(`#profile-img`);
- //Derived constructor
- super("img", content, false);
+ //call derived constructor
+ super('img');
+ }
+
+ popPrompt(){
+ //Call derived method
+ super.popPrompt();
+
+ this.promptNode.placeholder = this.contentNode.src;
+ }
+
+ async closePrompt(event){
+ //Call derived constructor
+ super.closePrompt(event);
+
+ //If we're not cancelling
+ if(event.key == "Enter"){
+ //Create empty update object
+ let updateObj = {};
+
+ //Fill field
+ updateObj[this.field] = this.promptNode.value;
+
+ //Send er' off
+ const update = await utils.ajax.updateProfile(updateObj);
+
+ //Fill content from update
+ this.contentNode.src = update[this.field];
+ }
}
}
@@ -169,11 +190,11 @@ class tokeList{
}
toggleTokeList(){
- if(this.tokeList.checkVisibility()){
- this.tokeList.style.display = "none";
+ if(this.tokeList.style.visibility == "visible"){
+ this.tokeList.style.visibility = "collapse";
this.tokeListToggleIcon.classList.replace("bi-caret-down-fill","bi-caret-left-fill");
}else{
- this.tokeList.style.display = "block";
+ this.tokeList.style.visibility = "visible";
this.tokeListToggleIcon.classList.replace("bi-caret-left-fill","bi-caret-down-fill");
}
}
@@ -183,7 +204,9 @@ class deleteAccountButton{
constructor(){
this.deleteLink = document.querySelector('#account-settings-delete-button');
- this.setupInput();
+ if(this.deleteLink != null){
+ this.setupInput();
+ }
}
setupInput(){
@@ -218,9 +241,10 @@ class deleteAccountPopup{
}
//Object Instantiation
-new profileTextEditPrompt("signature");
-new profileTextEditPrompt("bio", true);
-new profileImgEditPrompt();
-new tokeList();
-new passwordResetPrompt();
-new deleteAccountButton();
\ No newline at end of file
+const imgPrompt = new profileUpdateImagePrompt();
+const pronounsPrompt = new profileUpdateTextPrompt('pronouns');
+const signaturePrompt = new profileUpdateTextPrompt('signature');
+const bioPrompt = new profileUpdateTextPrompt('bio', true);
+const profileTokeList = new tokeList();
+const accountPassResetPrompt = new passwordResetPrompt();
+const accountDeleteButton = new deleteAccountButton();
\ No newline at end of file