45cb4d260e
* Refactor the Settings page into a tabbed UI to reduce confusion with all the different forms and save buttons * Add a DM Privacy setting to your page * Update the About page
549 lines
25 KiB
HTML
549 lines
25 KiB
HTML
{{define "title"}}User Settings{{end}}
|
|
{{define "content"}}
|
|
<div class="container">
|
|
<section class="hero is-info is-bold">
|
|
<div class="hero-body">
|
|
<div class="container">
|
|
<h1 class="title">User Settings</h1>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{{ $User := .CurrentUser }}
|
|
|
|
<div class="block p-4">
|
|
<div class="tabs is-boxed">
|
|
<ul>
|
|
<li class="is-active">
|
|
<a href="/settings#profile" class="nonshy-tab-button">
|
|
Profile
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="/settings#prefs" class="nonshy-tab-button">
|
|
Preferences
|
|
</a>
|
|
</li>
|
|
|
|
<li>
|
|
<a href="/settings#account" class="nonshy-tab-button">
|
|
Account
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="card" id="profile">
|
|
<header class="card-header has-background-link">
|
|
<p class="card-header-title has-text-light">
|
|
<i class="fa fa-user pr-2"></i>
|
|
My Profile
|
|
</p>
|
|
</header>
|
|
|
|
<form method="POST" action="/settings">
|
|
<input type="hidden" name="intent" value="profile">
|
|
{{InputCSRF}}
|
|
|
|
<div class="card-content">
|
|
<p class="block">
|
|
The fields here are shown on your <a href="/u/{{.CurrentUser.Username}}">profile page</a>
|
|
and are all optional. Fields with a <i class="fa fa-lock"></i> icon are not shown on
|
|
your page but may drive some data that is (e.g., your current age derived from your birthdate).
|
|
</p>
|
|
|
|
<div class="columns">
|
|
<div class="column field is-half">
|
|
<label class="label" for="display_name">Display Name</label>
|
|
<input type="text" class="input"
|
|
id="display_name"
|
|
name="display_name"
|
|
placeholder="John Doe"
|
|
value="{{or $User.Name ""}}">
|
|
</div>
|
|
|
|
<div class="column field is-half">
|
|
<label class="label" for="dob">Birthdate <i class="fa fa-lock"></i></label>
|
|
<input type="date" class="input{{if not $User.Birthdate.IsZero}} cursor-not-allowed{{end}}"
|
|
id="dob"
|
|
name="dob"
|
|
value="{{if not $User.Birthdate.IsZero}}{{$User.Birthdate.Format "2006-01-02"}}{{end}}"
|
|
required
|
|
{{if not $User.Birthdate.IsZero}}readonly{{end}}>
|
|
<p class="help">
|
|
Used to show your age on your profile.
|
|
{{if not $User.Birthdate.IsZero}}
|
|
If you entered a wrong birthdate, <a href="/contact">contact</a> support to change it.
|
|
{{end}}
|
|
</p>
|
|
|
|
<!-- Don't show age checkbox -->
|
|
<label class="checkbox">
|
|
<input type="checkbox"
|
|
name="hide_age"
|
|
value="true"
|
|
{{if eq ($User.GetProfileField "hide_age") "true"}}checked{{end}}>
|
|
Don't show my age on my profile
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="columns">
|
|
<div class="column field is-half">
|
|
<label class="label" for="gender">Gender</label>
|
|
<div class="select is-fullwidth">
|
|
<select id="gender" name="gender">
|
|
<option value="">No answer</option>
|
|
{{range .Enum.Gender}}
|
|
<option value="{{.}}"{{if eq ($User.GetProfileField "gender") .}} selected{{end}}>{{.}}</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column field is-half">
|
|
<label class="label" for="pronouns">Pronouns</label>
|
|
<input type="text" class="input"
|
|
id="pronouns"
|
|
name="pronouns"
|
|
maxlength="30"
|
|
value="{{$User.GetProfileField "pronouns"}}">
|
|
<p class="help">e.g. he/him; she/her</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="columns">
|
|
<div class="column field is-half">
|
|
<label class="label" for="city">City/Location</label>
|
|
<input type="text" class="input"
|
|
id="city"
|
|
name="city"
|
|
value="{{$User.GetProfileField "city"}}">
|
|
</div>
|
|
|
|
|
|
<div class="column field is-half">
|
|
<label class="label" for="job">Job/Occupation</label>
|
|
<input type="text" class="input"
|
|
id="job"
|
|
name="job"
|
|
value="{{$User.GetProfileField "job"}}">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="columns">
|
|
<div class="column field is-half">
|
|
<label class="label" for="marital_status">Marital Status</label>
|
|
<div class="select is-fullwidth">
|
|
<select id="marital_status" name="marital_status">
|
|
<option value="">No answer</option>
|
|
{{range .Enum.MaritalStatus}}
|
|
<option value="{{.}}"{{if eq ($User.GetProfileField "marital_status") .}} selected{{end}}>{{.}}</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column field is-half">
|
|
<label class="label" for="relationship_type">Relationship Type</label>
|
|
<div class="select is-fullwidth">
|
|
<select id="relationship_type" name="relationship_type">
|
|
<option value="">No answer</option>
|
|
{{range .Enum.RelationshipType}}
|
|
<option value="{{.}}"{{if eq ($User.GetProfileField "relationship_type") .}} selected{{end}}>{{.}}</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="columns">
|
|
<div class="column field is-half">
|
|
<label class="label" for="orientation">Orientation</label>
|
|
<div class="select is-fullwidth">
|
|
<select id="orientation" name="orientation">
|
|
<option value="">No answer</option>
|
|
{{range .Enum.Orientation}}
|
|
<option value="{{.}}"{{if eq ($User.GetProfileField "orientation") .}} selected{{end}}>{{.}}</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label class="label">Here For</label>
|
|
<div class="columns is-multiline pb-5">
|
|
{{range .Enum.HereFor}}
|
|
<div class="column is-one-third pb-0">
|
|
<label class="checkbox">
|
|
<input type="checkbox"
|
|
name="here_for"
|
|
value="{{.}}"
|
|
{{if $User.ProfileFieldIn "here_for" .}}checked{{end}}>
|
|
{{.}}
|
|
</label>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label class="label" for="about_me">About Me</label>
|
|
<textarea class="textarea" cols="60" rows="4"
|
|
id="about_me"
|
|
name="about_me"
|
|
placeholder="A little blurb about myself">{{$User.GetProfileField "about_me"}}</textarea>
|
|
<p class="help">
|
|
Write a bit about yourself. <a href="/markdown" target="_blank">Markdown formatting</a> is supported here.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label class="label" for="interests">My Interests</label>
|
|
<textarea class="textarea" cols="60" rows="4"
|
|
id="interests"
|
|
name="interests"
|
|
placeholder="What kinds of things make you curious?">{{$User.GetProfileField "interests"}}</textarea>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label class="label" for="music_movies">Music/Bands/Movies</label>
|
|
<textarea class="textarea" cols="60" rows="4"
|
|
id="music_movies"
|
|
name="music_movies"
|
|
placeholder="What is your style of music or movie?">{{$User.GetProfileField "music_movies"}}</textarea>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<button type="submit" class="button is-primary">
|
|
Save Profile Settings
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Website Preferences -->
|
|
<form method="POST" action="/settings">
|
|
<input type="hidden" name="intent" value="preferences">
|
|
{{InputCSRF}}
|
|
|
|
<div class="card mb-5" id="prefs">
|
|
<header class="card-header has-background-success">
|
|
<p class="card-header-title has-text-dark-dark">
|
|
<i class="fa fa-square-check pr-2"></i>
|
|
Website Preferences
|
|
</p>
|
|
</header>
|
|
|
|
<div class="card-content">
|
|
<div class="field">
|
|
<label class="label">Profile Visibility</label>
|
|
<label class="checkbox">
|
|
<input type="radio"
|
|
name="visibility"
|
|
value="public"
|
|
{{if eq .CurrentUser.Visibility "public"}}checked{{end}}>
|
|
Public + Login Required
|
|
<i class="fa fa-eye ml-2 has-text-info"></i>
|
|
</label>
|
|
<p class="help">
|
|
The default is that users must be logged-in to even look at your profile
|
|
page. If your profile URL (/u/{{.CurrentUser.Username}}) is visited by a
|
|
logged-out browser, they are prompted to log in.
|
|
</p>
|
|
|
|
<label class="checkbox mt-2">
|
|
<input type="radio"
|
|
name="visibility"
|
|
value="external"
|
|
{{if eq .CurrentUser.Visibility "external"}}checked{{end}}>
|
|
Public + Limited Logged-out View
|
|
<i class="fa fa-eye ml-2 has-text-danger"></i>
|
|
</label>
|
|
<p class="help">
|
|
Your profile is fully visible to logged-in users, but if a logged-out browser
|
|
visits your page they will see a very minimal view: only your profile picture
|
|
and display name are shown.
|
|
<a href="/u/{{.CurrentUser.Username}}?view=external" target="_blank">Preview <i class="fa fa-external-link"></i></a>
|
|
</p>
|
|
|
|
<label class="checkbox mt-2">
|
|
<input type="radio"
|
|
name="visibility"
|
|
value="private"
|
|
{{if eq .CurrentUser.Visibility "private"}}checked{{end}}>
|
|
Mark my profile page as "private"
|
|
<i class="fa fa-lock ml-2 has-text-private"></i>
|
|
</label>
|
|
<p class="help">
|
|
If you check this box then only friends who you have approved are able to
|
|
see your profile page and gallery. Your gallery photos also will NOT appear
|
|
on the Site Gallery page. If your profile page is visited by a logged-out
|
|
viewer, they are prompted to log in.
|
|
</p>
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<div class="field">
|
|
<label class="label">Explicit Content Filter</label>
|
|
<label class="checkbox">
|
|
<input type="checkbox"
|
|
name="explicit"
|
|
value="true"
|
|
{{if .CurrentUser.Explicit}}checked{{end}}>
|
|
Show explicit content <i class="fa fa-fire has-text-danger ml-1"></i>
|
|
</label>
|
|
<p class="help">
|
|
Check this box if you are OK seeing explicit content on this site, which may
|
|
include erections or sexually charged content. These may appear on the Site
|
|
Gallery as well as user profile pages.
|
|
</p>
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<div class="field">
|
|
<label class="label mb-0">Who can send me the first <i class="fa fa-envelope"></i> Message?</label>
|
|
|
|
<div class="has-text-warning ml-4">
|
|
<small><em>
|
|
Note: this refers to Direct Messages on the main website
|
|
(not inside the chat room).
|
|
</em></small>
|
|
{{.CurrentUser.GetProfileField "dm_privacy"}}
|
|
</div>
|
|
|
|
<label class="checkbox">
|
|
<input type="radio"
|
|
name="dm_privacy"
|
|
value=""
|
|
{{if eq (.CurrentUser.GetProfileField "dm_privacy") ""}}checked{{end}}>
|
|
Anybody on the site
|
|
</label>
|
|
<p class="help">
|
|
Almost any member of the site may send you a Direct Message from your profile
|
|
page (except for maybe <a href="/faq#shy-faqs" target="_blank">Shy Accounts</a>).
|
|
</p>
|
|
|
|
<label class="checkbox">
|
|
<input type="radio"
|
|
name="dm_privacy"
|
|
value="friends"
|
|
{{if eq (.CurrentUser.GetProfileField "dm_privacy") "friends"}}checked{{end}}>
|
|
Only people on my Friends list
|
|
</label>
|
|
<p class="help">
|
|
Nobody can slide into your DMs except for friends (and admins if needed). Anybody
|
|
may <em>reply</em> to messages that you send to them.
|
|
</p>
|
|
|
|
<label class="checkbox">
|
|
<input type="radio"
|
|
name="dm_privacy"
|
|
value="nobody"
|
|
{{if eq (.CurrentUser.GetProfileField "dm_privacy") "nobody"}}checked{{end}}>
|
|
Nobody (close my DMs)
|
|
</label>
|
|
<p class="help">
|
|
Nobody can start a Direct Message conversation with you on the main website
|
|
(except an admin if necessary). Anybody may <em>reply</em> to messages that you
|
|
sent to them first.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- TODO: manually opt-in dark mode is hairy, look at
|
|
those media queries in bulma-prefers-dark.js!
|
|
<div class="field">
|
|
<label class="label">Website Theme</label>
|
|
<label class="checkbox">
|
|
<input type="radio"
|
|
name="theme"
|
|
value=""
|
|
{{if eq ($User.GetProfileField "theme") "" }}checked{{end}}>
|
|
Automatic
|
|
</label>
|
|
<p class="help">
|
|
Automatically chooses a theme based on your device settings.
|
|
</p>
|
|
|
|
<label class="checkbox">
|
|
<input type="radio"
|
|
name="theme"
|
|
value="light"
|
|
{{if eq ($User.GetProfileField "theme") "light" }}checked{{end}}>
|
|
Light
|
|
</label>
|
|
|
|
<label class="checkbox">
|
|
<input type="radio"
|
|
name="theme"
|
|
value="dark"
|
|
{{if eq ($User.GetProfileField "theme") "dark" }}checked{{end}}>
|
|
Dark
|
|
</label>
|
|
</div>
|
|
-->
|
|
|
|
<div class="field">
|
|
<button type="submit" class="button is-primary">
|
|
Save Website Preferences
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- Account Settings -->
|
|
<div id="account">
|
|
<form method="POST" action="/settings">
|
|
<input type="hidden" name="intent" value="settings">
|
|
{{InputCSRF}}
|
|
|
|
<div class="card mb-5">
|
|
<header class="card-header has-background-warning">
|
|
<p class="card-header-title has-text-dark-dark">
|
|
<i class="fa fa-gear pr-2"></i>
|
|
Account Settings
|
|
</p>
|
|
</header>
|
|
|
|
<div class="card-content">
|
|
<div class="field">
|
|
<label class="label" for="old_password">
|
|
Current Password
|
|
</label>
|
|
<input type="password" class="input"
|
|
name="old_password"
|
|
id="old_password"
|
|
placeholder="Current password"
|
|
required>
|
|
<p class="help">
|
|
Enter your current password before making any changes to your
|
|
email address or setting a new password.
|
|
</p>
|
|
</div>
|
|
<div class="field">
|
|
<label class="label" for="change_email">Change Email</label>
|
|
<input type="email" class="input"
|
|
id="change_email"
|
|
name="change_email"
|
|
placeholder="name@domain.com"
|
|
value="{{.CurrentUser.Email}}">
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label class="label">Change Password</label>
|
|
<input type="password" class="input mb-2"
|
|
name="new_password"
|
|
placeholder="New password">
|
|
<input type="password" class="input mb-2"
|
|
name="new_password2"
|
|
placeholder="Confirm new password">
|
|
</div>
|
|
|
|
<div class="field">
|
|
<button type="submit" class="button is-primary">
|
|
Save Account Settings
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- Delete Account -->
|
|
<div class="card mb-5">
|
|
<header class="card-header has-background-danger">
|
|
<p class="card-header-title has-text-light">
|
|
<i class="fa fa-gear pr-2"></i>
|
|
Delete Account
|
|
</p>
|
|
</header>
|
|
|
|
<div class="card-content">
|
|
<p class="block">
|
|
If you would like to delete your account, please click
|
|
on the button below.
|
|
</p>
|
|
|
|
<p class="block">
|
|
<a href="/account/delete" class="button is-danger">
|
|
Delete My Account
|
|
</a>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
{{define "scripts"}}
|
|
<script>
|
|
window.addEventListener("DOMContentLoaded", (event) => {
|
|
// The tabs
|
|
const $profile = document.querySelector("#profile"),
|
|
$prefs = document.querySelector("#prefs"),
|
|
$account = document.querySelector("#account")
|
|
buttons = Array.from(document.getElementsByClassName("nonshy-tab-button"));
|
|
|
|
// Hide all by default.
|
|
$profile.style.display = 'none';
|
|
$prefs.style.display = 'none';
|
|
$account.style.display = 'none';
|
|
|
|
// Current tab to select by default.
|
|
let $activeTab = $profile;
|
|
|
|
// Global function to toggle the active tab.
|
|
const showTab = (name) => {
|
|
name = name.replace(/\.$/, '');
|
|
if (!name) name = "profile";
|
|
$activeTab.style.display = 'none';
|
|
switch (name) {
|
|
case "prefs":
|
|
$activeTab = $prefs;
|
|
break
|
|
case "account":
|
|
$activeTab = $account;
|
|
break
|
|
default:
|
|
$activeTab = $profile;
|
|
}
|
|
|
|
// Update the is-active classes on all the tabs.
|
|
buttons.forEach(tab_ => {
|
|
let name_ = tab_.href.split("#").pop(),
|
|
parent = tab_.parentElement;
|
|
|
|
if (name !== name_) {
|
|
console.log("button: remove is-active", tab_);
|
|
parent.classList.remove("is-active");
|
|
} else {
|
|
console.log("button %s: ADD is-active", tab_);
|
|
parent.classList.add("is-active");
|
|
}
|
|
});
|
|
|
|
$activeTab.style.display = 'block';
|
|
history.replaceState(undefined, undefined, '#'+name);
|
|
};
|
|
|
|
// Wire the tab buttons up.
|
|
buttons.forEach(el => {
|
|
let name = el.href.split("#").pop();
|
|
el.addEventListener("click", (e) => {
|
|
showTab(name);
|
|
|
|
e.preventDefault();
|
|
});
|
|
})
|
|
|
|
|
|
showTab(window.location.hash.replace(/^#/, ''));
|
|
});
|
|
</script>
|
|
{{end}}
|