Minor design tweaks to the Follows page (#222)

* Filter outbound and inbound follows by active state
* Change pill appearance to distinguish it from buttons
* Signal destructive action when hovering unfollow buttons
* Add hover style to the top "tabs"/"filters"
* Make filters icon have the same width so selecting them doesn't change the options total width, which is mildly unnerving
This commit is contained in:
Gabriel Rodríguez Alberich 2022-12-21 20:57:14 +01:00 committed by GitHub
parent e2371a3cd7
commit 1349144e37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 16 deletions

View file

@ -63,7 +63,9 @@ class Follows(ListView):
) )
identity_ids = [identity.id for identity in context["page_obj"]] identity_ids = [identity.id for identity in context["page_obj"]]
context["outbound_ids"] = Follow.objects.filter( context["outbound_ids"] = Follow.objects.filter(
source=self.request.identity, target_id__in=identity_ids source=self.request.identity,
target_id__in=identity_ids,
state__in=FollowStates.group_active(),
).values_list("target_id", flat=True) ).values_list("target_id", flat=True)
else: else:
context["page_obj"].object_list = self.follows_to_identities( context["page_obj"].object_list = self.follows_to_identities(
@ -71,7 +73,9 @@ class Follows(ListView):
) )
identity_ids = [identity.id for identity in context["page_obj"]] identity_ids = [identity.id for identity in context["page_obj"]]
context["inbound_ids"] = Follow.objects.filter( context["inbound_ids"] = Follow.objects.filter(
target=self.request.identity, source_id__in=identity_ids target=self.request.identity,
source_id__in=identity_ids,
state__in=FollowStates.group_active(),
).values_list("source_id", flat=True) ).values_list("source_id", flat=True)
context["inbound"] = self.inbound context["inbound"] = self.inbound
context["num_inbound"] = Follow.objects.filter( context["num_inbound"] = Follow.objects.filter(

View file

@ -414,10 +414,11 @@ img.emoji {
.icon-menu .option .pill { .icon-menu .option .pill {
display: inline-block; display: inline-block;
padding: 5px 8px; padding: 2px 10px;
background: var(--color-highlight); background: var(--color-text-duller);
border-radius: 5px; border-radius: 20px;
margin: 0 5px 0 5px; margin: 0 5px 0 5px;
font-size: 70%;
} }
.icon-menu .option .pill.bad { .icon-menu .option .pill.bad {
@ -430,6 +431,16 @@ img.emoji {
margin: 14px 0 0 0; margin: 14px 0 0 0;
} }
.icon-menu .option .right {
display: inline-block;
float: right;
}
.icon-menu .option button {
margin-top: 8px;
margin-right: 20px;
}
.handle { .handle {
vertical-align: middle; vertical-align: middle;
display: inline-block; display: inline-block;
@ -466,26 +477,30 @@ form.inline {
padding: 0; padding: 0;
} }
form.follow { form.follow-profile {
float: right; float: right;
margin: 20px 0 0 0; margin: 20px 0 0 0;
font-size: 16px; font-size: 16px;
text-align: center; text-align: center;
} }
form.follow.has-reverse { form.follow-profile.has-reverse {
margin-top: 0; margin-top: 0;
} }
form.follow .reverse-follow { form.follow-profile .reverse-follow {
display: block; display: block;
margin: 0 0 5px 0; margin: 0 0 5px 0;
} }
form.follow button { form.follow-profile button {
margin: 0; margin: 0;
} }
form.follow {
display: inline;
}
form.search { form.search {
display: flex; display: flex;
margin: 0 0 20px 0; margin: 0 0 20px 0;
@ -721,6 +736,11 @@ button.danger,
background: var(--color-delete); background: var(--color-delete);
} }
button.destructive:hover,
.button.destructive:hover {
background: var(--color-delete);
}
button.secondary, button.secondary,
.button.secondary { .button.secondary {
background: var(--color-bg-menu); background: var(--color-bg-menu);
@ -889,14 +909,22 @@ table.metadata td .emoji {
.view-options a { .view-options a {
margin: 0 10px 0 0; margin: 0 10px 0 0;
padding: 4px 7px; padding: 4px 12px;
color: var(--color-text-duller); color: var(--color-text-duller);
background: var(--color-bg-box); background: var(--color-bg-box);
border-radius: 3px; border-radius: 3px;
} }
.view-options a:hover {
background: var(--color-text-dull);
}
.view-options a.selected { .view-options a.selected {
color: var(--color-text-main); color: var(--color-text-highlight);
}
.view-options .fa-solid {
min-width: 16px;
} }
/* Posts */ /* Posts */

View file

@ -22,13 +22,30 @@
{{ identity.html_name_or_handle }} {{ identity.html_name_or_handle }}
<small>@{{ identity.handle }}</small> <small>@{{ identity.handle }}</small>
</span> </span>
{% if identity.id in outbound_ids %} {% if identity.id in outbound_ids %}
<span class="pill">Following</span> <span class="pill">Following</span>
{% endif %} {% endif %}
{% if identity.id in inbound_ids %} {% if identity.id in inbound_ids %}
<span class="pill">Follows You</span> <span class="pill">Follows You</span>
{% endif %} {% endif %}
<time>{{ identity.follow_date | timedeltashort }} ago</time>
<div class="right">
{% if inbound %}
<form action="{{ identity.urls.action }}" method="POST" class="follow">
{% csrf_token %}
{% if identity.id in outbound_ids %}
<input type="hidden" name="action" value="unfollow">
<button class="destructive">Unfollow</button>
{% else %}
<input type="hidden" name="action" value="follow">
<button>Follow</button>
{% endif %}
</form>
{% endif %}
<time>{{ identity.follow_date | timedeltashort }} ago</time>
</div>
</a> </a>
{% empty %} {% empty %}
<p class="option empty">You have no follows.</p> <p class="option empty">You have no follows.</p>

View file

@ -24,14 +24,14 @@
<a class="button" href="{% url "settings_profile" %}">Edit Profile</a> <a class="button" href="{% url "settings_profile" %}">Edit Profile</a>
</form> </form>
{% else %} {% else %}
<form action="{{ identity.urls.action }}" method="POST" class="inline follow {% if reverse_follow %}has-reverse{% endif %}"> <form action="{{ identity.urls.action }}" method="POST" class="inline follow-profile {% if reverse_follow %}has-reverse{% endif %}">
{% csrf_token %} {% csrf_token %}
{% if reverse_follow %} {% if reverse_follow %}
<span class="reverse-follow">Follows You</span> <span class="reverse-follow">Follows You</span>
{% endif %} {% endif %}
{% if follow %} {% if follow %}
<input type="hidden" name="action" value="unfollow"> <input type="hidden" name="action" value="unfollow">
<button>Unfollow</button> <button class="destructive">Unfollow</button>
{% else %} {% else %}
<input type="hidden" name="action" value="follow"> <input type="hidden" name="action" value="follow">
<button>Follow</button> <button>Follow</button>
@ -76,7 +76,7 @@
<div class="stats"> <div class="stats">
<ul> <ul>
<li><strong>{{ following_count }}</strong> following</li> <li><strong>{{ following_count }}</strong> following</li>
<li><strong>{{ followers_count }}</strong> followers</li> <li><strong>{{ followers_count }}</strong> follower{{ followers_count|pluralize }}</li>
</ul> </ul>
</div> </div>
{% endif %} {% endif %}

View file

@ -13,7 +13,7 @@ def test_stats(client, identity, other_identity):
Follow.objects.create(source=other_identity, target=identity) Follow.objects.create(source=other_identity, target=identity)
Config.set_identity(identity, "visible_follows", True) Config.set_identity(identity, "visible_follows", True)
response = client.get(identity.urls.view) response = client.get(identity.urls.view)
assertContains(response, "<strong>1</strong> followers", status_code=200) assertContains(response, "<strong>1</strong> follower", status_code=200)
@pytest.mark.django_db @pytest.mark.django_db