563 lines
27 KiB
HTML
563 lines
27 KiB
HTML
{{define "title"}}People{{end}}
|
|
{{define "content"}}
|
|
<div class="container">
|
|
{{$Root := .}}
|
|
<section class="hero is-link is-bold">
|
|
<div class="hero-body">
|
|
<div class="container">
|
|
<h1 class="title">
|
|
{{if eq .Sort "distance"}}
|
|
<i class="fa fa-location-dot mr-2"></i>
|
|
Who's Nearby
|
|
{{else}}
|
|
<i class="fa fa-people-group mr-2"></i>
|
|
People
|
|
{{end}}
|
|
</h1>
|
|
<h2 class="subtitle">Member Directory</h2>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<form action="/members" method="GET">
|
|
<div class="p-4">
|
|
|
|
<div class="columns">
|
|
<div class="column">
|
|
Found {{FormatNumberCommas .Pager.Total}} user{{Pluralize64 .Pager.Total}}
|
|
(page {{.Pager.Page}} of {{.Pager.Pages}}).
|
|
</div>
|
|
</div>
|
|
|
|
{{if .FriendSearch}}
|
|
<div class="notification is-success is-light">
|
|
Currently searching within your <i class="fa fa-user-group"></i> Friends list.
|
|
</div>
|
|
{{else if eq .Sort "distance"}}
|
|
<div class="notification is-success is-light content">
|
|
<p>
|
|
Showing you <i class="fa fa-location-dot mr-1"></i> <strong>Who's Nearby.</strong>
|
|
</p>
|
|
|
|
<!-- Was it a manual city search? -->
|
|
{{if .City}}
|
|
<!-- If the current user has no location set, lead the way. -->
|
|
{{if not .MyLocation.Source}}
|
|
<p>
|
|
You will need to <a href="/settings#location">set your own location</a> first before you can search for other members by
|
|
their location. It's only fair!
|
|
</p>
|
|
{{else}}
|
|
<p>
|
|
You are searching for profiles near {{.City}}.
|
|
</p>
|
|
{{end}}
|
|
{{else}}
|
|
<!-- Show options to refresh their location -->
|
|
<p>
|
|
{{if eq .MyLocation.Source "geoip"}}
|
|
You had set your location to update automatically by your IP address <small>(currently {{.GeoIPInsights.Short}}).</small>
|
|
<a href="/settings#location">Change your location settings?</a>
|
|
{{else if eq .MyLocation.Source "gps"}}
|
|
You once set your location via your device's GPS coordinates.
|
|
<a href="/settings#location" id="gpsRefresh">Refresh to your current location now?</a>
|
|
{{else if eq .MyLocation.Source "pin"}}
|
|
You had set your location by dropping a pin on a map.
|
|
<a href="/settings#location">Update your location?</a>
|
|
{{else if eq .MyLocation.Source ""}}
|
|
You will need to <a href="/settings#location">set your location</a> first before we can sort people by distance from you.
|
|
{{end}}
|
|
</p>
|
|
{{end}}
|
|
</div>
|
|
{{else if eq .Certified "shy"}}
|
|
<div class="notification is-success is-light content">
|
|
<p>
|
|
Showing you <i class="fa fa-ghost"></i> <strong>Shy Accounts</strong>. These profiles may be marked as private or
|
|
have no photo available to you, as all of theirs are set to 'friends-only' or 'private.'
|
|
</p>
|
|
|
|
<p>
|
|
Shy Accounts are limited in the way they can interact with our non-shy members.
|
|
<a href="/faq#shy-faqs" target="_blank">Learn more <i class="fa fa-external-link"></i></a>
|
|
</p>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Restricted search terms -->
|
|
{{if .RestrictedSearchError}}
|
|
<div class="notification is-danger is-light content">
|
|
<p>
|
|
<i class="fa fa-hand mr-1"></i>
|
|
<strong>Child sexual abuse is illegal</strong>
|
|
</p>
|
|
|
|
<p>
|
|
We think that your search might be associated with child sexual abuse. Child sexual abuse or seeking
|
|
sexual imagery or contact with children can lead to imprisonment and other severe personal consequences,
|
|
and this abuse causes extreme harm to children and searching and viewing such material adds to that harm.
|
|
</p>
|
|
|
|
<p>
|
|
It is also against the <a href="/tos#child-exploitation">Terms of Service</a> of this website, and
|
|
members who violate this rule will be banned. This website is actively monitored to keep on top of this stuff,
|
|
and we cooperate enthusiastically with
|
|
<a href="https://www.missingkids.org/" title="National Center for Missing and Exploited Children">NCMEC</a>
|
|
and relevant law enforcement agencies.
|
|
</p>
|
|
</div>
|
|
{{end}}
|
|
|
|
<div class="block">
|
|
|
|
<div class="card nonshy-collapsible-mobile">
|
|
<header class="card-header has-background-link-light">
|
|
<p class="card-header-title has-text-dark">
|
|
Search Filters
|
|
</p>
|
|
<button class="card-header-icon" type="button">
|
|
<span class="icon">
|
|
<i class="fa fa-angle-up"></i>
|
|
</span>
|
|
</button>
|
|
</header>
|
|
<div class="card-content">
|
|
<div class="columns">
|
|
|
|
<div class="column pr-1">
|
|
<div class="field">
|
|
<label class="label" for="certified">Status:</label>
|
|
<div class="select is-fullwidth">
|
|
<select id="certified" name="certified" id="certified">
|
|
<optgroup label="Certification Status">
|
|
<option value="true">All certified members</option>
|
|
{{if .CurrentUser.IsAdmin}}
|
|
<option value="false"{{if eq $Root.Certified "false"}} selected{{end}}>☮ Non-certified only</option>
|
|
<option value="all"{{if eq $Root.Certified "all"}} selected{{end}}>☮ Show all users</option>
|
|
{{end}}
|
|
</optgroup>
|
|
<optgroup label="Profile Status">
|
|
<option value="shy"{{if eq $Root.Certified "shy"}} selected{{end}}>Shy Accounts</option>
|
|
<option value="admin"{{if eq $Root.Certified "admin"}} selected{{end}}>Website administrators</option>
|
|
</optgroup>
|
|
{{if .CurrentUser.HasAdminScope "admin.user.ban"}}
|
|
<optgroup label="Admin Options">
|
|
<option value="banned"{{if eq $Root.Certified "banned"}} selected{{end}}>☮ Banned</option>
|
|
<option value="disabled"{{if eq $Root.Certified "disabled"}} selected{{end}}>☮ Disabled</option>
|
|
</optgroup>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column px-1">
|
|
<div class="field">
|
|
<label class="label" for="name">Name or username:</label>
|
|
<input type="text" class="input"
|
|
name="name" id="name"
|
|
autocomplete="off"
|
|
value="{{$Root.EmailOrUsername}}">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column px-1">
|
|
<div class="field">
|
|
<label class="label" for="search">Profile text:</label>
|
|
<input type="text" class="input"
|
|
name="search" id="search"
|
|
autocomplete="off"
|
|
value="{{$Root.Search}}">
|
|
<p class="help">
|
|
Tip: you can <span class="has-text-success">"quote exact phrases"</span> and
|
|
<span class="has-text-success">-exclude</span> words (or
|
|
<span class="has-text-success">-"exclude phrases"</span>) from your search.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column pl-1">
|
|
<div class="field">
|
|
<label class="label" for="wcs">Location: <span class="tag is-success">New!</span></label>
|
|
<input type="text" class="input"
|
|
name="wcs" id="wcs"
|
|
autocomplete="off"
|
|
value="{{$Root.City}}">
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<div class="columns is-centered">
|
|
|
|
<div class="column pr-1">
|
|
<div class="field">
|
|
<label class="label">Age:</label>
|
|
<div class="columns is-mobile is-gapless">
|
|
<div class="column">
|
|
<div class="select is-fullwidth">
|
|
<select name="age_min">
|
|
<option value="">Min</option>
|
|
{{range IterRange 18 120}}
|
|
<option value="{{.}}"{{if eq $Root.AgeMin .}} selected{{end}}>{{.}}</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="column">
|
|
<div class="select is-fullwidth">
|
|
<select name="age_max">
|
|
<option value="">Max</option>
|
|
{{range IterRange 18 120}}
|
|
<option value="{{.}}"{{if eq $Root.AgeMax .}} selected{{end}}>{{.}}</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column px-1">
|
|
<div class="field">
|
|
<label class="label" for="gender">Gender:</label>
|
|
<div class="select is-fullwidth">
|
|
<select id="gender" name="gender">
|
|
<option value=""></option>
|
|
{{range .Enum.Gender}}
|
|
<option value="{{.}}"{{if eq $Root.Gender .}} selected{{end}}>{{.}}</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column px-1">
|
|
<div class="field">
|
|
<label class="label" for="orientation">Orientation:</label>
|
|
<div class="select is-fullwidth">
|
|
<select id="orientation" name="orientation">
|
|
<option value=""></option>
|
|
{{range .Enum.Orientation}}
|
|
<option value="{{.}}"{{if eq $Root.Orientation .}} selected{{end}}>{{.}}</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column pl-1">
|
|
<div class="field">
|
|
<label class="label" for="marital_status">Relationship:</label>
|
|
<div class="select is-fullwidth">
|
|
<select id="marital_status" name="marital_status">
|
|
<option value=""></option>
|
|
{{range .Enum.MaritalStatus}}
|
|
<option value="{{.}}"{{if eq $Root.MaritalStatus .}} selected{{end}}>{{.}}</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<div class="columns is-centered">
|
|
|
|
<div class="column pr-1">
|
|
<div class="field">
|
|
<label class="label" for="here_for">Here for:</label>
|
|
<div class="select is-fullwidth">
|
|
<select id="here_for" name="here_for">
|
|
<option value=""></option>
|
|
{{range .Enum.HereFor}}
|
|
<option value="{{.}}"{{if eq $Root.HereFor .}} selected{{end}}>{{.}}</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column px-1">
|
|
<div class="field">
|
|
<label class="label" for="friends">Miscellanous:</label>
|
|
<label class="checkbox">
|
|
<input type="checkbox"
|
|
name="friends"
|
|
id="friends"
|
|
value="true"
|
|
{{if .FriendSearch}}checked{{end}}>
|
|
Show only my friends
|
|
</label>
|
|
<label class="checkbox">
|
|
<input type="checkbox"
|
|
name="liked"
|
|
id="liked"
|
|
value="true"
|
|
{{if .LikedSearch}}checked{{end}}>
|
|
Show only my "Likes"
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column px-1">
|
|
<div class="field">
|
|
<label class="label" for="sort">Sort by:</label>
|
|
<div class="select is-fullwidth">
|
|
<select id="sort" name="sort">
|
|
<option value="last_login_at desc"{{if eq .Sort "last_login_at desc"}} selected{{end}}>Last login</option>
|
|
<option value="created_at desc"{{if eq .Sort "created_at desc"}} selected{{end}}>Signup date</option>
|
|
<option value="certified_at desc"{{if eq .Sort "certification_photos.updated_at desc"}} selected{{end}}>Certified date</option>
|
|
<option value="username"{{if eq .Sort "username"}} selected{{end}}>Username (a-z)</option>
|
|
<option value="username desc"{{if eq .Sort "username desc"}} selected{{end}}>Username (z-a)</option>
|
|
<option value="lower(name)"{{if eq .Sort "lower(name)"}} selected{{end}}>Name (a-z)</option>
|
|
<option value="lower(name) desc"{{if eq .Sort "lower(name) desc"}} selected{{end}}>Name (z-a)</option>
|
|
<option value="distance"{{if eq .Sort "distance"}} selected{{end}}>Distance to me</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="column pl-1 has-text-right">
|
|
<a href="/members" class="button">Reset</a>
|
|
<button type="submit" class="button is-success">
|
|
<span>Search</span>
|
|
<span class="icon"><i class="fa fa-search"></i></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{{SimplePager .Pager}}
|
|
|
|
<div class="columns is-multiline">
|
|
|
|
{{range .Users}}
|
|
<div class="column is-half-tablet is-one-third-desktop">
|
|
|
|
<div class="card">
|
|
<div class="card-content">
|
|
<div class="media block">
|
|
<div class="media-left">
|
|
{{template "avatar-64x64" .}}
|
|
|
|
<!-- Friendship badge -->
|
|
{{if $Root.FriendMap.Get .ID}}
|
|
<div>
|
|
<span class="is-size-7 has-text-warning">
|
|
<i class="fa fa-user-group" title="Friends"></i>
|
|
Friends
|
|
</span>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Liked badge -->
|
|
{{$LikedStats := $Root.LikedMap.Get .ID}}
|
|
{{if $LikedStats.UserLikes}}
|
|
<div>
|
|
<span class="is-size-7">
|
|
<i class="fa fa-heart has-text-danger" title="Friends"></i>
|
|
Liked
|
|
</span>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
<div class="media-content">
|
|
<p class="title is-4">
|
|
<a href="/u/{{.Username}}" class="has-text-dark">
|
|
{{if ne .Status "active"}}
|
|
<del>{{.NameOrUsername}}</del>
|
|
{{else}}
|
|
{{.NameOrUsername}}
|
|
{{end}}
|
|
</a>
|
|
{{if eq .Visibility "private"}}
|
|
<sup class="fa fa-mask is-size-7" title="Private Profile"></sup>
|
|
{{end}}
|
|
</p>
|
|
<p class="subtitle is-6 mb-2">
|
|
<span class="icon"><i class="fa fa-user"></i></span>
|
|
<a href="/u/{{.Username}}">{{.Username}}</a>
|
|
|
|
<!-- Not Certified or Shy Account badge -->
|
|
{{if not .Certified}}
|
|
<span class="has-text-danger is-size-7">
|
|
<i class="fa fa-certificate"></i>
|
|
<span>Not Certified!</span>
|
|
</span>
|
|
{{else if $Root.ShyMap.Get .ID}}
|
|
<span class="has-text-danger is-size-7">
|
|
<i class="fa fa-ghost"></i>
|
|
<span>Shy Account</span>
|
|
</span>
|
|
{{end}}
|
|
|
|
<!-- "(banned)" label -->
|
|
{{if ne .Status "active"}}<small>({{.Status}})</small>{{end}}
|
|
|
|
{{if .IsAdmin}}
|
|
<span class="tag is-danger is-light p-1" style="font-size: x-small">
|
|
<i class="fa fa-peace mr-1"></i>
|
|
<span>Admin</span>
|
|
</span>
|
|
{{end}}
|
|
|
|
<!-- Photo count pulled to the right -->
|
|
<a href="/u/{{.Username}}/photos" class="tag is-info is-light is-pulled-right">
|
|
<i class="fa fa-camera mr-2"></i>
|
|
{{$Root.PhotoCountMap.Get .ID}}
|
|
</a>
|
|
</p>
|
|
{{if .GetProfileField "city"}}
|
|
<p class="subtitle is-6 mb-2">
|
|
{{.GetProfileField "city"}}
|
|
</p>
|
|
{{end}}
|
|
<p class="subtitle is-7 mb-2">
|
|
{{if or (ne .GetDisplayAge "n/a")}}
|
|
<span class="mr-2">{{.GetDisplayAge}}</span>
|
|
{{end}}
|
|
|
|
{{if .GetProfileField "gender"}}
|
|
<span class="mr-2">{{.GetProfileField "gender"}}</span>
|
|
{{end}}
|
|
|
|
{{if .GetProfileField "pronouns"}}
|
|
<span class="mr-2">{{.GetProfileField "pronouns"}}</span>
|
|
{{end}}
|
|
|
|
{{if .GetProfileField "orientation"}}
|
|
<span class="mr-2">{{.GetProfileField "orientation"}}</span>
|
|
{{end}}
|
|
|
|
<!-- Chat room status -->
|
|
{{if $Root.UserOnChatMap.Get .Username}}
|
|
<div>
|
|
<span class="tag is-success is-light">
|
|
<i class="fa fa-user mr-2"></i>
|
|
Currently on chat!
|
|
</span>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Show a subfooter based on ordered by -->
|
|
{{if eq $Root.Sort "last_login_at desc"}}
|
|
<div>
|
|
<small>
|
|
Last logged in:
|
|
<span title="On {{.LastLoginAt.Format "Jan _2 2006 15:04:05 MST"}}">
|
|
{{SincePrettyCoarse .LastLoginAt}} ago
|
|
</span>
|
|
</small>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if or (eq $Root.Sort "created_at desc") (eq $Root.Sort "certification_photos.updated_at desc")}}
|
|
<div>
|
|
<small>
|
|
Member since:
|
|
<span title="On {{.CreatedAt.Format "Jan _2 2006 15:04:05 MST"}}">
|
|
{{SincePrettyCoarse .CreatedAt}} ago
|
|
</span>
|
|
</small>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Ordered by distance? -->
|
|
{{if eq $Root.Sort "distance"}}
|
|
<div>
|
|
{{$Root.DistanceMap.Get .ID}} away
|
|
</div>
|
|
{{end}}
|
|
</p>
|
|
</div>
|
|
</div><!-- media-block -->
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
{{end}}<!-- range .Friends -->
|
|
</div>
|
|
|
|
{{SimplePager .Pager}}
|
|
|
|
</div>
|
|
</form>
|
|
</div>
|
|
{{end}}
|
|
{{define "scripts"}}
|
|
|
|
<!-- Typeahead search for City -->
|
|
<script type="text/javascript" src="/static/js/jquery-3.7.1.min.js"></script>
|
|
<script type="text/javascript" src="/static/js/typeahead.bundle.js"></script>
|
|
<script type="text/javascript">
|
|
document.addEventListener('DOMContentLoaded', (e) => {
|
|
let backend = new Bloodhound({
|
|
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
|
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
|
remote: {
|
|
url: '/v1/world-cities?query=%QUERY',
|
|
wildcard: '%QUERY'
|
|
},
|
|
});
|
|
|
|
let $searchField = $("#wcs");
|
|
$searchField.typeahead({
|
|
autoselect: true
|
|
}, {
|
|
items: 4,
|
|
name: 'location',
|
|
displayKey: 'Canonical',
|
|
source: backend,
|
|
});
|
|
});
|
|
</script>
|
|
<style type="text/css">
|
|
/*****************************
|
|
* Twitter Typeahead Styling *
|
|
*****************************/
|
|
.twitter-typeahead {
|
|
width: 100%;
|
|
}
|
|
|
|
.tt-hint {
|
|
color: #999;
|
|
}
|
|
|
|
.tt-menu {
|
|
width: 300px;
|
|
margin-top: 4px;
|
|
padding: 4px 0;
|
|
background-color: #fff;
|
|
border: 1px solid #ccc;
|
|
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
-webkit-border-radius: 4px;
|
|
-moz-border-radius: 4px;
|
|
border-radius: 4px;
|
|
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
|
-moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
|
box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
|
}
|
|
|
|
.tt-suggestion {
|
|
padding: 3px 20px;
|
|
line-height: 24px;
|
|
color: #000;
|
|
}
|
|
|
|
.tt-suggestion:hover {
|
|
background-color: #ddd;
|
|
}
|
|
|
|
.tt-suggestion p {
|
|
margin: 0;
|
|
}
|
|
|
|
.tt-suggestion.tt-cursor {
|
|
color: #fff;
|
|
background-color: #0097cf;
|
|
|
|
}
|
|
</style>
|
|
{{end}} |